@elytracms/studio 0.0.100 → 0.0.101
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/analytics-cost.test.ts +1 -1
- package/convex/redirect-migration.test.ts +1 -1
- package/convex/redirects.ts +2 -2
- package/convex/shared-capture.convex.test.ts +165 -0
- package/dist/components/ai/ai-chat-panel-lazy.js +7 -2
- package/dist/components/ai/ai-chat-panel-lazy.js.map +1 -1
- package/dist/components/ai/proposal-card.js +2 -1
- package/dist/components/ai/proposal-card.js.map +1 -1
- package/dist/components/ai/proposal-unfilled.d.ts +14 -0
- package/dist/components/ai/proposal-unfilled.js +33 -0
- package/dist/components/ai/proposal-unfilled.js.map +1 -0
- package/dist/components/ai/translate-document-action.js +8 -6
- package/dist/components/ai/translate-document-action.js.map +1 -1
- package/dist/components/app-views/studio-config.d.ts +12 -12
- package/dist/components/app-views/studio-config.js.map +1 -1
- package/dist/components/builder/builder-store.d.ts +37 -1
- package/dist/components/builder/builder-store.js +21 -6
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-chrome-css.d.ts +1 -1
- package/dist/components/builder/canvas-chrome-css.js +1 -1
- package/dist/components/builder/canvas-chrome-css.js.map +1 -1
- package/dist/components/builder/canvas-chrome.d.ts +1 -1
- package/dist/components/builder/canvas-chrome.js +1 -1
- package/dist/components/builder/canvas-chrome.js.map +1 -1
- package/dist/components/builder/canvas-rebase.d.ts +4 -4
- package/dist/components/builder/canvas-rebase.js +3 -2
- package/dist/components/builder/canvas-rebase.js.map +1 -1
- package/dist/components/builder/canvas-render-context.d.ts +1 -1
- package/dist/components/builder/canvas-render-context.js +1 -1
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js +2 -1
- package/dist/components/builder/composition-field-editor-lazy.js.map +1 -1
- package/dist/components/builder/reuse-context.d.ts +8 -2
- package/dist/components/builder/reuse-context.js +62 -7
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.d.ts +106 -70
- package/dist/components/builder/reuse.js +125 -108
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +9 -1
- package/dist/components/cms/cms-store.js +1 -0
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/detail-editor.js +13 -13
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/prop-fields.js +1 -1
- package/dist/components/cms/prop-fields.js.map +1 -1
- package/dist/components/cms/rich-text/lazy.js +2 -1
- package/dist/components/cms/rich-text/lazy.js.map +1 -1
- package/dist/components/cms/rich-text/toolbar-state.d.ts +1 -1
- package/dist/components/cms/rich-text/toolbar-state.js +1 -1
- package/dist/components/cms/rich-text/toolbar-state.js.map +1 -1
- package/dist/components/cms/use-field-focus.js +3 -3
- package/dist/components/cms/use-field-focus.js.map +1 -1
- package/dist/components/cms/version-compare-lazy.js +2 -1
- package/dist/components/cms/version-compare-lazy.js.map +1 -1
- package/dist/components/components/components-index.js +1 -1
- package/dist/components/components/components-index.js.map +1 -1
- package/dist/components/deployment-setup-gate.d.ts +1 -1
- package/dist/components/deployment-setup-gate.js +1 -1
- package/dist/components/deployment-setup-gate.js.map +1 -1
- package/dist/components/load-failure.d.ts +62 -0
- package/dist/components/load-failure.js +110 -0
- package/dist/components/load-failure.js.map +1 -0
- package/dist/components/notifications/shell-findings.js +3 -3
- package/dist/components/notifications/shell-findings.js.map +1 -1
- package/dist/customization.d.ts +3 -3
- package/dist/customization.js.map +1 -1
- package/dist/lib/ai/apply-content.js +99 -28
- package/dist/lib/ai/apply-content.js.map +1 -1
- package/dist/lib/ai/chat-context.d.ts +73 -7
- package/dist/lib/ai/chat-context.js +133 -14
- package/dist/lib/ai/chat-context.js.map +1 -1
- package/dist/lib/ai/chat-state.d.ts +7 -1
- package/dist/lib/ai/chat-state.js.map +1 -1
- package/dist/lib/ai/constraints.d.ts +5 -0
- package/dist/lib/ai/constraints.js +21 -6
- package/dist/lib/ai/constraints.js.map +1 -1
- package/dist/lib/ai/fake-provider.d.ts +76 -26
- package/dist/lib/ai/fake-provider.js +210 -66
- package/dist/lib/ai/fake-provider.js.map +1 -1
- package/dist/lib/ai/index.d.ts +1 -0
- package/dist/lib/ai/index.js +1 -0
- package/dist/lib/ai/index.js.map +1 -1
- package/dist/lib/ai/keyless-assistant.d.ts +37 -0
- package/dist/lib/ai/keyless-assistant.js +193 -0
- package/dist/lib/ai/keyless-assistant.js.map +1 -0
- package/dist/lib/ai/shape.d.ts +25 -2
- package/dist/lib/ai/shape.js +58 -7
- package/dist/lib/ai/shape.js.map +1 -1
- package/dist/lib/ai/tools.d.ts +11 -1
- package/dist/lib/ai/tools.js +51 -6
- package/dist/lib/ai/tools.js.map +1 -1
- package/dist/lib/ai/translate-document.js +6 -5
- package/dist/lib/ai/translate-document.js.map +1 -1
- package/dist/lib/ai/types.d.ts +22 -7
- package/dist/lib/ai/types.js.map +1 -1
- package/dist/lib/ai/update-fields.js +9 -6
- package/dist/lib/ai/update-fields.js.map +1 -1
- package/dist/lib/ai/writer-form.d.ts +11 -3
- package/dist/lib/ai/writer-form.js +105 -18
- package/dist/lib/ai/writer-form.js.map +1 -1
- package/dist/lib/auth-errors.d.ts +1 -1
- package/dist/lib/auth-errors.js +1 -1
- package/dist/lib/auth-errors.js.map +1 -1
- package/dist/lib/engine-version.d.ts +1 -1
- package/dist/lib/engine-version.js +1 -1
- package/dist/lib/engine-version.js.map +1 -1
- package/dist/lib/i18n/messages.de.d.ts +1 -1
- package/dist/lib/i18n/messages.de.js +23 -7
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +18 -3
- package/dist/lib/i18n/messages.en.js +29 -9
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/cms-persistence.d.ts +18 -0
- package/dist/lib/operations/cms-persistence.js +47 -0
- package/dist/lib/operations/cms-persistence.js.map +1 -1
- package/dist/lib/workspace/index.d.ts +3 -3
- package/dist/lib/workspace/index.js +3 -3
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/router/navigate-once.d.ts +1 -1
- package/dist/router/navigate-once.js.map +1 -1
- package/dist/router/root.d.ts +3 -2
- package/dist/router/root.js +25 -4
- package/dist/router/root.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reuse-context.js","sourceRoot":"","sources":["../../../src/components/builder/reuse-context.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useCallback, useContext, useMemo, useState } from 'react'\nimport type { FormEvent, ReactNode } from 'react'\nimport { blockRootsOf, getNode, isStaticProp } from '@elytracms/core/project-graph'\nimport { readDocumentRef } from '@elytracms/core/cms-core'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Field,\n Input,\n Stack,\n toast,\n} from '@elytracms/studio/ui'\nimport { getStudioRegistry } from '../../lib/registry'\nimport { getStudioOperations } from '../../lib/operations'\nimport { PublishRefusedError } from '../../lib/operations/publish-with-revision'\nimport { resolveDeploymentReuse } from '../../lib/workspace'\nimport { localizedLabel, translate } from '../../lib/i18n'\nimport { useCms } from '../cms/cms-store'\nimport { useProjectSession } from '../project-session'\nimport { useBuilder } from './builder-store'\nimport { detachRefusal, resolveReuseCapability, runPromote } from './reuse'\nimport type { PromoteEffects, ReuseCapability, ReuseRefusal } from './reuse'\nimport { placementRefusalMessage } from './placement-refusal'\n\n/**\n * In-canvas reuse gestures (EC-282): \"Make reusable\" promotes a selected block to\n * a new reusable document and replaces it in place with a transcluding embed;\n * \"Detach to local copy\" inlines an embed's referenced blocks so a page can\n * diverge. Both round-trip through the existing persistence + in-Convex reference\n * index (EC-277), so where-used is correct immediately.\n *\n * The provider needs BOTH the builder store (the edited composition) and the CMS\n * store (to create/read the reusable document), so it mounts inside the\n * composition-field editor's `BuilderProvider`, itself inside the CMS document\n * editor. Where no provider is mounted (or the capability is absent), the menu\n * reads `null` and simply omits the gestures.\n */\nexport interface ReuseGestures {\n capability: ReuseCapability | null\n canMakeReusable: (nodeId: string) => boolean\n canDetach: (nodeId: string) => boolean\n /** Open the name dialog for promoting `nodeId`. */\n startMakeReusable: (nodeId: string) => void\n /** Replace a `Reusable` embed with an editable inline copy of its target's blocks. */\n detach: (nodeId: string) => void\n}\n\n/**\n * EC-690 — the publish step of \"Make reusable\" and its failure notice, for ONE promote. The\n * store's `publishDocument` reports a refusal on the session (`persistError` — an error notice of\n * the issues tray, with the reason) AND rejects with `PublishRefusedError` (EC-585). The refusal\n * is remembered here, so {@link promotePublishFailureNotice} does not report it a second time;\n * any other throw propagates (`runPromote` reads it as \"not published\").\n */\nexport function promotePublishEffects(deps: {\n publishDocument(ref: DocumentRef): Promise<void>\n isPublished(ref: DocumentRef): Promise<boolean>\n notify: { success(message: string): void; error(message: string): void }\n}): Pick<PromoteEffects, 'publish' | 'publishFailed'> {\n let refusalHeld = false\n return {\n publish: async (ref) => {\n try {\n await deps.publishDocument(ref)\n } catch (error) {\n if (error instanceof PublishRefusedError) {\n refusalHeld = true\n return false\n }\n throw error\n }\n return deps.isPublished(ref)\n },\n publishFailed: (name) => {\n const notice = promotePublishFailureNotice(name, refusalHeld)\n deps.notify[notice.variant](notice.message)\n },\n }\n}\n\n/**\n * EC-690 — the notice \"Make reusable\" raises when its publish did not land. A publish REFUSAL is\n * already held by the session (`persistError` — an error notice of the issues tray that stays\n * until dismissed, with the refusal's reason), so the outcome here is NOT a second report of the\n * same failure: it is what the action did make — a reusable DRAFT, to publish from its document.\n * A failure nobody reported (the publish threw elsewhere, or resolved without a published\n * version) is the error notice, as before.\n */\nexport function promotePublishFailureNotice(\n name: string,\n refusalHeld: boolean,\n): { variant: 'success' | 'error'; message: string } {\n return refusalHeld\n ? { variant: 'success', message: translate('builder.reuse.madeReusableDraft', { name }) }\n : { variant: 'error', message: translate('builder.reuse.madeReusablePublishFailed', { name }) }\n}\n\nconst ReuseContext = createContext<ReuseGestures | null>(null)\n\nexport function useReuse(): ReuseGestures | null {\n return useContext(ReuseContext)\n}\n\n/** A refused reuse gesture's visible reason (EC-584) — the judge's verdict, worded once. */\nfunction toastRefusal(refusal: ReuseRefusal): void {\n toast.error(placementRefusalMessage(refusal.verdict, refusal.fieldLabel))\n}\n\nexport function ReuseProvider({ children }: { children: ReactNode }) {\n const builder = useBuilder()\n const cms = useCms()\n const { projectId } = useProjectSession()\n const [pending, setPending] = useState<{ nodeId: string; defaultName: string } | null>(null)\n\n const manifests = useMemo(() => getStudioRegistry().registry.list(), [])\n // EC-467: the optional `reuse` declaration wins; absent, the heuristic runs\n // exactly as before. The config holder is static per studio boot, so it is read\n // inside the memo (like `useStudioNav` reads the sidebar holder). Resolution\n // ISSUES are surfaced once, by the shell rail — this provider is mounted per\n // composition field, so reporting here would repeat them per field.\n const capability = useMemo(\n () => resolveReuseCapability(manifests, cms.collections, resolveDeploymentReuse()),\n [manifests, cms.collections],\n )\n\n const canMakeReusable = useCallback(\n (nodeId: string): boolean => {\n if (!capability) return false\n const node = getNode(builder.present, nodeId)\n // Anything but the synthetic composition root can be promoted; nesting a\n // reusable inside a reusable is allowed (the renderer + bake are cycle-\n // guarded, EC-281), so an embed itself is still promotable.\n return node !== undefined && node.id !== builder.present.id\n },\n [capability, builder],\n )\n\n const canDetach = useCallback(\n (nodeId: string): boolean => {\n if (!capability) return false\n return getNode(builder.present, nodeId)?.componentId === capability.embedComponentId\n },\n [capability, builder],\n )\n\n const startMakeReusable = useCallback(\n (nodeId: string) => {\n if (!canMakeReusable(nodeId)) return\n const node = getNode(builder.present, nodeId)\n if (!node) return\n const manifestTitle = localizedLabel(manifests.find((m) => m.id === node.componentId)?.title) || undefined\n const collection = capability ? cms.getCollection(capability.collectionId) : undefined\n const defaultName =\n manifestTitle ?? (localizedLabel(collection?.form?.labelSingular) || localizedLabel(collection?.form?.label) || translate('builder.reuse.defaultElementName'))\n setPending({ nodeId, defaultName })\n },\n [canMakeReusable, builder, manifests, capability, cms],\n )\n\n const confirmMakeReusable = useCallback(\n (name: string, publish: boolean) => {\n const cap = capability\n if (!cap || !pending) return\n const node = getNode(builder.present, pending.nodeId)\n const collection = cms.getCollection(cap.collectionId)\n setPending(null)\n if (!node || !collection) return\n // EC-584 / EC-560: the placement preflight runs FIRST — a refused promote creates,\n // publishes and replaces nothing. Then (EC-595 A2 / EC-578) ONE insert-if-absent\n // create with a factory id, the in-place swap for the transcluding embed (the\n // action clones to a fresh id; the source `node` stays untouched in the new doc),\n // and the chosen publish. EC-300: PUBLISH keeps the section visible everywhere\n // immediately (the continuity-preserving default); SAVE DRAFT keeps it editable,\n // surfaced as a pending reference until published. No silent auto-publish (AD-16).\n void runPromote({\n root: builder.present,\n nodeId: pending.nodeId,\n node,\n name,\n publish,\n capability: cap,\n collection,\n existing: cms.documentsOf(cap.collectionId),\n locales: cms.localeConfig,\n placement: builder.placement,\n canvasFieldLabel: builder.field.label,\n effects: {\n newDocumentId: () => cms.newDocumentId(),\n insertDocument: (doc) => cms.insertDocument(doc),\n replaceInCanvas: (nodeId, embed) => builder.dispatch({ type: 'replace', id: nodeId, nodes: [embed] }),\n refused: toastRefusal,\n madeDraft: (label) => toast.success(translate('builder.reuse.madeReusableDraft', { name: label })),\n madePublished: (label) => toast.success(translate('builder.reuse.madeReusablePublished', { name: label })),\n // The publish and its failure notice (EC-690: a refusal the session already holds is\n // never reported twice) — see `promotePublishEffects`.\n ...promotePublishEffects({\n publishDocument: (ref) => cms.publishDocument(ref),\n // Success is the AUTHORITATIVE pointer after the publish settles (the same read the\n // store reconciles its badge from), never the resolution.\n isPublished: async (ref) => {\n if (projectId === undefined) return false\n const { operations } = await getStudioOperations()\n const record = await operations.documents.get({ projectId, ref })\n return record.ok && record.value.publishedVersion !== undefined\n },\n notify: { success: (message) => toast.success(message), error: (message) => toast.error(message) },\n }),\n },\n })\n },\n [capability, pending, builder, cms, projectId],\n )\n\n const detach = useCallback(\n (nodeId: string) => {\n const cap = capability\n if (!cap) return\n const node = getNode(builder.present, nodeId)\n if (!node || node.componentId !== cap.embedComponentId) return\n const prop = node.props?.[cap.relationProp]\n const ref = isStaticProp(prop) ? readDocumentRef(prop.value) : undefined\n if (!ref) {\n toast.error(translate('builder.reuse.noTargetToDetach'))\n return\n }\n const target = cms.getDocument(ref)\n const blocks = blockRootsOf(target?.values?.[cap.contentField])\n if (blocks.length === 0) {\n toast.error(translate('builder.reuse.noContentToDetach'))\n return\n }\n // EC-584 / EC-560: the inlined blocks land where the embed is — judged first, so\n // a refusal keeps the reference in place, says why, and dispatches nothing.\n const refusal = detachRefusal({\n root: builder.present,\n nodeId,\n blocks,\n placement: builder.placement,\n canvasFieldLabel: builder.field.label,\n })\n if (refusal) {\n toastRefusal(refusal)\n return\n }\n builder.dispatch({ type: 'replace', id: nodeId, nodes: blocks })\n toast.success(translate('builder.reuse.detachedToCopy'))\n },\n [capability, builder, cms],\n )\n\n const value = useMemo<ReuseGestures>(\n () => ({ capability, canMakeReusable, canDetach, startMakeReusable, detach }),\n [capability, canMakeReusable, canDetach, startMakeReusable, detach],\n )\n\n return (\n <ReuseContext.Provider value={value}>\n {children}\n <MakeReusableDialog\n open={pending !== null}\n defaultName={pending?.defaultName ?? ''}\n onConfirm={confirmMakeReusable}\n onCancel={() => setPending(null)}\n />\n </ReuseContext.Provider>\n )\n}\n\n/** Name-and-create dialog for the \"Make reusable\" gesture. */\nfunction MakeReusableDialog({\n open,\n defaultName,\n onConfirm,\n onCancel,\n}: {\n open: boolean\n defaultName: string\n /** `publish` chooses the new reusable's initial state (EC-300/AD-16). */\n onConfirm: (name: string, publish: boolean) => void\n onCancel: () => void\n}) {\n const [name, setName] = useState(defaultName)\n // Re-seed the field each time the dialog opens for a new selection.\n const [seededFor, setSeededFor] = useState<string | null>(null)\n if (open && seededFor !== defaultName) {\n setName(defaultName)\n setSeededFor(defaultName)\n }\n\n const empty = name.trim() === ''\n function commit(publish: boolean) {\n if (empty) return\n onConfirm(name.trim(), publish)\n setSeededFor(null)\n }\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) {\n onCancel()\n setSeededFor(null)\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{translate('builder.reuse.makeReusable')}</DialogTitle>\n <DialogDescription>\n {translate('builder.reuse.makeReusableDescription')}\n </DialogDescription>\n </DialogHeader>\n {/* Enter submits the primary action (Publish) — the continuity-preserving default. */}\n <form\n onSubmit={(event: FormEvent) => {\n event.preventDefault()\n commit(true)\n }}\n >\n <Stack gap=\"3\">\n <Field label={translate('builder.reuse.nameLabel')} htmlFor=\"make-reusable-name\" required>\n <Input\n id=\"make-reusable-name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder={translate('builder.reuse.namePlaceholder')}\n autoFocus\n required\n />\n </Field>\n </Stack>\n <DialogFooter className=\"mt-4\">\n {/* Cancel pinned left; the two commit actions group right. */}\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"mr-auto\" onClick={onCancel}>\n {translate('common.cancel')}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={empty}\n onClick={() => commit(false)}\n data-testid=\"make-reusable-draft\"\n >\n {translate('builder.reuse.saveDraft')}\n </Button>\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={empty}\n data-testid=\"make-reusable-publish\"\n >\n {translate('builder.reuse.publish')}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reuse-context.js","sourceRoot":"","sources":["../../../src/components/builder/reuse-context.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport type { FormEvent, ReactNode } from 'react'\nimport { blockRootsOf, getNode, isStaticProp } from '@elytracms/core/project-graph'\nimport { documentKey, readDocumentRef } from '@elytracms/core/cms-core'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Field,\n Input,\n Stack,\n toast,\n} from '@elytracms/studio/ui'\nimport { getStudioRegistry } from '../../lib/registry'\nimport { getStudioOperations } from '../../lib/operations'\nimport { ensureReferenceIndex } from '../../lib/references/references-store'\nimport { PublishRefusedError } from '../../lib/operations/publish-with-revision'\nimport { resolveDeploymentReuse } from '../../lib/workspace'\nimport { localizedLabel, translate } from '../../lib/i18n'\nimport { useCms } from '../cms/cms-store'\nimport { useProjectSession } from '../project-session'\nimport { useBuilder } from './builder-store'\nimport { createPromoteHistory, detachRefusal, resolveReuseCapability, runPromote } from './reuse'\nimport type { PromoteEffects, ReuseCapability, ReuseRefusal } from './reuse'\nimport { placementRefusalMessage } from './placement-refusal'\n\n/**\n * In-canvas reuse gestures (EC-282): \"Make reusable\" promotes a selected block to\n * a new reusable document and replaces it in place with a transcluding embed;\n * \"Detach to local copy\" inlines an embed's referenced blocks so a page can\n * diverge. Both round-trip through the existing persistence + in-Convex reference\n * index (EC-277), so where-used is correct immediately.\n *\n * The provider needs BOTH the builder store (the edited composition) and the CMS\n * store (to create/read the reusable document), so it mounts inside the\n * composition-field editor's `BuilderProvider`, itself inside the CMS document\n * editor. Where no provider is mounted (or the capability is absent — EC-728: the\n * project declares no `reuse` embed), the menu reads `null` and simply omits the gestures.\n *\n * EC-728 — *Make reusable* is ONE canvas history entry that records the document it\n * created. When an Undo or Redo crosses it, this provider performs the document side\n * (`createPromoteHistory`): Undo deletes the document only when it is provably nobody\n * else's (never published, referenced nowhere, unchanged since its create), else keeps\n * it and says why; Redo re-inserts what Undo removed.\n */\nexport interface ReuseGestures {\n capability: ReuseCapability | null\n canMakeReusable: (nodeId: string) => boolean\n canDetach: (nodeId: string) => boolean\n /** Open the name dialog for promoting `nodeId`. */\n startMakeReusable: (nodeId: string) => void\n /** Replace a `Reusable` embed with an editable inline copy of its target's blocks. */\n detach: (nodeId: string) => void\n}\n\n/**\n * EC-690 — the publish step of \"Make reusable\" and its failure notice, for ONE promote. The\n * store's `publishDocument` reports a refusal on the session (`persistError` — an error notice of\n * the issues tray, with the reason) AND rejects with `PublishRefusedError` (EC-585). The refusal\n * is remembered here, so {@link promotePublishFailureNotice} does not report it a second time;\n * any other throw propagates (`runPromote` reads it as \"not published\").\n */\nexport function promotePublishEffects(deps: {\n publishDocument(ref: DocumentRef): Promise<void>\n isPublished(ref: DocumentRef): Promise<boolean>\n notify: { success(message: string): void; error(message: string): void }\n}): Pick<PromoteEffects, 'publish' | 'publishFailed'> {\n let refusalHeld = false\n return {\n publish: async (ref) => {\n try {\n await deps.publishDocument(ref)\n } catch (error) {\n if (error instanceof PublishRefusedError) {\n refusalHeld = true\n return false\n }\n throw error\n }\n return deps.isPublished(ref)\n },\n publishFailed: (name) => {\n const notice = promotePublishFailureNotice(name, refusalHeld)\n deps.notify[notice.variant](notice.message)\n },\n }\n}\n\n/**\n * EC-690 — the notice \"Make reusable\" raises when its publish did not land. A publish REFUSAL is\n * already held by the session (`persistError` — an error notice of the issues tray that stays\n * until dismissed, with the refusal's reason), so the outcome here is NOT a second report of the\n * same failure: it is what the action did make — a reusable DRAFT, to publish from its document.\n * A failure nobody reported (the publish threw elsewhere, or resolved without a published\n * version) is the error notice, as before.\n */\nexport function promotePublishFailureNotice(\n name: string,\n refusalHeld: boolean,\n): { variant: 'success' | 'error'; message: string } {\n return refusalHeld\n ? { variant: 'success', message: translate('builder.reuse.madeReusableDraft', { name }) }\n : { variant: 'error', message: translate('builder.reuse.madeReusablePublishFailed', { name }) }\n}\n\nconst ReuseContext = createContext<ReuseGestures | null>(null)\n\nexport function useReuse(): ReuseGestures | null {\n return useContext(ReuseContext)\n}\n\n/** A refused reuse gesture's visible reason (EC-584) — the judge's verdict, worded once. */\nfunction toastRefusal(refusal: ReuseRefusal): void {\n toast.error(placementRefusalMessage(refusal.verdict, refusal.fieldLabel))\n}\n\nexport function ReuseProvider({ children }: { children: ReactNode }) {\n const builder = useBuilder()\n const cms = useCms()\n const { projectId } = useProjectSession()\n const [pending, setPending] = useState<{ nodeId: string; defaultName: string } | null>(null)\n\n const manifests = useMemo(() => getStudioRegistry().registry.list(), [])\n // EC-728: the `reuse` declaration is the only source of the capability (declared,\n // never inferred). The config holder is static per studio boot, so it is read\n // inside the memo (like `useStudioNav` reads the sidebar holder). Resolution\n // ISSUES are surfaced once, by the shell — this provider is mounted per\n // composition field, so reporting here would repeat them per field.\n const capability = useMemo(\n () => resolveReuseCapability(manifests, cms.collections, resolveDeploymentReuse()),\n [manifests, cms.collections],\n )\n\n // EC-728 — the document side of an Undo/Redo across a *Make reusable* step. The work runs\n // after the render that applied the step (the page's restore is already committed, the\n // flush awaits it), so it reads the latest stores through refs.\n const cmsRef = useRef(cms)\n cmsRef.current = cms\n const projectRef = useRef(projectId)\n projectRef.current = projectId\n const [promoteHistory] = useState(() =>\n createPromoteHistory({\n flush: () => cmsRef.current.flushPersistence(),\n read: async (ref) => {\n const project = projectRef.current\n if (project === undefined) throw new Error('no project')\n const { operations } = await getStudioOperations()\n const record = await operations.documents.get({ projectId: project, ref })\n if (record.ok) return { published: record.value.publishedVersion !== undefined }\n if (record.error.code === 'not-found') return undefined\n throw new Error(record.error.message)\n },\n referrers: async (ref) => {\n const project = projectRef.current\n if (project === undefined) throw new Error('no project')\n const studio = await getStudioOperations()\n // A settled index, as the delete pre-flight reads it: a provider that does not\n // maintain the index in its write path updates it after the write's event.\n await ensureReferenceIndex(studio, project)\n await studio.references.flush()\n const inbound = await studio.operations.references.inbound({\n projectId: project,\n target: { type: 'document', id: documentKey(ref) },\n })\n if (!inbound.ok) throw new Error(inbound.error.message)\n return inbound.value.length\n },\n deleteCreated: (ref) => cmsRef.current.deleteCreatedDocument(ref),\n insert: (document) => cmsRef.current.insertDocument(document),\n // A kept document the editor can act on is the outcome of a successful Undo; a removal\n // that FAILED stays in the issues tray until dismissed (EC-690's error channel).\n notify: (key, name) =>\n key === 'builder.reuse.undoKeptFailed'\n ? toast.error(translate(key, { name }))\n : toast.success(translate(key, { name })),\n }),\n )\n const handledSeq = useRef(builder.historyEffect?.seq ?? 0)\n const step = builder.historyEffect\n useEffect(() => {\n if (!step || step.seq <= handledSeq.current) return\n handledSeq.current = step.seq\n void promoteHistory.crossed(step)\n }, [step, promoteHistory])\n\n const canMakeReusable = useCallback(\n (nodeId: string): boolean => {\n if (!capability) return false\n const node = getNode(builder.present, nodeId)\n // Anything but the synthetic composition root can be promoted; nesting a\n // reusable inside a reusable is allowed (the renderer + bake are cycle-\n // guarded, EC-281), so an embed itself is still promotable.\n return node !== undefined && node.id !== builder.present.id\n },\n [capability, builder],\n )\n\n const canDetach = useCallback(\n (nodeId: string): boolean => {\n if (!capability) return false\n return getNode(builder.present, nodeId)?.componentId === capability.embedComponentId\n },\n [capability, builder],\n )\n\n const startMakeReusable = useCallback(\n (nodeId: string) => {\n if (!canMakeReusable(nodeId)) return\n const node = getNode(builder.present, nodeId)\n if (!node) return\n const manifestTitle = localizedLabel(manifests.find((m) => m.id === node.componentId)?.title) || undefined\n const collection = capability ? cms.getCollection(capability.collectionId) : undefined\n const defaultName =\n manifestTitle ?? (localizedLabel(collection?.form?.labelSingular) || localizedLabel(collection?.form?.label) || translate('builder.reuse.defaultElementName'))\n setPending({ nodeId, defaultName })\n },\n [canMakeReusable, builder, manifests, capability, cms],\n )\n\n const confirmMakeReusable = useCallback(\n (name: string, publish: boolean) => {\n const cap = capability\n if (!cap || !pending) return\n const node = getNode(builder.present, pending.nodeId)\n const collection = cms.getCollection(cap.collectionId)\n setPending(null)\n if (!node || !collection) return\n // EC-584 / EC-560: the placement preflight runs FIRST — a refused promote creates,\n // publishes and replaces nothing. Then (EC-595 A2 / EC-578) ONE insert-if-absent\n // create with a factory id, the in-place swap for the transcluding embed (the\n // action clones to a fresh id; the source `node` stays untouched in the new doc),\n // and the chosen publish. EC-300: PUBLISH keeps the section visible everywhere\n // immediately (the continuity-preserving default); SAVE DRAFT keeps it editable,\n // surfaced as a pending reference until published. No silent auto-publish (AD-16).\n void runPromote({\n root: builder.present,\n nodeId: pending.nodeId,\n node,\n name,\n publish,\n capability: cap,\n collection,\n existing: cms.documentsOf(cap.collectionId),\n locales: cms.localeConfig,\n placement: builder.placement,\n canvasFieldLabel: builder.field.label,\n effects: {\n newDocumentId: () => cms.newDocumentId(),\n insertDocument: (doc) => cms.insertDocument(doc),\n replaceInCanvas: (nodeId, embed, effect) =>\n builder.dispatch({ type: 'replace', id: nodeId, nodes: [embed], effect }),\n refused: toastRefusal,\n madeDraft: (label) => toast.success(translate('builder.reuse.madeReusableDraft', { name: label })),\n madePublished: (label) => toast.success(translate('builder.reuse.madeReusablePublished', { name: label })),\n // The publish and its failure notice (EC-690: a refusal the session already holds is\n // never reported twice) — see `promotePublishEffects`.\n ...promotePublishEffects({\n publishDocument: (ref) => cms.publishDocument(ref),\n // Success is the AUTHORITATIVE pointer after the publish settles (the same read the\n // store reconciles its badge from), never the resolution.\n isPublished: async (ref) => {\n if (projectId === undefined) return false\n const { operations } = await getStudioOperations()\n const record = await operations.documents.get({ projectId, ref })\n return record.ok && record.value.publishedVersion !== undefined\n },\n notify: { success: (message) => toast.success(message), error: (message) => toast.error(message) },\n }),\n },\n })\n },\n [capability, pending, builder, cms, projectId],\n )\n\n const detach = useCallback(\n (nodeId: string) => {\n const cap = capability\n if (!cap) return\n const node = getNode(builder.present, nodeId)\n if (!node || node.componentId !== cap.embedComponentId) return\n const prop = node.props?.[cap.relationProp]\n const ref = isStaticProp(prop) ? readDocumentRef(prop.value) : undefined\n if (!ref) {\n toast.error(translate('builder.reuse.noTargetToDetach'))\n return\n }\n const target = cms.getDocument(ref)\n const blocks = blockRootsOf(target?.values?.[cap.contentField])\n if (blocks.length === 0) {\n toast.error(translate('builder.reuse.noContentToDetach'))\n return\n }\n // EC-584 / EC-560: the inlined blocks land where the embed is — judged first, so\n // a refusal keeps the reference in place, says why, and dispatches nothing.\n const refusal = detachRefusal({\n root: builder.present,\n nodeId,\n blocks,\n placement: builder.placement,\n canvasFieldLabel: builder.field.label,\n })\n if (refusal) {\n toastRefusal(refusal)\n return\n }\n builder.dispatch({ type: 'replace', id: nodeId, nodes: blocks })\n toast.success(translate('builder.reuse.detachedToCopy'))\n },\n [capability, builder, cms],\n )\n\n const value = useMemo<ReuseGestures>(\n () => ({ capability, canMakeReusable, canDetach, startMakeReusable, detach }),\n [capability, canMakeReusable, canDetach, startMakeReusable, detach],\n )\n\n return (\n <ReuseContext.Provider value={value}>\n {children}\n <MakeReusableDialog\n open={pending !== null}\n defaultName={pending?.defaultName ?? ''}\n onConfirm={confirmMakeReusable}\n onCancel={() => setPending(null)}\n />\n </ReuseContext.Provider>\n )\n}\n\n/** Name-and-create dialog for the \"Make reusable\" gesture. */\nfunction MakeReusableDialog({\n open,\n defaultName,\n onConfirm,\n onCancel,\n}: {\n open: boolean\n defaultName: string\n /** `publish` chooses the new reusable's initial state (EC-300/AD-16). */\n onConfirm: (name: string, publish: boolean) => void\n onCancel: () => void\n}) {\n const [name, setName] = useState(defaultName)\n // Re-seed the field each time the dialog opens for a new selection.\n const [seededFor, setSeededFor] = useState<string | null>(null)\n if (open && seededFor !== defaultName) {\n setName(defaultName)\n setSeededFor(defaultName)\n }\n\n const empty = name.trim() === ''\n function commit(publish: boolean) {\n if (empty) return\n onConfirm(name.trim(), publish)\n setSeededFor(null)\n }\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) {\n onCancel()\n setSeededFor(null)\n }\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{translate('builder.reuse.makeReusable')}</DialogTitle>\n <DialogDescription>\n {translate('builder.reuse.makeReusableDescription')}\n </DialogDescription>\n </DialogHeader>\n {/* Enter submits the primary action (Publish) — the continuity-preserving default. */}\n <form\n onSubmit={(event: FormEvent) => {\n event.preventDefault()\n commit(true)\n }}\n >\n <Stack gap=\"3\">\n <Field label={translate('builder.reuse.nameLabel')} htmlFor=\"make-reusable-name\" required>\n <Input\n id=\"make-reusable-name\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder={translate('builder.reuse.namePlaceholder')}\n autoFocus\n required\n />\n </Field>\n </Stack>\n <DialogFooter className=\"mt-4\">\n {/* Cancel pinned left; the two commit actions group right. */}\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"mr-auto\" onClick={onCancel}>\n {translate('common.cancel')}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={empty}\n onClick={() => commit(false)}\n data-testid=\"make-reusable-draft\"\n >\n {translate('builder.reuse.saveDraft')}\n </Button>\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={empty}\n data-testid=\"make-reusable-publish\"\n >\n {translate('builder.reuse.publish')}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n )\n}\n"]}
|
|
@@ -2,6 +2,8 @@ import type { ComponentManifest } from '@elytracms/core/component-registry';
|
|
|
2
2
|
import type { CmsDocument, CollectionDef, DocumentRef, LocaleConfig } from '@elytracms/core/cms-core';
|
|
3
3
|
import type { ComponentNode, PlacementScope, PlacementVerdict } from '@elytracms/core/project-graph';
|
|
4
4
|
import type { CustomizationIssue } from '@elytracms/core/studio-core';
|
|
5
|
+
import type { DeleteCreatedOutcome } from '../../lib/operations/cms-persistence.js';
|
|
6
|
+
import type { CanvasHistoryEffect } from './builder-store.js';
|
|
5
7
|
/**
|
|
6
8
|
* The reuse capability (EC-282): the engine-generic description of how a project
|
|
7
9
|
* models reusable elements. **AD-a (EC-467): reusable elements are SINGULAR per
|
|
@@ -9,40 +11,22 @@ import type { CustomizationIssue } from '@elytracms/core/studio-core';
|
|
|
9
11
|
* Multiple reuse collections are deliberately not supported, which is why this is
|
|
10
12
|
* one value and never a list.
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* **EC-728 (owner ruling 2026-10-31, "Declare, never infer"): the capability exists
|
|
15
|
+
* only when the project DECLARES its embed** — `defineStudio({ reuse: { component } })`
|
|
16
|
+
* ({@link StudioReuseConfig}). The engine never guesses one from a component's shape.
|
|
17
|
+
* The shape test it used to run (no slots, exactly one cardinality-one `relation`
|
|
18
|
+
* prop whose target collection holds a `blocks` field) cannot tell an embed from an
|
|
19
|
+
* ordinary card that links to a page with a canvas: EC-462 refused the guess when two
|
|
20
|
+
* components matched, and EC-728 measured the one-candidate guess crowning a "read
|
|
21
|
+
* next" link card — *Make reusable* then moved a block's content into a new document
|
|
22
|
+
* and left a link card in its place. A guess with a destructive gesture attached is
|
|
23
|
+
* the bug, so there is no guess.
|
|
20
24
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* and the demo's OptionBox were both claimed as "the embed", so their ordinary
|
|
27
|
-
* relation picks rendered the reusable-element placeholder, grew Detach/Make-
|
|
28
|
-
* reusable gestures, and fed embed-worded publish-integrity issues. Two
|
|
29
|
-
* explicit-declaration disqualifiers close the observed class:
|
|
30
|
-
*
|
|
31
|
-
* - a manifest with a `listing` declaration is a QUERY host (EC-255) — its
|
|
32
|
-
* relation prop feeds the query (a `{ prop }` operand of `listing.where`),
|
|
33
|
-
* never a transclusion pointer;
|
|
34
|
-
* - a relation prop with `form.hidden` (predicate or `true`) is conditional/
|
|
35
|
-
* auxiliary — EC-394 strips a hidden relation's ref at publish, so it cannot
|
|
36
|
-
* coherently be what the component transcludes.
|
|
37
|
-
*
|
|
38
|
-
* Both read only the CANDIDATE manifest's own declarations (never the target's
|
|
39
|
-
* contents) and can only EXCLUDE, so a genuine pure embed (which declares
|
|
40
|
-
* neither) is always kept. EC-462's residual — a bare unconditional
|
|
41
|
-
* single-relation display component (e.g. a page teaser) is at rest
|
|
42
|
-
* indistinguishable from a genuine embed — is closed by EC-467's optional
|
|
43
|
-
* {@link StudioReuseConfig} declaration: a project that hits ambiguity declares
|
|
44
|
-
* its way out, and the ambiguity is LOUD instead of silently disabling the
|
|
45
|
-
* gestures. See {@link resolveReuse}.
|
|
25
|
+
* What the capability drives (and therefore what an undeclared project does not get):
|
|
26
|
+
* the in-canvas gestures (*Make reusable* / *Detach to local copy*), the canvas
|
|
27
|
+
* placeholder for an embed whose target is a draft or missing (EC-300), and the reuse
|
|
28
|
+
* config issues. Transclusion itself does not depend on it — the runtime renderer
|
|
29
|
+
* injects `renderBlocks` for every manifest that consumes relations.
|
|
46
30
|
*/
|
|
47
31
|
export interface ReuseCapability {
|
|
48
32
|
/** The embed component, e.g. `project.Reusable`. */
|
|
@@ -57,8 +41,8 @@ export interface ReuseCapability {
|
|
|
57
41
|
contentCardinality: 'one' | 'many';
|
|
58
42
|
}
|
|
59
43
|
/**
|
|
60
|
-
* EC-467 (AD-b)
|
|
61
|
-
* `defineStudio({ reuse: { component: 'project.Reusable' } })`. See
|
|
44
|
+
* EC-467 (AD-b) → EC-728 — THE declaration of the reuse embed (absent: the project has
|
|
45
|
+
* no reusable elements): `defineStudio({ reuse: { component: 'project.Reusable' } })`. See
|
|
62
46
|
* {@link import('../app-views/studio-config').StudioConfig.reuse} for the
|
|
63
47
|
* consumer-facing contract; this is the shape {@link resolveReuse} consumes.
|
|
64
48
|
*
|
|
@@ -78,16 +62,17 @@ export interface StudioReuseConfig {
|
|
|
78
62
|
}
|
|
79
63
|
/**
|
|
80
64
|
* EC-467 — the resolution of the project's reuse capability: the capability (or
|
|
81
|
-
* `null`), plus the config issues a developer must SEE
|
|
65
|
+
* `null`), plus the config issues a developer must SEE (a declaration that cannot
|
|
66
|
+
* resolve).
|
|
82
67
|
*
|
|
83
68
|
* The issues ride the EC-236 {@link CustomizationIssue} surface (`point: 'reuse'`),
|
|
84
|
-
* exactly like the sidebar's and the field renderers' — so they render
|
|
85
|
-
*
|
|
69
|
+
* exactly like the sidebar's and the field renderers' — so they render in the header
|
|
70
|
+
* Issues popover on every surface (EC-690's one issues tray), the studio's home for
|
|
86
71
|
* project-CONFIGURATION problems (the document-scoped Issues pane is the wrong
|
|
87
72
|
* home: this is not a content problem in one document).
|
|
88
73
|
*
|
|
89
74
|
* EC-478: each issue carries a `messageRef` (catalog key + identifier values)
|
|
90
|
-
* alongside its prebuilt English, so the
|
|
75
|
+
* alongside its prebuilt English, so the tray renders it in the active UI
|
|
91
76
|
* locale. This module stays pure — it names a key, it never calls `translate`;
|
|
92
77
|
* `lib/persona/labels.ts` resolves it at the render site. That is what makes the
|
|
93
78
|
* whole list localize together, which is the mixed-language outcome EC-467
|
|
@@ -95,41 +80,30 @@ export interface StudioReuseConfig {
|
|
|
95
80
|
*/
|
|
96
81
|
export interface ReuseResolution {
|
|
97
82
|
capability: ReuseCapability | null;
|
|
98
|
-
/** Empty whenever the
|
|
83
|
+
/** Empty whenever the declaration resolves — and when there is none ("this project has none"). */
|
|
99
84
|
issues: CustomizationIssue[];
|
|
100
85
|
}
|
|
101
86
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* and for issue copy; the resolution rule lives in {@link resolveReuse}.
|
|
105
|
-
*/
|
|
106
|
-
export declare function inferredEmbedCandidates(manifests: readonly ComponentManifest[], collections: readonly CollectionDef[]): ReuseCapability[];
|
|
107
|
-
/**
|
|
108
|
-
* Resolve the project's ONE reuse capability (AD-a) plus any config issues —
|
|
109
|
-
* EC-467's full matrix (AD-c):
|
|
110
|
-
*
|
|
111
|
-
* | Declaration | Candidates | Result |
|
|
112
|
-
* | --- | --- | --- |
|
|
113
|
-
* | present, resolves | any | the declared capability, no issue |
|
|
114
|
-
* | present, does not resolve | any | `null` + an ERROR issue (misconfiguration) |
|
|
115
|
-
* | absent | exactly 1 | that candidate, no issue (the zero-config default) |
|
|
116
|
-
* | absent | 2 or more | `null` + a WARNING issue naming every candidate |
|
|
117
|
-
* | absent | 0 | `null`, **no issue** — a project need not use reusable elements |
|
|
87
|
+
* Resolve the project's ONE reuse capability (AD-a) plus any config issues — EC-728's
|
|
88
|
+
* matrix (declare, never infer):
|
|
118
89
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
90
|
+
* | Declaration | Result |
|
|
91
|
+
* | --- | --- |
|
|
92
|
+
* | present, resolves | the declared capability, no issue |
|
|
93
|
+
* | present, does not resolve | `null` + an ERROR issue (misconfiguration) |
|
|
94
|
+
* | absent | `null`, **no issue** — the project has no reusable elements |
|
|
123
95
|
*
|
|
124
|
-
* The
|
|
125
|
-
* that
|
|
96
|
+
* The absent row is deliberately silent: a project need not use reusable elements,
|
|
97
|
+
* and naming a component that "looks like an embed" would be the guess again, as
|
|
98
|
+
* advice (EC-728). An unresolvable declaration disables the gestures and is reported
|
|
99
|
+
* once, in the header Issues popover.
|
|
126
100
|
*/
|
|
127
101
|
export declare function resolveReuse(manifests: readonly ComponentManifest[], collections: readonly CollectionDef[], declaration?: StudioReuseConfig): ReuseResolution;
|
|
128
102
|
/**
|
|
129
|
-
* The project's reuse capability alone, or `null` when it is
|
|
103
|
+
* The project's reuse capability alone, or `null` when it is undeclared or
|
|
130
104
|
* misdeclared — for callers that act on the capability and do not surface config
|
|
131
|
-
* issues themselves (the
|
|
132
|
-
* the shell
|
|
105
|
+
* issues themselves (the gestures, the canvas placeholder). The issues are surfaced
|
|
106
|
+
* ONCE, by the shell; see {@link resolveReuse}.
|
|
133
107
|
*/
|
|
134
108
|
export declare function resolveReuseCapability(manifests: readonly ComponentManifest[], collections: readonly CollectionDef[], declaration?: StudioReuseConfig): ReuseCapability | null;
|
|
135
109
|
/** A slug for `name`, suffixed `-2`/`-3`/… until it is free among `taken`. */
|
|
@@ -137,7 +111,7 @@ export declare function uniqueSlug(name: string, taken: ReadonlySet<string>): st
|
|
|
137
111
|
/**
|
|
138
112
|
* The values for a new reusable document promoted from `node` (EC-282): seeded
|
|
139
113
|
* defaults, the given `name` on the title field, the node on the content field,
|
|
140
|
-
* and a collision-safe slug on any UNIQUE text field (e.g.
|
|
114
|
+
* and a collision-safe slug on any UNIQUE text field (e.g. a production site's
|
|
141
115
|
* `internalId`) so the created document is publish-valid without hardcoding that
|
|
142
116
|
* field's name. Other required fields, if any, are completed by the editor when
|
|
143
117
|
* they open the new reusable.
|
|
@@ -155,7 +129,16 @@ export declare function buildReusableValues(collection: CollectionDef, capabilit
|
|
|
155
129
|
* whose target doesn't resolve (→ placeholder) without reaching into prop internals.
|
|
156
130
|
*/
|
|
157
131
|
export declare function reuseEmbedRef(node: ComponentNode, capability: ReuseCapability): DocumentRef | null;
|
|
158
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* The `Reusable` embed node referencing the new document (id minted by the action).
|
|
134
|
+
*
|
|
135
|
+
* EC-728 — CANONICAL from the first write: the prop is core's `staticProp` (bare `{ value }`,
|
|
136
|
+
* EC-312), never `{ kind: 'static', value }`. The canvas commits its node patches raw, while
|
|
137
|
+
* the draft takes the same write through the self-typing lens, which strips a redundant
|
|
138
|
+
* `kind`; a non-canonical node therefore made the two views of the canvas field disagree, the
|
|
139
|
+
* draft reported the disagreement as a change made underneath the canvas, and the rebase
|
|
140
|
+
* dropped *Make reusable*'s own undo step (`reuse-undo.test.ts`).
|
|
141
|
+
*/
|
|
159
142
|
export declare function makeEmbedNode(capability: ReuseCapability, documentId: string): ComponentNode;
|
|
160
143
|
/**
|
|
161
144
|
* Why a reuse gesture is refused before it does anything: the one core placement
|
|
@@ -205,7 +188,11 @@ export declare function detachRefusal(args: {
|
|
|
205
188
|
export interface PromoteEffects {
|
|
206
189
|
newDocumentId(): string;
|
|
207
190
|
insertDocument(doc: CmsDocument): void;
|
|
208
|
-
|
|
191
|
+
/**
|
|
192
|
+
* The in-place swap — ONE history entry carrying `effect` (EC-728: the created document, so
|
|
193
|
+
* Undo can remove it when that is safe and Redo can re-insert it).
|
|
194
|
+
*/
|
|
195
|
+
replaceInCanvas(nodeId: string, embed: ComponentNode, effect: CanvasHistoryEffect): void;
|
|
209
196
|
/** Publish the new reusable; resolves `true` only when the document IS published afterwards. */
|
|
210
197
|
publish(ref: DocumentRef): Promise<boolean>;
|
|
211
198
|
refused(refusal: ReuseRefusal): void;
|
|
@@ -216,8 +203,9 @@ export interface PromoteEffects {
|
|
|
216
203
|
/**
|
|
217
204
|
* Run "Make reusable" (EC-282) — the preflight first (EC-584: a refusal creates,
|
|
218
205
|
* publishes and replaces NOTHING), then ONE insert-if-absent create of the reusable
|
|
219
|
-
* document (EC-595 A2), the in-place swap for the embed
|
|
220
|
-
*
|
|
206
|
+
* document (EC-595 A2), the in-place swap for the embed — one canvas history entry that
|
|
207
|
+
* records the created document (EC-728) — and the chosen publish, whose success notice is
|
|
208
|
+
* shown only when the document is actually published.
|
|
221
209
|
*/
|
|
222
210
|
export declare function runPromote(args: {
|
|
223
211
|
root: ComponentNode;
|
|
@@ -235,3 +223,51 @@ export declare function runPromote(args: {
|
|
|
235
223
|
canvasFieldLabel: string;
|
|
236
224
|
effects: PromoteEffects;
|
|
237
225
|
}): Promise<'refused' | 'draft' | 'published' | 'publish-failed'>;
|
|
226
|
+
/**
|
|
227
|
+
* What Undo did with the document *Make reusable* created: `deleted`, or already `gone`, or
|
|
228
|
+
* KEPT — because it is `published`, was `edited` since it was made, is `referenced` elsewhere,
|
|
229
|
+
* or the removal `failed`. The block is restored in every case (the canvas entry is a snapshot).
|
|
230
|
+
*/
|
|
231
|
+
export type PromoteUndoOutcome = 'deleted' | 'gone' | 'published' | 'edited' | 'referenced' | 'failed';
|
|
232
|
+
/** The authoritative reads and the one write Undo needs — injected, so every branch is testable. */
|
|
233
|
+
export interface PromoteUndoDeps {
|
|
234
|
+
/** Await every queued write: the page's restored value lands before anything is judged. */
|
|
235
|
+
flush(): Promise<void>;
|
|
236
|
+
/** The document's record now (`undefined`: it no longer exists). */
|
|
237
|
+
read(ref: DocumentRef): Promise<{
|
|
238
|
+
published: boolean;
|
|
239
|
+
} | undefined>;
|
|
240
|
+
/** How many reference-index entries (draft or published, any document) point at it now. */
|
|
241
|
+
referrers(ref: DocumentRef): Promise<number>;
|
|
242
|
+
/** The conditional delete — at the revision this session's create landed at (`CmsPersister.deleteCreated`). */
|
|
243
|
+
deleteCreated(ref: DocumentRef): Promise<DeleteCreatedOutcome>;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* EC-728 — Undo of *Make reusable*, the document side. The created document is deleted ONLY
|
|
247
|
+
* when every authoritative fact at Undo time says nobody else has it: never published (the
|
|
248
|
+
* record), referenced nowhere — after the page's own restore has landed — (the reference
|
|
249
|
+
* index, both variants), and unchanged since its create (the delete's revision precondition,
|
|
250
|
+
* checked by the store in its own step, which also refuses a strict referrer). Anything else
|
|
251
|
+
* keeps it, with the reason. A read that throws keeps it too: an unproven fact never deletes.
|
|
252
|
+
*/
|
|
253
|
+
export declare function undoPromote(effect: CanvasHistoryEffect, deps: PromoteUndoDeps): Promise<PromoteUndoOutcome>;
|
|
254
|
+
/** The catalog keys of the kept-document notices (EN + DE in the studio catalogs). */
|
|
255
|
+
export type ReuseUndoNoticeKey = 'builder.reuse.undoKeptPublished' | 'builder.reuse.undoKeptEdited' | 'builder.reuse.undoKeptReferenced' | 'builder.reuse.undoKeptFailed';
|
|
256
|
+
/** The notice for a KEPT document (EC-728 — it names the document and why); none when it went. */
|
|
257
|
+
export declare function undoPromoteNotice(outcome: PromoteUndoOutcome): ReuseUndoNoticeKey | undefined;
|
|
258
|
+
/**
|
|
259
|
+
* EC-728 — the document side of every Undo/Redo that crosses a *Make reusable* step, for one
|
|
260
|
+
* canvas. Crossings run strictly in order (a Redo waits for the Undo before it), so a fast
|
|
261
|
+
* Undo → Redo never re-inserts a document whose removal is still in flight. Redo re-inserts
|
|
262
|
+
* (the same id, insert-if-absent) exactly the documents ITS Undo removed or found gone — never
|
|
263
|
+
* one Undo kept (it is still there) — and the canvas entry re-swaps the embed.
|
|
264
|
+
*/
|
|
265
|
+
export declare function createPromoteHistory(deps: PromoteUndoDeps & {
|
|
266
|
+
insert(document: CmsDocument): void;
|
|
267
|
+
notify(key: ReuseUndoNoticeKey, name: string): void;
|
|
268
|
+
}): {
|
|
269
|
+
crossed(step: {
|
|
270
|
+
direction: 'undo' | 'redo';
|
|
271
|
+
effect: CanvasHistoryEffect;
|
|
272
|
+
}): Promise<void>;
|
|
273
|
+
};
|