@happyvertical/smrt-content 0.43.10 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/content-list.md +61 -5
- package/dist/chunks/{content-corrections-BxfA3tW1.js → content-corrections-B4mPd_th.js} +6 -3
- package/dist/chunks/content-corrections-B4mPd_th.js.map +1 -0
- package/dist/chunks/content-query-D1bLBzMT.js +4092 -0
- package/dist/chunks/{content-query-4w62u5_0.js.map → content-query-D1bLBzMT.js.map} +1 -1
- package/dist/chunks/{content-reviews-BWrYEQc6.js → content-reviews-lBoqJY7Y.js} +6 -3
- package/dist/chunks/content-reviews-lBoqJY7Y.js.map +1 -0
- package/dist/chunks/{content-versions-Di3vcTgb.js → content-versions-B0OUI1ut.js} +6 -3
- package/dist/chunks/content-versions-B0OUI1ut.js.map +1 -0
- package/dist/chunks/{contents-BV8RoP_R.js → contents-CRG2Snrb.js} +2 -2
- package/dist/chunks/{contents-BV8RoP_R.js.map → contents-CRG2Snrb.js.map} +1 -1
- package/dist/content-contribution.d.ts +1 -1
- package/dist/content-contribution.d.ts.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +33 -6
- package/dist/server/content-list-actions.d.ts +10 -3
- package/dist/server/content-list-actions.d.ts.map +1 -1
- package/dist/server/content-list-lifecycle.d.ts +20 -0
- package/dist/server/content-list-lifecycle.d.ts.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +189 -25
- package/dist/server.js.map +1 -1
- package/dist/smrt-knowledge.json +17 -5
- package/dist/svelte/components/ContentAgentChat.svelte +10 -0
- package/dist/svelte/components/ContentAgentChat.svelte.d.ts +10 -0
- package/dist/svelte/components/ContentAgentChat.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentBodyEditor.svelte +9 -0
- package/dist/svelte/components/ContentBodyEditor.svelte.d.ts +9 -0
- package/dist/svelte/components/ContentBodyEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentBodyRenderer.svelte +3 -0
- package/dist/svelte/components/ContentBodyRenderer.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentBodyRenderer.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentClaimAuditTool.svelte +3 -0
- package/dist/svelte/components/ContentClaimAuditTool.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentClaimAuditTool.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentContributionForm.svelte +7 -0
- package/dist/svelte/components/ContentContributionForm.svelte.d.ts +7 -0
- package/dist/svelte/components/ContentContributionForm.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentContributionInbox.svelte +8 -0
- package/dist/svelte/components/ContentContributionInbox.svelte.d.ts +8 -0
- package/dist/svelte/components/ContentContributionInbox.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentContributionPortal.svelte +5 -0
- package/dist/svelte/components/ContentContributionPortal.svelte.d.ts +5 -0
- package/dist/svelte/components/ContentContributionPortal.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentContributionTypeManager.svelte +3 -0
- package/dist/svelte/components/ContentContributionTypeManager.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentContributionTypeManager.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentContributorManager.svelte +3 -0
- package/dist/svelte/components/ContentContributorManager.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentContributorManager.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentCorrectionsTool.svelte +4 -0
- package/dist/svelte/components/ContentCorrectionsTool.svelte.d.ts +4 -0
- package/dist/svelte/components/ContentCorrectionsTool.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentEditor.svelte +16 -0
- package/dist/svelte/components/ContentEditor.svelte.d.ts +16 -0
- package/dist/svelte/components/ContentEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentGovernanceAssignmentEditor.svelte +4 -0
- package/dist/svelte/components/ContentGovernanceAssignmentEditor.svelte.d.ts +4 -0
- package/dist/svelte/components/ContentGovernanceAssignmentEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentGovernanceManager.svelte +3 -0
- package/dist/svelte/components/ContentGovernanceManager.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentGovernanceManager.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentGovernancePanel.svelte +16 -0
- package/dist/svelte/components/ContentGovernancePanel.svelte.d.ts +16 -0
- package/dist/svelte/components/ContentGovernancePanel.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentGovernancePolicyEditor.svelte +3 -0
- package/dist/svelte/components/ContentGovernancePolicyEditor.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentGovernancePolicyEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentGovernanceProfileEditor.svelte +4 -0
- package/dist/svelte/components/ContentGovernanceProfileEditor.svelte.d.ts +4 -0
- package/dist/svelte/components/ContentGovernanceProfileEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentGovernanceTool.svelte +5 -0
- package/dist/svelte/components/ContentGovernanceTool.svelte.d.ts +5 -0
- package/dist/svelte/components/ContentGovernanceTool.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentImageBrowser.svelte +10 -0
- package/dist/svelte/components/ContentImageBrowser.svelte.d.ts +10 -0
- package/dist/svelte/components/ContentImageBrowser.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentImageChooser.svelte +4 -0
- package/dist/svelte/components/ContentImageChooser.svelte.d.ts +4 -0
- package/dist/svelte/components/ContentImageChooser.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentList.svelte +201 -22
- package/dist/svelte/components/ContentList.svelte.d.ts +13 -0
- package/dist/svelte/components/ContentList.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentListLifecyclePanel.svelte +341 -0
- package/dist/svelte/components/ContentListLifecyclePanel.svelte.d.ts +17 -0
- package/dist/svelte/components/ContentListLifecyclePanel.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ContentMetadataFields.svelte +2 -0
- package/dist/svelte/components/ContentMetadataFields.svelte.d.ts +2 -0
- package/dist/svelte/components/ContentMetadataFields.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentReferencesPanel.svelte +3 -0
- package/dist/svelte/components/ContentReferencesPanel.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentReferencesPanel.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentReviewStatusTray.svelte +5 -0
- package/dist/svelte/components/ContentReviewStatusTray.svelte.d.ts +5 -0
- package/dist/svelte/components/ContentReviewStatusTray.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentStatusFields.svelte +2 -0
- package/dist/svelte/components/ContentStatusFields.svelte.d.ts +2 -0
- package/dist/svelte/components/ContentStatusFields.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentTitleField.svelte +4 -0
- package/dist/svelte/components/ContentTitleField.svelte.d.ts +4 -0
- package/dist/svelte/components/ContentTitleField.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentTransparencyReport.svelte +3 -0
- package/dist/svelte/components/ContentTransparencyReport.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentTransparencyReport.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentTransparencyTool.svelte +3 -0
- package/dist/svelte/components/ContentTransparencyTool.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentTransparencyTool.svelte.d.ts.map +1 -1
- package/dist/svelte/components/ContentVersionsTool.svelte +3 -0
- package/dist/svelte/components/ContentVersionsTool.svelte.d.ts +3 -0
- package/dist/svelte/components/ContentVersionsTool.svelte.d.ts.map +1 -1
- package/dist/svelte/components/GovernedContentEditor.svelte +20 -0
- package/dist/svelte/components/GovernedContentEditor.svelte.d.ts +20 -0
- package/dist/svelte/components/GovernedContentEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/content-list-lifecycle.d.ts +132 -0
- package/dist/svelte/content-list-lifecycle.d.ts.map +1 -0
- package/dist/svelte/content-list-lifecycle.js +439 -0
- package/dist/svelte/i18n.contribution.d.ts +27 -0
- package/dist/svelte/i18n.contribution.d.ts.map +1 -1
- package/dist/svelte/i18n.contribution.js +27 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +1 -0
- package/dist/svelte/routes/ContentContributionsRoute.svelte +4 -0
- package/dist/svelte/routes/ContentContributionsRoute.svelte.d.ts +4 -0
- package/dist/svelte/routes/ContentContributionsRoute.svelte.d.ts.map +1 -1
- package/dist/svelte/routes/ContentFactsRoute.svelte +5 -0
- package/dist/svelte/routes/ContentFactsRoute.svelte.d.ts +5 -0
- package/dist/svelte/routes/ContentFactsRoute.svelte.d.ts.map +1 -1
- package/dist/svelte/routes/ContentGovernanceRoute.svelte +4 -0
- package/dist/svelte/routes/ContentGovernanceRoute.svelte.d.ts +4 -0
- package/dist/svelte/routes/ContentGovernanceRoute.svelte.d.ts.map +1 -1
- package/dist/svelte/routes/ContentWorkspaceRoute.svelte +5 -0
- package/dist/svelte/routes/ContentWorkspaceRoute.svelte.d.ts +5 -0
- package/dist/svelte/routes/ContentWorkspaceRoute.svelte.d.ts.map +1 -1
- package/dist/svelte/routes/PublishedArticleRoute.svelte +3 -0
- package/dist/svelte/routes/PublishedArticleRoute.svelte.d.ts +3 -0
- package/dist/svelte/routes/PublishedArticleRoute.svelte.d.ts.map +1 -1
- package/package.json +16 -15
- package/dist/chunks/content-corrections-BxfA3tW1.js.map +0 -1
- package/dist/chunks/content-query-4w62u5_0.js +0 -4092
- package/dist/chunks/content-reviews-BWrYEQc6.js.map +0 -1
- package/dist/chunks/content-versions-Di3vcTgb.js.map +0 -1
|
@@ -11,9 +11,13 @@ import { M } from '../i18n.editor.js';
|
|
|
11
11
|
const { t } = useI18n();
|
|
12
12
|
|
|
13
13
|
export interface Props {
|
|
14
|
+
/** Content body text from which images are extracted. */
|
|
14
15
|
body: string;
|
|
16
|
+
/** Format of the body content for correct image extraction. */
|
|
15
17
|
format?: ContentBodyFormat | null;
|
|
18
|
+
/** Index of the currently selected image within the body. */
|
|
16
19
|
selectedIndex?: number;
|
|
20
|
+
/** Invoked when the user selects an image by index. */
|
|
17
21
|
onSelect?: (index: number) => void;
|
|
18
22
|
}
|
|
19
23
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { type ContentBodyFormat } from '../../body-format';
|
|
2
2
|
export interface Props {
|
|
3
|
+
/** Content body text from which images are extracted. */
|
|
3
4
|
body: string;
|
|
5
|
+
/** Format of the body content for correct image extraction. */
|
|
4
6
|
format?: ContentBodyFormat | null;
|
|
7
|
+
/** Index of the currently selected image within the body. */
|
|
5
8
|
selectedIndex?: number;
|
|
9
|
+
/** Invoked when the user selects an image by index. */
|
|
6
10
|
onSelect?: (index: number) => void;
|
|
7
11
|
}
|
|
8
12
|
declare const ContentImageChooser: import("svelte").Component<Props, {}, "">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentImageChooser.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ContentImageChooser.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAoED,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"ContentImageChooser.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ContentImageChooser.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,KAAK;IACpB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAoED,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|
|
@@ -45,6 +45,11 @@ import { Button, Pagination } from '@happyvertical/smrt-ui/ui';
|
|
|
45
45
|
import type { Snippet } from 'svelte';
|
|
46
46
|
import { untrack } from 'svelte';
|
|
47
47
|
import type { ContentData } from '../../mock-smrt-client.js';
|
|
48
|
+
import type { ContentListLifecycleBinding } from '../content-list-lifecycle.js';
|
|
49
|
+
import {
|
|
50
|
+
readContentListLifecycleSummary,
|
|
51
|
+
reconcileContentListLifecycleSelection,
|
|
52
|
+
} from '../content-list-lifecycle.js';
|
|
48
53
|
import {
|
|
49
54
|
applyContentListFilter,
|
|
50
55
|
buildContentListColumns,
|
|
@@ -123,6 +128,7 @@ import {
|
|
|
123
128
|
readContentListViewStateFromSearchParams,
|
|
124
129
|
} from '../content-list-url-state.js';
|
|
125
130
|
import { M } from '../i18n.contribution.js';
|
|
131
|
+
import ContentListLifecyclePanel from './ContentListLifecyclePanel.svelte';
|
|
126
132
|
import ImageThumbnail from './ImageThumbnail.svelte';
|
|
127
133
|
|
|
128
134
|
const { t } = useI18n();
|
|
@@ -290,6 +296,7 @@ function workflowJobStatusLabel(status: string): string {
|
|
|
290
296
|
type ContentListDropNotice = ContentListStateDrop | ContentListQueryDrop;
|
|
291
297
|
|
|
292
298
|
interface Props {
|
|
299
|
+
/** Base URL for content API requests. */
|
|
293
300
|
apiBaseUrl?: string;
|
|
294
301
|
/**
|
|
295
302
|
* Client-side rows. Ignored when `query` is supplied — the server then owns
|
|
@@ -297,12 +304,19 @@ interface Props {
|
|
|
297
304
|
* source of truth.
|
|
298
305
|
*/
|
|
299
306
|
contents?: ContentData[];
|
|
307
|
+
/** Filter content by this type; no filtering applied when omitted. */
|
|
300
308
|
type?: string;
|
|
309
|
+
/** Initial view layout mode for the content list. */
|
|
301
310
|
defaultViewMode?: ContentListViewMode;
|
|
311
|
+
/** Invoked when the user requests to edit a content item. */
|
|
302
312
|
onEdit: (content: ContentData) => void;
|
|
313
|
+
/** Invoked when the user requests to delete a content item. */
|
|
303
314
|
onDelete: (content: ContentData) => void;
|
|
315
|
+
/** Invoked when the user requests to create new content. */
|
|
304
316
|
onAdd: () => void;
|
|
317
|
+
/** Optional UI controls rendered above the content list. */
|
|
305
318
|
controls?: Snippet;
|
|
319
|
+
/** Returns a URL to view the published content; null hides the view link. */
|
|
306
320
|
getViewHref?: (content: ContentData) => string | null;
|
|
307
321
|
/** Announced uniformly by every presentation; #2455 extends it. */
|
|
308
322
|
loading?: boolean;
|
|
@@ -327,6 +341,10 @@ interface Props {
|
|
|
327
341
|
jobs?: ContentListJobBinding;
|
|
328
342
|
/** Opt-in, authenticated preview/apply client for bulk workflows (#2453). */
|
|
329
343
|
workflows?: ContentListWorkflowBinding;
|
|
344
|
+
/** Opt-in, server-authoritative trash/restore/permanent-delete lifecycle. */
|
|
345
|
+
lifecycle?: ContentListLifecycleBinding;
|
|
346
|
+
/** Locks the status query to deleted content and exposes trash actions. */
|
|
347
|
+
lifecycleMode?: 'active' | 'trash';
|
|
330
348
|
}
|
|
331
349
|
|
|
332
350
|
let {
|
|
@@ -348,6 +366,8 @@ let {
|
|
|
348
366
|
savedViews = undefined,
|
|
349
367
|
jobs = undefined,
|
|
350
368
|
workflows = undefined,
|
|
369
|
+
lifecycle = undefined,
|
|
370
|
+
lifecycleMode = 'active',
|
|
351
371
|
}: Props = $props();
|
|
352
372
|
|
|
353
373
|
const initialQuery = untrack(() => query);
|
|
@@ -417,6 +437,7 @@ const urlStateOptions: ContentListUrlStateOptions = {
|
|
|
417
437
|
|
|
418
438
|
const controller = createContentListController({
|
|
419
439
|
type: untrack(() => type),
|
|
440
|
+
...(untrack(() => lifecycleMode) === 'trash' ? { status: 'deleted' } : {}),
|
|
420
441
|
// Local mode keeps the historical unpaginated list.
|
|
421
442
|
...(serverPageSize === null ? {} : { pageSize: serverPageSize }),
|
|
422
443
|
});
|
|
@@ -446,6 +467,10 @@ let resultNotices = $state<ContentListQueryNotices>({
|
|
|
446
467
|
* its own total ever arrived.
|
|
447
468
|
*/
|
|
448
469
|
let settledSignature = $state<string | undefined>(undefined);
|
|
470
|
+
let settledLifecycleQuery = $state<ContentListDataQueryRequest | undefined>(
|
|
471
|
+
undefined,
|
|
472
|
+
);
|
|
473
|
+
let settledLifecycleFingerprint = $state<string | undefined>(undefined);
|
|
449
474
|
|
|
450
475
|
function toSearchParams(
|
|
451
476
|
input: URLSearchParams | string | null | undefined,
|
|
@@ -472,22 +497,34 @@ if (initialUrlState?.params !== undefined && initialUrlState?.params !== null) {
|
|
|
472
497
|
// the same link just restored. Folding the lock into the restored patch keeps
|
|
473
498
|
// it to one `replaceState`, and leaves the effect's first run a no-op.
|
|
474
499
|
const initialLockedType = normalizeContentListTypeLock(untrack(() => type));
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
500
|
+
const initialTrashMode = untrack(() => lifecycleMode) === 'trash';
|
|
501
|
+
const lockedFilters = [...(reading.state.filters ?? [])].filter(
|
|
502
|
+
(filter) =>
|
|
503
|
+
(initialLockedType === null ||
|
|
504
|
+
filter.columnId !== CONTENT_LIST_TYPE_FILTER_ID) &&
|
|
505
|
+
(!initialTrashMode ||
|
|
506
|
+
filter.columnId !== CONTENT_LIST_STATUS_FILTER_ID),
|
|
507
|
+
);
|
|
508
|
+
if (initialLockedType !== null) {
|
|
509
|
+
lockedFilters.push({
|
|
510
|
+
columnId: CONTENT_LIST_TYPE_FILTER_ID,
|
|
511
|
+
operator: 'equals',
|
|
512
|
+
value: initialLockedType,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
if (initialTrashMode) {
|
|
516
|
+
lockedFilters.push({
|
|
517
|
+
columnId: CONTENT_LIST_STATUS_FILTER_ID,
|
|
518
|
+
operator: 'equals',
|
|
519
|
+
value: 'deleted',
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
const patch = {
|
|
523
|
+
...reading.state,
|
|
524
|
+
...(initialLockedType !== null || initialTrashMode
|
|
525
|
+
? { filters: lockedFilters }
|
|
526
|
+
: {}),
|
|
527
|
+
};
|
|
491
528
|
applyContentListViewState(controller, patch, restoreOptions);
|
|
492
529
|
restoreDrops = reading.dropped;
|
|
493
530
|
}
|
|
@@ -507,6 +544,7 @@ const queryRequestOptions: ContentListQueryRequestOptions | undefined =
|
|
|
507
544
|
}
|
|
508
545
|
: undefined;
|
|
509
546
|
const serverBacked = queryBinding !== undefined;
|
|
547
|
+
let locallyRemovedLifecycleIds = $state<Set<string>>(new Set());
|
|
510
548
|
|
|
511
549
|
let snapshot = $state(controller.snapshot());
|
|
512
550
|
let viewMode: ContentListViewMode = $state(untrack(() => defaultViewMode));
|
|
@@ -524,6 +562,7 @@ const MAX_DEFERRED_JOB_COMPLETIONS = 50;
|
|
|
524
562
|
let completedJobs = $state<ContentListJob[]>([]);
|
|
525
563
|
let completedJobsOverflowed = $state(false);
|
|
526
564
|
let activeQueryKey = $state<string | undefined>(undefined);
|
|
565
|
+
let lifecycleRefreshPending = $state(false);
|
|
527
566
|
|
|
528
567
|
// Job state is subscribed once so hosts can use a framework-free controller.
|
|
529
568
|
// Only transitions observed after the initial snapshot are completion events;
|
|
@@ -689,8 +728,20 @@ const columnLabels = $derived({
|
|
|
689
728
|
|
|
690
729
|
const queryColumns = $derived(buildContentListColumns(columnLabels));
|
|
691
730
|
const sourceContents = $derived(
|
|
692
|
-
|
|
731
|
+
(queryBinding
|
|
732
|
+
? contentListQueryRowsToContents(queryBinding.rows)
|
|
733
|
+
: contents
|
|
734
|
+
).filter((content) => !locallyRemovedLifecycleIds.has(String(content.id))),
|
|
693
735
|
);
|
|
736
|
+
|
|
737
|
+
$effect(() => {
|
|
738
|
+
if (!queryBinding || refreshing || isLoading) return;
|
|
739
|
+
const removed = locallyRemovedLifecycleIds;
|
|
740
|
+
if (removed.size === 0) return;
|
|
741
|
+
const visible = new Set(queryBinding.rows.map((row) => String(row.id)));
|
|
742
|
+
const retained = new Set([...removed].filter((id) => visible.has(id)));
|
|
743
|
+
if (retained.size !== removed.size) locallyRemovedLifecycleIds = retained;
|
|
744
|
+
});
|
|
694
745
|
const rows = $derived(toContentListRows(sourceContents));
|
|
695
746
|
const visibleRowIds = $derived(
|
|
696
747
|
new Set(rows.filter((row) => row.identified).map((row) => String(row.id))),
|
|
@@ -835,12 +886,38 @@ function refreshQuery(): void {
|
|
|
835
886
|
void queryBinding
|
|
836
887
|
.refresh()
|
|
837
888
|
.then((result) => {
|
|
838
|
-
if (result !== undefined && activeQueryKey === key)
|
|
839
|
-
|
|
889
|
+
if (result !== undefined && activeQueryKey === key) {
|
|
890
|
+
if (executedWorkflowQuery) {
|
|
891
|
+
settleWorkflowQueryResult(
|
|
892
|
+
result,
|
|
893
|
+
executedWorkflowQuery,
|
|
894
|
+
querySignature,
|
|
895
|
+
);
|
|
896
|
+
} else {
|
|
897
|
+
resultNotices = readContentListQueryNotices(result);
|
|
898
|
+
}
|
|
899
|
+
settleLifecycleResult(result, lifecycleQueryRequest, querySignature);
|
|
900
|
+
}
|
|
840
901
|
})
|
|
841
902
|
.catch(() => undefined);
|
|
842
903
|
}
|
|
843
904
|
|
|
905
|
+
function requestLifecycleRefresh(): void {
|
|
906
|
+
if (!queryBinding?.refresh) return;
|
|
907
|
+
if (refreshing || isLoading) {
|
|
908
|
+
lifecycleRefreshPending = true;
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
lifecycleRefreshPending = false;
|
|
912
|
+
refreshQuery();
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
$effect(() => {
|
|
916
|
+
if (!lifecycleRefreshPending || refreshing || isLoading) return;
|
|
917
|
+
lifecycleRefreshPending = false;
|
|
918
|
+
refreshQuery();
|
|
919
|
+
});
|
|
920
|
+
|
|
844
921
|
function settleWorkflowQueryResult(
|
|
845
922
|
result: unknown,
|
|
846
923
|
request: ContentListDataQueryRequest,
|
|
@@ -870,6 +947,27 @@ function settleWorkflowQueryResult(
|
|
|
870
947
|
settledWorkflowRevision = null;
|
|
871
948
|
}
|
|
872
949
|
|
|
950
|
+
function settleLifecycleResult(
|
|
951
|
+
result: unknown,
|
|
952
|
+
request: ContentListDataQueryRequest | undefined,
|
|
953
|
+
signature: string,
|
|
954
|
+
): void {
|
|
955
|
+
if (
|
|
956
|
+
!request ||
|
|
957
|
+
result === null ||
|
|
958
|
+
typeof result !== 'object' ||
|
|
959
|
+
Array.isArray(result)
|
|
960
|
+
) {
|
|
961
|
+
settledLifecycleQuery = undefined;
|
|
962
|
+
settledLifecycleFingerprint = undefined;
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const fingerprint = (result as Record<string, unknown>).queryFingerprint;
|
|
966
|
+
settledLifecycleQuery = request;
|
|
967
|
+
settledLifecycleFingerprint =
|
|
968
|
+
typeof fingerprint === 'string' ? fingerprint : undefined;
|
|
969
|
+
settledSignature = signature;
|
|
970
|
+
}
|
|
873
971
|
/**
|
|
874
972
|
* A retry re-reads the same query, so its answer replaces the rendered rows —
|
|
875
973
|
* and therefore has to replace the completeness flags that describe them too.
|
|
@@ -895,6 +993,7 @@ function retryQuery(): void {
|
|
|
895
993
|
)
|
|
896
994
|
return;
|
|
897
995
|
settleWorkflowQueryResult(result, request, signature);
|
|
996
|
+
settleLifecycleResult(result, lifecycleQueryRequest, signature);
|
|
898
997
|
})
|
|
899
998
|
.catch(() => undefined);
|
|
900
999
|
}
|
|
@@ -922,6 +1021,7 @@ const querySignature = $derived(
|
|
|
922
1021
|
let executedSignature: string | undefined;
|
|
923
1022
|
let executedWorkflowQuery: ContentListDataQueryRequest | null = null;
|
|
924
1023
|
let publishedUrlSignature: string | undefined;
|
|
1024
|
+
let lifecycleQueryRequest: ContentListDataQueryRequest | undefined;
|
|
925
1025
|
|
|
926
1026
|
$effect(() => {
|
|
927
1027
|
const signature = querySignature;
|
|
@@ -968,6 +1068,7 @@ $effect(() => {
|
|
|
968
1068
|
// flags, which the binding itself does not expose.
|
|
969
1069
|
activeQueryKey = contentListQueryRequestKey(translated.request);
|
|
970
1070
|
executedWorkflowQuery = translated.request;
|
|
1071
|
+
lifecycleQueryRequest = translated.request;
|
|
971
1072
|
void queryBinding
|
|
972
1073
|
.execute(translated.request)
|
|
973
1074
|
.then((result) => {
|
|
@@ -977,6 +1078,7 @@ $effect(() => {
|
|
|
977
1078
|
// may be clamped against them and workflows may bind to the exact
|
|
978
1079
|
// settled request.
|
|
979
1080
|
settleWorkflowQueryResult(result, translated.request, signature);
|
|
1081
|
+
settleLifecycleResult(result, translated.request, signature);
|
|
980
1082
|
})
|
|
981
1083
|
.catch(() => undefined);
|
|
982
1084
|
}
|
|
@@ -1116,6 +1218,23 @@ const workflowQueuedJob = $derived(
|
|
|
1116
1218
|
workflowQueuedJobs.find((job) => job.intent === workflowIntentSignature()) ??
|
|
1117
1219
|
workflowQueuedJobs[0],
|
|
1118
1220
|
);
|
|
1221
|
+
const lifecycleViewKey = $derived(
|
|
1222
|
+
JSON.stringify([
|
|
1223
|
+
lifecycleMode,
|
|
1224
|
+
querySignature,
|
|
1225
|
+
[...tableState.selectedRowIds].map(String).sort(),
|
|
1226
|
+
]),
|
|
1227
|
+
);
|
|
1228
|
+
const lifecycleQuery = $derived(
|
|
1229
|
+
serverBacked && settledSignature === querySignature
|
|
1230
|
+
? settledLifecycleQuery
|
|
1231
|
+
: undefined,
|
|
1232
|
+
);
|
|
1233
|
+
const lifecycleExactMatchingCount = $derived(
|
|
1234
|
+
serverBacked && settledSignature === querySignature
|
|
1235
|
+
? contentListQueryExactTotal(queryBinding?.total)
|
|
1236
|
+
: queryRows.length,
|
|
1237
|
+
);
|
|
1119
1238
|
|
|
1120
1239
|
/** Synthetic ids the adapter minted for rows that carry no durable identity. */
|
|
1121
1240
|
const unidentifiedRowKeys = $derived(
|
|
@@ -1145,6 +1264,23 @@ $effect(() => {
|
|
|
1145
1264
|
);
|
|
1146
1265
|
});
|
|
1147
1266
|
|
|
1267
|
+
// Trash is a view, not an editable select value. Keep its status predicate
|
|
1268
|
+
// locked against URL restores and agent-driven filter commands.
|
|
1269
|
+
$effect(() => {
|
|
1270
|
+
if (lifecycleMode !== 'trash') return;
|
|
1271
|
+
if (
|
|
1272
|
+
isContentListFilterExactly(
|
|
1273
|
+
tableState,
|
|
1274
|
+
CONTENT_LIST_STATUS_FILTER_ID,
|
|
1275
|
+
'deleted',
|
|
1276
|
+
)
|
|
1277
|
+
)
|
|
1278
|
+
return;
|
|
1279
|
+
untrack(() =>
|
|
1280
|
+
applyContentListFilter(controller, CONTENT_LIST_STATUS_FILTER_ID, 'deleted'),
|
|
1281
|
+
);
|
|
1282
|
+
});
|
|
1283
|
+
|
|
1148
1284
|
/**
|
|
1149
1285
|
* What each toolbar select may display, and whether it can display the live
|
|
1150
1286
|
* predicate at all.
|
|
@@ -2044,7 +2180,29 @@ function handleFilter(columnId: string, value: string) {
|
|
|
2044
2180
|
}
|
|
2045
2181
|
|
|
2046
2182
|
function rowActions(row: ContentListRow) {
|
|
2047
|
-
return contentListRowActions(row, {
|
|
2183
|
+
return contentListRowActions(row, {
|
|
2184
|
+
getViewHref,
|
|
2185
|
+
canEdit: lifecycleMode !== 'trash',
|
|
2186
|
+
canDelete: lifecycleMode !== 'trash' && lifecycle === undefined,
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
function handleLifecycleComplete(
|
|
2191
|
+
result: import('@happyvertical/smrt-ui/data').DataSurfaceActionResult,
|
|
2192
|
+
) {
|
|
2193
|
+
const removed = new Set(locallyRemovedLifecycleIds);
|
|
2194
|
+
for (const outcome of readContentListLifecycleSummary(result).outcomes) {
|
|
2195
|
+
if (outcome.status === 'accepted') removed.add(String(outcome.rowId));
|
|
2196
|
+
}
|
|
2197
|
+
locallyRemovedLifecycleIds = removed;
|
|
2198
|
+
controller.dispatch({
|
|
2199
|
+
type: 'setSelectedRows',
|
|
2200
|
+
rowIds: reconcileContentListLifecycleSelection(
|
|
2201
|
+
tableState.selectedRowIds,
|
|
2202
|
+
result,
|
|
2203
|
+
),
|
|
2204
|
+
});
|
|
2205
|
+
requestLifecycleRefresh();
|
|
2048
2206
|
}
|
|
2049
2207
|
|
|
2050
2208
|
function viewHref(row: ContentListRow): string | null {
|
|
@@ -2119,7 +2277,11 @@ const tableColumns: DataTableColumn<ContentListRow>[] = $derived([
|
|
|
2119
2277
|
</script>
|
|
2120
2278
|
|
|
2121
2279
|
{#snippet tableEmptyState()}
|
|
2122
|
-
<p class="table-empty-state">
|
|
2280
|
+
<p class="table-empty-state">
|
|
2281
|
+
{lifecycleMode === 'trash'
|
|
2282
|
+
? t(M['content.content_list.trash_empty'])
|
|
2283
|
+
: t(M['content.content_list.empty'])}
|
|
2284
|
+
</p>
|
|
2123
2285
|
{/snippet}
|
|
2124
2286
|
|
|
2125
2287
|
{#snippet selectHeader()}
|
|
@@ -2259,6 +2421,7 @@ const tableColumns: DataTableColumn<ContentListRow>[] = $derived([
|
|
|
2259
2421
|
</Select>
|
|
2260
2422
|
{/if}
|
|
2261
2423
|
|
|
2424
|
+
{#if lifecycleMode !== 'trash'}
|
|
2262
2425
|
<Select
|
|
2263
2426
|
aria-label={t(M['content.content_list.filter_status'])}
|
|
2264
2427
|
value={selectedStatus}
|
|
@@ -2281,6 +2444,7 @@ const tableColumns: DataTableColumn<ContentListRow>[] = $derived([
|
|
|
2281
2444
|
</option>
|
|
2282
2445
|
{/if}
|
|
2283
2446
|
</Select>
|
|
2447
|
+
{/if}
|
|
2284
2448
|
|
|
2285
2449
|
{#if savedViews}
|
|
2286
2450
|
<div class="saved-views" role="group" aria-label={t(M['content.content_list.saved_views'])}>
|
|
@@ -2560,6 +2724,19 @@ const tableColumns: DataTableColumn<ContentListRow>[] = $derived([
|
|
|
2560
2724
|
</div>
|
|
2561
2725
|
{/if}
|
|
2562
2726
|
|
|
2727
|
+
{#if lifecycle}
|
|
2728
|
+
<ContentListLifecyclePanel
|
|
2729
|
+
binding={lifecycle}
|
|
2730
|
+
mode={lifecycleMode}
|
|
2731
|
+
selectedRowIds={tableState.selectedRowIds}
|
|
2732
|
+
query={lifecycleQuery}
|
|
2733
|
+
queryFingerprint={settledLifecycleFingerprint}
|
|
2734
|
+
exactMatchingCount={lifecycleExactMatchingCount}
|
|
2735
|
+
viewKey={lifecycleViewKey}
|
|
2736
|
+
oncomplete={handleLifecycleComplete}
|
|
2737
|
+
/>
|
|
2738
|
+
{/if}
|
|
2739
|
+
|
|
2563
2740
|
{#if workflows && (selectedCount > 0 || workflowError || workflowResult)}
|
|
2564
2741
|
<section class="content-workflows" aria-label={t(M['content.content_list.bulk_workflows'])}>
|
|
2565
2742
|
<Select
|
|
@@ -2703,7 +2880,9 @@ const tableColumns: DataTableColumn<ContentListRow>[] = $derived([
|
|
|
2703
2880
|
</div>
|
|
2704
2881
|
{:else if pageRows.length === 0}
|
|
2705
2882
|
<div class="state-panel empty-state">
|
|
2706
|
-
{
|
|
2883
|
+
{lifecycleMode === 'trash'
|
|
2884
|
+
? t(M['content.content_list.trash_empty'])
|
|
2885
|
+
: t(M['content.content_list.empty'])}
|
|
2707
2886
|
</div>
|
|
2708
2887
|
{:else if viewMode === 'detailed'}
|
|
2709
2888
|
<div class="content-detailed">
|
|
@@ -25,12 +25,14 @@ export interface ContentListUrlStateBinding {
|
|
|
25
25
|
}
|
|
26
26
|
import type { Snippet } from 'svelte';
|
|
27
27
|
import type { ContentData } from '../../mock-smrt-client.js';
|
|
28
|
+
import type { ContentListLifecycleBinding } from '../content-list-lifecycle.js';
|
|
28
29
|
import { type ContentListDataSurface, type ContentListViewMode } from '../content-list-controller.js';
|
|
29
30
|
import { type ContentListQuerySource } from '../content-list-query.js';
|
|
30
31
|
import { type ContentListJobBinding } from '../content-list-runtime.js';
|
|
31
32
|
import { type ContentListSavedViewStore } from '../content-list-saved-views.js';
|
|
32
33
|
import { type ContentListWorkflowBinding } from '../content-list-workflows.js';
|
|
33
34
|
interface Props {
|
|
35
|
+
/** Base URL for content API requests. */
|
|
34
36
|
apiBaseUrl?: string;
|
|
35
37
|
/**
|
|
36
38
|
* Client-side rows. Ignored when `query` is supplied — the server then owns
|
|
@@ -38,12 +40,19 @@ interface Props {
|
|
|
38
40
|
* source of truth.
|
|
39
41
|
*/
|
|
40
42
|
contents?: ContentData[];
|
|
43
|
+
/** Filter content by this type; no filtering applied when omitted. */
|
|
41
44
|
type?: string;
|
|
45
|
+
/** Initial view layout mode for the content list. */
|
|
42
46
|
defaultViewMode?: ContentListViewMode;
|
|
47
|
+
/** Invoked when the user requests to edit a content item. */
|
|
43
48
|
onEdit: (content: ContentData) => void;
|
|
49
|
+
/** Invoked when the user requests to delete a content item. */
|
|
44
50
|
onDelete: (content: ContentData) => void;
|
|
51
|
+
/** Invoked when the user requests to create new content. */
|
|
45
52
|
onAdd: () => void;
|
|
53
|
+
/** Optional UI controls rendered above the content list. */
|
|
46
54
|
controls?: Snippet;
|
|
55
|
+
/** Returns a URL to view the published content; null hides the view link. */
|
|
47
56
|
getViewHref?: (content: ContentData) => string | null;
|
|
48
57
|
/** Announced uniformly by every presentation; #2455 extends it. */
|
|
49
58
|
loading?: boolean;
|
|
@@ -68,6 +77,10 @@ interface Props {
|
|
|
68
77
|
jobs?: ContentListJobBinding;
|
|
69
78
|
/** Opt-in, authenticated preview/apply client for bulk workflows (#2453). */
|
|
70
79
|
workflows?: ContentListWorkflowBinding;
|
|
80
|
+
/** Opt-in, server-authoritative trash/restore/permanent-delete lifecycle. */
|
|
81
|
+
lifecycle?: ContentListLifecycleBinding;
|
|
82
|
+
/** Locks the status query to deleted content and exposes trash actions. */
|
|
83
|
+
lifecycleMode?: 'active' | 'trash';
|
|
71
84
|
}
|
|
72
85
|
declare const ContentList: import("svelte").Component<Props, {}, "">;
|
|
73
86
|
type ContentList = ReturnType<typeof ContentList>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentList.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ContentList.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,IAAI,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,6BAA6B,KACjC,IAAI,CAAC;IACV,uEAAuE;IACvE,OAAO,CAAC,EAAE,0BAA0B,CAAC;CACtC;AAcD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EASL,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EAiBzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAOL,KAAK,sBAAsB,EAU5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,qBAAqB,EAG3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,0BAA0B,EAOhC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"ContentList.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ContentList.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,IAAI,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,6BAA6B,KACjC,IAAI,CAAC;IACV,uEAAuE;IACvE,OAAO,CAAC,EAAE,0BAA0B,CAAC;CACtC;AAcD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAKhF,OAAO,EASL,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EAiBzB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAOL,KAAK,sBAAsB,EAU5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,qBAAqB,EAG3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,0BAA0B,EAOhC,MAAM,8BAA8B,CAAC;AAiBtC,UAAU,KAAK;IACb,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,6DAA6D;IAC7D,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,+DAA+D;IAC/D,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC,4DAA4D;IAC5D,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,GAAG,IAAI,CAAC;IACtD,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,0BAA0B,CAAC;IACtC,oFAAoF;IACpF,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,6EAA6E;IAC7E,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,0BAA0B,CAAC;IACvC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACxC,2EAA2E;IAC3E,aAAa,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CACpC;AAgnFD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|