@elytracms/studio 0.0.14 → 0.0.16
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 +8 -31
- package/convex/content.ts +3 -44
- package/convex/delivery.ts +8 -42
- package/convex/functions.ts +17 -2
- package/convex/members.ts +2 -2
- package/convex/referenceMaintenance.ts +4 -73
- package/convex/references.ts +4 -2
- package/convex/schema.ts +17 -37
- package/convex/sync.ts +10 -42
- package/convex/triggers.ts +57 -0
- package/convex/webhooks.ts +3 -2
- package/dist/components/app-views/default-modules.d.ts +41 -0
- package/dist/components/app-views/default-modules.js +201 -0
- package/dist/components/app-views/default-modules.js.map +1 -0
- package/dist/components/app-views/module.d.ts +93 -0
- package/dist/components/app-views/module.js +75 -0
- package/dist/components/app-views/module.js.map +1 -0
- package/dist/components/app-views/sidebar.d.ts +95 -0
- package/dist/components/app-views/sidebar.js +153 -0
- package/dist/components/app-views/sidebar.js.map +1 -0
- package/dist/components/builder/builder-store.d.ts +92 -40
- package/dist/components/builder/builder-store.js +30 -126
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-breakpoints.d.ts +53 -0
- package/dist/components/builder/canvas-breakpoints.js +55 -0
- package/dist/components/builder/canvas-breakpoints.js.map +1 -0
- package/dist/components/builder/canvas.js +35 -61
- package/dist/components/builder/canvas.js.map +1 -1
- package/dist/components/builder/clipboard-actions.js +3 -3
- package/dist/components/builder/clipboard-actions.js.map +1 -1
- package/dist/components/builder/composition-field-editor.js +31 -40
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/insert-context.js +1 -1
- package/dist/components/builder/insert-context.js.map +1 -1
- package/dist/components/builder/page-tree.js +3 -4
- package/dist/components/builder/page-tree.js.map +1 -1
- package/dist/components/builder/property-inspector.js +4 -64
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/cms/bulk-actions.d.ts +23 -5
- package/dist/components/cms/bulk-actions.js +7 -3
- package/dist/components/cms/bulk-actions.js.map +1 -1
- package/dist/components/cms/bulk-bar.d.ts +22 -6
- package/dist/components/cms/bulk-bar.js +46 -9
- package/dist/components/cms/bulk-bar.js.map +1 -1
- package/dist/components/cms/cell.d.ts +0 -4
- package/dist/components/cms/cell.js +1 -5
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/cms-index.d.ts +4 -2
- package/dist/components/cms/cms-index.js +6 -4
- package/dist/components/cms/cms-index.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +7 -6
- package/dist/components/cms/cms-store.js +55 -18
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +8 -4
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/collections-sidebar.d.ts +10 -1
- package/dist/components/cms/collections-sidebar.js +13 -2
- package/dist/components/cms/collections-sidebar.js.map +1 -1
- package/dist/components/cms/detail-editor.js +2 -2
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/doc-state.d.ts +0 -5
- package/dist/components/cms/doc-state.js +1 -7
- package/dist/components/cms/doc-state.js.map +1 -1
- package/dist/components/cms/editable-cell.js +1 -1
- package/dist/components/cms/editable-cell.js.map +1 -1
- package/dist/components/cms/field-control.d.ts +11 -2
- package/dist/components/cms/field-control.js +22 -1
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/field-renderer.d.ts +71 -0
- package/dist/components/cms/field-renderer.js +67 -0
- package/dist/components/cms/field-renderer.js.map +1 -0
- package/dist/components/cms/filter-builder.js +6 -28
- package/dist/components/cms/filter-builder.js.map +1 -1
- package/dist/components/cms/scalar-value-editor.d.ts +35 -0
- package/dist/components/cms/scalar-value-editor.js +43 -0
- package/dist/components/cms/scalar-value-editor.js.map +1 -0
- package/dist/components/collab/collab-context.d.ts +6 -14
- package/dist/components/collab/collab-context.js +3 -12
- package/dist/components/collab/collab-context.js.map +1 -1
- package/dist/components/collab/collab-seed.d.ts +7 -19
- package/dist/components/collab/collab-seed.js +9 -31
- package/dist/components/collab/collab-seed.js.map +1 -1
- package/dist/components/components/registry-browser.js +6 -12
- package/dist/components/components/registry-browser.js.map +1 -1
- package/dist/components/guards.d.ts +0 -9
- package/dist/components/guards.js +0 -12
- package/dist/components/guards.js.map +1 -1
- package/dist/components/project-session.js +8 -3
- package/dist/components/project-session.js.map +1 -1
- package/dist/components/section-nav.d.ts +10 -10
- package/dist/components/section-nav.js +48 -25
- package/dist/components/section-nav.js.map +1 -1
- package/dist/components/section-state.d.ts +0 -2
- package/dist/components/section-state.js +0 -9
- package/dist/components/section-state.js.map +1 -1
- package/dist/components/section-surface.d.ts +3 -7
- package/dist/components/section-surface.js +6 -14
- package/dist/components/section-surface.js.map +1 -1
- package/dist/components/sections.d.ts +0 -1
- package/dist/components/sections.js +0 -10
- package/dist/components/sections.js.map +1 -1
- package/dist/components/studio-project-screen.d.ts +3 -4
- package/dist/components/studio-project-screen.js +41 -160
- package/dist/components/studio-project-screen.js.map +1 -1
- package/dist/components/studio-shell.d.ts +0 -4
- package/dist/components/studio-shell.js +14 -14
- package/dist/components/studio-shell.js.map +1 -1
- package/dist/lib/data/collection-content.d.ts +19 -1
- package/dist/lib/data/collection-content.js +16 -0
- package/dist/lib/data/collection-content.js.map +1 -1
- package/dist/lib/operations/graph-commands.d.ts +2 -6
- package/dist/lib/operations/graph-commands.js +1 -2
- package/dist/lib/operations/graph-commands.js.map +1 -1
- package/dist/lib/operations/index.d.ts +0 -2
- package/dist/lib/operations/index.js +0 -2
- package/dist/lib/operations/index.js.map +1 -1
- package/dist/lib/operations/session-hydration.d.ts +14 -24
- package/dist/lib/operations/session-hydration.js +15 -34
- package/dist/lib/operations/session-hydration.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.d.ts +1 -3
- package/dist/lib/persistence/convex-adapter.js +1 -154
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/lib/persona/labels.js +0 -2
- package/dist/lib/persona/labels.js.map +1 -1
- package/dist/lib/references/reference-model.d.ts +0 -16
- package/dist/lib/references/reference-model.js +2 -54
- package/dist/lib/references/reference-model.js.map +1 -1
- package/dist/lib/references/references-store.js +3 -4
- package/dist/lib/references/references-store.js.map +1 -1
- package/dist/lib/registry/index.d.ts +0 -16
- package/dist/lib/registry/index.js +0 -15
- package/dist/lib/registry/index.js.map +1 -1
- package/dist/lib/webhooks/tags.js +2 -16
- package/dist/lib/webhooks/tags.js.map +1 -1
- package/dist/lib/workspace/index.d.ts +27 -1
- package/dist/lib/workspace/index.js +34 -0
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/router/match.d.ts +22 -34
- package/dist/router/match.js +22 -40
- package/dist/router/match.js.map +1 -1
- package/package.json +3 -2
- package/convex/graphs.ts +0 -55
- package/convex/publishing.ts +0 -76
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell.js","sourceRoot":"","sources":["../../../src/components/cms/cell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Boxes, Check, Image, Link2, Minus } from 'lucide-react'\nimport { readAssetId, readDocumentRef } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef, DocumentRef, FieldDef } from '@elytracms/core/cms-core'\nimport { blockRootsOf } from '@elytracms/core/project-graph'\nimport type { AssetRecord } from '@elytracms/core/persistence'\nimport { Badge, Code, Text } from '@elytracms/studio/ui'\nimport { localeChipLabel, resolveDisplayedValue } from '@elytracms/studio/lib/locale'\nimport type { DisplayedFallback } from '@elytracms/studio/lib/locale'\nimport { useOptionalAssets } from '../assets/assets-store'\nimport { useCms } from './cms-store'\n\n/**\n * Render a document's field value for a table cell, by field type (brief\n * §8.4, EC-070), resolved in the studio's ambient active locale (EC-176).\n * A value served via EC-018 locale fallback carries a visible chip — never\n * silently mixed in as if it were translated.\n */\nexport function CellValue({\n collection,\n doc,\n field,\n}: {\n collection: CollectionDef\n doc: CmsDocument\n field: FieldDef\n}) {\n const cms = useCms()\n const { value, fallback } = resolveDisplayedValue(\n collection,\n doc,\n field.name,\n cms.activeLocale,\n cms.localeConfig,\n )\n\n if (value === undefined || value === null || value === '') {\n return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n }\n\n return (\n <span className=\"inline-flex min-w-0 max-w-full items-center gap-1.5\">\n <TypedCellValue field={field} value={value} />\n <FallbackChip fallback={fallback} testId={`cell-fallback-${doc.id}-${field.name}`} />\n </span>\n )\n}\n\n/**\n * Subtle source-locale chip on a fallback-displayed value (EC-176): e.g. a\n * German view showing untranslated English content gets an \"EN\" marker.\n */\nexport function FallbackChip({\n fallback,\n testId,\n}: {\n fallback: DisplayedFallback | null\n testId: string\n}) {\n if (fallback === null) return null\n return (\n <Badge\n variant=\"outline\"\n data-testid={testId}\n title={fallbackTitle(fallback)}\n className=\"shrink-0 px-1 py-0 text-[0.6rem] uppercase tracking-wide text-muted-foreground\"\n >\n {localeChipLabel(fallback.sourceLocale)}\n </Badge>\n )\n}\n\n/** Plain-language tooltip of a fallback chip. */\nexport function fallbackTitle(fallback: DisplayedFallback): string {\n return `Showing ${localeChipLabel(fallback.sourceLocale)} (fallback) — no ${localeChipLabel(\n fallback.requestedLocale,\n )} translation yet. Edit to translate.`\n}\n\nfunction TypedCellValue({ field, value }: { field: FieldDef; value: unknown }) {\n switch (field.type) {\n case 'boolean':\n return value === true ? (\n <Check className=\"size-4 text-success\" />\n ) : (\n <Minus className=\"size-3.5 text-muted-foreground/50\" />\n )\n case 'select':\n return <Badge variant=\"outline\">{String(value)}</Badge>\n case 'number':\n return <Text size=\"sm\" mono>{String(value)}</Text>\n case 'date':\n return (\n <Text size=\"sm\" tone=\"muted\" mono>\n {String(value).slice(0, 10)}\n </Text>\n )\n case 'richText':\n return (\n <Text size=\"xs\" tone=\"subtle\">\n {stripHtml(String(value)).slice(0, 40) || 'rich text'}\n </Text>\n )\n case 'relation':\n return <RelationCell value={value} />\n case 'asset':\n return <AssetCell value={value} />\n case 'blocks':\n return <BlocksCell value={value} />\n case 'object': {\n // EC-253: list-view summary, never `[object Object]`. A repeater shows its\n // item count; a single object is edited in the detail form, not the cell.\n if (field.cardinality === 'many') {\n const count = Array.isArray(value) ? value.length : 0\n return (\n <Badge variant=\"outline\">\n {count} {count === 1 ? 'item' : 'items'}\n </Badge>\n )\n }\n return (\n <Text size=\"xs\" tone=\"subtle\">\n {value && typeof value === 'object' ? 'object' : '—'}\n </Text>\n )\n }\n default:\n return (\n <Text size=\"sm\" className=\"truncate\">\n {String(value)}\n </Text>\n )\n }\n}\n\nfunction RelationCell({ value }: { value: unknown }) {\n const cms = useCms()\n const refs = toRefArray(value)\n if (refs.length === 0) return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n return (\n <div className=\"flex flex-wrap items-center gap-1\">\n {refs.slice(0, 3).map((ref, i) => (\n <Badge key={`${ref.id}-${i}`} variant=\"info\">\n <Link2 className=\"size-3\" /> {cms.titleOf(ref)}\n </Badge>\n ))}\n {refs.length > 3 ? <Text size=\"xs\" tone=\"subtle\">+{refs.length - 3}</Text> : null}\n </div>\n )\n}\n\n/**\n * A blocks/composition cell: a count of TOP-LEVEL blocks (EC-212) — matching\n * what the canvas/page-tree present as the block list, never `[object Object]`.\n */\nfunction BlocksCell({ value }: { value: unknown }) {\n const count = blockRootsOf(value).length\n if (count === 0) return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n return (\n <Badge variant=\"outline\">\n <Boxes className=\"size-3\" /> {count} {count === 1 ? 'block' : 'blocks'}\n </Badge>\n )\n}\n\nfunction AssetCell({ value }: { value: unknown }) {\n const cms = useCms()\n const assetStore = useOptionalAssets()\n const assetCollectionId = cms.collections.find((c) => c.kind === 'asset')?.id ?? 'asset'\n // EC-277: tolerate self-typed `{ type:'asset', id }` envelopes and legacy bare ids.\n const ids = (Array.isArray(value) ? value : [value])\n .map(readAssetId)\n .filter((id): id is string => id !== undefined)\n if (ids.length === 0) return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n const first = ids[0]!\n const record = assetStore?.assets.find((asset) => asset.id === first)\n const label =\n record?.title ?? record?.filename ?? cms.titleOf({ collection: assetCollectionId, id: first })\n return (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <AssetPreview record={record} label={label} />\n {ids.length > 1 ? <Text size=\"xs\" tone=\"subtle\">+{ids.length - 1}</Text> : null}\n </div>\n )\n}\n\n/**\n * An asset reference in a cell: an image thumbnail for image assets with a\n * resolvable URL (EC-212), otherwise the labelled icon badge (and the same\n * badge whenever no `<AssetsProvider>` is mounted to resolve the record).\n */\nfunction AssetPreview({ record, label }: { record: AssetRecord | undefined; label: string }) {\n const isImage = record?.contentType.startsWith('image/') ?? false\n const url = record?.url\n if (isImage && url && url.startsWith('http')) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <img\n src={url}\n alt={record?.alt ?? label}\n loading=\"lazy\"\n className=\"size-7 shrink-0 rounded border border-border bg-muted object-cover\"\n />\n <Text size=\"xs\" tone=\"subtle\" className=\"max-w-[10rem] truncate\">\n {label}\n </Text>\n </span>\n )\n }\n return (\n <Badge variant=\"outline\">\n <Image className=\"size-3\" /> {label}\n </Badge>\n )\n}\n\n/**\n * Normalize a relation value (single ref or array of refs) into an array of\n * `DocumentRef`s. EC-277: unwraps self-typed `{ type:'reference', ... }` envelopes\n * and legacy bare `{ collection, id }` via the shared tolerant reader.\n */\nexport function toRefArray(value: unknown): DocumentRef[] {\n const list = Array.isArray(value) ? value : [value]\n return list.map(readDocumentRef).filter((ref): ref is DocumentRef => ref !== undefined)\n}\n\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim()\n}\n\n/** Render a small mono code for the raw stored value (debug/primary-cell hint). */\nexport function RawValue({ value }: { value: unknown }) {\n return <Code tone=\"muted\">{typeof value === 'string' ? value : JSON.stringify(value)}</Code>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cell.js","sourceRoot":"","sources":["../../../src/components/cms/cell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Boxes, Check, Image, Link2, Minus } from 'lucide-react'\nimport { readAssetId, readDocumentRef } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef, DocumentRef, FieldDef } from '@elytracms/core/cms-core'\nimport { blockRootsOf } from '@elytracms/core/project-graph'\nimport type { AssetRecord } from '@elytracms/core/persistence'\nimport { Badge, Text } from '@elytracms/studio/ui'\nimport { localeChipLabel, resolveDisplayedValue } from '@elytracms/studio/lib/locale'\nimport type { DisplayedFallback } from '@elytracms/studio/lib/locale'\nimport { useOptionalAssets } from '../assets/assets-store'\nimport { useCms } from './cms-store'\n\n/**\n * Render a document's field value for a table cell, by field type (brief\n * §8.4, EC-070), resolved in the studio's ambient active locale (EC-176).\n * A value served via EC-018 locale fallback carries a visible chip — never\n * silently mixed in as if it were translated.\n */\nexport function CellValue({\n collection,\n doc,\n field,\n}: {\n collection: CollectionDef\n doc: CmsDocument\n field: FieldDef\n}) {\n const cms = useCms()\n const { value, fallback } = resolveDisplayedValue(\n collection,\n doc,\n field.name,\n cms.activeLocale,\n cms.localeConfig,\n )\n\n if (value === undefined || value === null || value === '') {\n return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n }\n\n return (\n <span className=\"inline-flex min-w-0 max-w-full items-center gap-1.5\">\n <TypedCellValue field={field} value={value} />\n <FallbackChip fallback={fallback} testId={`cell-fallback-${doc.id}-${field.name}`} />\n </span>\n )\n}\n\n/**\n * Subtle source-locale chip on a fallback-displayed value (EC-176): e.g. a\n * German view showing untranslated English content gets an \"EN\" marker.\n */\nexport function FallbackChip({\n fallback,\n testId,\n}: {\n fallback: DisplayedFallback | null\n testId: string\n}) {\n if (fallback === null) return null\n return (\n <Badge\n variant=\"outline\"\n data-testid={testId}\n title={fallbackTitle(fallback)}\n className=\"shrink-0 px-1 py-0 text-[0.6rem] uppercase tracking-wide text-muted-foreground\"\n >\n {localeChipLabel(fallback.sourceLocale)}\n </Badge>\n )\n}\n\n/** Plain-language tooltip of a fallback chip. */\nexport function fallbackTitle(fallback: DisplayedFallback): string {\n return `Showing ${localeChipLabel(fallback.sourceLocale)} (fallback) — no ${localeChipLabel(\n fallback.requestedLocale,\n )} translation yet. Edit to translate.`\n}\n\nfunction TypedCellValue({ field, value }: { field: FieldDef; value: unknown }) {\n switch (field.type) {\n case 'boolean':\n return value === true ? (\n <Check className=\"size-4 text-success\" />\n ) : (\n <Minus className=\"size-3.5 text-muted-foreground/50\" />\n )\n case 'select':\n return <Badge variant=\"outline\">{String(value)}</Badge>\n case 'number':\n return <Text size=\"sm\" mono>{String(value)}</Text>\n case 'date':\n return (\n <Text size=\"sm\" tone=\"muted\" mono>\n {String(value).slice(0, 10)}\n </Text>\n )\n case 'richText':\n return (\n <Text size=\"xs\" tone=\"subtle\">\n {stripHtml(String(value)).slice(0, 40) || 'rich text'}\n </Text>\n )\n case 'relation':\n return <RelationCell value={value} />\n case 'asset':\n return <AssetCell value={value} />\n case 'blocks':\n return <BlocksCell value={value} />\n case 'object': {\n // EC-253: list-view summary, never `[object Object]`. A repeater shows its\n // item count; a single object is edited in the detail form, not the cell.\n if (field.cardinality === 'many') {\n const count = Array.isArray(value) ? value.length : 0\n return (\n <Badge variant=\"outline\">\n {count} {count === 1 ? 'item' : 'items'}\n </Badge>\n )\n }\n return (\n <Text size=\"xs\" tone=\"subtle\">\n {value && typeof value === 'object' ? 'object' : '—'}\n </Text>\n )\n }\n default:\n return (\n <Text size=\"sm\" className=\"truncate\">\n {String(value)}\n </Text>\n )\n }\n}\n\nfunction RelationCell({ value }: { value: unknown }) {\n const cms = useCms()\n const refs = toRefArray(value)\n if (refs.length === 0) return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n return (\n <div className=\"flex flex-wrap items-center gap-1\">\n {refs.slice(0, 3).map((ref, i) => (\n <Badge key={`${ref.id}-${i}`} variant=\"info\">\n <Link2 className=\"size-3\" /> {cms.titleOf(ref)}\n </Badge>\n ))}\n {refs.length > 3 ? <Text size=\"xs\" tone=\"subtle\">+{refs.length - 3}</Text> : null}\n </div>\n )\n}\n\n/**\n * A blocks/composition cell: a count of TOP-LEVEL blocks (EC-212) — matching\n * what the canvas/page-tree present as the block list, never `[object Object]`.\n */\nfunction BlocksCell({ value }: { value: unknown }) {\n const count = blockRootsOf(value).length\n if (count === 0) return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n return (\n <Badge variant=\"outline\">\n <Boxes className=\"size-3\" /> {count} {count === 1 ? 'block' : 'blocks'}\n </Badge>\n )\n}\n\nfunction AssetCell({ value }: { value: unknown }) {\n const cms = useCms()\n const assetStore = useOptionalAssets()\n const assetCollectionId = cms.collections.find((c) => c.kind === 'asset')?.id ?? 'asset'\n // EC-277: tolerate self-typed `{ type:'asset', id }` envelopes and legacy bare ids.\n const ids = (Array.isArray(value) ? value : [value])\n .map(readAssetId)\n .filter((id): id is string => id !== undefined)\n if (ids.length === 0) return <Minus className=\"size-3.5 text-muted-foreground/50\" />\n const first = ids[0]!\n const record = assetStore?.assets.find((asset) => asset.id === first)\n const label =\n record?.title ?? record?.filename ?? cms.titleOf({ collection: assetCollectionId, id: first })\n return (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <AssetPreview record={record} label={label} />\n {ids.length > 1 ? <Text size=\"xs\" tone=\"subtle\">+{ids.length - 1}</Text> : null}\n </div>\n )\n}\n\n/**\n * An asset reference in a cell: an image thumbnail for image assets with a\n * resolvable URL (EC-212), otherwise the labelled icon badge (and the same\n * badge whenever no `<AssetsProvider>` is mounted to resolve the record).\n */\nfunction AssetPreview({ record, label }: { record: AssetRecord | undefined; label: string }) {\n const isImage = record?.contentType.startsWith('image/') ?? false\n const url = record?.url\n if (isImage && url && url.startsWith('http')) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <img\n src={url}\n alt={record?.alt ?? label}\n loading=\"lazy\"\n className=\"size-7 shrink-0 rounded border border-border bg-muted object-cover\"\n />\n <Text size=\"xs\" tone=\"subtle\" className=\"max-w-[10rem] truncate\">\n {label}\n </Text>\n </span>\n )\n }\n return (\n <Badge variant=\"outline\">\n <Image className=\"size-3\" /> {label}\n </Badge>\n )\n}\n\n/**\n * Normalize a relation value (single ref or array of refs) into an array of\n * `DocumentRef`s. EC-277: unwraps self-typed `{ type:'reference', ... }` envelopes\n * and legacy bare `{ collection, id }` via the shared tolerant reader.\n */\nexport function toRefArray(value: unknown): DocumentRef[] {\n const list = Array.isArray(value) ? value : [value]\n return list.map(readDocumentRef).filter((ref): ref is DocumentRef => ref !== undefined)\n}\n\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim()\n}\n"]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The CMS section landing view (EC-223 Stage 6): the collection grid, shown when
|
|
3
3
|
* no collection is selected. Takes `projectId` as a prop; the splat resolver
|
|
4
|
-
* mounts it inside the CMS provider so {@link useCms} resolves.
|
|
4
|
+
* mounts it inside the CMS provider so {@link useCms} resolves. `focusCollections`
|
|
5
|
+
* (EC-239) narrows the grid for a focused CMS module instance.
|
|
5
6
|
*/
|
|
6
|
-
export declare function CmsIndex({ projectId }: {
|
|
7
|
+
export declare function CmsIndex({ projectId, focusCollections, }: {
|
|
7
8
|
projectId: string;
|
|
9
|
+
focusCollections?: readonly string[];
|
|
8
10
|
}): import("react").JSX.Element;
|
|
@@ -3,16 +3,18 @@ import { Database, FileCog } from 'lucide-react';
|
|
|
3
3
|
import { isSingleton } from '@elytracms/core/cms-core';
|
|
4
4
|
import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router';
|
|
5
5
|
import { useCms } from '@elytracms/studio/components/cms/cms-store';
|
|
6
|
-
import { CollectionsSidebar } from '@elytracms/studio/components/cms/collections-sidebar';
|
|
6
|
+
import { CollectionsSidebar, focusCollectionList, } from '@elytracms/studio/components/cms/collections-sidebar';
|
|
7
7
|
import { Card, Code, Heading, Spacer, Stack, Text } from '@elytracms/studio/ui';
|
|
8
8
|
/**
|
|
9
9
|
* The CMS section landing view (EC-223 Stage 6): the collection grid, shown when
|
|
10
10
|
* no collection is selected. Takes `projectId` as a prop; the splat resolver
|
|
11
|
-
* mounts it inside the CMS provider so {@link useCms} resolves.
|
|
11
|
+
* mounts it inside the CMS provider so {@link useCms} resolves. `focusCollections`
|
|
12
|
+
* (EC-239) narrows the grid for a focused CMS module instance.
|
|
12
13
|
*/
|
|
13
|
-
export function CmsIndex({ projectId }) {
|
|
14
|
+
export function CmsIndex({ projectId, focusCollections, }) {
|
|
14
15
|
const cms = useCms();
|
|
15
|
-
|
|
16
|
+
const collections = focusCollectionList(cms.collections, focusCollections);
|
|
17
|
+
return (_jsxs("div", { className: "mx-auto w-full max-w-3xl p-4 sm:p-6", children: [_jsx("div", { className: "mb-6 h-72 overflow-hidden rounded-lg border border-border md:hidden", children: _jsx(CollectionsSidebar, { projectId: projectId, focusCollections: focusCollections }) }), _jsxs(Stack, { gap: "6", children: [_jsxs(Stack, { gap: "1", children: [_jsx(Heading, { size: "display", children: "Content" }), _jsx(Text, { tone: "muted", children: "Schema-driven collections. Open a collection to browse its documents as a table and edit them in the detail editor." })] }), _jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: collections.map((collection) => {
|
|
16
18
|
// EC-217: a singleton reads as one fixed document — a distinct icon
|
|
17
19
|
// and a "Single document" note instead of a (always-1) row count.
|
|
18
20
|
const singleton = isSingleton(collection);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cms-index.js","sourceRoot":"","sources":["../../../src/components/cms/cms-index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,4CAA4C,CAAA;AACnE,OAAO,
|
|
1
|
+
{"version":3,"file":"cms-index.js","sourceRoot":"","sources":["../../../src/components/cms/cms-index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,4CAA4C,CAAA;AACnE,OAAO,EACL,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,SAAS,EACT,gBAAgB,GAIjB;IACC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAA;IACpB,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAA;IAE1E,OAAO,CACL,eAAK,SAAS,EAAC,qCAAqC,aAClD,cAAK,SAAS,EAAC,qEAAqE,YAClF,KAAC,kBAAkB,IAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,GAAI,GAC5E,EACN,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,aACZ,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,aACZ,KAAC,OAAO,IAAC,IAAI,EAAC,SAAS,wBAAkB,EACzC,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,oIAGX,IACD,EACR,cAAK,SAAS,EAAC,2BAA2B,YACvC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;4BAC9B,oEAAoE;4BACpE,kEAAkE;4BAClE,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,CAAA;4BACzC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAA;4BAC3C,OAAO,CACL,KAAC,IAAI,IAEH,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,YAEtE,MAAC,IAAI,IAAC,SAAS,EAAC,uEAAuE,aACrF,eAAM,SAAS,EAAC,mFAAmF,YACjG,KAAC,IAAI,IAAC,SAAS,EAAC,QAAQ,GAAG,GACtB,EACP,MAAC,KAAK,IAAC,GAAG,EAAC,MAAM,EAAC,SAAS,EAAC,SAAS,aACnC,KAAC,IAAI,IAAC,MAAM,EAAC,UAAU,EAAC,SAAS,EAAC,UAAU,YACzC,UAAU,CAAC,IAAI,EAAE,KAAK,IAAI,UAAU,CAAC,EAAE,GACnC,EACP,MAAC,IAAI,IAAC,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,OAAO,aACjC,UAAU,CAAC,EAAE,cAAK,UAAU,CAAC,MAAM,CAAC,MAAM,eACtC,IACD,EACR,KAAC,MAAM,KAAG,EACT,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,mBAAmB,gCAEnD,CACR,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,IAAI,kBAC9B,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,GACjC,CACR,IACI,IA1BF,UAAU,CAAC,EAAE,CA2Bb,CACR,CAAA;wBACH,CAAC,CAAC,GACE,IACA,IACJ,CACP,CAAA;AACH,CAAC","sourcesContent":["import { Database, FileCog } from 'lucide-react'\nimport { isSingleton } from '@elytracms/core/cms-core'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { useCms } from '@elytracms/studio/components/cms/cms-store'\nimport {\n CollectionsSidebar,\n focusCollectionList,\n} from '@elytracms/studio/components/cms/collections-sidebar'\nimport { Card, Code, Heading, Spacer, Stack, Text } from '@elytracms/studio/ui'\n\n/**\n * The CMS section landing view (EC-223 Stage 6): the collection grid, shown when\n * no collection is selected. Takes `projectId` as a prop; the splat resolver\n * mounts it inside the CMS provider so {@link useCms} resolves. `focusCollections`\n * (EC-239) narrows the grid for a focused CMS module instance.\n */\nexport function CmsIndex({\n projectId,\n focusCollections,\n}: {\n projectId: string\n focusCollections?: readonly string[]\n}) {\n const cms = useCms()\n const collections = focusCollectionList(cms.collections, focusCollections)\n\n return (\n <div className=\"mx-auto w-full max-w-3xl p-4 sm:p-6\">\n <div className=\"mb-6 h-72 overflow-hidden rounded-lg border border-border md:hidden\">\n <CollectionsSidebar projectId={projectId} focusCollections={focusCollections} />\n </div>\n <Stack gap=\"6\">\n <Stack gap=\"1\">\n <Heading size=\"display\">Content</Heading>\n <Text tone=\"muted\">\n Schema-driven collections. Open a collection to browse its documents as a table and edit\n them in the detail editor.\n </Text>\n </Stack>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {collections.map((collection) => {\n // EC-217: a singleton reads as one fixed document — a distinct icon\n // and a \"Single document\" note instead of a (always-1) row count.\n const singleton = isSingleton(collection)\n const Icon = singleton ? FileCog : Database\n return (\n <Link\n key={collection.id}\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsCollection(collection.id) }}\n >\n <Card className=\"flex items-center gap-3 p-4 transition-colors hover:border-primary/30\">\n <span className=\"grid size-9 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground\">\n <Icon className=\"size-4\" />\n </span>\n <Stack gap=\"none\" className=\"min-w-0\">\n <Text weight=\"semibold\" className=\"truncate\">\n {collection.form?.label ?? collection.id}\n </Text>\n <Code tone=\"muted\" className=\"w-fit\">\n {collection.id} · {collection.fields.length} fields\n </Code>\n </Stack>\n <Spacer />\n {singleton ? (\n <Text size=\"xs\" tone=\"muted\" className=\"whitespace-nowrap\">\n Single document\n </Text>\n ) : (\n <Text size=\"sm\" tone=\"muted\" mono>\n {cms.documentsOf(collection.id).length}\n </Text>\n )}\n </Card>\n </Link>\n )\n })}\n </div>\n </Stack>\n </div>\n )\n}\n"]}
|
|
@@ -4,7 +4,7 @@ import type { DocumentVersionRecord } from '@elytracms/core/persistence';
|
|
|
4
4
|
import type { OperationError } from '@elytracms/studio/lib/operations';
|
|
5
5
|
import type { TableViewState } from '@elytracms/studio/lib/cms-views';
|
|
6
6
|
import type { CellCommitInput, CellCommitOutcome } from './cell-edit';
|
|
7
|
-
import type { BulkAction, BulkReport } from './bulk-actions';
|
|
7
|
+
import type { BulkAction, BulkReport, BulkSetField } from './bulk-actions';
|
|
8
8
|
/**
|
|
9
9
|
* A saved table view (EC-169, supersedes the EC-071 column presets): a named
|
|
10
10
|
* bundle of filters (closed AD-3 vocabulary), sort, and visible/ordered
|
|
@@ -111,7 +111,7 @@ export interface CmsStore {
|
|
|
111
111
|
restoreDocumentVersion(ref: DocumentRef, version: number): Promise<CmsDocument | null>;
|
|
112
112
|
importDocuments(collectionId: string, docs: unknown[]): ImportReport;
|
|
113
113
|
validate(doc: CmsDocument): CmsValidationIssue[];
|
|
114
|
-
isFieldReadOnly(
|
|
114
|
+
isFieldReadOnly(field: FieldDef): boolean;
|
|
115
115
|
viewsOf(collectionId: string): SavedView[];
|
|
116
116
|
activeViewId(collectionId: string): string;
|
|
117
117
|
/** Switch views — resets the working table state to the view's state. */
|
|
@@ -134,11 +134,12 @@ export interface CmsStore {
|
|
|
134
134
|
/** Delete a named view — a view-only operation; documents are never touched. */
|
|
135
135
|
deleteView(collectionId: string, viewId: string): Promise<boolean>;
|
|
136
136
|
/**
|
|
137
|
-
* Bulk publish/unpublish/delete (EC-169): one operations
|
|
138
|
-
* per-item outcomes in the report — partial failure is
|
|
139
|
-
* silent. Only succeeded items mutate the session.
|
|
137
|
+
* Bulk publish/unpublish/delete (EC-169) + set-field (EC-247): one operations
|
|
138
|
+
* command PER item, per-item outcomes in the report — partial failure is
|
|
139
|
+
* enumerated, never silent. Only succeeded items mutate the session. A
|
|
140
|
+
* `set-field` carries its `{ field, value }` payload.
|
|
140
141
|
*/
|
|
141
|
-
runBulk(collectionId: string, ids: readonly string[], action: BulkAction): Promise<BulkReport>;
|
|
142
|
+
runBulk(collectionId: string, ids: readonly string[], action: BulkAction, setField?: BulkSetField): Promise<BulkReport>;
|
|
142
143
|
/**
|
|
143
144
|
* Mirror a collection into the session (e.g. an accepted AI-generated
|
|
144
145
|
* schema, EC-097). Replaces by id. Session-only: persistence happens through
|
|
@@ -9,12 +9,8 @@ import { slugify } from '@elytracms/studio/lib/utils';
|
|
|
9
9
|
import { createCmsPersister, getStudioOperations } from '@elytracms/studio/lib/operations';
|
|
10
10
|
import { ALL_VIEW_ID, canonicalViewState, defaultViewState, deleteSavedView, loadSavedViews, newViewId, normalizeViewState, saveSavedView, viewStatesEqual, } from '@elytracms/studio/lib/cms-views';
|
|
11
11
|
import { useOptionalAssets } from '../assets/assets-store';
|
|
12
|
-
import { commitCellEdit } from './cell-edit';
|
|
12
|
+
import { applyCellValue, commitCellEdit } from './cell-edit';
|
|
13
13
|
import { runBulkAction } from './bulk-actions';
|
|
14
|
-
/** Demo per-field access (brief §8.4, EC-078). Read-only fields render disabled. */
|
|
15
|
-
const READ_ONLY_FIELDS = {
|
|
16
|
-
asset: ['url'],
|
|
17
|
-
};
|
|
18
14
|
/**
|
|
19
15
|
* Mint a collision-safe, slug-derived page id (EC-192): the slug of the page name,
|
|
20
16
|
* suffixed `-2`/`-3`/… until it is free among the ids already taken. Empty or
|
|
@@ -455,10 +451,7 @@ export function CmsProvider({ children, projectId, initialCollections, initialDo
|
|
|
455
451
|
}
|
|
456
452
|
return report;
|
|
457
453
|
}, [registry, documents, localeConfig, assetExists]);
|
|
458
|
-
const isFieldReadOnly = useCallback((
|
|
459
|
-
return (field.form?.readOnly === true ||
|
|
460
|
-
(READ_ONLY_FIELDS[collectionId]?.includes(field.name) ?? false));
|
|
461
|
-
}, []);
|
|
454
|
+
const isFieldReadOnly = useCallback((field) => field.form?.readOnly === true, []);
|
|
462
455
|
// --- Saved views (EC-169) -------------------------------------------------
|
|
463
456
|
// Load the project's persisted views once (operations query). Views saved by
|
|
464
457
|
// other editors/sessions on the same project show up here.
|
|
@@ -590,7 +583,27 @@ export function CmsProvider({ children, projectId, initialCollections, initialDo
|
|
|
590
583
|
return true;
|
|
591
584
|
}, [dispatchViewMutation, activeViews, dropTableState]);
|
|
592
585
|
// --- Bulk actions (EC-169) ------------------------------------------------
|
|
593
|
-
const runBulk = useCallback(async (collectionId, ids, action) => {
|
|
586
|
+
const runBulk = useCallback(async (collectionId, ids, action, setField) => {
|
|
587
|
+
const collection = registry.get(collectionId);
|
|
588
|
+
// A set-field needs both the field payload AND the collection def to fold
|
|
589
|
+
// the value the locale-aware way — guard so a misconfigured call fails
|
|
590
|
+
// loud rather than silently no-opping each item.
|
|
591
|
+
if (action === 'set-field' && (!setField || !collection)) {
|
|
592
|
+
return {
|
|
593
|
+
action,
|
|
594
|
+
...(setField ? { setField } : {}),
|
|
595
|
+
results: ids.map((id) => ({
|
|
596
|
+
ref: { collection: collectionId, id },
|
|
597
|
+
title: titleOf({ collection: collectionId, id }),
|
|
598
|
+
ok: false,
|
|
599
|
+
reason: 'Set-field is missing its field/value or the collection schema.',
|
|
600
|
+
error: { code: 'unknown', message: 'Invalid set-field request.' },
|
|
601
|
+
})),
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
// The next document for a set-field item: fold the value into the active
|
|
605
|
+
// locale's bag (localized) or the shared `values` (non-localized).
|
|
606
|
+
const setFieldDoc = (doc) => applyCellValue(collection, doc, setField.field, activeLocale, setField.value);
|
|
594
607
|
let dispatch;
|
|
595
608
|
const persister = persisterRef.current;
|
|
596
609
|
if (persister && projectId !== undefined) {
|
|
@@ -598,11 +611,30 @@ export function CmsProvider({ children, projectId, initialCollections, initialDo
|
|
|
598
611
|
// command per item (same ordering contract as commitFieldEdit).
|
|
599
612
|
await persister.ensureBaseline();
|
|
600
613
|
const { operations } = await getStudioOperations();
|
|
601
|
-
dispatch = (bulkAction, ref) =>
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
614
|
+
dispatch = (bulkAction, ref) => {
|
|
615
|
+
if (bulkAction === 'delete')
|
|
616
|
+
return operations.documents.delete({ projectId, ref });
|
|
617
|
+
if (bulkAction === 'publish')
|
|
618
|
+
return operations.documents.publish({ projectId, ref });
|
|
619
|
+
if (bulkAction === 'unpublish')
|
|
620
|
+
return operations.documents.unpublish({ projectId, ref });
|
|
621
|
+
// set-field: upsert the document carrying the new value. The write
|
|
622
|
+
// path self-types it through the schema lens (EC-277); a scalar field
|
|
623
|
+
// stores its scalar as-is.
|
|
624
|
+
const current = documentsRef.current.find((d) => d.collection === ref.collection && d.id === ref.id);
|
|
625
|
+
if (!current) {
|
|
626
|
+
return Promise.resolve({
|
|
627
|
+
ok: false,
|
|
628
|
+
error: {
|
|
629
|
+
code: 'not-found',
|
|
630
|
+
message: 'Document is no longer in the session.',
|
|
631
|
+
entity: 'cms-document',
|
|
632
|
+
key: `${ref.collection}:${ref.id}`,
|
|
633
|
+
},
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
return operations.documents.upsert({ projectId, document: setFieldDoc(current) });
|
|
637
|
+
};
|
|
606
638
|
}
|
|
607
639
|
return runBulkAction({
|
|
608
640
|
documents: documentsRef.current,
|
|
@@ -619,12 +651,17 @@ export function CmsProvider({ children, projectId, initialCollections, initialDo
|
|
|
619
651
|
assetExists,
|
|
620
652
|
}),
|
|
621
653
|
// EC-224: a succeeded publish/unpublish moves the version pointer
|
|
622
|
-
// (`publishedKeys`)
|
|
654
|
+
// (`publishedKeys`) via setPublished — there is no separate flat
|
|
655
|
+
// `state` mirror to keep in sync (published-ness is derived from the
|
|
656
|
+
// pointer set).
|
|
623
657
|
applyState: (ref, state) => setPublished(ref, state === 'published'),
|
|
624
658
|
applyDelete: (ref) => setDocuments((prev) => prev.filter((d) => !(d.collection === ref.collection && d.id === ref.id))),
|
|
659
|
+
// EC-247: fold the new value into the session document (same
|
|
660
|
+
// locale-aware path the dispatched upsert used).
|
|
661
|
+
applySetField: (ref) => setDocuments((prev) => prev.map((d) => d.collection === ref.collection && d.id === ref.id ? setFieldDoc(d) : d)),
|
|
625
662
|
...(dispatch ? { dispatch } : {}),
|
|
626
|
-
}, collectionId, ids, action);
|
|
627
|
-
}, [projectId, titleOf, registry, localeConfig, setPublished, assetExists]);
|
|
663
|
+
}, collectionId, ids, action, setField);
|
|
664
|
+
}, [projectId, titleOf, registry, localeConfig, activeLocale, setPublished, assetExists]);
|
|
628
665
|
const store$ = useMemo(() => ({
|
|
629
666
|
...(projectId !== undefined ? { projectId } : {}),
|
|
630
667
|
collections,
|