@elytracms/studio 0.0.33 → 0.0.34
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/dist/components/app-views/default-modules.js +13 -6
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +7 -6
- package/dist/components/cms/cms-store.js +18 -10
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/detail-editor.js +7 -2
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/details-pane.js +4 -3
- package/dist/components/cms/details-pane.js.map +1 -1
- package/dist/components/cms/field-renderer.js +2 -1
- package/dist/components/cms/field-renderer.js.map +1 -1
- package/dist/components/cms/import-export.js +3 -2
- package/dist/components/cms/import-export.js.map +1 -1
- package/dist/components/cms/issues-pane.js +3 -2
- package/dist/components/cms/issues-pane.js.map +1 -1
- package/dist/lib/cms-views/view-model.js +3 -2
- package/dist/lib/cms-views/view-model.js.map +1 -1
- package/dist/lib/i18n/i18n.d.ts +19 -1
- package/dist/lib/i18n/i18n.js +45 -6
- package/dist/lib/i18n/i18n.js.map +1 -1
- package/dist/lib/i18n/index.d.ts +1 -1
- package/dist/lib/i18n/index.js +1 -1
- package/dist/lib/i18n/index.js.map +1 -1
- package/dist/lib/i18n/messages.en.js +24 -0
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/references/reference-model.js +6 -4
- package/dist/lib/references/reference-model.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
import { Blocks, Database, FileCog, Image, LayoutGrid, Puzzle, Settings as SettingsIcon, Signpost, Users, } from 'lucide-react';
|
|
4
|
-
import { extendCollectionDef, isSingleton,
|
|
4
|
+
import { extendCollectionDef, isSingleton, resolveSingletonDocument } from '@elytracms/core/cms-core';
|
|
5
5
|
import { Navigate, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router';
|
|
6
6
|
import { Text } from '@elytracms/studio/ui';
|
|
7
|
-
import { translate } from '@elytracms/studio/lib/i18n';
|
|
7
|
+
import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
|
|
8
8
|
import { getInstantiatedKit } from '@elytracms/studio/lib/starters/kit-session';
|
|
9
9
|
import { cmsDeepLink, componentsDeepLink, usersDeepLink, redirectsDeepLink, groupNode, separatorNode, viewNode, } from './module';
|
|
10
10
|
import { SectionSurface } from '../section-surface';
|
|
@@ -85,8 +85,9 @@ function cmsCollectionLeaf(collection) {
|
|
|
85
85
|
const singleton = isSingleton(collection);
|
|
86
86
|
return viewNode(cmsView({
|
|
87
87
|
collection: collection.id,
|
|
88
|
-
//
|
|
89
|
-
|
|
88
|
+
// Non-hook `localizedLabel` resolves the (possibly `{ en, de }`) collection label
|
|
89
|
+
// against the active UI locale, so a German editor sees German collection names.
|
|
90
|
+
label: localizedLabel(collection.form?.label, collection.id),
|
|
90
91
|
icon: singleton ? FileCog : collection.kind === 'asset' ? Image : Database,
|
|
91
92
|
}));
|
|
92
93
|
}
|
|
@@ -122,7 +123,13 @@ export function redirectsView(config = {}) {
|
|
|
122
123
|
return {
|
|
123
124
|
id: 'redirects',
|
|
124
125
|
get label() {
|
|
125
|
-
|
|
126
|
+
// Prefer an explicit rail label, then a consumer-*customized* collection label,
|
|
127
|
+
// else the localized catalog nav label. Never let the built-in English schema
|
|
128
|
+
// label ('Redirects') preempt translation — compare against the built-in default.
|
|
129
|
+
const customized = localizedLabel(schema.form?.label);
|
|
130
|
+
const builtin = localizedLabel(redirectsCollectionDef.form?.label);
|
|
131
|
+
return (config.label ??
|
|
132
|
+
(customized && customized !== builtin ? customized : translate('nav.redirects.label')));
|
|
126
133
|
},
|
|
127
134
|
get description() {
|
|
128
135
|
return translate('nav.redirects.description');
|
|
@@ -390,7 +397,7 @@ function SingletonGate({ projectId, collectionId }) {
|
|
|
390
397
|
return _jsx(CollectionTable, { projectId: projectId, collectionId: collectionId });
|
|
391
398
|
}
|
|
392
399
|
return (_jsx("div", { className: "grid h-full place-items-center p-8", children: _jsx(Text, { size: "sm", tone: "muted", children: translate('appViews.singleton.opening', {
|
|
393
|
-
label:
|
|
400
|
+
label: localizedLabel(collection?.form?.label, collectionId),
|
|
394
401
|
}) }) }));
|
|
395
402
|
}
|
|
396
403
|
/** Failed/denied persisted CMS mutations are always visible (EC-141). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-modules.js","sourceRoot":"","sources":["../../../src/components/app-views/default-modules.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect } from 'react'\nimport type { ReactNode } from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport {\n Blocks,\n Database,\n FileCog,\n Image,\n LayoutGrid,\n Puzzle,\n Settings as SettingsIcon,\n Signpost,\n Users,\n} from 'lucide-react'\nimport { extendCollectionDef, isSingleton, resolveLabel, resolveSingletonDocument } from '@elytracms/core/cms-core'\nimport type {\n CollectionDef,\n CollectionFieldOverride,\n CollectionFormMeta,\n} from '@elytracms/core/cms-core'\nimport type { Project, SectionId, SectionState } from '@elytracms/core/studio-core'\nimport { Navigate, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { Text } from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { getInstantiatedKit } from '@elytracms/studio/lib/starters/kit-session'\nimport {\n cmsDeepLink,\n componentsDeepLink,\n usersDeepLink,\n redirectsDeepLink,\n groupNode,\n separatorNode,\n viewNode,\n type AppViewContext,\n type AppViewDeepLink,\n type AppViewModule,\n type NavPermission,\n type SidebarViewNode,\n} from './module'\nimport { SectionSurface } from '../section-surface'\nimport { SectionStateView } from '../section-state'\nimport { SettingsForm } from '../settings-form'\nimport { AssetLibrary } from '../assets/asset-library'\nimport { UsersModule } from '../users/users-module'\nimport { RedirectsModule } from '../redirects/redirects-module'\nimport { redirectsCollectionDef } from '../redirects/redirects-schema'\nimport { ExtensionsView } from '../extensions/extensions-view'\nimport { RegistryBrowser } from '../components/registry-browser'\nimport { ComponentsIndex } from '../components/components-index'\nimport { ComponentDetail } from '../components/component-detail'\nimport { CmsSessionGate } from '../project-session'\nimport { CmsProvider, useCms } from '../cms/cms-store'\nimport { focusCollectionList } from '../cms/collection-focus'\nimport { CmsIndex } from '../cms/cms-index'\nimport { CollectionTable } from '../cms/collection-table'\nimport { DetailEditor } from '../cms/detail-editor'\nimport { OperationErrorBanner } from '../operation-error'\n\n/**\n * EC-237/239 — the studio's BUILT-IN views + the consumer-facing `nav` namespace,\n * an instance of the EC-236 customization seam.\n *\n * Each built-in surface (the former `StudioSectionResolver` case body) is promoted\n * to a self-contained {@link AppViewModule} factory. The `nav` namespace is the\n * single, typed builder a consuming repo's `studio.config.tsx` uses to declare its\n * section rail — `nav.cms(...)`, `nav.group(...)`, `nav.view(...)` — passing the\n * view objects (and a focus config) DIRECTLY, never a string id. The CMS surface\n * is a factory ({@link cmsView}) so a focused view (\"Catalog\", \"Categories\") is the\n * SAME surface instantiated with config, not a copy — the EC-239 reuse proof.\n */\n\n// --- The CMS surface, reusable via a config factory (the EC-239 reuse seam) ---\n\n/** Config for a CMS-backed view — `collections`/`collection` focus the lens (EC-239). */\nexport interface CmsViewConfig {\n /** Explicit stable id (the route segment). Omitted → derived from the focus. */\n id?: string\n label?: string\n description?: string\n icon?: LucideIcon\n /**\n * Scope the rail auto-expansion (EC-293) to these collection ids, in order. The\n * parent expands into one focused-lens child per id; the parent index shows the\n * same subset. Omitted → every collection. Ignored for a single-collection lens.\n */\n collections?: readonly string[]\n /** Single-collection lens: a LEAF rail item that opens straight into this collection. */\n collection?: string\n /**\n * EC-293 escape hatch: explicit rail children for this CMS parent, overriding the\n * default per-collection auto-expansion. Ignored for a single-collection lens.\n */\n children?: SidebarViewNode[]\n /** The availability section this view rides on (EC-221); defaults to `cms`. */\n availabilitySection?: SectionId\n /** OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18). See {@link BuiltinViewConfig.visible}. */\n visible?: NavPermission\n}\n\n/** Common label/icon overrides for a built-in view (`nav.redirects({ label: 'URLs' })`). */\nexport interface BuiltinViewConfig {\n label?: string\n icon?: LucideIcon\n /**\n * OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18): hide this\n * rail item for principals it returns `false` for; absent → always visible. The\n * policy (which roles) lives in the consuming project, never the engine. E.g.\n * `nav.users({ visible: ({ role }) => role === 'admin' })`.\n */\n visible?: NavPermission\n}\n\n/**\n * Config for the **redirects** rail (EC-311) — a built-in view whose engine-owned\n * schema is customizable. Beyond the shared label/icon/visible, a mount may rename\n * the rail (`form`) and **override built-in fields by equal name** (`fields`):\n * naming, permissions (`form.readOnly`), rendering (`form.control` → `fieldRenderers`)\n * and validation. The canonical `from`/`to`/`permanent`/`enabled` names+types are\n * contract-locked (a type change on one is a loud config error), but a *net-new*\n * field is allowed (EC-311 Tier 2): it's appended and persists in the redirect\n * record's `meta` bag — editorial only, so it never reaches delivery/routing.\n */\nexport interface RedirectsViewConfig extends BuiltinViewConfig {\n /** Rename the rail (e.g. `{ label: 'URLs' }`). */\n form?: Partial<CollectionFormMeta>\n /** Override built-in redirect fields, matched by `name`. */\n fields?: readonly CollectionFieldOverride[]\n}\n\n/** Config for a fully custom view (`nav.view({...})`) — the net-new surface escape hatch. */\nexport interface CustomViewConfig {\n /** Explicit stable id (the route segment). Omitted → a slug of the label. */\n id?: string\n label: string\n description?: string\n icon?: LucideIcon\n render: (ctx: AppViewContext) => ReactNode\n parsePath?: (segments: string[]) => AppViewDeepLink | null\n availabilitySection?: SectionId\n /** OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18). See {@link BuiltinViewConfig.visible}. */\n visible?: NavPermission\n}\n\nfunction slugify(label: string): string {\n return label.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'view'\n}\n\n/** Derive a stable, deterministic id from the CMS focus (overridable via `config.id`). */\nfunction cmsViewId(config: CmsViewConfig): string {\n if (config.id) return config.id\n if (config.collection) return `cms:${config.collection}`\n if (config.collections && config.collections.length > 0) {\n return `cms:${[...config.collections].join('-')}`\n }\n return 'cms'\n}\n\n/**\n * Build a CMS view — the default `cms` view, or a focused instance. Every instance\n * shares one surface ({@link CmsScreen}); `collections` narrows the sidebar + index\n * to a subset, `collection` is a single-collection lens that opens straight into\n * that collection's list. The id is derived from the focus (deterministic, stable\n * across rail reorders) unless `id` is given — so two focused views never collide.\n */\nexport function cmsView(config: CmsViewConfig = {}): AppViewModule {\n const single = config.collection\n const focus = single ? [single] : config.collections\n return {\n id: cmsViewId(config),\n // Lazy label/description (EC-241): the sidebar is built when the consumer's\n // `studio.config` module loads — BEFORE `createStudio` seeds the i18n config — so\n // resolving here would bake English. A getter defers resolution to render, when\n // the config is present and the browser locale is known.\n get label() {\n return config.label ?? translate('nav.cms.label')\n },\n get description() {\n return config.description ?? translate('nav.cms.description')\n },\n icon: config.icon ?? Database,\n availabilitySection: config.availabilitySection ?? 'cms',\n // A single-collection lens routes `[]`→that collection, `[d]`→its document;\n // an unfocused / multi-collection view uses the full index/collection/document arity.\n parsePath: single\n ? (segments) =>\n segments.length === 0\n ? { collectionId: single, documentId: null }\n : segments.length === 1\n ? { collectionId: single, documentId: segments[0]! }\n : null\n : cmsDeepLink,\n render: (ctx) => (\n <CmsScreen\n project={ctx.project}\n collectionId={ctx.deepLink.collectionId ?? null}\n documentId={ctx.deepLink.documentId ?? null}\n state={ctx.search.state}\n field={ctx.search.field}\n focusCollections={focus}\n />\n ),\n }\n}\n\n/**\n * A focused-lens rail child for one collection (EC-293) — the SAME `cms:<id>` view a\n * single-collection `nav.cms({ collection })` produces, carrying the collection's own\n * label + a singleton-aware icon (the former `CollectionsSidebar` row, lifted into\n * the rail). CMS auto-expansion maps the project's collections through this.\n */\nfunction cmsCollectionLeaf(collection: CollectionDef): SidebarViewNode {\n const singleton = isSingleton(collection)\n return viewNode(\n cmsView({\n collection: collection.id,\n // Rail resolution is pure (outside React) → default-language collection label.\n label: resolveLabel(collection.form?.label) ?? collection.id,\n icon: singleton ? FileCog : collection.kind === 'asset' ? Image : Database,\n }),\n )\n}\n\n/** The components registry browser view. */\nexport function componentsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'components',\n get label() {\n return config.label ?? translate('nav.components.label')\n },\n get description() {\n return translate('nav.components.description')\n },\n icon: config.icon ?? Blocks,\n availabilitySection: 'components',\n parsePath: componentsDeepLink,\n render: (ctx) => (\n <ComponentsScreen\n projectId={ctx.projectId}\n componentId={ctx.deepLink.componentId ?? null}\n state={ctx.search.state}\n />\n ),\n }\n}\n\n/**\n * The Redirects view (EC-303) — editorial redirects as DATA, an editor-owned CRUD\n * surface (create/edit/delete) over the portable list/edit surfaces. Routes are no\n * longer shown in the admin (they're code; native `next.config`/`vercel` own static\n * forwards, evaluated before these). Rides on the CMS availability (a content/\n * routing concern). `[]` is the list; `[redirectId]` opens that redirect's detail.\n */\nexport function redirectsView(config: RedirectsViewConfig = {}): AppViewModule {\n // EC-311: merge any field/label overrides over the engine-owned def ONCE, at config\n // build (config-as-code — a locked violation throws here, at `defineStudio` mount).\n // Tier 2: `additiveFields: 'allow'` — a net-new field is appended and persists in the\n // redirect record's `meta` bag (the canonical from/to/permanent/enabled stay locked).\n const schema = extendCollectionDef(redirectsCollectionDef, config, { additiveFields: 'allow' })\n return {\n id: 'redirects',\n get label() {\n return config.label ?? resolveLabel(schema.form?.label) ?? translate('nav.redirects.label')\n },\n get description() {\n return translate('nav.redirects.description')\n },\n icon: config.icon ?? Signpost,\n availabilitySection: 'cms',\n parsePath: redirectsDeepLink,\n render: (ctx) =>\n ctx.search.state && ctx.search.state !== 'working' ? (\n <SectionStateView state={ctx.search.state} title={translate('nav.redirects.label')} />\n ) : (\n <RedirectsModule\n projectId={ctx.projectId}\n redirectId={ctx.deepLink.redirectId ?? null}\n schema={schema}\n />\n ),\n }\n}\n\n/** The asset library view. */\nexport function assetsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'assets',\n get label() {\n return config.label ?? translate('nav.assets.label')\n },\n get description() {\n return translate('nav.assets.description')\n },\n icon: config.icon ?? Image,\n availabilitySection: 'assets',\n render: (ctx) => (\n <SectionSurface project={ctx.project} section=\"assets\" forcedState={ctx.search.state}>\n {/* The AssetsProvider is mounted at the project level (EC-195). */}\n <AssetLibrary projectId={ctx.projectId} focusAssetId={ctx.search.asset} />\n </SectionSurface>\n ),\n }\n}\n\n/**\n * The studio Users view (EC-240) — an admin-only roster of who has access to this\n * deployment and their role. A first-class section (its own rail entry), modeled\n * like the Assets library; the surface itself gates to admins and renders a\n * \"restricted\" state otherwise. Rides on the `settings` availability (an\n * admin/config concern, so it appears/hides with a project's settings surface).\n */\nexport function usersView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'users',\n get label() {\n return config.label ?? translate('nav.users.label')\n },\n get description() {\n return translate('nav.users.description')\n },\n icon: config.icon ?? Users,\n availabilitySection: 'users',\n // EC-240: `[]` is the roster; `[userId]` opens that member in the portable edit\n // shell (AD-19 reuse — the same `DetailEditor` body over the users source).\n parsePath: usersDeepLink,\n render: (ctx) =>\n ctx.search.state && ctx.search.state !== 'working' ? (\n <SectionStateView state={ctx.search.state} title={translate('nav.users.label')} />\n ) : (\n <UsersModule projectId={ctx.projectId} userId={ctx.deepLink.userId ?? null} />\n ),\n }\n}\n\n/** The extensions marketplace view. */\nexport function extensionsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'extensions',\n get label() {\n return config.label ?? translate('nav.extensions.label')\n },\n get description() {\n return translate('nav.extensions.description')\n },\n icon: config.icon ?? Puzzle,\n availabilitySection: 'extensions',\n render: (ctx) =>\n ctx.search.state && ctx.search.state !== 'working' ? (\n <SectionStateView state={ctx.search.state} title={translate('nav.extensions.label')} />\n ) : (\n <ExtensionsView />\n ),\n }\n}\n\n/** The project settings view. */\nexport function settingsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'settings',\n get label() {\n return config.label ?? translate('nav.settings.label')\n },\n get description() {\n return translate('nav.settings.description')\n },\n icon: config.icon ?? SettingsIcon,\n availabilitySection: 'settings',\n render: (ctx) => (\n <SectionSurface project={ctx.project} section=\"settings\" forcedState={ctx.search.state}>\n <SettingsForm project={ctx.project} />\n </SectionSurface>\n ),\n }\n}\n\n/** The legacy `builder` redirect — a hidden, routable view (so `/builder?page=` still lands). */\nexport function builderView(): AppViewModule {\n return {\n id: 'builder',\n label: 'Builder',\n description: 'Legacy builder route — redirects to the page document editor.',\n icon: Blocks,\n hidden: true,\n render: (ctx) => (\n // Retired surface (EC-187 slice 6): a page is a document in the `page`\n // collection. `?page=<id>` lands on that document; else the page list.\n <Navigate\n to={STUDIO_PROJECT_ROUTE}\n params={{\n projectId: ctx.projectId,\n _splat: ctx.search.page\n ? studioPath.cmsDocument('page', ctx.search.page)\n : studioPath.cmsCollection('page'),\n }}\n replace\n />\n ),\n }\n}\n\n/** Build a fully custom view (the `nav.view(...)` escape hatch). */\nexport function customView(config: CustomViewConfig): AppViewModule {\n return {\n id: config.id ?? slugify(config.label),\n label: config.label,\n description: config.description ?? config.label,\n icon: config.icon ?? LayoutGrid,\n render: config.render,\n ...(config.parsePath ? { parsePath: config.parsePath } : {}),\n ...(config.availabilitySection ? { availabilitySection: config.availabilitySection } : {}),\n }\n}\n\n/**\n * The studio's built-in views in canonical rail order (components · CMS · routes ·\n * assets · extensions · settings), plus the hidden `builder` redirect (routable but\n * unlisted). The default rail (no `defineStudio({ sidebar })`) is these as plain\n * entries; the router registry always includes them so deep-links resolve even\n * when a consumer's rail omits one.\n */\nexport const DEFAULT_VIEWS: readonly AppViewModule[] = [\n componentsView(),\n cmsView(),\n redirectsView(),\n assetsView(),\n extensionsView(),\n usersView(),\n settingsView(),\n builderView(),\n]\n\n/**\n * The `nav` namespace — the single typed builder for `studio.config.tsx`'s section\n * rail. Each call returns a {@link SidebarViewNode} (or a group / separator) that\n * carries its view DIRECTLY: `nav.cms({ collection })` is a focused CMS view,\n * `nav.view({ render })` a net-new surface, `nav.group(label, [...])` a header with\n * sub-views, `nav.separator()` a divider. No string ids, no `moduleId` — the rail\n * is the views.\n */\n/**\n * Forward the OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18)\n * from a `nav.*` config onto the built view, so gating is settable on EVERY nav\n * item — not just Users. Absent → the view is unchanged (always visible).\n */\nfunction withNavPermission(view: AppViewModule, config: { visible?: NavPermission }): AppViewModule {\n if (!config.visible) return view\n // Copy property DESCRIPTORS (not a spread) so a built-in view's lazy `label`/\n // `description` getters (EC-241) survive — a spread would invoke them at build time,\n // baking English before `createStudio` seeds the i18n config.\n return Object.defineProperties({} as AppViewModule, {\n ...Object.getOwnPropertyDescriptors(view),\n visible: { value: config.visible, enumerable: true, configurable: true, writable: true },\n })\n}\n\nexport const nav = {\n /**\n * The CMS view. `nav.cms()` / `nav.cms({ collections })` is a PARENT that nests its\n * collections in the rail (each a focused `cms:<id>` lens); `nav.cms({ collection })`\n * is a single-collection LEAF; `nav.cms({ children })` supplies explicit children.\n */\n cms: (config: CmsViewConfig = {}): SidebarViewNode => {\n const view = withNavPermission(cmsView(config), config)\n // A single-collection lens is a leaf — it opens that collection directly.\n if (config.collection) return viewNode(view)\n // Otherwise a parent that expands its collections as nested rail children (EC-293).\n const node: SidebarViewNode = { kind: 'view', view }\n if (config.children) node.children = config.children\n else\n node.expand = (collections) =>\n focusCollectionList(collections, config.collections).map(cmsCollectionLeaf)\n return node\n },\n /** The component registry browser. */\n components: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(componentsView(config), config)),\n /** The asset library. */\n assets: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(assetsView(config), config)),\n /** Editorial redirects (EC-303); built-in fields customizable by name (EC-311). */\n redirects: (config: RedirectsViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(redirectsView(config), config)),\n /** Project settings. */\n settings: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(settingsView(config), config)),\n /** The extensions marketplace. */\n extensions: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(extensionsView(config), config)),\n /** The admin users roster (EC-240). */\n users: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(usersView(config), config)),\n /** A fully custom view — pass your own `render` (and optional `parsePath`). */\n view: (config: CustomViewConfig): SidebarViewNode =>\n viewNode(withNavPermission(customView(config), config)),\n /** A labelled group of views (a header with sub-entries). */\n group: (label: string, children: SidebarViewNode[]) => groupNode(label, children),\n /** A divider between rail sections. */\n separator: () => separatorNode(),\n} as const\n\n// --- Surfaces (the view render bodies; CMS gains a focus lens) ---\n\n/**\n * Components section (EC-050): a registry-browser sidebar beside the active\n * screen — the index (no selection) or a component's detail. Forced states\n * (?state=) replace the whole surface.\n */\nfunction ComponentsScreen({\n projectId,\n componentId,\n state,\n}: {\n projectId: string\n componentId: string | null\n state?: SectionState\n}) {\n if (state && state !== 'working') {\n return <SectionStateView state={state} title={translate('nav.components.label')} />\n }\n return (\n <div className=\"flex h-full min-h-0\">\n <aside className=\"hidden h-full min-h-0 w-[300px] shrink-0 border-r border-border md:block\">\n <RegistryBrowser projectId={projectId} activeComponentId={componentId ?? undefined} />\n </aside>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {componentId === null ? (\n <ComponentsIndex projectId={projectId} />\n ) : (\n <ComponentDetail projectId={projectId} componentId={componentId} />\n )}\n </div>\n </div>\n )\n}\n\n/**\n * CMS section: hydrates the persisted (or kit-seeded) collections + documents, then\n * renders the active screen full-width (index, a collection table, or a document\n * editor). EC-293: the collection list lives in the section rail (nested under the\n * CMS view), so there is no in-surface collections sidebar. Forced states (?state=)\n * replace the whole surface. `focusCollections` (EC-239) narrows the index to a\n * subset, so a focused view (\"Catalog\") reuses this surface with config.\n */\nfunction CmsScreen({\n project,\n collectionId,\n documentId,\n state,\n field,\n focusCollections,\n}: {\n project: Project\n collectionId: string | null\n documentId: string | null\n state?: SectionState\n field?: string\n focusCollections?: readonly string[]\n}) {\n const projectId = project.id\n if (state && state !== 'working') {\n return <SectionStateView state={state} title={translate('nav.cms.label')} />\n }\n\n // A project created from a starter kit (EC-119) opens the CMS on the kit's schemas + content.\n const kit = getInstantiatedKit(projectId)\n\n return (\n // EC-177 gap 1: in Convex mode every CMS mount loads the CURRENT persisted\n // schema + documents (fixtures only when nothing is persisted — first run).\n // Playground renders synchronously with `null` → fixture seeds, as before.\n <CmsSessionGate>\n {(cms) => (\n <CmsProvider\n key={projectId}\n projectId={projectId}\n initialCollections={cms?.collections ?? kit?.collections}\n initialDocuments={cms?.documents ?? kit?.documents}\n initialPublishedKeys={cms?.publishedKeys}\n initialLocaleConfig={\n cms\n ? // Hydrated sessions follow the project's persisted locale settings.\n { default: project.settings.defaultLocale, locales: [...project.settings.locales] }\n : kit?.localeConfig\n }\n >\n <div className=\"flex h-full min-h-0 flex-col\">\n <CmsPersistErrorBanner />\n {/* EC-293: the collection list now lives in the section rail (nested\n under the CMS view), so the surface is full-width — the old 240px\n CollectionsSidebar aside is gone. */}\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n <CmsContent\n projectId={projectId}\n collectionId={collectionId}\n documentId={documentId}\n field={field}\n focusCollections={focusCollections}\n />\n </div>\n </div>\n </CmsProvider>\n )}\n </CmsSessionGate>\n )\n}\n\n/** Resolves the active CMS screen inside the provider (needs the live store). */\nfunction CmsContent({\n projectId,\n collectionId,\n documentId,\n field,\n focusCollections,\n}: {\n projectId: string\n collectionId: string | null\n documentId: string | null\n field?: string\n focusCollections?: readonly string[]\n}) {\n const cms = useCms()\n\n if (collectionId === null) return <CmsIndex projectId={projectId} focusCollections={focusCollections} />\n\n if (documentId === null) {\n const collection = cms.getCollection(collectionId)\n // EC-274: a singleton is a UI lens — at the collection URL it opens its one\n // document directly *while in its expected shape*, but degrades to the list\n // (with a \"for review\" lane) on drift. SingletonGate decides per the data.\n if (collection && isSingleton(collection)) {\n return <SingletonGate projectId={projectId} collectionId={collectionId} />\n }\n return <CollectionTable projectId={projectId} collectionId={collectionId} />\n }\n\n return (\n <DetailEditor\n projectId={projectId}\n collectionId={collectionId}\n documentId={documentId}\n focusPath={field}\n />\n )\n}\n\n/**\n * EC-274 — the singleton lens gate. At a singleton collection's URL, resolve its\n * lone document and open it directly; on drift (> 1 document) fall back to the\n * list with the \"for review\" lane so an editor can resolve the conflict.\n */\nfunction SingletonGate({ projectId, collectionId }: { projectId: string; collectionId: string }) {\n const cms = useCms()\n const collection = cms.getCollection(collectionId)\n const docs = cms.documentsOf(collectionId)\n const resolution = collection\n ? resolveSingletonDocument(collection, docs)\n : ({ kind: 'empty' } as const)\n\n // Materialize the lone document on first visit (an empty draft, persisted like\n // any create). Idempotent in the store; only fires while genuinely empty.\n useEffect(() => {\n if (resolution.kind === 'empty') cms.ensureSingletonDocument(collectionId)\n }, [resolution.kind, cms, collectionId])\n\n if (resolution.kind === 'ready') {\n return (\n <DetailEditor projectId={projectId} collectionId={collectionId} documentId={resolution.doc.id} />\n )\n }\n if (resolution.kind === 'drift') {\n return <CollectionTable projectId={projectId} collectionId={collectionId} />\n }\n return (\n <div className=\"grid h-full place-items-center p-8\">\n <Text size=\"sm\" tone=\"muted\">\n {translate('appViews.singleton.opening', {\n label: resolveLabel(collection?.form?.label) ?? collectionId,\n })}\n </Text>\n </div>\n )\n}\n\n/** Failed/denied persisted CMS mutations are always visible (EC-141). */\nfunction CmsPersistErrorBanner() {\n const cms = useCms()\n if (!cms.persistError) return null\n return (\n <div className=\"shrink-0 border-b border-border p-2\">\n <OperationErrorBanner error={cms.persistError} onDismiss={cms.clearPersistError} />\n </div>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"default-modules.js","sourceRoot":"","sources":["../../../src/components/app-views/default-modules.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect } from 'react'\nimport type { ReactNode } from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport {\n Blocks,\n Database,\n FileCog,\n Image,\n LayoutGrid,\n Puzzle,\n Settings as SettingsIcon,\n Signpost,\n Users,\n} from 'lucide-react'\nimport { extendCollectionDef, isSingleton, resolveSingletonDocument } from '@elytracms/core/cms-core'\nimport type {\n CollectionDef,\n CollectionFieldOverride,\n CollectionFormMeta,\n} from '@elytracms/core/cms-core'\nimport type { Project, SectionId, SectionState } from '@elytracms/core/studio-core'\nimport { Navigate, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { Text } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { getInstantiatedKit } from '@elytracms/studio/lib/starters/kit-session'\nimport {\n cmsDeepLink,\n componentsDeepLink,\n usersDeepLink,\n redirectsDeepLink,\n groupNode,\n separatorNode,\n viewNode,\n type AppViewContext,\n type AppViewDeepLink,\n type AppViewModule,\n type NavPermission,\n type SidebarViewNode,\n} from './module'\nimport { SectionSurface } from '../section-surface'\nimport { SectionStateView } from '../section-state'\nimport { SettingsForm } from '../settings-form'\nimport { AssetLibrary } from '../assets/asset-library'\nimport { UsersModule } from '../users/users-module'\nimport { RedirectsModule } from '../redirects/redirects-module'\nimport { redirectsCollectionDef } from '../redirects/redirects-schema'\nimport { ExtensionsView } from '../extensions/extensions-view'\nimport { RegistryBrowser } from '../components/registry-browser'\nimport { ComponentsIndex } from '../components/components-index'\nimport { ComponentDetail } from '../components/component-detail'\nimport { CmsSessionGate } from '../project-session'\nimport { CmsProvider, useCms } from '../cms/cms-store'\nimport { focusCollectionList } from '../cms/collection-focus'\nimport { CmsIndex } from '../cms/cms-index'\nimport { CollectionTable } from '../cms/collection-table'\nimport { DetailEditor } from '../cms/detail-editor'\nimport { OperationErrorBanner } from '../operation-error'\n\n/**\n * EC-237/239 — the studio's BUILT-IN views + the consumer-facing `nav` namespace,\n * an instance of the EC-236 customization seam.\n *\n * Each built-in surface (the former `StudioSectionResolver` case body) is promoted\n * to a self-contained {@link AppViewModule} factory. The `nav` namespace is the\n * single, typed builder a consuming repo's `studio.config.tsx` uses to declare its\n * section rail — `nav.cms(...)`, `nav.group(...)`, `nav.view(...)` — passing the\n * view objects (and a focus config) DIRECTLY, never a string id. The CMS surface\n * is a factory ({@link cmsView}) so a focused view (\"Catalog\", \"Categories\") is the\n * SAME surface instantiated with config, not a copy — the EC-239 reuse proof.\n */\n\n// --- The CMS surface, reusable via a config factory (the EC-239 reuse seam) ---\n\n/** Config for a CMS-backed view — `collections`/`collection` focus the lens (EC-239). */\nexport interface CmsViewConfig {\n /** Explicit stable id (the route segment). Omitted → derived from the focus. */\n id?: string\n label?: string\n description?: string\n icon?: LucideIcon\n /**\n * Scope the rail auto-expansion (EC-293) to these collection ids, in order. The\n * parent expands into one focused-lens child per id; the parent index shows the\n * same subset. Omitted → every collection. Ignored for a single-collection lens.\n */\n collections?: readonly string[]\n /** Single-collection lens: a LEAF rail item that opens straight into this collection. */\n collection?: string\n /**\n * EC-293 escape hatch: explicit rail children for this CMS parent, overriding the\n * default per-collection auto-expansion. Ignored for a single-collection lens.\n */\n children?: SidebarViewNode[]\n /** The availability section this view rides on (EC-221); defaults to `cms`. */\n availabilitySection?: SectionId\n /** OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18). See {@link BuiltinViewConfig.visible}. */\n visible?: NavPermission\n}\n\n/** Common label/icon overrides for a built-in view (`nav.redirects({ label: 'URLs' })`). */\nexport interface BuiltinViewConfig {\n label?: string\n icon?: LucideIcon\n /**\n * OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18): hide this\n * rail item for principals it returns `false` for; absent → always visible. The\n * policy (which roles) lives in the consuming project, never the engine. E.g.\n * `nav.users({ visible: ({ role }) => role === 'admin' })`.\n */\n visible?: NavPermission\n}\n\n/**\n * Config for the **redirects** rail (EC-311) — a built-in view whose engine-owned\n * schema is customizable. Beyond the shared label/icon/visible, a mount may rename\n * the rail (`form`) and **override built-in fields by equal name** (`fields`):\n * naming, permissions (`form.readOnly`), rendering (`form.control` → `fieldRenderers`)\n * and validation. The canonical `from`/`to`/`permanent`/`enabled` names+types are\n * contract-locked (a type change on one is a loud config error), but a *net-new*\n * field is allowed (EC-311 Tier 2): it's appended and persists in the redirect\n * record's `meta` bag — editorial only, so it never reaches delivery/routing.\n */\nexport interface RedirectsViewConfig extends BuiltinViewConfig {\n /** Rename the rail (e.g. `{ label: 'URLs' }`). */\n form?: Partial<CollectionFormMeta>\n /** Override built-in redirect fields, matched by `name`. */\n fields?: readonly CollectionFieldOverride[]\n}\n\n/** Config for a fully custom view (`nav.view({...})`) — the net-new surface escape hatch. */\nexport interface CustomViewConfig {\n /** Explicit stable id (the route segment). Omitted → a slug of the label. */\n id?: string\n label: string\n description?: string\n icon?: LucideIcon\n render: (ctx: AppViewContext) => ReactNode\n parsePath?: (segments: string[]) => AppViewDeepLink | null\n availabilitySection?: SectionId\n /** OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18). See {@link BuiltinViewConfig.visible}. */\n visible?: NavPermission\n}\n\nfunction slugify(label: string): string {\n return label.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'view'\n}\n\n/** Derive a stable, deterministic id from the CMS focus (overridable via `config.id`). */\nfunction cmsViewId(config: CmsViewConfig): string {\n if (config.id) return config.id\n if (config.collection) return `cms:${config.collection}`\n if (config.collections && config.collections.length > 0) {\n return `cms:${[...config.collections].join('-')}`\n }\n return 'cms'\n}\n\n/**\n * Build a CMS view — the default `cms` view, or a focused instance. Every instance\n * shares one surface ({@link CmsScreen}); `collections` narrows the sidebar + index\n * to a subset, `collection` is a single-collection lens that opens straight into\n * that collection's list. The id is derived from the focus (deterministic, stable\n * across rail reorders) unless `id` is given — so two focused views never collide.\n */\nexport function cmsView(config: CmsViewConfig = {}): AppViewModule {\n const single = config.collection\n const focus = single ? [single] : config.collections\n return {\n id: cmsViewId(config),\n // Lazy label/description (EC-241): the sidebar is built when the consumer's\n // `studio.config` module loads — BEFORE `createStudio` seeds the i18n config — so\n // resolving here would bake English. A getter defers resolution to render, when\n // the config is present and the browser locale is known.\n get label() {\n return config.label ?? translate('nav.cms.label')\n },\n get description() {\n return config.description ?? translate('nav.cms.description')\n },\n icon: config.icon ?? Database,\n availabilitySection: config.availabilitySection ?? 'cms',\n // A single-collection lens routes `[]`→that collection, `[d]`→its document;\n // an unfocused / multi-collection view uses the full index/collection/document arity.\n parsePath: single\n ? (segments) =>\n segments.length === 0\n ? { collectionId: single, documentId: null }\n : segments.length === 1\n ? { collectionId: single, documentId: segments[0]! }\n : null\n : cmsDeepLink,\n render: (ctx) => (\n <CmsScreen\n project={ctx.project}\n collectionId={ctx.deepLink.collectionId ?? null}\n documentId={ctx.deepLink.documentId ?? null}\n state={ctx.search.state}\n field={ctx.search.field}\n focusCollections={focus}\n />\n ),\n }\n}\n\n/**\n * A focused-lens rail child for one collection (EC-293) — the SAME `cms:<id>` view a\n * single-collection `nav.cms({ collection })` produces, carrying the collection's own\n * label + a singleton-aware icon (the former `CollectionsSidebar` row, lifted into\n * the rail). CMS auto-expansion maps the project's collections through this.\n */\nfunction cmsCollectionLeaf(collection: CollectionDef): SidebarViewNode {\n const singleton = isSingleton(collection)\n return viewNode(\n cmsView({\n collection: collection.id,\n // Non-hook `localizedLabel` resolves the (possibly `{ en, de }`) collection label\n // against the active UI locale, so a German editor sees German collection names.\n label: localizedLabel(collection.form?.label, collection.id),\n icon: singleton ? FileCog : collection.kind === 'asset' ? Image : Database,\n }),\n )\n}\n\n/** The components registry browser view. */\nexport function componentsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'components',\n get label() {\n return config.label ?? translate('nav.components.label')\n },\n get description() {\n return translate('nav.components.description')\n },\n icon: config.icon ?? Blocks,\n availabilitySection: 'components',\n parsePath: componentsDeepLink,\n render: (ctx) => (\n <ComponentsScreen\n projectId={ctx.projectId}\n componentId={ctx.deepLink.componentId ?? null}\n state={ctx.search.state}\n />\n ),\n }\n}\n\n/**\n * The Redirects view (EC-303) — editorial redirects as DATA, an editor-owned CRUD\n * surface (create/edit/delete) over the portable list/edit surfaces. Routes are no\n * longer shown in the admin (they're code; native `next.config`/`vercel` own static\n * forwards, evaluated before these). Rides on the CMS availability (a content/\n * routing concern). `[]` is the list; `[redirectId]` opens that redirect's detail.\n */\nexport function redirectsView(config: RedirectsViewConfig = {}): AppViewModule {\n // EC-311: merge any field/label overrides over the engine-owned def ONCE, at config\n // build (config-as-code — a locked violation throws here, at `defineStudio` mount).\n // Tier 2: `additiveFields: 'allow'` — a net-new field is appended and persists in the\n // redirect record's `meta` bag (the canonical from/to/permanent/enabled stay locked).\n const schema = extendCollectionDef(redirectsCollectionDef, config, { additiveFields: 'allow' })\n return {\n id: 'redirects',\n get label() {\n // Prefer an explicit rail label, then a consumer-*customized* collection label,\n // else the localized catalog nav label. Never let the built-in English schema\n // label ('Redirects') preempt translation — compare against the built-in default.\n const customized = localizedLabel(schema.form?.label)\n const builtin = localizedLabel(redirectsCollectionDef.form?.label)\n return (\n config.label ??\n (customized && customized !== builtin ? customized : translate('nav.redirects.label'))\n )\n },\n get description() {\n return translate('nav.redirects.description')\n },\n icon: config.icon ?? Signpost,\n availabilitySection: 'cms',\n parsePath: redirectsDeepLink,\n render: (ctx) =>\n ctx.search.state && ctx.search.state !== 'working' ? (\n <SectionStateView state={ctx.search.state} title={translate('nav.redirects.label')} />\n ) : (\n <RedirectsModule\n projectId={ctx.projectId}\n redirectId={ctx.deepLink.redirectId ?? null}\n schema={schema}\n />\n ),\n }\n}\n\n/** The asset library view. */\nexport function assetsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'assets',\n get label() {\n return config.label ?? translate('nav.assets.label')\n },\n get description() {\n return translate('nav.assets.description')\n },\n icon: config.icon ?? Image,\n availabilitySection: 'assets',\n render: (ctx) => (\n <SectionSurface project={ctx.project} section=\"assets\" forcedState={ctx.search.state}>\n {/* The AssetsProvider is mounted at the project level (EC-195). */}\n <AssetLibrary projectId={ctx.projectId} focusAssetId={ctx.search.asset} />\n </SectionSurface>\n ),\n }\n}\n\n/**\n * The studio Users view (EC-240) — an admin-only roster of who has access to this\n * deployment and their role. A first-class section (its own rail entry), modeled\n * like the Assets library; the surface itself gates to admins and renders a\n * \"restricted\" state otherwise. Rides on the `settings` availability (an\n * admin/config concern, so it appears/hides with a project's settings surface).\n */\nexport function usersView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'users',\n get label() {\n return config.label ?? translate('nav.users.label')\n },\n get description() {\n return translate('nav.users.description')\n },\n icon: config.icon ?? Users,\n availabilitySection: 'users',\n // EC-240: `[]` is the roster; `[userId]` opens that member in the portable edit\n // shell (AD-19 reuse — the same `DetailEditor` body over the users source).\n parsePath: usersDeepLink,\n render: (ctx) =>\n ctx.search.state && ctx.search.state !== 'working' ? (\n <SectionStateView state={ctx.search.state} title={translate('nav.users.label')} />\n ) : (\n <UsersModule projectId={ctx.projectId} userId={ctx.deepLink.userId ?? null} />\n ),\n }\n}\n\n/** The extensions marketplace view. */\nexport function extensionsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'extensions',\n get label() {\n return config.label ?? translate('nav.extensions.label')\n },\n get description() {\n return translate('nav.extensions.description')\n },\n icon: config.icon ?? Puzzle,\n availabilitySection: 'extensions',\n render: (ctx) =>\n ctx.search.state && ctx.search.state !== 'working' ? (\n <SectionStateView state={ctx.search.state} title={translate('nav.extensions.label')} />\n ) : (\n <ExtensionsView />\n ),\n }\n}\n\n/** The project settings view. */\nexport function settingsView(config: BuiltinViewConfig = {}): AppViewModule {\n return {\n id: 'settings',\n get label() {\n return config.label ?? translate('nav.settings.label')\n },\n get description() {\n return translate('nav.settings.description')\n },\n icon: config.icon ?? SettingsIcon,\n availabilitySection: 'settings',\n render: (ctx) => (\n <SectionSurface project={ctx.project} section=\"settings\" forcedState={ctx.search.state}>\n <SettingsForm project={ctx.project} />\n </SectionSurface>\n ),\n }\n}\n\n/** The legacy `builder` redirect — a hidden, routable view (so `/builder?page=` still lands). */\nexport function builderView(): AppViewModule {\n return {\n id: 'builder',\n label: 'Builder',\n description: 'Legacy builder route — redirects to the page document editor.',\n icon: Blocks,\n hidden: true,\n render: (ctx) => (\n // Retired surface (EC-187 slice 6): a page is a document in the `page`\n // collection. `?page=<id>` lands on that document; else the page list.\n <Navigate\n to={STUDIO_PROJECT_ROUTE}\n params={{\n projectId: ctx.projectId,\n _splat: ctx.search.page\n ? studioPath.cmsDocument('page', ctx.search.page)\n : studioPath.cmsCollection('page'),\n }}\n replace\n />\n ),\n }\n}\n\n/** Build a fully custom view (the `nav.view(...)` escape hatch). */\nexport function customView(config: CustomViewConfig): AppViewModule {\n return {\n id: config.id ?? slugify(config.label),\n label: config.label,\n description: config.description ?? config.label,\n icon: config.icon ?? LayoutGrid,\n render: config.render,\n ...(config.parsePath ? { parsePath: config.parsePath } : {}),\n ...(config.availabilitySection ? { availabilitySection: config.availabilitySection } : {}),\n }\n}\n\n/**\n * The studio's built-in views in canonical rail order (components · CMS · routes ·\n * assets · extensions · settings), plus the hidden `builder` redirect (routable but\n * unlisted). The default rail (no `defineStudio({ sidebar })`) is these as plain\n * entries; the router registry always includes them so deep-links resolve even\n * when a consumer's rail omits one.\n */\nexport const DEFAULT_VIEWS: readonly AppViewModule[] = [\n componentsView(),\n cmsView(),\n redirectsView(),\n assetsView(),\n extensionsView(),\n usersView(),\n settingsView(),\n builderView(),\n]\n\n/**\n * The `nav` namespace — the single typed builder for `studio.config.tsx`'s section\n * rail. Each call returns a {@link SidebarViewNode} (or a group / separator) that\n * carries its view DIRECTLY: `nav.cms({ collection })` is a focused CMS view,\n * `nav.view({ render })` a net-new surface, `nav.group(label, [...])` a header with\n * sub-views, `nav.separator()` a divider. No string ids, no `moduleId` — the rail\n * is the views.\n */\n/**\n * Forward the OPTIONAL, default-open nav-permission predicate (EC-240 / AD-18)\n * from a `nav.*` config onto the built view, so gating is settable on EVERY nav\n * item — not just Users. Absent → the view is unchanged (always visible).\n */\nfunction withNavPermission(view: AppViewModule, config: { visible?: NavPermission }): AppViewModule {\n if (!config.visible) return view\n // Copy property DESCRIPTORS (not a spread) so a built-in view's lazy `label`/\n // `description` getters (EC-241) survive — a spread would invoke them at build time,\n // baking English before `createStudio` seeds the i18n config.\n return Object.defineProperties({} as AppViewModule, {\n ...Object.getOwnPropertyDescriptors(view),\n visible: { value: config.visible, enumerable: true, configurable: true, writable: true },\n })\n}\n\nexport const nav = {\n /**\n * The CMS view. `nav.cms()` / `nav.cms({ collections })` is a PARENT that nests its\n * collections in the rail (each a focused `cms:<id>` lens); `nav.cms({ collection })`\n * is a single-collection LEAF; `nav.cms({ children })` supplies explicit children.\n */\n cms: (config: CmsViewConfig = {}): SidebarViewNode => {\n const view = withNavPermission(cmsView(config), config)\n // A single-collection lens is a leaf — it opens that collection directly.\n if (config.collection) return viewNode(view)\n // Otherwise a parent that expands its collections as nested rail children (EC-293).\n const node: SidebarViewNode = { kind: 'view', view }\n if (config.children) node.children = config.children\n else\n node.expand = (collections) =>\n focusCollectionList(collections, config.collections).map(cmsCollectionLeaf)\n return node\n },\n /** The component registry browser. */\n components: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(componentsView(config), config)),\n /** The asset library. */\n assets: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(assetsView(config), config)),\n /** Editorial redirects (EC-303); built-in fields customizable by name (EC-311). */\n redirects: (config: RedirectsViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(redirectsView(config), config)),\n /** Project settings. */\n settings: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(settingsView(config), config)),\n /** The extensions marketplace. */\n extensions: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(extensionsView(config), config)),\n /** The admin users roster (EC-240). */\n users: (config: BuiltinViewConfig = {}): SidebarViewNode =>\n viewNode(withNavPermission(usersView(config), config)),\n /** A fully custom view — pass your own `render` (and optional `parsePath`). */\n view: (config: CustomViewConfig): SidebarViewNode =>\n viewNode(withNavPermission(customView(config), config)),\n /** A labelled group of views (a header with sub-entries). */\n group: (label: string, children: SidebarViewNode[]) => groupNode(label, children),\n /** A divider between rail sections. */\n separator: () => separatorNode(),\n} as const\n\n// --- Surfaces (the view render bodies; CMS gains a focus lens) ---\n\n/**\n * Components section (EC-050): a registry-browser sidebar beside the active\n * screen — the index (no selection) or a component's detail. Forced states\n * (?state=) replace the whole surface.\n */\nfunction ComponentsScreen({\n projectId,\n componentId,\n state,\n}: {\n projectId: string\n componentId: string | null\n state?: SectionState\n}) {\n if (state && state !== 'working') {\n return <SectionStateView state={state} title={translate('nav.components.label')} />\n }\n return (\n <div className=\"flex h-full min-h-0\">\n <aside className=\"hidden h-full min-h-0 w-[300px] shrink-0 border-r border-border md:block\">\n <RegistryBrowser projectId={projectId} activeComponentId={componentId ?? undefined} />\n </aside>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {componentId === null ? (\n <ComponentsIndex projectId={projectId} />\n ) : (\n <ComponentDetail projectId={projectId} componentId={componentId} />\n )}\n </div>\n </div>\n )\n}\n\n/**\n * CMS section: hydrates the persisted (or kit-seeded) collections + documents, then\n * renders the active screen full-width (index, a collection table, or a document\n * editor). EC-293: the collection list lives in the section rail (nested under the\n * CMS view), so there is no in-surface collections sidebar. Forced states (?state=)\n * replace the whole surface. `focusCollections` (EC-239) narrows the index to a\n * subset, so a focused view (\"Catalog\") reuses this surface with config.\n */\nfunction CmsScreen({\n project,\n collectionId,\n documentId,\n state,\n field,\n focusCollections,\n}: {\n project: Project\n collectionId: string | null\n documentId: string | null\n state?: SectionState\n field?: string\n focusCollections?: readonly string[]\n}) {\n const projectId = project.id\n if (state && state !== 'working') {\n return <SectionStateView state={state} title={translate('nav.cms.label')} />\n }\n\n // A project created from a starter kit (EC-119) opens the CMS on the kit's schemas + content.\n const kit = getInstantiatedKit(projectId)\n\n return (\n // EC-177 gap 1: in Convex mode every CMS mount loads the CURRENT persisted\n // schema + documents (fixtures only when nothing is persisted — first run).\n // Playground renders synchronously with `null` → fixture seeds, as before.\n <CmsSessionGate>\n {(cms) => (\n <CmsProvider\n key={projectId}\n projectId={projectId}\n initialCollections={cms?.collections ?? kit?.collections}\n initialDocuments={cms?.documents ?? kit?.documents}\n initialPublishedKeys={cms?.publishedKeys}\n initialLocaleConfig={\n cms\n ? // Hydrated sessions follow the project's persisted locale settings.\n { default: project.settings.defaultLocale, locales: [...project.settings.locales] }\n : kit?.localeConfig\n }\n >\n <div className=\"flex h-full min-h-0 flex-col\">\n <CmsPersistErrorBanner />\n {/* EC-293: the collection list now lives in the section rail (nested\n under the CMS view), so the surface is full-width — the old 240px\n CollectionsSidebar aside is gone. */}\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n <CmsContent\n projectId={projectId}\n collectionId={collectionId}\n documentId={documentId}\n field={field}\n focusCollections={focusCollections}\n />\n </div>\n </div>\n </CmsProvider>\n )}\n </CmsSessionGate>\n )\n}\n\n/** Resolves the active CMS screen inside the provider (needs the live store). */\nfunction CmsContent({\n projectId,\n collectionId,\n documentId,\n field,\n focusCollections,\n}: {\n projectId: string\n collectionId: string | null\n documentId: string | null\n field?: string\n focusCollections?: readonly string[]\n}) {\n const cms = useCms()\n\n if (collectionId === null) return <CmsIndex projectId={projectId} focusCollections={focusCollections} />\n\n if (documentId === null) {\n const collection = cms.getCollection(collectionId)\n // EC-274: a singleton is a UI lens — at the collection URL it opens its one\n // document directly *while in its expected shape*, but degrades to the list\n // (with a \"for review\" lane) on drift. SingletonGate decides per the data.\n if (collection && isSingleton(collection)) {\n return <SingletonGate projectId={projectId} collectionId={collectionId} />\n }\n return <CollectionTable projectId={projectId} collectionId={collectionId} />\n }\n\n return (\n <DetailEditor\n projectId={projectId}\n collectionId={collectionId}\n documentId={documentId}\n focusPath={field}\n />\n )\n}\n\n/**\n * EC-274 — the singleton lens gate. At a singleton collection's URL, resolve its\n * lone document and open it directly; on drift (> 1 document) fall back to the\n * list with the \"for review\" lane so an editor can resolve the conflict.\n */\nfunction SingletonGate({ projectId, collectionId }: { projectId: string; collectionId: string }) {\n const cms = useCms()\n const collection = cms.getCollection(collectionId)\n const docs = cms.documentsOf(collectionId)\n const resolution = collection\n ? resolveSingletonDocument(collection, docs)\n : ({ kind: 'empty' } as const)\n\n // Materialize the lone document on first visit (an empty draft, persisted like\n // any create). Idempotent in the store; only fires while genuinely empty.\n useEffect(() => {\n if (resolution.kind === 'empty') cms.ensureSingletonDocument(collectionId)\n }, [resolution.kind, cms, collectionId])\n\n if (resolution.kind === 'ready') {\n return (\n <DetailEditor projectId={projectId} collectionId={collectionId} documentId={resolution.doc.id} />\n )\n }\n if (resolution.kind === 'drift') {\n return <CollectionTable projectId={projectId} collectionId={collectionId} />\n }\n return (\n <div className=\"grid h-full place-items-center p-8\">\n <Text size=\"sm\" tone=\"muted\">\n {translate('appViews.singleton.opening', {\n label: localizedLabel(collection?.form?.label, collectionId),\n })}\n </Text>\n </div>\n )\n}\n\n/** Failed/denied persisted CMS mutations are always visible (EC-141). */\nfunction CmsPersistErrorBanner() {\n const cms = useCms()\n if (!cms.persistError) return null\n return (\n <div className=\"shrink-0 border-b border-border p-2\">\n <OperationErrorBanner error={cms.persistError} onDismiss={cms.clearPersistError} />\n </div>\n )\n}\n"]}
|
|
@@ -168,15 +168,16 @@ export declare function CmsProvider({ children, projectId, initialCollections, i
|
|
|
168
168
|
}): import("react").JSX.Element;
|
|
169
169
|
export declare function useCms(): CmsStore;
|
|
170
170
|
/**
|
|
171
|
-
* A field's display label (EC-241): resolve its (possibly localized) `form.label
|
|
172
|
-
*
|
|
173
|
-
* a
|
|
174
|
-
*
|
|
171
|
+
* A field's display label (EC-241): resolve its (possibly localized) `form.label`,
|
|
172
|
+
* falling back to the field name. **`locale` defaults to the active UI locale** —
|
|
173
|
+
* a bare `fieldLabel(field)` localizes a `{ en, de }` map against the browser locale
|
|
174
|
+
* (via the non-hook `localizedLabel`), so a German editor sees German labels. Pass an
|
|
175
|
+
* explicit `locale` only to force a specific one (e.g. a content-locale variant view).
|
|
175
176
|
*/
|
|
176
177
|
export declare function fieldLabel(field: FieldDef, locale?: string): string;
|
|
177
|
-
/** A collection's plural display label (EC-241): localized `form.label`, else its id. */
|
|
178
|
+
/** A collection's plural display label (EC-241): localized `form.label`, else its id. Defaults to the active UI locale. */
|
|
178
179
|
export declare function collectionLabel(collection: CollectionDef, locale?: string): string;
|
|
179
|
-
/** A collection's singular display label (EC-241): localized `form.labelSingular`, else the plural. */
|
|
180
|
+
/** A collection's singular display label (EC-241): localized `form.labelSingular`, else the plural. Defaults to the active UI locale. */
|
|
180
181
|
export declare function collectionLabelSingular(collection: CollectionDef, locale?: string): string;
|
|
181
182
|
export { primaryField };
|
|
182
183
|
export type { Locale };
|
|
@@ -3,7 +3,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, use
|
|
|
3
3
|
import { createCollectionRegistry, createDocumentStore, documentKey, documentSchema, resolveDocumentTitle, resolveField, resolveLabel, sampleDocuments, seedDefaults, sampleFilterableCollections, sampleLocaleConfig, samplePublishedKeys, resolveSingletonDocument, titleFieldOf, validateDocument, } from '@elytracms/core/cms-core';
|
|
4
4
|
import { validateCompositionValue } from '@elytracms/core/project-graph';
|
|
5
5
|
import { collectComponentEmbeds, parseRichTextValue } from '@elytracms/core/rich-text';
|
|
6
|
-
import { translate } from '@elytracms/studio/lib/i18n';
|
|
6
|
+
import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
|
|
7
7
|
import { configureStudioLocales, useStudioLocale } from '@elytracms/studio/lib/locale';
|
|
8
8
|
import { getStudioRegistry, studioManifestLookup } from '@elytracms/studio/lib/registry';
|
|
9
9
|
import { resolveDeploymentCollections } from '@elytracms/studio/lib/workspace';
|
|
@@ -652,21 +652,29 @@ export function useCms() {
|
|
|
652
652
|
return store;
|
|
653
653
|
}
|
|
654
654
|
/**
|
|
655
|
-
* A field's display label (EC-241): resolve its (possibly localized) `form.label
|
|
656
|
-
*
|
|
657
|
-
* a
|
|
658
|
-
*
|
|
655
|
+
* A field's display label (EC-241): resolve its (possibly localized) `form.label`,
|
|
656
|
+
* falling back to the field name. **`locale` defaults to the active UI locale** —
|
|
657
|
+
* a bare `fieldLabel(field)` localizes a `{ en, de }` map against the browser locale
|
|
658
|
+
* (via the non-hook `localizedLabel`), so a German editor sees German labels. Pass an
|
|
659
|
+
* explicit `locale` only to force a specific one (e.g. a content-locale variant view).
|
|
659
660
|
*/
|
|
660
661
|
export function fieldLabel(field, locale) {
|
|
661
|
-
|
|
662
|
+
if (locale !== undefined)
|
|
663
|
+
return resolveLabel(field.form?.label, locale) ?? field.name;
|
|
664
|
+
return localizedLabel(field.form?.label, field.name);
|
|
662
665
|
}
|
|
663
|
-
/** A collection's plural display label (EC-241): localized `form.label`, else its id. */
|
|
666
|
+
/** A collection's plural display label (EC-241): localized `form.label`, else its id. Defaults to the active UI locale. */
|
|
664
667
|
export function collectionLabel(collection, locale) {
|
|
665
|
-
|
|
668
|
+
if (locale !== undefined)
|
|
669
|
+
return resolveLabel(collection.form?.label, locale) ?? collection.id;
|
|
670
|
+
return localizedLabel(collection.form?.label, collection.id);
|
|
666
671
|
}
|
|
667
|
-
/** A collection's singular display label (EC-241): localized `form.labelSingular`, else the plural. */
|
|
672
|
+
/** A collection's singular display label (EC-241): localized `form.labelSingular`, else the plural. Defaults to the active UI locale. */
|
|
668
673
|
export function collectionLabelSingular(collection, locale) {
|
|
669
|
-
|
|
674
|
+
if (locale !== undefined) {
|
|
675
|
+
return resolveLabel(collection.form?.labelSingular, locale) ?? collectionLabel(collection, locale);
|
|
676
|
+
}
|
|
677
|
+
return localizedLabel(collection.form?.labelSingular) || collectionLabel(collection);
|
|
670
678
|
}
|
|
671
679
|
export { primaryField };
|
|
672
680
|
//# sourceMappingURL=cms-store.js.map
|