@elytracms/studio 0.0.74 → 0.0.75
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/convex/cms.ts +67 -3
- package/convex/schema.ts +9 -0
- package/dist/components/app-views/default-modules.js +1 -1
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +19 -2
- package/dist/components/cms/cms-store.js +43 -2
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +33 -17
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/column-width.d.ts +8 -0
- package/dist/components/cms/column-width.js +8 -0
- package/dist/components/cms/column-width.js.map +1 -1
- package/dist/components/cms/doc-state.d.ts +46 -0
- package/dist/components/cms/doc-state.js +47 -1
- package/dist/components/cms/doc-state.js.map +1 -1
- package/dist/components/collection-view/cms-collection-view-source.js +5 -4
- package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
- package/dist/lib/cms-views/view-model.d.ts +29 -11
- package/dist/lib/cms-views/view-model.js +43 -16
- package/dist/lib/cms-views/view-model.js.map +1 -1
- package/dist/lib/collection-view/collection-view-source.d.ts +6 -5
- package/dist/lib/collection-view/collection-view-source.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +4 -0
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +2 -0
- package/dist/lib/i18n/messages.en.js +7 -0
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/session-hydration.d.ts +11 -0
- package/dist/lib/operations/session-hydration.js +6 -0
- package/dist/lib/operations/session-hydration.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.js +9 -1
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/ui/status-dot.d.ts +17 -6
- package/dist/ui/status-dot.js +9 -7
- package/dist/ui/status-dot.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cms-collection-view-source.js","sourceRoot":"","sources":["../../../src/components/collection-view/cms-collection-view-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,4BAA4B,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAMvG,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAA;AACrF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAE5D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,0BAA0B,CAAC,YAAoB;IAC7D,MAAM,GAAG,GAAG,MAAM,EAAE,CAAA;IACpB,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAA;IACtC,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;IAClD,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;IAExE,+EAA+E;IAC/E,MAAM,iBAAiB,GAAG,OAAO,CAC/B,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,EAAE,IAAI,OAAO,EACpE,CAAC,GAAG,CAAC,WAAW,CAAC,CAClB,CAAA;IAED,+EAA+E;IAC/E,+EAA+E;IAC/E,MAAM,UAAU,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,uBAAuB,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,KAAK,YAAY,CAAC,EAC5F,CAAC,YAAY,CAAC,CACf,CAAA;IACD,2EAA2E;IAC3E,uEAAuE;IACvE,8EAA8E;IAC9E,sDAAsD;IACtD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAA;QAC3C,MAAM,QAAQ,GAAG,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAA;QAC1C,KAAK,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,sBAAsB,CAAC;gBACjC,MAAM,EAAE,uBAAuB,EAAE;gBACjC,WAAW,EAAE,4BAA4B,EAAE;gBAC3C,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,UAAU;gBACV,GAAG,EAAE,SAAS;gBACd,QAAQ;gBACR,MAAM,EAAE,GAAG,CAAC,YAAY;aACzB,CAAC,CAAA;YACF,IAAI,GAAG;gBAAE,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACrC,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAA;IAE/E,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAA;IACvF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAA;IACxF,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAA2D,EAAE,EAAE,CAC9D,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,EACzC,CAAC,GAAG,EAAE,YAAY,CAAC,CACpB,CAAA;IACD,qFAAqF;IACrF,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC;QACrC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,YAAY,CAAC;QAC9C,SAAS,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,CAAC;KAC/D,CAAC,EACF,CAAC,GAAG,EAAE,YAAY,CAAC,CACpB,CAAA;IACD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAA;IACvF,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,KAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,EAC3F,CAAC,GAAG,EAAE,YAAY,CAAC,CACpB,CAAA;IACD,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,EAAU,EAA6B,EAAE;QACxC,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAClE,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAA;QAC7B,OAAO;YACL,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAA;IACH,CAAC,EACD,CAAC,UAAU,CAAC,CACb,CAAA;IACD,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAE5D,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAA;QAC5B,MAAM,YAAY,GAA+B;YAC/C,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,IAAI;YACZ,SAAS,EAAE,IAAI,EAAE,yDAAyD;YAC1E,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,UAAU;YACnB,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC;YACrC,YAAY,EAAE,IAAI;SACnB,CAAA;QACD,MAAM,MAAM,GAAyB;YACnC,YAAY;YACZ,MAAM,EAAE,UAAU;YAClB,YAAY;YACZ,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,iBAAiB;YACjB,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,SAAS;YACT,GAAG,EAAE,GAAG,CAAC,WAAW;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,6EAA6E;YAC7E,gFAAgF;YAChF,mBAAmB,EAAE,GAAG,CAAC,WAAW;YACpC,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,eAAe,EAAE,GAAG,CAAC,eAAe;YACpC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,YAAY;YACZ,SAAS,EAAE,GAAG,CAAC,YAAY;YAC3B,cAAc,EAAE,GAAG,CAAC,iBAAiB;YACrC,2EAA2E;YAC3E,KAAK,EAAE,KAAK,IAAI,EAAE;gBAChB,MAAM,GAAG,CAAC,uBAAuB,EAAE,CAAA;gBACnC,MAAM,GAAG,CAAC,gBAAgB,EAAE,CAAA;YAC9B,CAAC;YACD,UAAU,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC;YACpE,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC;YAChD,SAAS;YACT,YAAY;YACZ,KAAK;YACL,OAAO;YACP,MAAM;YACN,IAAI,EAAE,GAAG,CAAC,YAAY;YACtB,MAAM,EAAE,GAAG,CAAC,cAAc;YAC1B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC;YACjF,UAAU,EAAE;gBACV,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,OAAO,EAAE,GAAG,CAAC,eAAe;gBAC5B,SAAS,EAAE,GAAG,CAAC,iBAAiB;gBAChC,QAAQ;aACT;YACD,6EAA6E;YAC7E,gFAAgF;YAChF,qFAAqF;YACrF,UAAU,EAAE;gBACV,SAAS,EAAE,GAAG,CAAC,iBAAiB;gBAChC,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;aAC7B;YACD,UAAU,EAAE;gBACV,OAAO,EAAE,CAAC,GAAgB,EAAE,OAAe,EAAE,KAAK,EAAE,EAAE,CACpD,GAAG,CAAC,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC;gBACjD,2EAA2E;gBAC3E,qEAAqE;gBACrE,IAAI,EAAE,KAAK,EAAE,GAAgB,EAAE,EAAE;oBAC/B,MAAM,GAAG,CAAC,gBAAgB,EAAE,CAAA;oBAC5B,OAAO,GAAG,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAA;gBACtC,CAAC;aACF;YACD,aAAa,EAAE;gBACb,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC;aACnD;SACF,CAAA;QACD,OAAO,MAAM,CAAA;IACf,CAAC,EAAE;QACD,UAAU;QACV,YAAY;QACZ,GAAG;QACH,UAAU;QACV,SAAS;QACT,SAAS;QACT,YAAY;QACZ,KAAK;QACL,OAAO;QACP,MAAM;QACN,YAAY;QACZ,QAAQ;QACR,iBAAiB;KAClB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { useCallback, useMemo } from 'react'\nimport { isHierarchical } from '@elytracms/core/cms-core'\nimport type { DocumentRef, DocumentUrl } from '@elytracms/core/cms-core'\nimport { studioPath } from '@elytracms/studio/router'\nimport { resolveDeploymentFrontendUrl, resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace'\nimport type {\n CollectionViewCapabilities,\n CollectionViewSource,\n ResolvedAsset,\n} from '@elytracms/studio/lib/collection-view/collection-view-source'\nimport { useCms } from '../cms/cms-store'\nimport { useOptionalAssets } from '../assets/assets-store'\nimport { usePublishedDocuments } from '@elytracms/studio/lib/cms/published-documents'\nimport { resolveDocumentLiveUrl } from '../cms/use-live-url'\n\n/**\n * Assemble a {@link CollectionViewSource} for a `cmsDocuments` collection from the\n * ambient `CmsStore` + its side contexts (assets, published pool) + the\n * deployment config reads (EC-240 / AD-19). This is the CMS adapter: a\n * behaviour-preserving pass-through so the portable list + edit surfaces render\n * over the source instead of `useCms()` directly, byte-for-byte as before.\n *\n * Returns `null` for an unknown collection id (the caller renders the fallback).\n *\n * Referential stability: collection-parameterised methods are `useCallback`-bound\n * and the source object is `useMemo`-ed, so the surfaces' `useMemo` dependency\n * arrays stay stable across renders (the inline-edit order snapshot depends on it).\n */\nexport function useCmsCollectionViewSource(collectionId: string): CollectionViewSource | null {\n const cms = useCms()\n const assetStore = useOptionalAssets()\n const collection = cms.getCollection(collectionId)\n const publishedDocs = usePublishedDocuments(cms.projectId, collectionId)\n\n // The asset collection id is resolved once from the schema (as the cell does).\n const assetCollectionId = useMemo(\n () => cms.collections.find((c) => c.kind === 'asset')?.id ?? 'asset',\n [cms.collections],\n )\n\n // Live-URL column: the published pool × deployment routes, memoised exactly as\n // the table did — derived from PUBLISHED snapshots, never draft rows (EC-205).\n const isRoutable = useMemo(\n () => resolveDeploymentRoutes().some((route) => route.document?.collection === collectionId),\n [collectionId],\n )\n // EC-384: `resolveDocumentLiveUrl` merges the stored routes with the kit's\n // fallback-home rule (same as the document editor's header affordance,\n // `use-live-url.ts`) — otherwise a fallback-addressed home page showed no URL\n // in this column even though the live site serves it.\n const liveUrlMap = useMemo(() => {\n if (!collection || !isRoutable) return null\n const siblings = [...publishedDocs.byId.values()]\n const map = new Map<string, DocumentUrl>()\n for (const published of siblings) {\n const url = resolveDocumentLiveUrl({\n routes: resolveDeploymentRoutes(),\n frontendUrl: resolveDeploymentFrontendUrl(),\n localeConfig: cms.localeConfig,\n collection,\n doc: published,\n siblings,\n locale: cms.activeLocale,\n })\n if (url) map.set(published.id, url)\n }\n return map\n }, [collection, isRoutable, publishedDocs, cms.localeConfig, cms.activeLocale])\n\n const documents = useCallback(() => cms.documentsOf(collectionId), [cms, collectionId])\n const viewState = useCallback(() => cms.tableStateOf(collectionId), [cms, collectionId])\n const setViewState = useCallback(\n (update: Parameters<CollectionViewSource['setViewState']>[0]) =>\n cms.setTableState(collectionId, update),\n [cms, collectionId],\n )\n // Named views (EC-246b): config-as-code lenses the header selector switches between.\n const views = useMemo(\n () => ({\n list: () => cms.viewsOf(collectionId),\n activeId: () => cms.activeViewId(collectionId),\n setActive: (id: string) => cms.setActiveView(collectionId, id),\n }),\n [cms, collectionId],\n )\n const create = useCallback(() => cms.createDocument(collectionId), [cms, collectionId])\n const imports = useMemo(\n () => ({ importDocuments: (items: unknown[]) => cms.importDocuments(collectionId, items) }),\n [cms, collectionId],\n )\n const resolveAsset = useCallback(\n (id: string): ResolvedAsset | undefined => {\n const record = assetStore?.assets.find((asset) => asset.id === id)\n if (!record) return undefined\n return {\n ...(record.url !== undefined ? { url: record.url } : {}),\n contentType: record.contentType,\n ...(record.title !== undefined ? { title: record.title } : {}),\n filename: record.filename,\n ...(record.alt !== undefined ? { alt: record.alt } : {}),\n }\n },\n [assetStore],\n )\n const liveUrls = useCallback(() => liveUrlMap, [liveUrlMap])\n\n return useMemo(() => {\n if (!collection) return null\n const capabilities: CollectionViewCapabilities = {\n publish: true,\n versions: true,\n locales: true,\n inlineEdit: true,\n create: true,\n duplicate: true, // EC-442: CMS collections only (owner call — rails skip)\n remove: true,\n bulk: true,\n liveUrl: isRoutable,\n hierarchy: isHierarchical(collection),\n importExport: true,\n }\n const source: CollectionViewSource = {\n collectionId,\n schema: collection,\n capabilities,\n ...(cms.projectId !== undefined ? { projectId: cms.projectId } : {}),\n assetCollectionId,\n localeConfig: cms.localeConfig,\n activeLocale: cms.activeLocale,\n documents,\n get: cms.getDocument,\n titleOf: cms.titleOf,\n // References are collection-based (EC-072): resolve candidates of ANY target\n // collection the schema declares — the workspace doc store already serves them.\n referenceCandidates: cms.documentsOf,\n collections: cms.collections,\n isFieldReadOnly: cms.isFieldReadOnly,\n validate: cms.validate,\n resolveAsset,\n lastError: cms.persistError,\n clearLastError: cms.clearPersistError,\n // Baseline + queue flush, so a pre-flight reference-index read is current.\n flush: async () => {\n await cms.ensurePersistedBaseline()\n await cms.flushPersistence()\n },\n detailPath: (id: string) => studioPath.cmsDocument(collectionId, id),\n listPath: studioPath.cmsCollection(collectionId),\n viewState,\n setViewState,\n views,\n imports,\n create,\n save: cms.saveDocument,\n remove: cms.deleteDocument,\n bulk: (ids, action, setField) => cms.runBulk(collectionId, ids, action, setField),\n publishing: {\n isPublished: cms.isPublished,\n publish: cms.publishDocument,\n unpublish: cms.unpublishDocument,\n liveUrls,\n },\n // EC-445: per-document timestamps behind the $updatedAt column, sourced from\n // the store (hydration seeds them from the persisted `cmsDocuments.updatedAt`).\n // `publishedAt` is a reserved follow-up — no data path yet, so it returns undefined.\n timestamps: {\n updatedAt: cms.documentUpdatedAt,\n publishedAt: () => undefined,\n },\n versioning: {\n restore: (ref: DocumentRef, version: number, scope) =>\n cms.restoreDocumentVersion(ref, version, scope),\n // Flush-before-read ordering folds into the loader (EC-224) so any surface\n // that mutated the history still lists an authoritative version set.\n load: async (ref: DocumentRef) => {\n await cms.flushPersistence()\n return cms.loadDocumentVersions(ref)\n },\n },\n inlineEditing: {\n commitField: (input) => cms.commitFieldEdit(input),\n },\n }\n return source\n }, [\n collection,\n collectionId,\n cms,\n isRoutable,\n documents,\n viewState,\n setViewState,\n views,\n imports,\n create,\n resolveAsset,\n liveUrls,\n assetCollectionId,\n ])\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cms-collection-view-source.js","sourceRoot":"","sources":["../../../src/components/collection-view/cms-collection-view-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useMemo } from 'react'\nimport { isHierarchical } from '@elytracms/core/cms-core'\nimport type { DocumentRef, DocumentUrl } from '@elytracms/core/cms-core'\nimport { studioPath } from '@elytracms/studio/router'\nimport { resolveDeploymentFrontendUrl, resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace'\nimport type {\n CollectionViewCapabilities,\n CollectionViewSource,\n ResolvedAsset,\n} from '@elytracms/studio/lib/collection-view/collection-view-source'\nimport { useCms } from '../cms/cms-store'\nimport { useOptionalAssets } from '../assets/assets-store'\nimport { usePublishedDocuments } from '@elytracms/studio/lib/cms/published-documents'\nimport { resolveDocumentLiveUrl } from '../cms/use-live-url'\n\n/**\n * Assemble a {@link CollectionViewSource} for a `cmsDocuments` collection from the\n * ambient `CmsStore` + its side contexts (assets, published pool) + the\n * deployment config reads (EC-240 / AD-19). This is the CMS adapter: a\n * behaviour-preserving pass-through so the portable list + edit surfaces render\n * over the source instead of `useCms()` directly, byte-for-byte as before.\n *\n * Returns `null` for an unknown collection id (the caller renders the fallback).\n *\n * Referential stability: collection-parameterised methods are `useCallback`-bound\n * and the source object is `useMemo`-ed, so the surfaces' `useMemo` dependency\n * arrays stay stable across renders (the inline-edit order snapshot depends on it).\n */\nexport function useCmsCollectionViewSource(collectionId: string): CollectionViewSource | null {\n const cms = useCms()\n const assetStore = useOptionalAssets()\n const collection = cms.getCollection(collectionId)\n const publishedDocs = usePublishedDocuments(cms.projectId, collectionId)\n\n // The asset collection id is resolved once from the schema (as the cell does).\n const assetCollectionId = useMemo(\n () => cms.collections.find((c) => c.kind === 'asset')?.id ?? 'asset',\n [cms.collections],\n )\n\n // Live-URL column: the published pool × deployment routes, memoised exactly as\n // the table did — derived from PUBLISHED snapshots, never draft rows (EC-205).\n const isRoutable = useMemo(\n () => resolveDeploymentRoutes().some((route) => route.document?.collection === collectionId),\n [collectionId],\n )\n // EC-384: `resolveDocumentLiveUrl` merges the stored routes with the kit's\n // fallback-home rule (same as the document editor's header affordance,\n // `use-live-url.ts`) — otherwise a fallback-addressed home page showed no URL\n // in this column even though the live site serves it.\n const liveUrlMap = useMemo(() => {\n if (!collection || !isRoutable) return null\n const siblings = [...publishedDocs.byId.values()]\n const map = new Map<string, DocumentUrl>()\n for (const published of siblings) {\n const url = resolveDocumentLiveUrl({\n routes: resolveDeploymentRoutes(),\n frontendUrl: resolveDeploymentFrontendUrl(),\n localeConfig: cms.localeConfig,\n collection,\n doc: published,\n siblings,\n locale: cms.activeLocale,\n })\n if (url) map.set(published.id, url)\n }\n return map\n }, [collection, isRoutable, publishedDocs, cms.localeConfig, cms.activeLocale])\n\n const documents = useCallback(() => cms.documentsOf(collectionId), [cms, collectionId])\n const viewState = useCallback(() => cms.tableStateOf(collectionId), [cms, collectionId])\n const setViewState = useCallback(\n (update: Parameters<CollectionViewSource['setViewState']>[0]) =>\n cms.setTableState(collectionId, update),\n [cms, collectionId],\n )\n // Named views (EC-246b): config-as-code lenses the header selector switches between.\n const views = useMemo(\n () => ({\n list: () => cms.viewsOf(collectionId),\n activeId: () => cms.activeViewId(collectionId),\n setActive: (id: string) => cms.setActiveView(collectionId, id),\n }),\n [cms, collectionId],\n )\n const create = useCallback(() => cms.createDocument(collectionId), [cms, collectionId])\n const imports = useMemo(\n () => ({ importDocuments: (items: unknown[]) => cms.importDocuments(collectionId, items) }),\n [cms, collectionId],\n )\n const resolveAsset = useCallback(\n (id: string): ResolvedAsset | undefined => {\n const record = assetStore?.assets.find((asset) => asset.id === id)\n if (!record) return undefined\n return {\n ...(record.url !== undefined ? { url: record.url } : {}),\n contentType: record.contentType,\n ...(record.title !== undefined ? { title: record.title } : {}),\n filename: record.filename,\n ...(record.alt !== undefined ? { alt: record.alt } : {}),\n }\n },\n [assetStore],\n )\n const liveUrls = useCallback(() => liveUrlMap, [liveUrlMap])\n\n return useMemo(() => {\n if (!collection) return null\n const capabilities: CollectionViewCapabilities = {\n publish: true,\n versions: true,\n locales: true,\n inlineEdit: true,\n create: true,\n duplicate: true, // EC-442: CMS collections only (owner call — rails skip)\n remove: true,\n bulk: true,\n liveUrl: isRoutable,\n hierarchy: isHierarchical(collection),\n importExport: true,\n }\n const source: CollectionViewSource = {\n collectionId,\n schema: collection,\n capabilities,\n ...(cms.projectId !== undefined ? { projectId: cms.projectId } : {}),\n assetCollectionId,\n localeConfig: cms.localeConfig,\n activeLocale: cms.activeLocale,\n documents,\n get: cms.getDocument,\n titleOf: cms.titleOf,\n // References are collection-based (EC-072): resolve candidates of ANY target\n // collection the schema declares — the workspace doc store already serves them.\n referenceCandidates: cms.documentsOf,\n collections: cms.collections,\n isFieldReadOnly: cms.isFieldReadOnly,\n validate: cms.validate,\n resolveAsset,\n lastError: cms.persistError,\n clearLastError: cms.clearPersistError,\n // Baseline + queue flush, so a pre-flight reference-index read is current.\n flush: async () => {\n await cms.ensurePersistedBaseline()\n await cms.flushPersistence()\n },\n detailPath: (id: string) => studioPath.cmsDocument(collectionId, id),\n listPath: studioPath.cmsCollection(collectionId),\n viewState,\n setViewState,\n views,\n imports,\n create,\n save: cms.saveDocument,\n remove: cms.deleteDocument,\n bulk: (ids, action, setField) => cms.runBulk(collectionId, ids, action, setField),\n publishing: {\n isPublished: cms.isPublished,\n publish: cms.publishDocument,\n unpublish: cms.unpublishDocument,\n liveUrls,\n },\n // EC-445/EC-447: per-document timestamps behind the $updatedAt + $publishedAt\n // columns, sourced from the store (hydration seeds them from the persisted\n // `cmsDocuments.updatedAt` / `.publishedAt`; the store re-stamps on the edit +\n // publish/unpublish paths). Both are referentially-stable store accessors.\n timestamps: {\n updatedAt: cms.documentUpdatedAt,\n publishedAt: cms.documentPublishedAt,\n },\n versioning: {\n restore: (ref: DocumentRef, version: number, scope) =>\n cms.restoreDocumentVersion(ref, version, scope),\n // Flush-before-read ordering folds into the loader (EC-224) so any surface\n // that mutated the history still lists an authoritative version set.\n load: async (ref: DocumentRef) => {\n await cms.flushPersistence()\n return cms.loadDocumentVersions(ref)\n },\n },\n inlineEditing: {\n commitField: (input) => cms.commitFieldEdit(input),\n },\n }\n return source\n }, [\n collection,\n collectionId,\n cms,\n isRoutable,\n documents,\n viewState,\n setViewState,\n views,\n imports,\n create,\n resolveAsset,\n liveUrls,\n assetCollectionId,\n ])\n}\n"]}
|
|
@@ -83,12 +83,18 @@ export declare const STATE_FIELD = "$state";
|
|
|
83
83
|
* like a schema field (orderable / hideable / includable), but they are NOT drawn
|
|
84
84
|
* from `collection.fields` — the column UNIVERSE is `[...schemaFields, ...pseudoColumns]`.
|
|
85
85
|
*
|
|
86
|
-
* - `$state` — publication status
|
|
86
|
+
* - `$state` — publication status. A reserved `$`-key, but NO LONGER a reorderable
|
|
87
|
+
* column: EC-448 promoted it to a FIXED structural leading column (checkbox →
|
|
88
|
+
* status-dot → title), so it is NOT emitted by {@link pseudoColumns} and never
|
|
89
|
+
* participates in the reorderable columns/hidden/order model. It stays a reserved
|
|
90
|
+
* key (filter + sort) and {@link isPseudoColumn} still recognizes it, so an authored
|
|
91
|
+
* view listing `$state` is a harmless no-op (see {@link resolveConfigColumns}).
|
|
87
92
|
* - `$url` — the derived delivery URL (routable collections only; NON-sortable).
|
|
88
93
|
* - `$updatedAt` — the record's last-write timestamp.
|
|
89
|
-
* - `$publishedAt` —
|
|
90
|
-
*
|
|
91
|
-
*
|
|
94
|
+
* - `$publishedAt` — the record's FIRST-publish instant (EC-447; opt-in, HIDDEN by
|
|
95
|
+
* default). Now materialized end-to-end (`cmsDocuments.publishedAt` → source
|
|
96
|
+
* `timestamps.publishedAt`) and emitted by {@link pseudoColumns} when the source
|
|
97
|
+
* both materializes timestamps and has a publish lifecycle.
|
|
92
98
|
*/
|
|
93
99
|
export declare const URL_FIELD = "$url";
|
|
94
100
|
export declare const PUBLISHED_AT_FIELD = "$publishedAt";
|
|
@@ -102,18 +108,30 @@ export declare function isPseudoColumn(name: string): boolean;
|
|
|
102
108
|
export interface PseudoColumnOptions {
|
|
103
109
|
/** The source materializes per-document timestamps → `$updatedAt` applies. */
|
|
104
110
|
timestamps?: boolean;
|
|
105
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* The collection has a publish lifecycle. Gates `$publishedAt` (with `timestamps`).
|
|
113
|
+
* EC-448: it no longer gates a reorderable `$state` column — `$state` is the FIXED
|
|
114
|
+
* structural status column, gated by the same signal at the render site, not here.
|
|
115
|
+
*/
|
|
106
116
|
publishing?: boolean;
|
|
107
117
|
/** The collection resolves delivery URLs → `$url` applies (mirrors `urlByDocId`). */
|
|
108
118
|
routable?: boolean;
|
|
109
119
|
}
|
|
110
120
|
/**
|
|
111
|
-
* The reserved pseudo-columns that APPLY to a collection, in their default
|
|
112
|
-
* order (EC-445): `$updatedAt`,
|
|
113
|
-
* `routable` (a non-routable collection has no URL column, not an empty one),
|
|
114
|
-
* on `
|
|
115
|
-
*
|
|
116
|
-
*
|
|
121
|
+
* The reserved REORDERABLE pseudo-columns that APPLY to a collection, in their default
|
|
122
|
+
* appended order (EC-445/EC-447): `$updatedAt`, `$publishedAt`, then `$url`. `$url` is
|
|
123
|
+
* gated on `routable` (a non-routable collection has no URL column, not an empty one),
|
|
124
|
+
* `$updatedAt` on `timestamps`. `$publishedAt` (EC-447) needs BOTH `timestamps` (its
|
|
125
|
+
* materialized value) AND `publishing` (a publish lifecycle to have a publish date) —
|
|
126
|
+
* it is OPT-IN, HIDDEN by default (`DEFAULT_HIDDEN_PSEUDO_COLUMNS`), so it joins the
|
|
127
|
+
* universe/picker without appearing in the baseline lens.
|
|
128
|
+
*
|
|
129
|
+
* NOTE (EC-448): `$state` is NO LONGER emitted here. It became a FIXED structural
|
|
130
|
+
* leading column (checkbox → status-dot → title), rendered by `collection-table.tsx`
|
|
131
|
+
* regardless of the reorderable model — so it is never in the order/hide/picker set,
|
|
132
|
+
* even though `publishing` is what gates BOTH it and the status column's presence.
|
|
133
|
+
* `opts.publishing` therefore only affects `$publishedAt` here. Pure — a caller
|
|
134
|
+
* (`pseudoColumnsForSource`) supplies the signals from the source.
|
|
117
135
|
*/
|
|
118
136
|
export declare function pseudoColumns(collection: CollectionDef, opts?: PseudoColumnOptions): string[];
|
|
119
137
|
/**
|
|
@@ -63,17 +63,29 @@ const STATE_VALUES = ['draft', 'published'];
|
|
|
63
63
|
* like a schema field (orderable / hideable / includable), but they are NOT drawn
|
|
64
64
|
* from `collection.fields` — the column UNIVERSE is `[...schemaFields, ...pseudoColumns]`.
|
|
65
65
|
*
|
|
66
|
-
* - `$state` — publication status
|
|
66
|
+
* - `$state` — publication status. A reserved `$`-key, but NO LONGER a reorderable
|
|
67
|
+
* column: EC-448 promoted it to a FIXED structural leading column (checkbox →
|
|
68
|
+
* status-dot → title), so it is NOT emitted by {@link pseudoColumns} and never
|
|
69
|
+
* participates in the reorderable columns/hidden/order model. It stays a reserved
|
|
70
|
+
* key (filter + sort) and {@link isPseudoColumn} still recognizes it, so an authored
|
|
71
|
+
* view listing `$state` is a harmless no-op (see {@link resolveConfigColumns}).
|
|
67
72
|
* - `$url` — the derived delivery URL (routable collections only; NON-sortable).
|
|
68
73
|
* - `$updatedAt` — the record's last-write timestamp.
|
|
69
|
-
* - `$publishedAt` —
|
|
70
|
-
*
|
|
71
|
-
*
|
|
74
|
+
* - `$publishedAt` — the record's FIRST-publish instant (EC-447; opt-in, HIDDEN by
|
|
75
|
+
* default). Now materialized end-to-end (`cmsDocuments.publishedAt` → source
|
|
76
|
+
* `timestamps.publishedAt`) and emitted by {@link pseudoColumns} when the source
|
|
77
|
+
* both materializes timestamps and has a publish lifecycle.
|
|
72
78
|
*/
|
|
73
79
|
export const URL_FIELD = '$url';
|
|
74
80
|
export const PUBLISHED_AT_FIELD = '$publishedAt';
|
|
75
81
|
export const UPDATED_AT_FIELD = '$updatedAt';
|
|
76
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Every reserved pseudo-column key. `$state` is included (it is still a reserved
|
|
84
|
+
* `$`-key: the filter/sort axis + the FIXED structural status column, EC-448) so
|
|
85
|
+
* {@link isPseudoColumn} never mistakes it for a schema field — but it is NOT a
|
|
86
|
+
* reorderable column, so it is absent from the `pseudo` sets {@link pseudoColumns}
|
|
87
|
+
* emits into the order/hide/picker model.
|
|
88
|
+
*/
|
|
77
89
|
const PSEUDO_COLUMN_FIELDS = [
|
|
78
90
|
STATE_FIELD,
|
|
79
91
|
URL_FIELD,
|
|
@@ -90,20 +102,32 @@ export function isPseudoColumn(name) {
|
|
|
90
102
|
*/
|
|
91
103
|
const DEFAULT_HIDDEN_PSEUDO_COLUMNS = new Set([PUBLISHED_AT_FIELD]);
|
|
92
104
|
/**
|
|
93
|
-
* The reserved pseudo-columns that APPLY to a collection, in their default
|
|
94
|
-
* order (EC-445): `$updatedAt`,
|
|
95
|
-
* `routable` (a non-routable collection has no URL column, not an empty one),
|
|
96
|
-
* on `
|
|
97
|
-
*
|
|
98
|
-
*
|
|
105
|
+
* The reserved REORDERABLE pseudo-columns that APPLY to a collection, in their default
|
|
106
|
+
* appended order (EC-445/EC-447): `$updatedAt`, `$publishedAt`, then `$url`. `$url` is
|
|
107
|
+
* gated on `routable` (a non-routable collection has no URL column, not an empty one),
|
|
108
|
+
* `$updatedAt` on `timestamps`. `$publishedAt` (EC-447) needs BOTH `timestamps` (its
|
|
109
|
+
* materialized value) AND `publishing` (a publish lifecycle to have a publish date) —
|
|
110
|
+
* it is OPT-IN, HIDDEN by default (`DEFAULT_HIDDEN_PSEUDO_COLUMNS`), so it joins the
|
|
111
|
+
* universe/picker without appearing in the baseline lens.
|
|
112
|
+
*
|
|
113
|
+
* NOTE (EC-448): `$state` is NO LONGER emitted here. It became a FIXED structural
|
|
114
|
+
* leading column (checkbox → status-dot → title), rendered by `collection-table.tsx`
|
|
115
|
+
* regardless of the reorderable model — so it is never in the order/hide/picker set,
|
|
116
|
+
* even though `publishing` is what gates BOTH it and the status column's presence.
|
|
117
|
+
* `opts.publishing` therefore only affects `$publishedAt` here. Pure — a caller
|
|
118
|
+
* (`pseudoColumnsForSource`) supplies the signals from the source.
|
|
99
119
|
*/
|
|
100
120
|
export function pseudoColumns(collection, opts = {}) {
|
|
101
121
|
void collection; // reserved for future per-collection gating; kept for API symmetry
|
|
102
122
|
const cols = [];
|
|
103
123
|
if (opts.timestamps)
|
|
104
124
|
cols.push(UPDATED_AT_FIELD);
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
// EC-447: a publish date needs both a timestamps source (the value) AND a publish
|
|
126
|
+
// lifecycle (the meaning). Hidden by default → surfaced via the Display picker / a
|
|
127
|
+
// config view's `columns`, never a blank column on a rail that can't publish.
|
|
128
|
+
if (opts.timestamps && opts.publishing)
|
|
129
|
+
cols.push(PUBLISHED_AT_FIELD);
|
|
130
|
+
// EC-448: $state is structural (fixed leading column), not a reorderable pseudo-column.
|
|
107
131
|
if (opts.routable)
|
|
108
132
|
cols.push(URL_FIELD);
|
|
109
133
|
return cols;
|
|
@@ -444,9 +468,12 @@ export function resolveConfigColumns(collection, visible, pseudo = []) {
|
|
|
444
468
|
const rest = universe.filter((name) => !seen.has(name));
|
|
445
469
|
// EC-445: a schema-ONLY authored list (mentioning no pseudo-column) keeps the
|
|
446
470
|
// applicable pseudo-columns at their DEFAULT visibility — so a consumer's
|
|
447
|
-
// pre-EC-445 `columns:[…schema…]` list still shows today's
|
|
448
|
-
// Mentioning ANY pseudo-column switches them to the visible-list rule
|
|
449
|
-
|
|
471
|
+
// pre-EC-445 `columns:[…schema…]` list still shows today's url (+ updatedAt).
|
|
472
|
+
// Mentioning ANY reorderable pseudo-column switches them to the visible-list rule
|
|
473
|
+
// (only listed shows). EC-448: `$state` is EXCLUDED here — it is a fixed structural
|
|
474
|
+
// column, not a reorderable one, so an authored `$state` is an inert no-op: it must
|
|
475
|
+
// not flip the visible-list rule (nor is it in the universe, so it is simply dropped).
|
|
476
|
+
const mentionsPseudo = visible.some((name) => isPseudoColumn(name) && name !== STATE_FIELD);
|
|
450
477
|
const keepVisible = mentionsPseudo
|
|
451
478
|
? new Set()
|
|
452
479
|
: new Set(pseudo.filter((name) => !DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(name)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-model.js","sourceRoot":"","sources":["../../../src/lib/cms-views/view-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod'\nimport {\n documentDefaultLocale,\n localizedStringSchema,\n resolveField,\n resolveLabel,\n titleFieldOf,\n} from '@elytracms/core/cms-core'\nimport { localizedLabel } from '@elytracms/studio/lib/i18n'\nimport type {\n CmsDocument,\n CollectionDef,\n FieldDef,\n LocaleConfig,\n LocalizedString,\n} from '@elytracms/core/cms-core'\nimport {\n FILTER_OPERATORS,\n compareListEntries,\n filterScalarOf,\n filterableFields,\n matchesFieldValue,\n validateWhere,\n} from '@elytracms/core/content'\nimport type {\n FilterCondition,\n FilterOperator,\n FilterScalar,\n NormalizedCondition,\n WhereInput,\n} from '@elytracms/core/content'\n\n/**\n * The pure table-view model for the CMS collection table (EC-169).\n *\n * A view bundles three things: filters in the closed AD-3 vocabulary\n * (`eq`/`in`/`lt`/`lte`/`gt`/`gte`, AND-only — exactly `@elytracms/core/content`'s\n * query model, evaluated with the same matching/ordering primitives), a sort\n * (field + direction), and the visible/ordered columns. Everything here is\n * plain data + functions so filtering, dirtiness, and column edits are\n * testable without a DOM.\n *\n * Filters are offered ONLY on fields the schema declares `filterable: true`\n * (EC-143), plus one built-in option: the document's publication state. The\n * state is document metadata, not a schema field — it powers the\n * \"show me drafts → bulk publish\" working set and still speaks only the\n * closed vocabulary (`eq`/`in`).\n */\n\n// --- Schemas (single source of truth — persisted view records reuse these) ----\n\nexport const filterScalarSchema = z.union([z.string(), z.number(), z.boolean()])\n\nexport const filterClauseSchema = z.object({\n /** A schema field name, or {@link STATE_FIELD} for the publication state. */\n field: z.string().min(1),\n op: z.enum(FILTER_OPERATORS),\n /** `in` carries an array of scalars; every other operator one scalar. */\n value: z.union([filterScalarSchema, z.array(filterScalarSchema)]),\n})\nexport type FilterClause = z.infer<typeof filterClauseSchema>\n\nexport const viewSortSchema = z.object({\n field: z.string().min(1),\n dir: z.enum(['asc', 'desc']),\n})\nexport type ViewSort = z.infer<typeof viewSortSchema>\n\nexport const tableViewStateSchema = z.object({\n /** AND-only list of conditions (no OR, no nesting — vision AD-3). */\n filters: z.array(filterClauseSchema),\n sort: viewSortSchema.nullable(),\n /**\n * The canonical column order (field names) — EVERY column, visible or not\n * (EC-213). Order is independent of visibility: hiding then re-showing a\n * column keeps its place. Schema fields absent here resolve in at the end\n * (see {@link resolveColumns}).\n */\n columns: z.array(z.string().min(1)),\n /**\n * The subset of {@link TableViewState.columns} that is hidden. Defaults to\n * `[]` so views persisted before EC-213 (no `hidden` key) load unchanged.\n */\n hidden: z.array(z.string().min(1)).default([]),\n})\nexport type TableViewState = z.infer<typeof tableViewStateSchema>\n\n// --- The built-in publication-state filter column ------------------------------\n\n/**\n * Sentinel field key for the publication state. `$`-prefixed so it can never\n * collide with a schema field name (`fieldDefSchema` names are identifiers).\n */\nexport const STATE_FIELD = '$state'\n\nconst STATE_VALUES = ['draft', 'published'] as const\n\n// --- Reserved pseudo-COLUMNS (EC-445) ------------------------------------------\n\n/**\n * Reserved pseudo-COLUMN keys — the columns-axis siblings of the filter-axis\n * {@link STATE_FIELD}. `$`-prefixed so they can never collide with a schema field\n * name; they participate in a view's `columns` list AND the Display picker exactly\n * like a schema field (orderable / hideable / includable), but they are NOT drawn\n * from `collection.fields` — the column UNIVERSE is `[...schemaFields, ...pseudoColumns]`.\n *\n * - `$state` — publication status (already a filter pseudo-field; now a column too).\n * - `$url` — the derived delivery URL (routable collections only; NON-sortable).\n * - `$updatedAt` — the record's last-write timestamp.\n * - `$publishedAt` — when the live version was published (opt-in, HIDDEN by default).\n * RESERVED: its data path (materialize `publishedAt`) is an EC-445 follow-up, so it\n * is not yet emitted by {@link pseudoColumns}; the constant + sort support ship now.\n */\nexport const URL_FIELD = '$url'\nexport const PUBLISHED_AT_FIELD = '$publishedAt'\nexport const UPDATED_AT_FIELD = '$updatedAt'\n\n/** Every reserved pseudo-column key (the columns-axis `$state` included). */\nconst PSEUDO_COLUMN_FIELDS: readonly string[] = [\n STATE_FIELD,\n URL_FIELD,\n PUBLISHED_AT_FIELD,\n UPDATED_AT_FIELD,\n]\n\n/** Is `name` a reserved pseudo-column (a `$`-key, not a schema field)? */\nexport function isPseudoColumn(name: string): boolean {\n return PSEUDO_COLUMN_FIELDS.includes(name)\n}\n\n/**\n * Pseudo-columns HIDDEN by default (opt-in): the extra publish timestamp. Everything\n * else applicable (`$updatedAt`/`$state`/`$url`) is on by default (owner, 2026-07-17).\n */\nconst DEFAULT_HIDDEN_PSEUDO_COLUMNS: ReadonlySet<string> = new Set([PUBLISHED_AT_FIELD])\n\n/**\n * Capability signals that make a pseudo-column applicable to a collection/source\n * (EC-445). Supplied by the caller from the portable source — the model stays pure.\n */\nexport interface PseudoColumnOptions {\n /** The source materializes per-document timestamps → `$updatedAt` applies. */\n timestamps?: boolean\n /** The collection has a publish lifecycle → `$state` applies (EC-346 gate). */\n publishing?: boolean\n /** The collection resolves delivery URLs → `$url` applies (mirrors `urlByDocId`). */\n routable?: boolean\n}\n\n/**\n * The reserved pseudo-columns that APPLY to a collection, in their default appended\n * order (EC-445): `$updatedAt`, then `$state`, then `$url`. `$url` is gated on\n * `routable` (a non-routable collection has no URL column, not an empty one), `$state`\n * on `publishing` (a lifecycle-less rail shows no status), `$updatedAt` on `timestamps`.\n * `$publishedAt` is reserved but not yet emitted (its data path is an EC-445 follow-up).\n * Pure — a caller (`pseudoColumnsForSource`) supplies the signals from the source.\n */\nexport function pseudoColumns(collection: CollectionDef, opts: PseudoColumnOptions = {}): string[] {\n void collection // reserved for future per-collection gating; kept for API symmetry\n const cols: string[] = []\n if (opts.timestamps) cols.push(UPDATED_AT_FIELD)\n if (opts.publishing) cols.push(STATE_FIELD)\n if (opts.routable) cols.push(URL_FIELD)\n return cols\n}\n\n/**\n * The per-document metadata accessors the pseudo-DATE columns sort by (EC-445) — the\n * columns-axis analogue of {@link IsPublished}. Threaded into the sort machinery so a\n * `$updatedAt`/`$publishedAt` sort orders by the source's materialized timestamp; a\n * missing accessor (fixtures/tests) sorts those rows last. `$url` is derived → never sorted.\n */\nexport interface PseudoColumnMeta {\n updatedAt?(doc: CmsDocument): string | undefined\n publishedAt?(doc: CmsDocument): string | undefined\n}\n\n/** One field the filter builder may offer. */\nexport interface FilterableFieldOption {\n /** Clause field key: a schema field name, or {@link STATE_FIELD}. */\n field: string\n label: string\n /** The schema field def, or `null` for the built-in publication state. */\n def: FieldDef | null\n}\n\nexport const STATE_OPTION: FilterableFieldOption = {\n field: STATE_FIELD,\n label: 'State',\n def: null,\n}\n\n/**\n * The closed list of fields the filter builder offers: exactly the schema's\n * `filterable: true` fields (EC-143) plus the publication state. Nothing else\n * is ever offered — the UI builds queries, it does not invent a language.\n */\nexport function filterableFieldOptions(collection: CollectionDef): FilterableFieldOption[] {\n const schemaOptions = filterableFields(collection).map((field) => ({\n field: field.name,\n label: localizedLabel(field.form?.label, field.name),\n def: field,\n }))\n return [...schemaOptions, STATE_OPTION]\n}\n\nexport function filterOptionFor(\n collection: CollectionDef,\n field: string,\n): FilterableFieldOption | undefined {\n return filterableFieldOptions(collection).find((option) => option.field === field)\n}\n\n// --- Operators per field type (EC-345) ------------------------------------------\n\n/**\n * The per-type operator SET the builder offers (EC-345), always a subset of the\n * closed `FILTER_OPERATORS` — the UI narrows the vocabulary, it never extends it.\n * Ratified sets (Oli, 2026-07-08):\n *\n * - text: contains (default) · equals · starts with · ends with · empty\n * - number: equals · < · ≤ · > · ≥ · empty\n * - date: equals · before · … · after · empty (same ops as number, date labels)\n * - boolean: is\n * - select: is · is any of · empty\n * - relation / asset: is · is any of · empty (relation value = the relation picker;\n * `eq` on a `multiple` relation is membership — array-contains, EC-255 semantics)\n * - state pseudo-field: is · is any of (unchanged — a publication state is never empty)\n */\nexport function operatorsFor(option: FilterableFieldOption): FilterOperator[] {\n if (option.def === null) return ['eq', 'in'] // publication state\n switch (option.def.type) {\n case 'boolean':\n return ['eq']\n case 'number':\n case 'date':\n return ['eq', 'lt', 'lte', 'gt', 'gte', 'empty']\n case 'select':\n case 'relation':\n case 'asset':\n return ['eq', 'in', 'empty']\n default:\n // text (and any other string-shaped field)\n return ['contains', 'eq', 'startsWith', 'endsWith', 'empty']\n }\n}\n\n/**\n * A visual choice in the operator dropdown (EC-345). Usually one per operator,\n * but `empty` splits into two — \"is empty\" (`true`) and \"is not empty\" (`false`) —\n * so an editor never has to reason about a boolean value; the choice carries the\n * preset. `token` is the `<option value>`, `labelKey` a catalog key ({@link operatorLabelKey}).\n */\nexport interface OperatorChoice {\n token: string\n op: FilterOperator\n /** Value forced when this choice is picked (the `empty` true/false), else undefined. */\n presetValue?: FilterScalar\n labelKey: string\n}\n\n/**\n * The operator dropdown entries for a field (EC-345): {@link operatorsFor} expanded\n * for display, with `empty` shown as the two self-describing choices.\n */\nexport function operatorChoices(option: FilterableFieldOption): OperatorChoice[] {\n const choices: OperatorChoice[] = []\n for (const op of operatorsFor(option)) {\n if (op === 'empty') {\n choices.push({ token: 'empty:true', op, presetValue: true, labelKey: 'cms.filter.op.isEmpty' })\n choices.push({\n token: 'empty:false',\n op,\n presetValue: false,\n labelKey: 'cms.filter.op.isNotEmpty',\n })\n continue\n }\n choices.push({ token: op, op, labelKey: operatorLabelKey(op, option) })\n }\n return choices\n}\n\n/**\n * The catalog key for an operator's label (EC-241/EC-345), keyed by operator AND\n * field type — `eq` reads \"equals\" on text/number, \"on\" on a date, \"is\" on an\n * enum-like field; `lt` reads \"less than\" on a number, \"before\" on a date. `empty`\n * additionally depends on its VALUE (is empty / is not empty). Pure → unit-tested.\n */\nexport function operatorLabelKey(\n op: FilterOperator,\n option: FilterableFieldOption | undefined,\n value?: FilterScalar | readonly FilterScalar[],\n): string {\n const type = option?.def?.type\n switch (op) {\n case 'contains':\n return 'cms.filter.op.contains'\n case 'startsWith':\n return 'cms.filter.op.startsWith'\n case 'endsWith':\n return 'cms.filter.op.endsWith'\n case 'in':\n return 'cms.filter.op.isAnyOf'\n case 'empty':\n return value === false ? 'cms.filter.op.isNotEmpty' : 'cms.filter.op.isEmpty'\n case 'eq':\n // \"on\" for a date; \"is\" for enum-like refs; \"equals\" for text/number/unknown\n // (and the publication-state pseudo-field, whose `def` is null → unchanged).\n if (type === 'date') return 'cms.filter.op.on'\n if (type === 'boolean' || type === 'select' || type === 'relation' || type === 'asset') {\n return 'cms.filter.op.is'\n }\n return 'cms.filter.op.equals'\n case 'lt':\n return type === 'date' ? 'cms.filter.op.before' : 'cms.filter.op.lessThan'\n case 'lte':\n return type === 'date' ? 'cms.filter.op.onOrBefore' : 'cms.filter.op.atMost'\n case 'gt':\n return type === 'date' ? 'cms.filter.op.after' : 'cms.filter.op.greaterThan'\n case 'gte':\n return type === 'date' ? 'cms.filter.op.onOrAfter' : 'cms.filter.op.atLeast'\n }\n}\n\n/** A sensible starting clause when a field is added to the builder (EC-345). */\nexport function defaultClause(option: FilterableFieldOption): FilterClause {\n if (option.def === null) return { field: STATE_FIELD, op: 'eq', value: 'published' }\n switch (option.def.type) {\n case 'boolean':\n return { field: option.field, op: 'eq', value: true }\n case 'number':\n case 'date':\n return { field: option.field, op: 'eq', value: option.def.type === 'number' ? 0 : '' }\n case 'select':\n return { field: option.field, op: 'eq', value: option.def.options[0]?.value ?? '' }\n case 'relation':\n case 'asset':\n return { field: option.field, op: 'eq', value: '' }\n default:\n // text (and any other string-shaped field): `contains` is the natural default\n return { field: option.field, op: 'contains', value: '' }\n }\n}\n\n// --- Text ⇄ scalar coercion (the value inputs of the builder) -------------------\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/\n\n/** Coerce one text input into the scalar a clause compares against. */\nexport function scalarFromText(\n option: FilterableFieldOption | undefined,\n raw: string,\n): FilterScalar {\n const type = option?.def?.type\n if (type === 'number') {\n const trimmed = raw.trim()\n if (trimmed === '') return raw // an emptied input must not become eq 0\n const parsed = Number(trimmed)\n return Number.isNaN(parsed) ? raw : parsed\n }\n if (type === 'boolean') return raw === 'true'\n // Stored dates are full ISO strings; a date-input value compares correctly\n // once expanded to midnight UTC (ISO strings order by code units).\n if (type === 'date' && DATE_ONLY.test(raw)) return `${raw}T00:00:00.000Z`\n return raw\n}\n\n/** Parse a comma-separated list for the `in` operator. */\nexport function scalarListFromText(\n option: FilterableFieldOption | undefined,\n raw: string,\n): FilterScalar[] {\n return raw\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part !== '')\n .map((part) => scalarFromText(option, part))\n}\n\nexport function scalarListToText(value: FilterScalar | FilterScalar[]): string {\n const list = Array.isArray(value) ? value : [value]\n return list.map(String).join(', ')\n}\n\n// --- Clause validation -----------------------------------------------------------\n\n/** A structured problem with one clause (by index in the filter list). */\nexport interface ClauseIssue {\n index: number\n message: string\n}\n\n/**\n * Validate clauses against the collection schema. Schema-field clauses run\n * through the canonical `validateWhere` (EC-143: `filterable` enforcement +\n * operator/value shape); state clauses check the `eq`/`in` subset and the\n * draft/published value set. Invalid clauses (e.g. a persisted view whose\n * field is no longer filterable) are reported — never silently applied.\n */\nexport function validateClauses(\n collection: CollectionDef,\n clauses: readonly FilterClause[],\n): ClauseIssue[] {\n const issues: ClauseIssue[] = []\n clauses.forEach((clause, index) => {\n if (clause.field === STATE_FIELD) {\n if (clause.op !== 'eq' && clause.op !== 'in') {\n issues.push({ index, message: 'State filters support only \"eq\" and \"in\".' })\n return\n }\n const values = Array.isArray(clause.value) ? clause.value : [clause.value]\n if (!values.every((value) => (STATE_VALUES as readonly unknown[]).includes(value))) {\n issues.push({ index, message: 'State must be \"draft\" or \"published\".' })\n }\n return\n }\n const where: WhereInput = {\n [clause.field]: { [clause.op]: clause.value } as FilterCondition,\n }\n const errors = validateWhere(collection, where)\n if (errors.length > 0) issues.push({ index, message: errors[0]!.message })\n })\n return issues\n}\n\n// --- Matching & sorting (delegates to @elytracms/core/content's primitives) -------------\n\n/**\n * Published-ness source for the `$state` pseudo-field (EC-224): the version\n * POINTER, supplied by the caller as `cms.isPublished`. Defaults to \"nothing\n * published\" — a bare row carries no publish signal now that the flat `state`\n * field is gone, so the table (which knows the pointer) passes the real\n * predicate; fixtures/tests that don't surface `$state` get the safe default.\n */\nexport type IsPublished = (doc: CmsDocument) => boolean\nconst defaultIsPublished: IsPublished = () => false\n\n/**\n * The RAW locale-resolved value a document exposes for a clause field — an array\n * for a `multiple` relation/asset, a ref object for a single one, a scalar\n * otherwise. Matching runs on this (via `matchesFieldValue`) so it agrees with the\n * delivery/listing path exactly: array-contains for `multiple` relations (EC-255)\n * and whole-value `empty` semantics (EC-345). Sorting keeps its own scalar reduction.\n */\nfunction rawValueOf(\n collection: CollectionDef,\n doc: CmsDocument,\n field: string,\n localeConfig: LocaleConfig,\n isPublished: IsPublished,\n): unknown {\n if (field === STATE_FIELD) return isPublished(doc) ? 'published' : 'draft'\n if (!collection.fields.some((f) => f.name === field)) return undefined\n const locale = documentDefaultLocale(doc, localeConfig)\n return resolveField(collection, doc, field, locale, localeConfig).value\n}\n\n/** The scalar a document exposes for a SORT field, locale-resolved. */\nfunction scalarOf(\n collection: CollectionDef,\n doc: CmsDocument,\n field: string,\n localeConfig: LocaleConfig,\n isPublished: IsPublished,\n meta: PseudoColumnMeta = {},\n): FilterScalar | null {\n if (field === STATE_FIELD) return isPublished(doc) ? 'published' : 'draft'\n // EC-445: the pseudo-DATE columns sort by the source's materialized ISO timestamp\n // (ISO strings order lexicographically = chronologically); `$url` is derived → not sortable.\n if (field === UPDATED_AT_FIELD) return meta.updatedAt?.(doc) ?? null\n if (field === PUBLISHED_AT_FIELD) return meta.publishedAt?.(doc) ?? null\n if (field === URL_FIELD) return null\n if (!collection.fields.some((f) => f.name === field)) return null\n const locale = documentDefaultLocale(doc, localeConfig)\n return filterScalarOf(resolveField(collection, doc, field, locale, localeConfig).value)\n}\n\n/**\n * Does a document satisfy one clause? Identical verdict to the content accessors'\n * delivery/listing path: both reduce to `@elytracms/core/content`'s\n * `matchesFieldValue` over the RAW field value (so `contains`/`empty`/multiple-\n * relation membership all behave the same on the table as on the live site).\n */\nexport function clauseMatches(\n collection: CollectionDef,\n doc: CmsDocument,\n localeConfig: LocaleConfig,\n clause: FilterClause,\n isPublished: IsPublished = defaultIsPublished,\n): boolean {\n const value = rawValueOf(collection, doc, clause.field, localeConfig, isPublished)\n const condition = { [clause.op]: clause.value } as NormalizedCondition\n return matchesFieldValue(value, condition)\n}\n\n/**\n * Sort documents by one column in the canonical deterministic order\n * (`compareListEntries`: typed value order, id-ascending tiebreak). Unlike the\n * content accessors, the *table* may sort any rendered column — sorting is a\n * presentation concern here; the `filterable` flag governs filters.\n */\nexport function sortViewDocuments(\n collection: CollectionDef,\n docs: readonly CmsDocument[],\n localeConfig: LocaleConfig,\n sort: ViewSort | null,\n isPublished: IsPublished = defaultIsPublished,\n meta: PseudoColumnMeta = {},\n): CmsDocument[] {\n if (sort === null) return [...docs]\n const positions = new Map(\n docs.map((doc) => [\n doc.id,\n scalarOf(collection, doc, sort.field, localeConfig, isPublished, meta),\n ]),\n )\n return [...docs].sort((a, b) =>\n compareListEntries(\n { id: a.id, sortValue: positions.get(a.id) ?? null },\n { id: b.id, sortValue: positions.get(b.id) ?? null },\n sort.dir,\n ),\n )\n}\n\n/** The filtered + sorted documents of a view, plus any clause issues. */\nexport interface AppliedViewState {\n docs: CmsDocument[]\n /** Clauses that failed validation — reported AND excluded from matching. */\n issues: ClauseIssue[]\n}\n\n/**\n * Apply a view state to a document list: validate clauses, AND-match the valid\n * ones, sort. Invalid clauses never filter silently — they come back as\n * issues for the UI to surface.\n */\nexport function applyViewState(\n collection: CollectionDef,\n docs: readonly CmsDocument[],\n localeConfig: LocaleConfig,\n state: TableViewState,\n isPublished: IsPublished = defaultIsPublished,\n meta: PseudoColumnMeta = {},\n): AppliedViewState {\n const issues = validateClauses(collection, state.filters)\n const invalid = new Set(issues.map((issue) => issue.index))\n const active = state.filters.filter((_, index) => !invalid.has(index))\n const matched = docs.filter((doc) =>\n active.every((clause) => clauseMatches(collection, doc, localeConfig, clause, isPublished)),\n )\n return {\n docs: sortViewDocuments(collection, matched, localeConfig, state.sort, isPublished, meta),\n issues,\n }\n}\n\n// --- View state construction, equality, columns ----------------------------------\n\n/** The id of the synthesized built-in \"All entries\" baseline view (EC-444). */\nexport const ALL_VIEW_ID = 'all'\n\n/** The default (unnamed) view: no filters, no sort, every field visible. */\n/**\n * Field types kept OFF the default table columns (EC-246b): the composite editing\n * surfaces — a blocks canvas, rich text, a structured object/repeater — read as\n * noise in a scalar list. `filterable` no longer forces (or governs) a column; the\n * default lens is \"all scalars\". These stay in the column picker one toggle away,\n * and any named view may list them in its `columns`; they're just off by default.\n */\nconst NON_DEFAULT_COLUMN_TYPES = new Set<FieldDef['type']>(['blocks', 'richText', 'object'])\n\n/**\n * Field names OFF the built-in baseline lens by default: exactly the composite\n * editing surfaces (blocks/richText/object) — always noise in a scalar list. The\n * default lens is \"all scalars\"; there is no per-field column opt-out any more\n * (EC-444 hard-removed `form.column`). A field stays in the picker one toggle away,\n * and a view curates columns by declaring an explicit `columns` list (or the\n * `id: 'default'` baseline override).\n */\nfunction defaultHiddenColumns(collection: CollectionDef, pseudo: readonly string[] = []): string[] {\n const composites = collection.fields\n .filter((f) => NON_DEFAULT_COLUMN_TYPES.has(f.type))\n .map((f) => f.name)\n // EC-445: applicable opt-in pseudo-columns ($publishedAt) start hidden; the rest\n // ($updatedAt/$state/$url) are visible by default (owner: keep them on).\n const hiddenPseudo = pseudo.filter((name) => DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(name))\n return [...composites, ...hiddenPseudo]\n}\n\nexport function defaultViewState(\n collection: CollectionDef,\n pseudo: readonly string[] = [],\n): TableViewState {\n return {\n filters: [],\n sort: null,\n // Every field keeps a slot (order + picker), but the composite surfaces start\n // hidden so the default lens is the collection's scalar columns (EC-246b/EC-444).\n // EC-445: the applicable reserved pseudo-columns append after the data columns.\n columns: orderedColumnNames(collection, pseudo),\n hidden: defaultHiddenColumns(collection, pseudo),\n }\n}\n\n/**\n * Resolve an authored VISIBLE column list (EC-444) into the internal two-axis\n * `{columns, hidden}` table state. The authored list is exactly the columns shown,\n * in order; every OTHER schema field is appended (in schema order) and hidden — the\n * same shape {@link defaultViewState} produces, so {@link resolveColumns} renders\n * precisely the authored list, visible, in that order. An omitted (or empty) list\n * inherits the collection's default lens (all scalars visible, composites hidden).\n * Unknown names in the authored list (a field the schema no longer has) are dropped.\n */\nexport function resolveConfigColumns(\n collection: CollectionDef,\n visible: readonly string[] | undefined,\n pseudo: readonly string[] = [],\n): Pick<TableViewState, 'columns' | 'hidden'> {\n if (visible === undefined || visible.length === 0) {\n const base = defaultViewState(collection, pseudo)\n return { columns: base.columns, hidden: base.hidden }\n }\n const universe = orderedColumnNames(collection, pseudo)\n const inUniverse = new Set(universe)\n const seen = new Set<string>()\n const shown: string[] = []\n for (const name of visible) {\n if (inUniverse.has(name) && !seen.has(name)) {\n shown.push(name)\n seen.add(name)\n }\n }\n const rest = universe.filter((name) => !seen.has(name))\n // EC-445: a schema-ONLY authored list (mentioning no pseudo-column) keeps the\n // applicable pseudo-columns at their DEFAULT visibility — so a consumer's\n // pre-EC-445 `columns:[…schema…]` list still shows today's status + url (+ updatedAt).\n // Mentioning ANY pseudo-column switches them to the visible-list rule (only listed shows).\n const mentionsPseudo = visible.some(isPseudoColumn)\n const keepVisible = mentionsPseudo\n ? new Set<string>()\n : new Set(pseudo.filter((name) => !DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(name)))\n const hidden = rest.filter((name) => !keepVisible.has(name))\n return { columns: [...shown, ...rest], hidden }\n}\n\n/** The reserved `views[]` id whose entry OVERRIDES the synthesized baseline view (EC-444). */\nexport const DEFAULT_VIEW_OVERRIDE_ID = 'default'\n\n/**\n * A config-declared view (EC-246b/EC-444) — the flat authoring shape a collection\n * declares in `cms/` config: `{ name, initial?, filters?, sort?, columns? }`.\n * Filters/sort/columns sit at the top level (no nested `state` wrapper). The\n * studio validates + interprets these; `cms-core` stores them opaquely (it\n * can't reference the filter vocabulary without a layering cycle).\n */\nexport const configViewSchema = z.object({\n /**\n * Optional stable id; defaults to a slug of `name`. The reserved value\n * {@link DEFAULT_VIEW_OVERRIDE_ID} (`'default'`) marks the baseline-override entry.\n */\n id: z.string().min(1).optional(),\n /**\n * View label; localizable (EC-343): a plain string or a `{ locale }` map, resolved\n * at the render site via the same `resolveLabel` path as `form.label` (EC-241).\n */\n name: localizedStringSchema,\n /**\n * When true this view seeds the collection's INITIAL active view (EC-343/EC-444) —\n * the curated lens an editor lands on before picking one. At most one per collection;\n * a duplicate is a visible validation issue ({@link configViewIssues}), never silent.\n * The baseline lens stays available and stays the fallback.\n */\n initial: z.boolean().optional(),\n /**\n * @deprecated EC-444 — renamed to {@link ConfigView.initial}. Still read as an alias\n * for one release (`initial ?? default`) with a console warning; removed next release.\n * Distinct from a field's default VALUE and from the reserved `id: 'default'` override.\n */\n default: z.boolean().optional(),\n filters: z.array(filterClauseSchema).optional(),\n sort: viewSortSchema.nullable().optional(),\n /**\n * The single ordered list of VISIBLE columns (EC-444): what you list is what shows,\n * in that order. Omit to inherit the collection's default columns (all scalars). The\n * two-axis `{columns, hidden}` internal state is derived by {@link resolveConfigColumns}.\n */\n columns: z.array(z.string().min(1)).optional(),\n})\nexport type ConfigView = z.infer<typeof configViewSchema>\n\n/**\n * A resolved view: identity + the table state it restores (matches `SavedView`).\n * `name` stays a {@link LocalizedString} — resolved at the render site (EC-343), like\n * `form.label`. `initial` marks the first-load seed (see {@link defaultConfigViewId}),\n * resolved from the authored `initial ?? default` flag (EC-444).\n */\nexport interface ResolvedView {\n id: string\n name: LocalizedString\n state: TableViewState\n initial?: boolean\n}\n\n/**\n * Slug used to derive a config view's stable id from its name. A localized name\n * (EC-343) slugs its DEFAULT-locale text so the id is stable across the active UI\n * locale (an id must not shift when a German editor loads the same config).\n */\nfunction configViewId(name: LocalizedString, index: number): string {\n const text = resolveLabel(name) ?? ''\n const slug = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return `config:${slug || index}`\n}\n\n/**\n * Resolve a collection's config-declared `views` into full {@link ResolvedView}s\n * (EC-246b). Each is validated with {@link configViewSchema}; malformed entries\n * and duplicate ids are dropped (defensive). Columns fall back to the collection\n * default when a view doesn't pin them, so a filter-only view still renders every\n * column. Config views are shared and change only in\n * code — the runtime never mutates them.\n */\nexport function configViewsFor(\n collection: CollectionDef,\n pseudo: readonly string[] = [],\n): ResolvedView[] {\n const declared = collection.views\n if (!Array.isArray(declared)) return []\n const seen = new Set<string>()\n const resolved: ResolvedView[] = []\n declared.forEach((raw, index) => {\n const parsed = configViewSchema.safeParse(raw)\n if (!parsed.success) return\n const view = parsed.data\n const id = view.id ?? configViewId(view.name, index)\n if (seen.has(id)) return\n seen.add(id)\n // EC-444: `initial` supersedes the deprecated `default` alias (one-release window).\n const initial = view.initial ?? view.default\n const { columns, hidden } = resolveConfigColumns(collection, view.columns, pseudo)\n resolved.push({\n id,\n name: view.name,\n ...(initial ? { initial: true } : {}),\n state: normalizeViewState({\n filters: view.filters ?? [],\n sort: view.sort ?? null,\n columns,\n hidden,\n }),\n })\n })\n return resolved\n}\n\n/**\n * Does the collection declare a baseline-override view (a config view whose id is\n * {@link DEFAULT_VIEW_OVERRIDE_ID})? When true the synthesized \"All entries\" lens is\n * replaced by that entry verbatim (see {@link resolveCollectionViews}), EC-444.\n */\nexport function hasDefaultViewOverride(collection: CollectionDef): boolean {\n return configViewsFor(collection).some((view) => view.id === DEFAULT_VIEW_OVERRIDE_ID)\n}\n\n/**\n * The ordered view list a collection surfaces (EC-444): the baseline first, then the\n * config-declared views in declaration order. The baseline is either an authored\n * OVERRIDE (the config view whose id is {@link DEFAULT_VIEW_OVERRIDE_ID}, used\n * VERBATIM and NOT repeated among the trailing views) or, absent one, the\n * `synthesizedBaseline` the caller passes (the studio's translated \"All entries\"\n * lens). Pure — the store supplies the synthesized baseline (i18n-bound `name`).\n */\nexport function resolveCollectionViews(\n collection: CollectionDef,\n synthesizedBaseline: ResolvedView,\n pseudo: readonly string[] = [],\n): ResolvedView[] {\n const configViews = configViewsFor(collection, pseudo)\n const overrideIndex = configViews.findIndex((view) => view.id === DEFAULT_VIEW_OVERRIDE_ID)\n if (overrideIndex < 0) return [synthesizedBaseline, ...configViews]\n const override = configViews[overrideIndex]!\n const rest = configViews.filter((_, index) => index !== overrideIndex)\n return [override, ...rest]\n}\n\n/**\n * The ids of config views that still use the DEPRECATED `default` flag without the\n * new `initial` (EC-444). Drives the one-release deprecation warning (mirrors the\n * duplicate-default channel); empty once every view has migrated to `initial`.\n */\nexport function deprecatedDefaultFlagViewIds(collection: CollectionDef): string[] {\n const declared = collection.views\n if (!Array.isArray(declared)) return []\n const seen = new Set<string>()\n const ids: string[] = []\n declared.forEach((raw, index) => {\n const parsed = configViewSchema.safeParse(raw)\n if (!parsed.success) return\n const view = parsed.data\n const id = view.id ?? configViewId(view.name, index)\n if (seen.has(id)) return\n seen.add(id)\n if (view.default !== undefined && view.initial === undefined) ids.push(id)\n })\n return ids\n}\n\n/**\n * The id of the config view flagged `initial: true` (EC-343/EC-444; `default` read\n * as a deprecated alias) — the seed for a collection's INITIAL active view. When\n * several are flagged (a misconfiguration, reported by {@link configViewIssues}) the\n * FIRST in declaration order wins deterministically; when none is flagged the caller\n * falls back to the baseline lens. `undefined` when the collection flags none.\n */\nexport function defaultConfigViewId(collection: CollectionDef): string | undefined {\n return configViewsFor(collection).find((view) => view.initial)?.id\n}\n\n/** A config-level problem with a collection's declared views (EC-343/EC-444). */\nexport interface ConfigViewIssue {\n /** Stable code (kept from EC-343 to avoid catalog churn); reads \"duplicate initial\". */\n code: 'duplicate-default'\n message: string\n /** The offending view ids (all views flagged `initial`, in declaration order). */\n viewIds: string[]\n}\n\n/**\n * Validate a collection's config-declared views (EC-343/EC-444): at most one may set\n * `initial: true` (`default` counted as its deprecated alias). A duplicate is returned\n * as an explicit, structured issue — never silently swallowed — so the studio can\n * surface it (the first still wins deterministically for seeding, per\n * {@link defaultConfigViewId}). Pure and schema-only; the DOM-free counterpart of the\n * \"failures are first-class\" contract.\n */\nexport function configViewIssues(collection: CollectionDef): ConfigViewIssue[] {\n const initials = configViewsFor(collection).filter((view) => view.initial)\n if (initials.length <= 1) return []\n const viewIds = initials.map((view) => view.id)\n return [\n {\n code: 'duplicate-default',\n message: `Collection \"${collection.id}\" declares ${initials.length} initial views (${viewIds.join(', ')}); at most one view may set \\`initial: true\\`. Seeding \"${viewIds[0]}\".`,\n viewIds,\n },\n ]\n}\n\n/**\n * The default column order: the schema's title field first (it becomes the\n * default title/link column — EC-213 drops the separate primary-column\n * selector, treating the first visible column as the title), then the\n * remaining fields in schema order.\n */\nfunction orderedColumnNames(collection: CollectionDef, pseudo: readonly string[] = []): string[] {\n const names = collection.fields.map((field) => field.name)\n const title = titleFieldOf(collection)?.name\n const schemaOrdered =\n title === undefined || !names.includes(title)\n ? names\n : [title, ...names.filter((name) => name !== title)]\n // EC-445: the column UNIVERSE = schema fields, then the applicable reserved\n // pseudo-columns (they are NOT in `collection.fields`).\n return [...schemaOrdered, ...pseudo]\n}\n\n/** Deep-cloned canonical form (stable key order via the Zod shape). */\nexport function normalizeViewState(state: TableViewState): TableViewState {\n return tableViewStateSchema.parse(state)\n}\n\n/** Structural equality on normalized states — drives the \"unsaved changes\" affordance. */\nexport function viewStatesEqual(a: TableViewState, b: TableViewState): boolean {\n return JSON.stringify(normalizeViewState(a)) === JSON.stringify(normalizeViewState(b))\n}\n\n/** One column of a view resolved against the current schema (EC-213). */\nexport interface ResolvedColumn {\n /** The schema field name. */\n field: string\n /** Whether the column renders (`false` ⇒ in {@link TableViewState.hidden}). */\n visible: boolean\n}\n\n/**\n * Resolve a view's columns against the live schema (EC-213): every schema\n * field exactly once, in the view's saved order, with any fields the view\n * predates appended (visible) and any fields no longer in the schema dropped.\n * This is the single source of truth for \"which columns, in what order, shown\n * or hidden\" — order is preserved across hide/show because visibility lives in\n * `hidden`, never in the order.\n */\nexport function resolveColumns(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): ResolvedColumn[] {\n const schemaNames = collection.fields.map((field) => field.name)\n // EC-445: the valid universe to KEEP from the saved order is schema fields PLUS the\n // applicable pseudo-columns (which are not in `collection.fields`) — so a seeded\n // `$state`/`$url`/`$updatedAt` is preserved + ordered, never dropped as \"unknown\".\n const keep = new Set([...schemaNames, ...pseudo])\n const hidden = new Set(state.hidden)\n const inState = new Set(state.columns)\n // Keep the saved order, restricted to the live universe and de-duplicated (a\n // corrupted persisted state must never render one field as two columns).\n const ordered: string[] = []\n const seen = new Set<string>()\n for (const name of state.columns) {\n if (keep.has(name) && !seen.has(name)) {\n ordered.push(name)\n seen.add(name)\n }\n }\n // Append universe members the saved order predates: new schema fields (EC-213\n // discovery), then applicable pseudo-columns not yet placed (EC-445).\n const appended = [\n ...schemaNames.filter((name) => !seen.has(name)),\n ...pseudo.filter((name) => !seen.has(name)),\n ]\n return [...ordered, ...appended].map((field) => {\n // A freshly-appended opt-in pseudo-column ($publishedAt) starts hidden; once it\n // is in the saved order (an editor un-hid it) its visibility follows `hidden`.\n const defaultHiddenAppend = DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(field) && !inState.has(field)\n return { field, visible: !hidden.has(field) && !defaultHiddenAppend }\n })\n}\n\n/** The visible columns of a view, in render order (EC-213). */\nexport function visibleColumns(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): string[] {\n return resolveColumns(collection, state, pseudo)\n .filter((column) => column.visible)\n .map((column) => column.field)\n}\n\n/**\n * The title/link column — the document IDENTITY column (EC-242): the schema title\n * field, shown as the leftmost linked cell whose content is `resolveDocumentTitle`\n * (a string `titleField` or a function pattern). Always present regardless of\n * column visibility — it is the document's identity, not a toggleable data column —\n * and excluded from the data columns so the title never shows twice. Falls back to\n * the first visible column, then the first field, then `id`, when no title field\n * is resolvable (e.g. a function title with no backing `title` field).\n */\nexport function primaryColumn(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): string {\n return (\n titleFieldOf(collection)?.name ??\n // EC-445: a pseudo-column is never the identity column (it has no title value) —\n // fall back to the first visible SCHEMA column.\n visibleColumns(collection, state, pseudo).find((name) => !isPseudoColumn(name)) ??\n collection.fields[0]?.name ??\n 'id'\n )\n}\n\n/**\n * Reconcile `columns` to the full resolved order so column edits operate on a\n * complete, stable order (drops removed fields, pins appended ones), and prune\n * `hidden` to fields the live schema still has (a column removed from the schema\n * must not leave dead `hidden` cruft that trips dirty-detection / persists).\n */\nfunction withResolvedOrder(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): TableViewState {\n const columns = resolveColumns(collection, state, pseudo).map((column) => column.field)\n const live = new Set(columns)\n const hidden = state.hidden.filter((name) => live.has(name))\n return { ...state, columns, hidden }\n}\n\n/**\n * The canonical, schema-resolved form of a view state — full column order with\n * `hidden` pruned to live fields (EC-213). Two states that render identically\n * share one canonical form, so dirty-detection never trips on a mere column\n * reconciliation or a stale `hidden` entry (only a real filter/sort/visibility/\n * order change counts as \"unsaved\").\n */\nexport function canonicalViewState(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): TableViewState {\n return normalizeViewState(withResolvedOrder(collection, state, pseudo))\n}\n\n/**\n * Toggle a column's visibility — position is preserved (EC-213): visibility\n * lives in `hidden`, the order in `columns` is untouched. Columns the saved\n * order predates are pinned into `columns` first so their place is stable.\n */\nexport function toggleColumn(\n collection: CollectionDef,\n state: TableViewState,\n field: string,\n pseudo: readonly string[] = [],\n): TableViewState {\n const base = withResolvedOrder(collection, state, pseudo)\n const hidden = base.hidden.includes(field)\n ? base.hidden.filter((name) => name !== field)\n : [...base.hidden, field]\n return { ...base, hidden }\n}\n\n/** Move a column one position left (-1) or right (+1) in the full column order. */\nexport function moveColumn(\n collection: CollectionDef,\n state: TableViewState,\n field: string,\n delta: -1 | 1,\n pseudo: readonly string[] = [],\n): TableViewState {\n const base = withResolvedOrder(collection, state, pseudo)\n const from = base.columns.indexOf(field)\n const to = from + delta\n if (from < 0 || to < 0 || to >= base.columns.length) return state\n const columns = [...base.columns]\n columns.splice(from, 1)\n columns.splice(to, 0, field)\n return { ...base, columns }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"view-model.js","sourceRoot":"","sources":["../../../src/lib/cms-views/view-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod'\nimport {\n documentDefaultLocale,\n localizedStringSchema,\n resolveField,\n resolveLabel,\n titleFieldOf,\n} from '@elytracms/core/cms-core'\nimport { localizedLabel } from '@elytracms/studio/lib/i18n'\nimport type {\n CmsDocument,\n CollectionDef,\n FieldDef,\n LocaleConfig,\n LocalizedString,\n} from '@elytracms/core/cms-core'\nimport {\n FILTER_OPERATORS,\n compareListEntries,\n filterScalarOf,\n filterableFields,\n matchesFieldValue,\n validateWhere,\n} from '@elytracms/core/content'\nimport type {\n FilterCondition,\n FilterOperator,\n FilterScalar,\n NormalizedCondition,\n WhereInput,\n} from '@elytracms/core/content'\n\n/**\n * The pure table-view model for the CMS collection table (EC-169).\n *\n * A view bundles three things: filters in the closed AD-3 vocabulary\n * (`eq`/`in`/`lt`/`lte`/`gt`/`gte`, AND-only — exactly `@elytracms/core/content`'s\n * query model, evaluated with the same matching/ordering primitives), a sort\n * (field + direction), and the visible/ordered columns. Everything here is\n * plain data + functions so filtering, dirtiness, and column edits are\n * testable without a DOM.\n *\n * Filters are offered ONLY on fields the schema declares `filterable: true`\n * (EC-143), plus one built-in option: the document's publication state. The\n * state is document metadata, not a schema field — it powers the\n * \"show me drafts → bulk publish\" working set and still speaks only the\n * closed vocabulary (`eq`/`in`).\n */\n\n// --- Schemas (single source of truth — persisted view records reuse these) ----\n\nexport const filterScalarSchema = z.union([z.string(), z.number(), z.boolean()])\n\nexport const filterClauseSchema = z.object({\n /** A schema field name, or {@link STATE_FIELD} for the publication state. */\n field: z.string().min(1),\n op: z.enum(FILTER_OPERATORS),\n /** `in` carries an array of scalars; every other operator one scalar. */\n value: z.union([filterScalarSchema, z.array(filterScalarSchema)]),\n})\nexport type FilterClause = z.infer<typeof filterClauseSchema>\n\nexport const viewSortSchema = z.object({\n field: z.string().min(1),\n dir: z.enum(['asc', 'desc']),\n})\nexport type ViewSort = z.infer<typeof viewSortSchema>\n\nexport const tableViewStateSchema = z.object({\n /** AND-only list of conditions (no OR, no nesting — vision AD-3). */\n filters: z.array(filterClauseSchema),\n sort: viewSortSchema.nullable(),\n /**\n * The canonical column order (field names) — EVERY column, visible or not\n * (EC-213). Order is independent of visibility: hiding then re-showing a\n * column keeps its place. Schema fields absent here resolve in at the end\n * (see {@link resolveColumns}).\n */\n columns: z.array(z.string().min(1)),\n /**\n * The subset of {@link TableViewState.columns} that is hidden. Defaults to\n * `[]` so views persisted before EC-213 (no `hidden` key) load unchanged.\n */\n hidden: z.array(z.string().min(1)).default([]),\n})\nexport type TableViewState = z.infer<typeof tableViewStateSchema>\n\n// --- The built-in publication-state filter column ------------------------------\n\n/**\n * Sentinel field key for the publication state. `$`-prefixed so it can never\n * collide with a schema field name (`fieldDefSchema` names are identifiers).\n */\nexport const STATE_FIELD = '$state'\n\nconst STATE_VALUES = ['draft', 'published'] as const\n\n// --- Reserved pseudo-COLUMNS (EC-445) ------------------------------------------\n\n/**\n * Reserved pseudo-COLUMN keys — the columns-axis siblings of the filter-axis\n * {@link STATE_FIELD}. `$`-prefixed so they can never collide with a schema field\n * name; they participate in a view's `columns` list AND the Display picker exactly\n * like a schema field (orderable / hideable / includable), but they are NOT drawn\n * from `collection.fields` — the column UNIVERSE is `[...schemaFields, ...pseudoColumns]`.\n *\n * - `$state` — publication status. A reserved `$`-key, but NO LONGER a reorderable\n * column: EC-448 promoted it to a FIXED structural leading column (checkbox →\n * status-dot → title), so it is NOT emitted by {@link pseudoColumns} and never\n * participates in the reorderable columns/hidden/order model. It stays a reserved\n * key (filter + sort) and {@link isPseudoColumn} still recognizes it, so an authored\n * view listing `$state` is a harmless no-op (see {@link resolveConfigColumns}).\n * - `$url` — the derived delivery URL (routable collections only; NON-sortable).\n * - `$updatedAt` — the record's last-write timestamp.\n * - `$publishedAt` — the record's FIRST-publish instant (EC-447; opt-in, HIDDEN by\n * default). Now materialized end-to-end (`cmsDocuments.publishedAt` → source\n * `timestamps.publishedAt`) and emitted by {@link pseudoColumns} when the source\n * both materializes timestamps and has a publish lifecycle.\n */\nexport const URL_FIELD = '$url'\nexport const PUBLISHED_AT_FIELD = '$publishedAt'\nexport const UPDATED_AT_FIELD = '$updatedAt'\n\n/**\n * Every reserved pseudo-column key. `$state` is included (it is still a reserved\n * `$`-key: the filter/sort axis + the FIXED structural status column, EC-448) so\n * {@link isPseudoColumn} never mistakes it for a schema field — but it is NOT a\n * reorderable column, so it is absent from the `pseudo` sets {@link pseudoColumns}\n * emits into the order/hide/picker model.\n */\nconst PSEUDO_COLUMN_FIELDS: readonly string[] = [\n STATE_FIELD,\n URL_FIELD,\n PUBLISHED_AT_FIELD,\n UPDATED_AT_FIELD,\n]\n\n/** Is `name` a reserved pseudo-column (a `$`-key, not a schema field)? */\nexport function isPseudoColumn(name: string): boolean {\n return PSEUDO_COLUMN_FIELDS.includes(name)\n}\n\n/**\n * Pseudo-columns HIDDEN by default (opt-in): the extra publish timestamp. Everything\n * else applicable (`$updatedAt`/`$state`/`$url`) is on by default (owner, 2026-07-17).\n */\nconst DEFAULT_HIDDEN_PSEUDO_COLUMNS: ReadonlySet<string> = new Set([PUBLISHED_AT_FIELD])\n\n/**\n * Capability signals that make a pseudo-column applicable to a collection/source\n * (EC-445). Supplied by the caller from the portable source — the model stays pure.\n */\nexport interface PseudoColumnOptions {\n /** The source materializes per-document timestamps → `$updatedAt` applies. */\n timestamps?: boolean\n /**\n * The collection has a publish lifecycle. Gates `$publishedAt` (with `timestamps`).\n * EC-448: it no longer gates a reorderable `$state` column — `$state` is the FIXED\n * structural status column, gated by the same signal at the render site, not here.\n */\n publishing?: boolean\n /** The collection resolves delivery URLs → `$url` applies (mirrors `urlByDocId`). */\n routable?: boolean\n}\n\n/**\n * The reserved REORDERABLE pseudo-columns that APPLY to a collection, in their default\n * appended order (EC-445/EC-447): `$updatedAt`, `$publishedAt`, then `$url`. `$url` is\n * gated on `routable` (a non-routable collection has no URL column, not an empty one),\n * `$updatedAt` on `timestamps`. `$publishedAt` (EC-447) needs BOTH `timestamps` (its\n * materialized value) AND `publishing` (a publish lifecycle to have a publish date) —\n * it is OPT-IN, HIDDEN by default (`DEFAULT_HIDDEN_PSEUDO_COLUMNS`), so it joins the\n * universe/picker without appearing in the baseline lens.\n *\n * NOTE (EC-448): `$state` is NO LONGER emitted here. It became a FIXED structural\n * leading column (checkbox → status-dot → title), rendered by `collection-table.tsx`\n * regardless of the reorderable model — so it is never in the order/hide/picker set,\n * even though `publishing` is what gates BOTH it and the status column's presence.\n * `opts.publishing` therefore only affects `$publishedAt` here. Pure — a caller\n * (`pseudoColumnsForSource`) supplies the signals from the source.\n */\nexport function pseudoColumns(collection: CollectionDef, opts: PseudoColumnOptions = {}): string[] {\n void collection // reserved for future per-collection gating; kept for API symmetry\n const cols: string[] = []\n if (opts.timestamps) cols.push(UPDATED_AT_FIELD)\n // EC-447: a publish date needs both a timestamps source (the value) AND a publish\n // lifecycle (the meaning). Hidden by default → surfaced via the Display picker / a\n // config view's `columns`, never a blank column on a rail that can't publish.\n if (opts.timestamps && opts.publishing) cols.push(PUBLISHED_AT_FIELD)\n // EC-448: $state is structural (fixed leading column), not a reorderable pseudo-column.\n if (opts.routable) cols.push(URL_FIELD)\n return cols\n}\n\n/**\n * The per-document metadata accessors the pseudo-DATE columns sort by (EC-445) — the\n * columns-axis analogue of {@link IsPublished}. Threaded into the sort machinery so a\n * `$updatedAt`/`$publishedAt` sort orders by the source's materialized timestamp; a\n * missing accessor (fixtures/tests) sorts those rows last. `$url` is derived → never sorted.\n */\nexport interface PseudoColumnMeta {\n updatedAt?(doc: CmsDocument): string | undefined\n publishedAt?(doc: CmsDocument): string | undefined\n}\n\n/** One field the filter builder may offer. */\nexport interface FilterableFieldOption {\n /** Clause field key: a schema field name, or {@link STATE_FIELD}. */\n field: string\n label: string\n /** The schema field def, or `null` for the built-in publication state. */\n def: FieldDef | null\n}\n\nexport const STATE_OPTION: FilterableFieldOption = {\n field: STATE_FIELD,\n label: 'State',\n def: null,\n}\n\n/**\n * The closed list of fields the filter builder offers: exactly the schema's\n * `filterable: true` fields (EC-143) plus the publication state. Nothing else\n * is ever offered — the UI builds queries, it does not invent a language.\n */\nexport function filterableFieldOptions(collection: CollectionDef): FilterableFieldOption[] {\n const schemaOptions = filterableFields(collection).map((field) => ({\n field: field.name,\n label: localizedLabel(field.form?.label, field.name),\n def: field,\n }))\n return [...schemaOptions, STATE_OPTION]\n}\n\nexport function filterOptionFor(\n collection: CollectionDef,\n field: string,\n): FilterableFieldOption | undefined {\n return filterableFieldOptions(collection).find((option) => option.field === field)\n}\n\n// --- Operators per field type (EC-345) ------------------------------------------\n\n/**\n * The per-type operator SET the builder offers (EC-345), always a subset of the\n * closed `FILTER_OPERATORS` — the UI narrows the vocabulary, it never extends it.\n * Ratified sets (Oli, 2026-07-08):\n *\n * - text: contains (default) · equals · starts with · ends with · empty\n * - number: equals · < · ≤ · > · ≥ · empty\n * - date: equals · before · … · after · empty (same ops as number, date labels)\n * - boolean: is\n * - select: is · is any of · empty\n * - relation / asset: is · is any of · empty (relation value = the relation picker;\n * `eq` on a `multiple` relation is membership — array-contains, EC-255 semantics)\n * - state pseudo-field: is · is any of (unchanged — a publication state is never empty)\n */\nexport function operatorsFor(option: FilterableFieldOption): FilterOperator[] {\n if (option.def === null) return ['eq', 'in'] // publication state\n switch (option.def.type) {\n case 'boolean':\n return ['eq']\n case 'number':\n case 'date':\n return ['eq', 'lt', 'lte', 'gt', 'gte', 'empty']\n case 'select':\n case 'relation':\n case 'asset':\n return ['eq', 'in', 'empty']\n default:\n // text (and any other string-shaped field)\n return ['contains', 'eq', 'startsWith', 'endsWith', 'empty']\n }\n}\n\n/**\n * A visual choice in the operator dropdown (EC-345). Usually one per operator,\n * but `empty` splits into two — \"is empty\" (`true`) and \"is not empty\" (`false`) —\n * so an editor never has to reason about a boolean value; the choice carries the\n * preset. `token` is the `<option value>`, `labelKey` a catalog key ({@link operatorLabelKey}).\n */\nexport interface OperatorChoice {\n token: string\n op: FilterOperator\n /** Value forced when this choice is picked (the `empty` true/false), else undefined. */\n presetValue?: FilterScalar\n labelKey: string\n}\n\n/**\n * The operator dropdown entries for a field (EC-345): {@link operatorsFor} expanded\n * for display, with `empty` shown as the two self-describing choices.\n */\nexport function operatorChoices(option: FilterableFieldOption): OperatorChoice[] {\n const choices: OperatorChoice[] = []\n for (const op of operatorsFor(option)) {\n if (op === 'empty') {\n choices.push({ token: 'empty:true', op, presetValue: true, labelKey: 'cms.filter.op.isEmpty' })\n choices.push({\n token: 'empty:false',\n op,\n presetValue: false,\n labelKey: 'cms.filter.op.isNotEmpty',\n })\n continue\n }\n choices.push({ token: op, op, labelKey: operatorLabelKey(op, option) })\n }\n return choices\n}\n\n/**\n * The catalog key for an operator's label (EC-241/EC-345), keyed by operator AND\n * field type — `eq` reads \"equals\" on text/number, \"on\" on a date, \"is\" on an\n * enum-like field; `lt` reads \"less than\" on a number, \"before\" on a date. `empty`\n * additionally depends on its VALUE (is empty / is not empty). Pure → unit-tested.\n */\nexport function operatorLabelKey(\n op: FilterOperator,\n option: FilterableFieldOption | undefined,\n value?: FilterScalar | readonly FilterScalar[],\n): string {\n const type = option?.def?.type\n switch (op) {\n case 'contains':\n return 'cms.filter.op.contains'\n case 'startsWith':\n return 'cms.filter.op.startsWith'\n case 'endsWith':\n return 'cms.filter.op.endsWith'\n case 'in':\n return 'cms.filter.op.isAnyOf'\n case 'empty':\n return value === false ? 'cms.filter.op.isNotEmpty' : 'cms.filter.op.isEmpty'\n case 'eq':\n // \"on\" for a date; \"is\" for enum-like refs; \"equals\" for text/number/unknown\n // (and the publication-state pseudo-field, whose `def` is null → unchanged).\n if (type === 'date') return 'cms.filter.op.on'\n if (type === 'boolean' || type === 'select' || type === 'relation' || type === 'asset') {\n return 'cms.filter.op.is'\n }\n return 'cms.filter.op.equals'\n case 'lt':\n return type === 'date' ? 'cms.filter.op.before' : 'cms.filter.op.lessThan'\n case 'lte':\n return type === 'date' ? 'cms.filter.op.onOrBefore' : 'cms.filter.op.atMost'\n case 'gt':\n return type === 'date' ? 'cms.filter.op.after' : 'cms.filter.op.greaterThan'\n case 'gte':\n return type === 'date' ? 'cms.filter.op.onOrAfter' : 'cms.filter.op.atLeast'\n }\n}\n\n/** A sensible starting clause when a field is added to the builder (EC-345). */\nexport function defaultClause(option: FilterableFieldOption): FilterClause {\n if (option.def === null) return { field: STATE_FIELD, op: 'eq', value: 'published' }\n switch (option.def.type) {\n case 'boolean':\n return { field: option.field, op: 'eq', value: true }\n case 'number':\n case 'date':\n return { field: option.field, op: 'eq', value: option.def.type === 'number' ? 0 : '' }\n case 'select':\n return { field: option.field, op: 'eq', value: option.def.options[0]?.value ?? '' }\n case 'relation':\n case 'asset':\n return { field: option.field, op: 'eq', value: '' }\n default:\n // text (and any other string-shaped field): `contains` is the natural default\n return { field: option.field, op: 'contains', value: '' }\n }\n}\n\n// --- Text ⇄ scalar coercion (the value inputs of the builder) -------------------\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/\n\n/** Coerce one text input into the scalar a clause compares against. */\nexport function scalarFromText(\n option: FilterableFieldOption | undefined,\n raw: string,\n): FilterScalar {\n const type = option?.def?.type\n if (type === 'number') {\n const trimmed = raw.trim()\n if (trimmed === '') return raw // an emptied input must not become eq 0\n const parsed = Number(trimmed)\n return Number.isNaN(parsed) ? raw : parsed\n }\n if (type === 'boolean') return raw === 'true'\n // Stored dates are full ISO strings; a date-input value compares correctly\n // once expanded to midnight UTC (ISO strings order by code units).\n if (type === 'date' && DATE_ONLY.test(raw)) return `${raw}T00:00:00.000Z`\n return raw\n}\n\n/** Parse a comma-separated list for the `in` operator. */\nexport function scalarListFromText(\n option: FilterableFieldOption | undefined,\n raw: string,\n): FilterScalar[] {\n return raw\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part !== '')\n .map((part) => scalarFromText(option, part))\n}\n\nexport function scalarListToText(value: FilterScalar | FilterScalar[]): string {\n const list = Array.isArray(value) ? value : [value]\n return list.map(String).join(', ')\n}\n\n// --- Clause validation -----------------------------------------------------------\n\n/** A structured problem with one clause (by index in the filter list). */\nexport interface ClauseIssue {\n index: number\n message: string\n}\n\n/**\n * Validate clauses against the collection schema. Schema-field clauses run\n * through the canonical `validateWhere` (EC-143: `filterable` enforcement +\n * operator/value shape); state clauses check the `eq`/`in` subset and the\n * draft/published value set. Invalid clauses (e.g. a persisted view whose\n * field is no longer filterable) are reported — never silently applied.\n */\nexport function validateClauses(\n collection: CollectionDef,\n clauses: readonly FilterClause[],\n): ClauseIssue[] {\n const issues: ClauseIssue[] = []\n clauses.forEach((clause, index) => {\n if (clause.field === STATE_FIELD) {\n if (clause.op !== 'eq' && clause.op !== 'in') {\n issues.push({ index, message: 'State filters support only \"eq\" and \"in\".' })\n return\n }\n const values = Array.isArray(clause.value) ? clause.value : [clause.value]\n if (!values.every((value) => (STATE_VALUES as readonly unknown[]).includes(value))) {\n issues.push({ index, message: 'State must be \"draft\" or \"published\".' })\n }\n return\n }\n const where: WhereInput = {\n [clause.field]: { [clause.op]: clause.value } as FilterCondition,\n }\n const errors = validateWhere(collection, where)\n if (errors.length > 0) issues.push({ index, message: errors[0]!.message })\n })\n return issues\n}\n\n// --- Matching & sorting (delegates to @elytracms/core/content's primitives) -------------\n\n/**\n * Published-ness source for the `$state` pseudo-field (EC-224): the version\n * POINTER, supplied by the caller as `cms.isPublished`. Defaults to \"nothing\n * published\" — a bare row carries no publish signal now that the flat `state`\n * field is gone, so the table (which knows the pointer) passes the real\n * predicate; fixtures/tests that don't surface `$state` get the safe default.\n */\nexport type IsPublished = (doc: CmsDocument) => boolean\nconst defaultIsPublished: IsPublished = () => false\n\n/**\n * The RAW locale-resolved value a document exposes for a clause field — an array\n * for a `multiple` relation/asset, a ref object for a single one, a scalar\n * otherwise. Matching runs on this (via `matchesFieldValue`) so it agrees with the\n * delivery/listing path exactly: array-contains for `multiple` relations (EC-255)\n * and whole-value `empty` semantics (EC-345). Sorting keeps its own scalar reduction.\n */\nfunction rawValueOf(\n collection: CollectionDef,\n doc: CmsDocument,\n field: string,\n localeConfig: LocaleConfig,\n isPublished: IsPublished,\n): unknown {\n if (field === STATE_FIELD) return isPublished(doc) ? 'published' : 'draft'\n if (!collection.fields.some((f) => f.name === field)) return undefined\n const locale = documentDefaultLocale(doc, localeConfig)\n return resolveField(collection, doc, field, locale, localeConfig).value\n}\n\n/** The scalar a document exposes for a SORT field, locale-resolved. */\nfunction scalarOf(\n collection: CollectionDef,\n doc: CmsDocument,\n field: string,\n localeConfig: LocaleConfig,\n isPublished: IsPublished,\n meta: PseudoColumnMeta = {},\n): FilterScalar | null {\n if (field === STATE_FIELD) return isPublished(doc) ? 'published' : 'draft'\n // EC-445: the pseudo-DATE columns sort by the source's materialized ISO timestamp\n // (ISO strings order lexicographically = chronologically); `$url` is derived → not sortable.\n if (field === UPDATED_AT_FIELD) return meta.updatedAt?.(doc) ?? null\n if (field === PUBLISHED_AT_FIELD) return meta.publishedAt?.(doc) ?? null\n if (field === URL_FIELD) return null\n if (!collection.fields.some((f) => f.name === field)) return null\n const locale = documentDefaultLocale(doc, localeConfig)\n return filterScalarOf(resolveField(collection, doc, field, locale, localeConfig).value)\n}\n\n/**\n * Does a document satisfy one clause? Identical verdict to the content accessors'\n * delivery/listing path: both reduce to `@elytracms/core/content`'s\n * `matchesFieldValue` over the RAW field value (so `contains`/`empty`/multiple-\n * relation membership all behave the same on the table as on the live site).\n */\nexport function clauseMatches(\n collection: CollectionDef,\n doc: CmsDocument,\n localeConfig: LocaleConfig,\n clause: FilterClause,\n isPublished: IsPublished = defaultIsPublished,\n): boolean {\n const value = rawValueOf(collection, doc, clause.field, localeConfig, isPublished)\n const condition = { [clause.op]: clause.value } as NormalizedCondition\n return matchesFieldValue(value, condition)\n}\n\n/**\n * Sort documents by one column in the canonical deterministic order\n * (`compareListEntries`: typed value order, id-ascending tiebreak). Unlike the\n * content accessors, the *table* may sort any rendered column — sorting is a\n * presentation concern here; the `filterable` flag governs filters.\n */\nexport function sortViewDocuments(\n collection: CollectionDef,\n docs: readonly CmsDocument[],\n localeConfig: LocaleConfig,\n sort: ViewSort | null,\n isPublished: IsPublished = defaultIsPublished,\n meta: PseudoColumnMeta = {},\n): CmsDocument[] {\n if (sort === null) return [...docs]\n const positions = new Map(\n docs.map((doc) => [\n doc.id,\n scalarOf(collection, doc, sort.field, localeConfig, isPublished, meta),\n ]),\n )\n return [...docs].sort((a, b) =>\n compareListEntries(\n { id: a.id, sortValue: positions.get(a.id) ?? null },\n { id: b.id, sortValue: positions.get(b.id) ?? null },\n sort.dir,\n ),\n )\n}\n\n/** The filtered + sorted documents of a view, plus any clause issues. */\nexport interface AppliedViewState {\n docs: CmsDocument[]\n /** Clauses that failed validation — reported AND excluded from matching. */\n issues: ClauseIssue[]\n}\n\n/**\n * Apply a view state to a document list: validate clauses, AND-match the valid\n * ones, sort. Invalid clauses never filter silently — they come back as\n * issues for the UI to surface.\n */\nexport function applyViewState(\n collection: CollectionDef,\n docs: readonly CmsDocument[],\n localeConfig: LocaleConfig,\n state: TableViewState,\n isPublished: IsPublished = defaultIsPublished,\n meta: PseudoColumnMeta = {},\n): AppliedViewState {\n const issues = validateClauses(collection, state.filters)\n const invalid = new Set(issues.map((issue) => issue.index))\n const active = state.filters.filter((_, index) => !invalid.has(index))\n const matched = docs.filter((doc) =>\n active.every((clause) => clauseMatches(collection, doc, localeConfig, clause, isPublished)),\n )\n return {\n docs: sortViewDocuments(collection, matched, localeConfig, state.sort, isPublished, meta),\n issues,\n }\n}\n\n// --- View state construction, equality, columns ----------------------------------\n\n/** The id of the synthesized built-in \"All entries\" baseline view (EC-444). */\nexport const ALL_VIEW_ID = 'all'\n\n/** The default (unnamed) view: no filters, no sort, every field visible. */\n/**\n * Field types kept OFF the default table columns (EC-246b): the composite editing\n * surfaces — a blocks canvas, rich text, a structured object/repeater — read as\n * noise in a scalar list. `filterable` no longer forces (or governs) a column; the\n * default lens is \"all scalars\". These stay in the column picker one toggle away,\n * and any named view may list them in its `columns`; they're just off by default.\n */\nconst NON_DEFAULT_COLUMN_TYPES = new Set<FieldDef['type']>(['blocks', 'richText', 'object'])\n\n/**\n * Field names OFF the built-in baseline lens by default: exactly the composite\n * editing surfaces (blocks/richText/object) — always noise in a scalar list. The\n * default lens is \"all scalars\"; there is no per-field column opt-out any more\n * (EC-444 hard-removed `form.column`). A field stays in the picker one toggle away,\n * and a view curates columns by declaring an explicit `columns` list (or the\n * `id: 'default'` baseline override).\n */\nfunction defaultHiddenColumns(collection: CollectionDef, pseudo: readonly string[] = []): string[] {\n const composites = collection.fields\n .filter((f) => NON_DEFAULT_COLUMN_TYPES.has(f.type))\n .map((f) => f.name)\n // EC-445: applicable opt-in pseudo-columns ($publishedAt) start hidden; the rest\n // ($updatedAt/$state/$url) are visible by default (owner: keep them on).\n const hiddenPseudo = pseudo.filter((name) => DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(name))\n return [...composites, ...hiddenPseudo]\n}\n\nexport function defaultViewState(\n collection: CollectionDef,\n pseudo: readonly string[] = [],\n): TableViewState {\n return {\n filters: [],\n sort: null,\n // Every field keeps a slot (order + picker), but the composite surfaces start\n // hidden so the default lens is the collection's scalar columns (EC-246b/EC-444).\n // EC-445: the applicable reserved pseudo-columns append after the data columns.\n columns: orderedColumnNames(collection, pseudo),\n hidden: defaultHiddenColumns(collection, pseudo),\n }\n}\n\n/**\n * Resolve an authored VISIBLE column list (EC-444) into the internal two-axis\n * `{columns, hidden}` table state. The authored list is exactly the columns shown,\n * in order; every OTHER schema field is appended (in schema order) and hidden — the\n * same shape {@link defaultViewState} produces, so {@link resolveColumns} renders\n * precisely the authored list, visible, in that order. An omitted (or empty) list\n * inherits the collection's default lens (all scalars visible, composites hidden).\n * Unknown names in the authored list (a field the schema no longer has) are dropped.\n */\nexport function resolveConfigColumns(\n collection: CollectionDef,\n visible: readonly string[] | undefined,\n pseudo: readonly string[] = [],\n): Pick<TableViewState, 'columns' | 'hidden'> {\n if (visible === undefined || visible.length === 0) {\n const base = defaultViewState(collection, pseudo)\n return { columns: base.columns, hidden: base.hidden }\n }\n const universe = orderedColumnNames(collection, pseudo)\n const inUniverse = new Set(universe)\n const seen = new Set<string>()\n const shown: string[] = []\n for (const name of visible) {\n if (inUniverse.has(name) && !seen.has(name)) {\n shown.push(name)\n seen.add(name)\n }\n }\n const rest = universe.filter((name) => !seen.has(name))\n // EC-445: a schema-ONLY authored list (mentioning no pseudo-column) keeps the\n // applicable pseudo-columns at their DEFAULT visibility — so a consumer's\n // pre-EC-445 `columns:[…schema…]` list still shows today's url (+ updatedAt).\n // Mentioning ANY reorderable pseudo-column switches them to the visible-list rule\n // (only listed shows). EC-448: `$state` is EXCLUDED here — it is a fixed structural\n // column, not a reorderable one, so an authored `$state` is an inert no-op: it must\n // not flip the visible-list rule (nor is it in the universe, so it is simply dropped).\n const mentionsPseudo = visible.some((name) => isPseudoColumn(name) && name !== STATE_FIELD)\n const keepVisible = mentionsPseudo\n ? new Set<string>()\n : new Set(pseudo.filter((name) => !DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(name)))\n const hidden = rest.filter((name) => !keepVisible.has(name))\n return { columns: [...shown, ...rest], hidden }\n}\n\n/** The reserved `views[]` id whose entry OVERRIDES the synthesized baseline view (EC-444). */\nexport const DEFAULT_VIEW_OVERRIDE_ID = 'default'\n\n/**\n * A config-declared view (EC-246b/EC-444) — the flat authoring shape a collection\n * declares in `cms/` config: `{ name, initial?, filters?, sort?, columns? }`.\n * Filters/sort/columns sit at the top level (no nested `state` wrapper). The\n * studio validates + interprets these; `cms-core` stores them opaquely (it\n * can't reference the filter vocabulary without a layering cycle).\n */\nexport const configViewSchema = z.object({\n /**\n * Optional stable id; defaults to a slug of `name`. The reserved value\n * {@link DEFAULT_VIEW_OVERRIDE_ID} (`'default'`) marks the baseline-override entry.\n */\n id: z.string().min(1).optional(),\n /**\n * View label; localizable (EC-343): a plain string or a `{ locale }` map, resolved\n * at the render site via the same `resolveLabel` path as `form.label` (EC-241).\n */\n name: localizedStringSchema,\n /**\n * When true this view seeds the collection's INITIAL active view (EC-343/EC-444) —\n * the curated lens an editor lands on before picking one. At most one per collection;\n * a duplicate is a visible validation issue ({@link configViewIssues}), never silent.\n * The baseline lens stays available and stays the fallback.\n */\n initial: z.boolean().optional(),\n /**\n * @deprecated EC-444 — renamed to {@link ConfigView.initial}. Still read as an alias\n * for one release (`initial ?? default`) with a console warning; removed next release.\n * Distinct from a field's default VALUE and from the reserved `id: 'default'` override.\n */\n default: z.boolean().optional(),\n filters: z.array(filterClauseSchema).optional(),\n sort: viewSortSchema.nullable().optional(),\n /**\n * The single ordered list of VISIBLE columns (EC-444): what you list is what shows,\n * in that order. Omit to inherit the collection's default columns (all scalars). The\n * two-axis `{columns, hidden}` internal state is derived by {@link resolveConfigColumns}.\n */\n columns: z.array(z.string().min(1)).optional(),\n})\nexport type ConfigView = z.infer<typeof configViewSchema>\n\n/**\n * A resolved view: identity + the table state it restores (matches `SavedView`).\n * `name` stays a {@link LocalizedString} — resolved at the render site (EC-343), like\n * `form.label`. `initial` marks the first-load seed (see {@link defaultConfigViewId}),\n * resolved from the authored `initial ?? default` flag (EC-444).\n */\nexport interface ResolvedView {\n id: string\n name: LocalizedString\n state: TableViewState\n initial?: boolean\n}\n\n/**\n * Slug used to derive a config view's stable id from its name. A localized name\n * (EC-343) slugs its DEFAULT-locale text so the id is stable across the active UI\n * locale (an id must not shift when a German editor loads the same config).\n */\nfunction configViewId(name: LocalizedString, index: number): string {\n const text = resolveLabel(name) ?? ''\n const slug = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return `config:${slug || index}`\n}\n\n/**\n * Resolve a collection's config-declared `views` into full {@link ResolvedView}s\n * (EC-246b). Each is validated with {@link configViewSchema}; malformed entries\n * and duplicate ids are dropped (defensive). Columns fall back to the collection\n * default when a view doesn't pin them, so a filter-only view still renders every\n * column. Config views are shared and change only in\n * code — the runtime never mutates them.\n */\nexport function configViewsFor(\n collection: CollectionDef,\n pseudo: readonly string[] = [],\n): ResolvedView[] {\n const declared = collection.views\n if (!Array.isArray(declared)) return []\n const seen = new Set<string>()\n const resolved: ResolvedView[] = []\n declared.forEach((raw, index) => {\n const parsed = configViewSchema.safeParse(raw)\n if (!parsed.success) return\n const view = parsed.data\n const id = view.id ?? configViewId(view.name, index)\n if (seen.has(id)) return\n seen.add(id)\n // EC-444: `initial` supersedes the deprecated `default` alias (one-release window).\n const initial = view.initial ?? view.default\n const { columns, hidden } = resolveConfigColumns(collection, view.columns, pseudo)\n resolved.push({\n id,\n name: view.name,\n ...(initial ? { initial: true } : {}),\n state: normalizeViewState({\n filters: view.filters ?? [],\n sort: view.sort ?? null,\n columns,\n hidden,\n }),\n })\n })\n return resolved\n}\n\n/**\n * Does the collection declare a baseline-override view (a config view whose id is\n * {@link DEFAULT_VIEW_OVERRIDE_ID})? When true the synthesized \"All entries\" lens is\n * replaced by that entry verbatim (see {@link resolveCollectionViews}), EC-444.\n */\nexport function hasDefaultViewOverride(collection: CollectionDef): boolean {\n return configViewsFor(collection).some((view) => view.id === DEFAULT_VIEW_OVERRIDE_ID)\n}\n\n/**\n * The ordered view list a collection surfaces (EC-444): the baseline first, then the\n * config-declared views in declaration order. The baseline is either an authored\n * OVERRIDE (the config view whose id is {@link DEFAULT_VIEW_OVERRIDE_ID}, used\n * VERBATIM and NOT repeated among the trailing views) or, absent one, the\n * `synthesizedBaseline` the caller passes (the studio's translated \"All entries\"\n * lens). Pure — the store supplies the synthesized baseline (i18n-bound `name`).\n */\nexport function resolveCollectionViews(\n collection: CollectionDef,\n synthesizedBaseline: ResolvedView,\n pseudo: readonly string[] = [],\n): ResolvedView[] {\n const configViews = configViewsFor(collection, pseudo)\n const overrideIndex = configViews.findIndex((view) => view.id === DEFAULT_VIEW_OVERRIDE_ID)\n if (overrideIndex < 0) return [synthesizedBaseline, ...configViews]\n const override = configViews[overrideIndex]!\n const rest = configViews.filter((_, index) => index !== overrideIndex)\n return [override, ...rest]\n}\n\n/**\n * The ids of config views that still use the DEPRECATED `default` flag without the\n * new `initial` (EC-444). Drives the one-release deprecation warning (mirrors the\n * duplicate-default channel); empty once every view has migrated to `initial`.\n */\nexport function deprecatedDefaultFlagViewIds(collection: CollectionDef): string[] {\n const declared = collection.views\n if (!Array.isArray(declared)) return []\n const seen = new Set<string>()\n const ids: string[] = []\n declared.forEach((raw, index) => {\n const parsed = configViewSchema.safeParse(raw)\n if (!parsed.success) return\n const view = parsed.data\n const id = view.id ?? configViewId(view.name, index)\n if (seen.has(id)) return\n seen.add(id)\n if (view.default !== undefined && view.initial === undefined) ids.push(id)\n })\n return ids\n}\n\n/**\n * The id of the config view flagged `initial: true` (EC-343/EC-444; `default` read\n * as a deprecated alias) — the seed for a collection's INITIAL active view. When\n * several are flagged (a misconfiguration, reported by {@link configViewIssues}) the\n * FIRST in declaration order wins deterministically; when none is flagged the caller\n * falls back to the baseline lens. `undefined` when the collection flags none.\n */\nexport function defaultConfigViewId(collection: CollectionDef): string | undefined {\n return configViewsFor(collection).find((view) => view.initial)?.id\n}\n\n/** A config-level problem with a collection's declared views (EC-343/EC-444). */\nexport interface ConfigViewIssue {\n /** Stable code (kept from EC-343 to avoid catalog churn); reads \"duplicate initial\". */\n code: 'duplicate-default'\n message: string\n /** The offending view ids (all views flagged `initial`, in declaration order). */\n viewIds: string[]\n}\n\n/**\n * Validate a collection's config-declared views (EC-343/EC-444): at most one may set\n * `initial: true` (`default` counted as its deprecated alias). A duplicate is returned\n * as an explicit, structured issue — never silently swallowed — so the studio can\n * surface it (the first still wins deterministically for seeding, per\n * {@link defaultConfigViewId}). Pure and schema-only; the DOM-free counterpart of the\n * \"failures are first-class\" contract.\n */\nexport function configViewIssues(collection: CollectionDef): ConfigViewIssue[] {\n const initials = configViewsFor(collection).filter((view) => view.initial)\n if (initials.length <= 1) return []\n const viewIds = initials.map((view) => view.id)\n return [\n {\n code: 'duplicate-default',\n message: `Collection \"${collection.id}\" declares ${initials.length} initial views (${viewIds.join(', ')}); at most one view may set \\`initial: true\\`. Seeding \"${viewIds[0]}\".`,\n viewIds,\n },\n ]\n}\n\n/**\n * The default column order: the schema's title field first (it becomes the\n * default title/link column — EC-213 drops the separate primary-column\n * selector, treating the first visible column as the title), then the\n * remaining fields in schema order.\n */\nfunction orderedColumnNames(collection: CollectionDef, pseudo: readonly string[] = []): string[] {\n const names = collection.fields.map((field) => field.name)\n const title = titleFieldOf(collection)?.name\n const schemaOrdered =\n title === undefined || !names.includes(title)\n ? names\n : [title, ...names.filter((name) => name !== title)]\n // EC-445: the column UNIVERSE = schema fields, then the applicable reserved\n // pseudo-columns (they are NOT in `collection.fields`).\n return [...schemaOrdered, ...pseudo]\n}\n\n/** Deep-cloned canonical form (stable key order via the Zod shape). */\nexport function normalizeViewState(state: TableViewState): TableViewState {\n return tableViewStateSchema.parse(state)\n}\n\n/** Structural equality on normalized states — drives the \"unsaved changes\" affordance. */\nexport function viewStatesEqual(a: TableViewState, b: TableViewState): boolean {\n return JSON.stringify(normalizeViewState(a)) === JSON.stringify(normalizeViewState(b))\n}\n\n/** One column of a view resolved against the current schema (EC-213). */\nexport interface ResolvedColumn {\n /** The schema field name. */\n field: string\n /** Whether the column renders (`false` ⇒ in {@link TableViewState.hidden}). */\n visible: boolean\n}\n\n/**\n * Resolve a view's columns against the live schema (EC-213): every schema\n * field exactly once, in the view's saved order, with any fields the view\n * predates appended (visible) and any fields no longer in the schema dropped.\n * This is the single source of truth for \"which columns, in what order, shown\n * or hidden\" — order is preserved across hide/show because visibility lives in\n * `hidden`, never in the order.\n */\nexport function resolveColumns(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): ResolvedColumn[] {\n const schemaNames = collection.fields.map((field) => field.name)\n // EC-445: the valid universe to KEEP from the saved order is schema fields PLUS the\n // applicable pseudo-columns (which are not in `collection.fields`) — so a seeded\n // `$state`/`$url`/`$updatedAt` is preserved + ordered, never dropped as \"unknown\".\n const keep = new Set([...schemaNames, ...pseudo])\n const hidden = new Set(state.hidden)\n const inState = new Set(state.columns)\n // Keep the saved order, restricted to the live universe and de-duplicated (a\n // corrupted persisted state must never render one field as two columns).\n const ordered: string[] = []\n const seen = new Set<string>()\n for (const name of state.columns) {\n if (keep.has(name) && !seen.has(name)) {\n ordered.push(name)\n seen.add(name)\n }\n }\n // Append universe members the saved order predates: new schema fields (EC-213\n // discovery), then applicable pseudo-columns not yet placed (EC-445).\n const appended = [\n ...schemaNames.filter((name) => !seen.has(name)),\n ...pseudo.filter((name) => !seen.has(name)),\n ]\n return [...ordered, ...appended].map((field) => {\n // A freshly-appended opt-in pseudo-column ($publishedAt) starts hidden; once it\n // is in the saved order (an editor un-hid it) its visibility follows `hidden`.\n const defaultHiddenAppend = DEFAULT_HIDDEN_PSEUDO_COLUMNS.has(field) && !inState.has(field)\n return { field, visible: !hidden.has(field) && !defaultHiddenAppend }\n })\n}\n\n/** The visible columns of a view, in render order (EC-213). */\nexport function visibleColumns(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): string[] {\n return resolveColumns(collection, state, pseudo)\n .filter((column) => column.visible)\n .map((column) => column.field)\n}\n\n/**\n * The title/link column — the document IDENTITY column (EC-242): the schema title\n * field, shown as the leftmost linked cell whose content is `resolveDocumentTitle`\n * (a string `titleField` or a function pattern). Always present regardless of\n * column visibility — it is the document's identity, not a toggleable data column —\n * and excluded from the data columns so the title never shows twice. Falls back to\n * the first visible column, then the first field, then `id`, when no title field\n * is resolvable (e.g. a function title with no backing `title` field).\n */\nexport function primaryColumn(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): string {\n return (\n titleFieldOf(collection)?.name ??\n // EC-445: a pseudo-column is never the identity column (it has no title value) —\n // fall back to the first visible SCHEMA column.\n visibleColumns(collection, state, pseudo).find((name) => !isPseudoColumn(name)) ??\n collection.fields[0]?.name ??\n 'id'\n )\n}\n\n/**\n * Reconcile `columns` to the full resolved order so column edits operate on a\n * complete, stable order (drops removed fields, pins appended ones), and prune\n * `hidden` to fields the live schema still has (a column removed from the schema\n * must not leave dead `hidden` cruft that trips dirty-detection / persists).\n */\nfunction withResolvedOrder(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): TableViewState {\n const columns = resolveColumns(collection, state, pseudo).map((column) => column.field)\n const live = new Set(columns)\n const hidden = state.hidden.filter((name) => live.has(name))\n return { ...state, columns, hidden }\n}\n\n/**\n * The canonical, schema-resolved form of a view state — full column order with\n * `hidden` pruned to live fields (EC-213). Two states that render identically\n * share one canonical form, so dirty-detection never trips on a mere column\n * reconciliation or a stale `hidden` entry (only a real filter/sort/visibility/\n * order change counts as \"unsaved\").\n */\nexport function canonicalViewState(\n collection: CollectionDef,\n state: TableViewState,\n pseudo: readonly string[] = [],\n): TableViewState {\n return normalizeViewState(withResolvedOrder(collection, state, pseudo))\n}\n\n/**\n * Toggle a column's visibility — position is preserved (EC-213): visibility\n * lives in `hidden`, the order in `columns` is untouched. Columns the saved\n * order predates are pinned into `columns` first so their place is stable.\n */\nexport function toggleColumn(\n collection: CollectionDef,\n state: TableViewState,\n field: string,\n pseudo: readonly string[] = [],\n): TableViewState {\n const base = withResolvedOrder(collection, state, pseudo)\n const hidden = base.hidden.includes(field)\n ? base.hidden.filter((name) => name !== field)\n : [...base.hidden, field]\n return { ...base, hidden }\n}\n\n/** Move a column one position left (-1) or right (+1) in the full column order. */\nexport function moveColumn(\n collection: CollectionDef,\n state: TableViewState,\n field: string,\n delta: -1 | 1,\n pseudo: readonly string[] = [],\n): TableViewState {\n const base = withResolvedOrder(collection, state, pseudo)\n const from = base.columns.indexOf(field)\n const to = from + delta\n if (from < 0 || to < 0 || to >= base.columns.length) return state\n const columns = [...base.columns]\n columns.splice(from, 1)\n columns.splice(to, 0, field)\n return { ...base, columns }\n}\n"]}
|
|
@@ -243,11 +243,12 @@ export interface PublishingCapability {
|
|
|
243
243
|
liveUrls?(): Map<string, DocumentUrl> | null;
|
|
244
244
|
}
|
|
245
245
|
/**
|
|
246
|
-
* `timestamps` capability (EC-445): per-document record timestamps as ISO
|
|
247
|
-
* or `undefined` when a document carries none
|
|
248
|
-
*
|
|
249
|
-
* `publishedAt` is
|
|
250
|
-
*
|
|
246
|
+
* `timestamps` capability (EC-445/EC-447): per-document record timestamps as ISO
|
|
247
|
+
* strings, or `undefined` when a document carries none. The `$updatedAt`/`$publishedAt`
|
|
248
|
+
* pseudo-columns read + sort by these. `updatedAt` is the last-write instant;
|
|
249
|
+
* `publishedAt` (EC-447) is the FIRST-publish instant — set-once on publish, cleared on
|
|
250
|
+
* unpublish, so it is `undefined` for a draft / never-published / currently-unpublished
|
|
251
|
+
* document (the column shows EmDash).
|
|
251
252
|
*/
|
|
252
253
|
export interface DocumentTimestampsCapability {
|
|
253
254
|
updatedAt(ref: DocumentRef): string | undefined;
|