@elytracms/studio 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/convex/assets.ts +107 -0
- package/convex/auth.config.ts +15 -0
- package/convex/auth.ts +50 -0
- package/convex/cliTokens.ts +63 -0
- package/convex/cms.ts +174 -0
- package/convex/content.ts +316 -0
- package/convex/delivery.ts +266 -0
- package/convex/functions.ts +35 -0
- package/convex/graphs.ts +51 -0
- package/convex/guard.ts +67 -0
- package/convex/http.ts +30 -0
- package/convex/members.ts +83 -0
- package/convex/publishing.ts +102 -0
- package/convex/references.ts +168 -0
- package/convex/schema.ts +173 -0
- package/convex/sync.ts +322 -0
- package/convex/tsconfig.json +12 -0
- package/convex/users.ts +23 -0
- package/convex/webhooks.ts +85 -0
- package/dist/components/assets/asset-library.d.ts +14 -0
- package/dist/components/assets/asset-library.js +191 -0
- package/dist/components/assets/asset-library.js.map +1 -0
- package/dist/components/assets/asset-metadata.d.ts +34 -0
- package/dist/components/assets/asset-metadata.js +40 -0
- package/dist/components/assets/asset-metadata.js.map +1 -0
- package/dist/components/assets/asset-search.d.ts +7 -0
- package/dist/components/assets/asset-search.js +12 -0
- package/dist/components/assets/asset-search.js.map +1 -0
- package/dist/components/assets/asset-selection.d.ts +17 -0
- package/dist/components/assets/asset-selection.js +33 -0
- package/dist/components/assets/asset-selection.js.map +1 -0
- package/dist/components/assets/assets-store.d.ts +51 -0
- package/dist/components/assets/assets-store.js +153 -0
- package/dist/components/assets/assets-store.js.map +1 -0
- package/dist/components/auth-context.d.ts +38 -0
- package/dist/components/auth-context.js +88 -0
- package/dist/components/auth-context.js.map +1 -0
- package/dist/components/backend-gate.d.ts +19 -0
- package/dist/components/backend-gate.js +63 -0
- package/dist/components/backend-gate.js.map +1 -0
- package/dist/components/breadcrumb-context.d.ts +39 -0
- package/dist/components/breadcrumb-context.js +38 -0
- package/dist/components/breadcrumb-context.js.map +1 -0
- package/dist/components/builder/blocks-model.d.ts +80 -0
- package/dist/components/builder/blocks-model.js +181 -0
- package/dist/components/builder/blocks-model.js.map +1 -0
- package/dist/components/builder/blocks-panel.d.ts +44 -0
- package/dist/components/builder/blocks-panel.js +147 -0
- package/dist/components/builder/blocks-panel.js.map +1 -0
- package/dist/components/builder/builder-store.d.ts +69 -0
- package/dist/components/builder/builder-store.js +294 -0
- package/dist/components/builder/builder-store.js.map +1 -0
- package/dist/components/builder/canvas-stylesheet.d.ts +4 -0
- package/dist/components/builder/canvas-stylesheet.js +24 -0
- package/dist/components/builder/canvas-stylesheet.js.map +1 -0
- package/dist/components/builder/canvas.d.ts +8 -0
- package/dist/components/builder/canvas.js +723 -0
- package/dist/components/builder/canvas.js.map +1 -0
- package/dist/components/builder/clipboard-actions.d.ts +93 -0
- package/dist/components/builder/clipboard-actions.js +246 -0
- package/dist/components/builder/clipboard-actions.js.map +1 -0
- package/dist/components/builder/composition-field-editor.d.ts +11 -0
- package/dist/components/builder/composition-field-editor.js +150 -0
- package/dist/components/builder/composition-field-editor.js.map +1 -0
- package/dist/components/builder/composition-scope.d.ts +16 -0
- package/dist/components/builder/composition-scope.js +7 -0
- package/dist/components/builder/composition-scope.js.map +1 -0
- package/dist/components/builder/drag-session.d.ts +41 -0
- package/dist/components/builder/drag-session.js +51 -0
- package/dist/components/builder/drag-session.js.map +1 -0
- package/dist/components/builder/fixture-thumbnail.d.ts +18 -0
- package/dist/components/builder/fixture-thumbnail.js +97 -0
- package/dist/components/builder/fixture-thumbnail.js.map +1 -0
- package/dist/components/builder/inline-edit.d.ts +142 -0
- package/dist/components/builder/inline-edit.js +136 -0
- package/dist/components/builder/inline-edit.js.map +1 -0
- package/dist/components/builder/insert-context.d.ts +14 -0
- package/dist/components/builder/insert-context.js +65 -0
- package/dist/components/builder/insert-context.js.map +1 -0
- package/dist/components/builder/insert-menu.d.ts +9 -0
- package/dist/components/builder/insert-menu.js +9 -0
- package/dist/components/builder/insert-menu.js.map +1 -0
- package/dist/components/builder/layout-inspector.d.ts +14 -0
- package/dist/components/builder/layout-inspector.js +84 -0
- package/dist/components/builder/layout-inspector.js.map +1 -0
- package/dist/components/builder/node-factory.d.ts +17 -0
- package/dist/components/builder/node-factory.js +90 -0
- package/dist/components/builder/node-factory.js.map +1 -0
- package/dist/components/builder/page-tree.d.ts +3 -0
- package/dist/components/builder/page-tree.js +207 -0
- package/dist/components/builder/page-tree.js.map +1 -0
- package/dist/components/builder/property-inspector.d.ts +1 -0
- package/dist/components/builder/property-inspector.js +233 -0
- package/dist/components/builder/property-inspector.js.map +1 -0
- package/dist/components/builder/rich-text-toolbar.d.ts +4 -0
- package/dist/components/builder/rich-text-toolbar.js +104 -0
- package/dist/components/builder/rich-text-toolbar.js.map +1 -0
- package/dist/components/builder/spacing-handles.d.ts +22 -0
- package/dist/components/builder/spacing-handles.js +213 -0
- package/dist/components/builder/spacing-handles.js.map +1 -0
- package/dist/components/cms/asset-picker.d.ts +12 -0
- package/dist/components/cms/asset-picker.js +60 -0
- package/dist/components/cms/asset-picker.js.map +1 -0
- package/dist/components/cms/bulk-actions.d.ts +60 -0
- package/dist/components/cms/bulk-actions.js +95 -0
- package/dist/components/cms/bulk-actions.js.map +1 -0
- package/dist/components/cms/bulk-bar.d.ts +23 -0
- package/dist/components/cms/bulk-bar.js +26 -0
- package/dist/components/cms/bulk-bar.js.map +1 -0
- package/dist/components/cms/cell-edit.d.ts +91 -0
- package/dist/components/cms/cell-edit.js +144 -0
- package/dist/components/cms/cell-edit.js.map +1 -0
- package/dist/components/cms/cell.d.ts +29 -0
- package/dist/components/cms/cell.js +127 -0
- package/dist/components/cms/cell.js.map +1 -0
- package/dist/components/cms/cms-index.d.ts +8 -0
- package/dist/components/cms/cms-index.js +23 -0
- package/dist/components/cms/cms-index.js.map +1 -0
- package/dist/components/cms/cms-store.d.ts +188 -0
- package/dist/components/cms/cms-store.js +702 -0
- package/dist/components/cms/cms-store.js.map +1 -0
- package/dist/components/cms/collection-table.d.ts +6 -0
- package/dist/components/cms/collection-table.js +250 -0
- package/dist/components/cms/collection-table.js.map +1 -0
- package/dist/components/cms/collections-sidebar.d.ts +9 -0
- package/dist/components/cms/collections-sidebar.js +25 -0
- package/dist/components/cms/collections-sidebar.js.map +1 -0
- package/dist/components/cms/detail-editor.d.ts +7 -0
- package/dist/components/cms/detail-editor.js +386 -0
- package/dist/components/cms/detail-editor.js.map +1 -0
- package/dist/components/cms/doc-state.d.ts +13 -0
- package/dist/components/cms/doc-state.js +18 -0
- package/dist/components/cms/doc-state.js.map +1 -0
- package/dist/components/cms/document-editor-context.d.ts +48 -0
- package/dist/components/cms/document-editor-context.js +23 -0
- package/dist/components/cms/document-editor-context.js.map +1 -0
- package/dist/components/cms/editable-cell.d.ts +22 -0
- package/dist/components/cms/editable-cell.js +176 -0
- package/dist/components/cms/editable-cell.js.map +1 -0
- package/dist/components/cms/field-control.d.ts +8 -0
- package/dist/components/cms/field-control.js +149 -0
- package/dist/components/cms/field-control.js.map +1 -0
- package/dist/components/cms/filter-builder.d.ts +12 -0
- package/dist/components/cms/filter-builder.js +84 -0
- package/dist/components/cms/filter-builder.js.map +1 -0
- package/dist/components/cms/import-export.d.ts +6 -0
- package/dist/components/cms/import-export.js +33 -0
- package/dist/components/cms/import-export.js.map +1 -0
- package/dist/components/cms/new-page-dialog.d.ts +22 -0
- package/dist/components/cms/new-page-dialog.js +42 -0
- package/dist/components/cms/new-page-dialog.js.map +1 -0
- package/dist/components/cms/reference-confirm.d.ts +25 -0
- package/dist/components/cms/reference-confirm.js +124 -0
- package/dist/components/cms/reference-confirm.js.map +1 -0
- package/dist/components/cms/relation-picker.d.ts +16 -0
- package/dist/components/cms/relation-picker.js +47 -0
- package/dist/components/cms/relation-picker.js.map +1 -0
- package/dist/components/cms/use-cell-edit.d.ts +33 -0
- package/dist/components/cms/use-cell-edit.js +125 -0
- package/dist/components/cms/use-cell-edit.js.map +1 -0
- package/dist/components/cms/versions-model.d.ts +15 -0
- package/dist/components/cms/versions-model.js +23 -0
- package/dist/components/cms/versions-model.js.map +1 -0
- package/dist/components/cms/versions-pane.d.ts +14 -0
- package/dist/components/cms/versions-pane.js +86 -0
- package/dist/components/cms/versions-pane.js.map +1 -0
- package/dist/components/cms/view-bar.d.ts +11 -0
- package/dist/components/cms/view-bar.js +80 -0
- package/dist/components/cms/view-bar.js.map +1 -0
- package/dist/components/collab/collab-context.d.ts +34 -0
- package/dist/components/collab/collab-context.js +52 -0
- package/dist/components/collab/collab-context.js.map +1 -0
- package/dist/components/collab/collab-seed.d.ts +27 -0
- package/dist/components/collab/collab-seed.js +42 -0
- package/dist/components/collab/collab-seed.js.map +1 -0
- package/dist/components/components/component-detail.d.ts +9 -0
- package/dist/components/components/component-detail.js +30 -0
- package/dist/components/components/component-detail.js.map +1 -0
- package/dist/components/components/component-status.d.ts +10 -0
- package/dist/components/components/component-status.js +30 -0
- package/dist/components/components/component-status.js.map +1 -0
- package/dist/components/components/components-index.d.ts +8 -0
- package/dist/components/components/components-index.js +42 -0
- package/dist/components/components/components-index.js.map +1 -0
- package/dist/components/components/field-inspector.d.ts +9 -0
- package/dist/components/components/field-inspector.js +38 -0
- package/dist/components/components/field-inspector.js.map +1 -0
- package/dist/components/components/fixture-runner.d.ts +10 -0
- package/dist/components/components/fixture-runner.js +24 -0
- package/dist/components/components/fixture-runner.js.map +1 -0
- package/dist/components/components/registry-browser.d.ts +4 -0
- package/dist/components/components/registry-browser.js +64 -0
- package/dist/components/components/registry-browser.js.map +1 -0
- package/dist/components/current-user-menu.d.ts +13 -0
- package/dist/components/current-user-menu.js +31 -0
- package/dist/components/current-user-menu.js.map +1 -0
- package/dist/components/dev-login-badge.d.ts +9 -0
- package/dist/components/dev-login-badge.js +18 -0
- package/dist/components/dev-login-badge.js.map +1 -0
- package/dist/components/extensions/extensions-view.d.ts +7 -0
- package/dist/components/extensions/extensions-view.js +126 -0
- package/dist/components/extensions/extensions-view.js.map +1 -0
- package/dist/components/guards.d.ts +27 -0
- package/dist/components/guards.js +46 -0
- package/dist/components/guards.js.map +1 -0
- package/dist/components/inspector/inspector-sidebar.d.ts +26 -0
- package/dist/components/inspector/inspector-sidebar.js +17 -0
- package/dist/components/inspector/inspector-sidebar.js.map +1 -0
- package/dist/components/operation-error.d.ts +17 -0
- package/dist/components/operation-error.js +54 -0
- package/dist/components/operation-error.js.map +1 -0
- package/dist/components/playground-badge.d.ts +10 -0
- package/dist/components/playground-badge.js +19 -0
- package/dist/components/playground-badge.js.map +1 -0
- package/dist/components/project-list.d.ts +15 -0
- package/dist/components/project-list.js +52 -0
- package/dist/components/project-list.js.map +1 -0
- package/dist/components/project-session.d.ts +46 -0
- package/dist/components/project-session.js +107 -0
- package/dist/components/project-session.js.map +1 -0
- package/dist/components/project-switcher.d.ts +11 -0
- package/dist/components/project-switcher.js +44 -0
- package/dist/components/project-switcher.js.map +1 -0
- package/dist/components/references/builder-deep-link.d.ts +12 -0
- package/dist/components/references/builder-deep-link.js +53 -0
- package/dist/components/references/builder-deep-link.js.map +1 -0
- package/dist/components/references/references-panel.d.ts +17 -0
- package/dist/components/references/references-panel.js +66 -0
- package/dist/components/references/references-panel.js.map +1 -0
- package/dist/components/routes/redirect-chain.d.ts +9 -0
- package/dist/components/routes/redirect-chain.js +16 -0
- package/dist/components/routes/redirect-chain.js.map +1 -0
- package/dist/components/routes/redirect-manager.d.ts +13 -0
- package/dist/components/routes/redirect-manager.js +24 -0
- package/dist/components/routes/redirect-manager.js.map +1 -0
- package/dist/components/routes/route-list.d.ts +35 -0
- package/dist/components/routes/route-list.js +69 -0
- package/dist/components/routes/route-list.js.map +1 -0
- package/dist/components/routes/routes-shell.d.ts +14 -0
- package/dist/components/routes/routes-shell.js +68 -0
- package/dist/components/routes/routes-shell.js.map +1 -0
- package/dist/components/section-nav.d.ts +17 -0
- package/dist/components/section-nav.js +33 -0
- package/dist/components/section-nav.js.map +1 -0
- package/dist/components/section-state.d.ts +24 -0
- package/dist/components/section-state.js +78 -0
- package/dist/components/section-state.js.map +1 -0
- package/dist/components/section-surface.d.ts +31 -0
- package/dist/components/section-surface.js +46 -0
- package/dist/components/section-surface.js.map +1 -0
- package/dist/components/sections.d.ts +38 -0
- package/dist/components/sections.js +72 -0
- package/dist/components/sections.js.map +1 -0
- package/dist/components/settings-form.d.ts +10 -0
- package/dist/components/settings-form.js +17 -0
- package/dist/components/settings-form.js.map +1 -0
- package/dist/components/studio-context.d.ts +22 -0
- package/dist/components/studio-context.js +48 -0
- package/dist/components/studio-context.js.map +1 -0
- package/dist/components/studio-project-screen.d.ts +19 -0
- package/dist/components/studio-project-screen.js +195 -0
- package/dist/components/studio-project-screen.js.map +1 -0
- package/dist/components/studio-shell.d.ts +18 -0
- package/dist/components/studio-shell.js +64 -0
- package/dist/components/studio-shell.js.map +1 -0
- package/dist/components/theme-context.d.ts +17 -0
- package/dist/components/theme-context.js +26 -0
- package/dist/components/theme-context.js.map +1 -0
- package/dist/components/workspace-gate.d.ts +12 -0
- package/dist/components/workspace-gate.js +27 -0
- package/dist/components/workspace-gate.js.map +1 -0
- package/dist/components/workspace-projects.d.ts +13 -0
- package/dist/components/workspace-projects.js +18 -0
- package/dist/components/workspace-projects.js.map +1 -0
- package/dist/lib/assets/delete-asset.d.ts +34 -0
- package/dist/lib/assets/delete-asset.js +34 -0
- package/dist/lib/assets/delete-asset.js.map +1 -0
- package/dist/lib/assets/image-dimensions.d.ts +18 -0
- package/dist/lib/assets/image-dimensions.js +26 -0
- package/dist/lib/assets/image-dimensions.js.map +1 -0
- package/dist/lib/assets/index.d.ts +9 -0
- package/dist/lib/assets/index.js +10 -0
- package/dist/lib/assets/index.js.map +1 -0
- package/dist/lib/assets/upload-state.d.ts +53 -0
- package/dist/lib/assets/upload-state.js +59 -0
- package/dist/lib/assets/upload-state.js.map +1 -0
- package/dist/lib/assets/upload.d.ts +56 -0
- package/dist/lib/assets/upload.js +125 -0
- package/dist/lib/assets/upload.js.map +1 -0
- package/dist/lib/auth/auth-adapter.d.ts +57 -0
- package/dist/lib/auth/auth-adapter.js +13 -0
- package/dist/lib/auth/auth-adapter.js.map +1 -0
- package/dist/lib/auth/convex-auth-adapter.d.ts +39 -0
- package/dist/lib/auth/convex-auth-adapter.js +171 -0
- package/dist/lib/auth/convex-auth-adapter.js.map +1 -0
- package/dist/lib/auth/dev-auto-login-adapter.d.ts +25 -0
- package/dist/lib/auth/dev-auto-login-adapter.js +40 -0
- package/dist/lib/auth/dev-auto-login-adapter.js.map +1 -0
- package/dist/lib/auth/index.d.ts +28 -0
- package/dist/lib/auth/index.js +61 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/local-auth-adapter.d.ts +57 -0
- package/dist/lib/auth/local-auth-adapter.js +78 -0
- package/dist/lib/auth/local-auth-adapter.js.map +1 -0
- package/dist/lib/auth/route-guard.d.ts +33 -0
- package/dist/lib/auth/route-guard.js +51 -0
- package/dist/lib/auth/route-guard.js.map +1 -0
- package/dist/lib/auth-errors.d.ts +42 -0
- package/dist/lib/auth-errors.js +74 -0
- package/dist/lib/auth-errors.js.map +1 -0
- package/dist/lib/bindings/section-bindings.d.ts +24 -0
- package/dist/lib/bindings/section-bindings.js +9 -0
- package/dist/lib/bindings/section-bindings.js.map +1 -0
- package/dist/lib/clipboard/index.d.ts +7 -0
- package/dist/lib/clipboard/index.js +8 -0
- package/dist/lib/clipboard/index.js.map +1 -0
- package/dist/lib/clipboard/os-clipboard.d.ts +46 -0
- package/dist/lib/clipboard/os-clipboard.js +105 -0
- package/dist/lib/clipboard/os-clipboard.js.map +1 -0
- package/dist/lib/clipboard/paste-issues.d.ts +34 -0
- package/dist/lib/clipboard/paste-issues.js +67 -0
- package/dist/lib/clipboard/paste-issues.js.map +1 -0
- package/dist/lib/clipboard/paste-target.d.ts +20 -0
- package/dist/lib/clipboard/paste-target.js +28 -0
- package/dist/lib/clipboard/paste-target.js.map +1 -0
- package/dist/lib/cms/published-documents.d.ts +30 -0
- package/dist/lib/cms/published-documents.js +75 -0
- package/dist/lib/cms/published-documents.js.map +1 -0
- package/dist/lib/cms-views/index.d.ts +9 -0
- package/dist/lib/cms-views/index.js +10 -0
- package/dist/lib/cms-views/index.js.map +1 -0
- package/dist/lib/cms-views/selection.d.ts +29 -0
- package/dist/lib/cms-views/selection.js +46 -0
- package/dist/lib/cms-views/selection.js.map +1 -0
- package/dist/lib/cms-views/view-model.d.ts +192 -0
- package/dist/lib/cms-views/view-model.js +353 -0
- package/dist/lib/cms-views/view-model.js.map +1 -0
- package/dist/lib/cms-views/views-store.d.ts +70 -0
- package/dist/lib/cms-views/views-store.js +129 -0
- package/dist/lib/cms-views/views-store.js.map +1 -0
- package/dist/lib/data/collection-content.d.ts +105 -0
- package/dist/lib/data/collection-content.js +196 -0
- package/dist/lib/data/collection-content.js.map +1 -0
- package/dist/lib/data/data-store.d.ts +97 -0
- package/dist/lib/data/data-store.js +205 -0
- package/dist/lib/data/data-store.js.map +1 -0
- package/dist/lib/data/index.d.ts +4 -0
- package/dist/lib/data/index.js +8 -0
- package/dist/lib/data/index.js.map +1 -0
- package/dist/lib/data/providers.d.ts +143 -0
- package/dist/lib/data/providers.js +255 -0
- package/dist/lib/data/providers.js.map +1 -0
- package/dist/lib/data/sample-capture.d.ts +30 -0
- package/dist/lib/data/sample-capture.js +70 -0
- package/dist/lib/data/sample-capture.js.map +1 -0
- package/dist/lib/data/sources-store.d.ts +42 -0
- package/dist/lib/data/sources-store.js +120 -0
- package/dist/lib/data/sources-store.js.map +1 -0
- package/dist/lib/dnd/drop-rules.d.ts +219 -0
- package/dist/lib/dnd/drop-rules.js +257 -0
- package/dist/lib/dnd/drop-rules.js.map +1 -0
- package/dist/lib/dnd/gap-drag.d.ts +66 -0
- package/dist/lib/dnd/gap-drag.js +95 -0
- package/dist/lib/dnd/gap-drag.js.map +1 -0
- package/dist/lib/locale/binding-fallback.d.ts +28 -0
- package/dist/lib/locale/binding-fallback.js +66 -0
- package/dist/lib/locale/binding-fallback.js.map +1 -0
- package/dist/lib/locale/fallback.d.ts +43 -0
- package/dist/lib/locale/fallback.js +52 -0
- package/dist/lib/locale/fallback.js.map +1 -0
- package/dist/lib/locale/index.d.ts +6 -0
- package/dist/lib/locale/index.js +7 -0
- package/dist/lib/locale/index.js.map +1 -0
- package/dist/lib/locale/locale-store.d.ts +40 -0
- package/dist/lib/locale/locale-store.js +61 -0
- package/dist/lib/locale/locale-store.js.map +1 -0
- package/dist/lib/locale/locale-switcher.d.ts +10 -0
- package/dist/lib/locale/locale-switcher.js +24 -0
- package/dist/lib/locale/locale-switcher.js.map +1 -0
- package/dist/lib/locale/route-variant.d.ts +14 -0
- package/dist/lib/locale/route-variant.js +11 -0
- package/dist/lib/locale/route-variant.js.map +1 -0
- package/dist/lib/locale/use-studio-locale.d.ts +10 -0
- package/dist/lib/locale/use-studio-locale.js +8 -0
- package/dist/lib/locale/use-studio-locale.js.map +1 -0
- package/dist/lib/operations/asset-repository.d.ts +15 -0
- package/dist/lib/operations/asset-repository.js +56 -0
- package/dist/lib/operations/asset-repository.js.map +1 -0
- package/dist/lib/operations/cms-persistence.d.ts +35 -0
- package/dist/lib/operations/cms-persistence.js +75 -0
- package/dist/lib/operations/cms-persistence.js.map +1 -0
- package/dist/lib/operations/graph-commands.d.ts +140 -0
- package/dist/lib/operations/graph-commands.js +86 -0
- package/dist/lib/operations/graph-commands.js.map +1 -0
- package/dist/lib/operations/graph-persistence.d.ts +27 -0
- package/dist/lib/operations/graph-persistence.js +35 -0
- package/dist/lib/operations/graph-persistence.js.map +1 -0
- package/dist/lib/operations/index.d.ts +13 -0
- package/dist/lib/operations/index.js +14 -0
- package/dist/lib/operations/index.js.map +1 -0
- package/dist/lib/operations/operations-package.d.ts +6 -0
- package/dist/lib/operations/operations-package.js +7 -0
- package/dist/lib/operations/operations-package.js.map +1 -0
- package/dist/lib/operations/persist-queue.d.ts +16 -0
- package/dist/lib/operations/persist-queue.js +18 -0
- package/dist/lib/operations/persist-queue.js.map +1 -0
- package/dist/lib/operations/session-hydration.d.ts +84 -0
- package/dist/lib/operations/session-hydration.js +112 -0
- package/dist/lib/operations/session-hydration.js.map +1 -0
- package/dist/lib/operations/studio-operations.d.ts +59 -0
- package/dist/lib/operations/studio-operations.js +92 -0
- package/dist/lib/operations/studio-operations.js.map +1 -0
- package/dist/lib/persistence/backend-mode.d.ts +69 -0
- package/dist/lib/persistence/backend-mode.js +120 -0
- package/dist/lib/persistence/backend-mode.js.map +1 -0
- package/dist/lib/persistence/convex-adapter.d.ts +34 -0
- package/dist/lib/persistence/convex-adapter.js +681 -0
- package/dist/lib/persistence/convex-adapter.js.map +1 -0
- package/dist/lib/persistence/convex-blob-storage.d.ts +57 -0
- package/dist/lib/persistence/convex-blob-storage.js +97 -0
- package/dist/lib/persistence/convex-blob-storage.js.map +1 -0
- package/dist/lib/persistence/convex-client.d.ts +19 -0
- package/dist/lib/persistence/convex-client.js +40 -0
- package/dist/lib/persistence/convex-client.js.map +1 -0
- package/dist/lib/persistence/index.d.ts +30 -0
- package/dist/lib/persistence/index.js +60 -0
- package/dist/lib/persistence/index.js.map +1 -0
- package/dist/lib/persona/labels.d.ts +23 -0
- package/dist/lib/persona/labels.js +122 -0
- package/dist/lib/persona/labels.js.map +1 -0
- package/dist/lib/rail.d.ts +11 -0
- package/dist/lib/rail.js +26 -0
- package/dist/lib/rail.js.map +1 -0
- package/dist/lib/references/impact.d.ts +64 -0
- package/dist/lib/references/impact.js +62 -0
- package/dist/lib/references/impact.js.map +1 -0
- package/dist/lib/references/index.d.ts +7 -0
- package/dist/lib/references/index.js +8 -0
- package/dist/lib/references/index.js.map +1 -0
- package/dist/lib/references/reference-model.d.ts +125 -0
- package/dist/lib/references/reference-model.js +242 -0
- package/dist/lib/references/reference-model.js.map +1 -0
- package/dist/lib/references/references-store.d.ts +65 -0
- package/dist/lib/references/references-store.js +221 -0
- package/dist/lib/references/references-store.js.map +1 -0
- package/dist/lib/registry/index.d.ts +65 -0
- package/dist/lib/registry/index.js +114 -0
- package/dist/lib/registry/index.js.map +1 -0
- package/dist/lib/registry/preview.d.ts +15 -0
- package/dist/lib/registry/preview.js +110 -0
- package/dist/lib/registry/preview.js.map +1 -0
- package/dist/lib/registry/project-components.d.ts +16 -0
- package/dist/lib/registry/project-components.js +152 -0
- package/dist/lib/registry/project-components.js.map +1 -0
- package/dist/lib/routing/index.d.ts +10 -0
- package/dist/lib/routing/index.js +11 -0
- package/dist/lib/routing/index.js.map +1 -0
- package/dist/lib/routing/routing-analysis.d.ts +26 -0
- package/dist/lib/routing/routing-analysis.js +37 -0
- package/dist/lib/routing/routing-analysis.js.map +1 -0
- package/dist/lib/routing/routing-store.d.ts +50 -0
- package/dist/lib/routing/routing-store.js +72 -0
- package/dist/lib/routing/routing-store.js.map +1 -0
- package/dist/lib/starters/kit-session.d.ts +5 -0
- package/dist/lib/starters/kit-session.js +17 -0
- package/dist/lib/starters/kit-session.js.map +1 -0
- package/dist/lib/theme.d.ts +21 -0
- package/dist/lib/theme.js +32 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.js +28 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/webhooks/config.d.ts +15 -0
- package/dist/lib/webhooks/config.js +64 -0
- package/dist/lib/webhooks/config.js.map +1 -0
- package/dist/lib/webhooks/dispatcher.d.ts +67 -0
- package/dist/lib/webhooks/dispatcher.js +61 -0
- package/dist/lib/webhooks/dispatcher.js.map +1 -0
- package/dist/lib/webhooks/index.d.ts +11 -0
- package/dist/lib/webhooks/index.js +10 -0
- package/dist/lib/webhooks/index.js.map +1 -0
- package/dist/lib/webhooks/signing.d.ts +15 -0
- package/dist/lib/webhooks/signing.js +24 -0
- package/dist/lib/webhooks/signing.js.map +1 -0
- package/dist/lib/webhooks/tags.d.ts +25 -0
- package/dist/lib/webhooks/tags.js +173 -0
- package/dist/lib/webhooks/tags.js.map +1 -0
- package/dist/lib/working-graph.d.ts +82 -0
- package/dist/lib/working-graph.js +113 -0
- package/dist/lib/working-graph.js.map +1 -0
- package/dist/lib/workspace/index.d.ts +109 -0
- package/dist/lib/workspace/index.js +206 -0
- package/dist/lib/workspace/index.js.map +1 -0
- package/dist/lib/workspace/switcher-source.d.ts +39 -0
- package/dist/lib/workspace/switcher-source.js +23 -0
- package/dist/lib/workspace/switcher-source.js.map +1 -0
- package/dist/lib/workspace/workspace-source.d.ts +47 -0
- package/dist/lib/workspace/workspace-source.js +67 -0
- package/dist/lib/workspace/workspace-source.js.map +1 -0
- package/dist/router/index.d.ts +32 -0
- package/dist/router/index.js +32 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/match.d.ts +75 -0
- package/dist/router/match.js +87 -0
- package/dist/router/match.js.map +1 -0
- package/dist/router/search.d.ts +22 -0
- package/dist/router/search.js +16 -0
- package/dist/router/search.js.map +1 -0
- package/dist/ui/avatar.d.ts +17 -0
- package/dist/ui/avatar.js +38 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/badge.js +23 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/button.d.ts +11 -0
- package/dist/ui/button.js +30 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/card.d.ts +11 -0
- package/dist/ui/card.js +23 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/dialog.d.ts +12 -0
- package/dist/ui/dialog.js +27 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +15 -0
- package/dist/ui/dropdown-menu.js +24 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/field.d.ts +15 -0
- package/dist/ui/field.js +14 -0
- package/dist/ui/field.js.map +1 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +7 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/inspector.d.ts +18 -0
- package/dist/ui/inspector.js +14 -0
- package/dist/ui/inspector.js.map +1 -0
- package/dist/ui/layout.d.ts +45 -0
- package/dist/ui/layout.js +48 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/panel.d.ts +12 -0
- package/dist/ui/panel.js +20 -0
- package/dist/ui/panel.js.map +1 -0
- package/dist/ui/separator.d.ts +6 -0
- package/dist/ui/separator.js +7 -0
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/toolbar.d.ts +9 -0
- package/dist/ui/toolbar.js +16 -0
- package/dist/ui/toolbar.js.map +1 -0
- package/dist/ui/typography.d.ts +50 -0
- package/dist/ui/typography.js +43 -0
- package/dist/ui/typography.js.map +1 -0
- package/package.json +149 -0
- package/src/styles/studio.css +101 -0
- package/src/styles/tokens.css +63 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { FlaskConical } from 'lucide-react';
|
|
3
|
+
import { Badge } from '@elytracms/studio/ui';
|
|
4
|
+
import { isPlaygroundMode } from '@elytracms/studio/lib/persistence';
|
|
5
|
+
/** Tooltip/accessible description — playground data is local and ephemeral. */
|
|
6
|
+
export const PLAYGROUND_BADGE_HINT = 'Playground mode: data lives in memory on this device and resets on reload. Nothing is saved to a backend.';
|
|
7
|
+
/**
|
|
8
|
+
* EC-153: the explicit playground-mode marker. When the studio runs on the
|
|
9
|
+
* seeded in-memory adapter (`VITE_ELYTRA_MODE=playground`) this badge is
|
|
10
|
+
* always visible in the shell header; in Convex mode it renders nothing.
|
|
11
|
+
* Deterministic: mode is resolved from build-time env, identical on SSR and
|
|
12
|
+
* client.
|
|
13
|
+
*/
|
|
14
|
+
export function PlaygroundBadge() {
|
|
15
|
+
if (!isPlaygroundMode())
|
|
16
|
+
return null;
|
|
17
|
+
return (_jsxs(Badge, { variant: "warning", title: PLAYGROUND_BADGE_HINT, "data-testid": "playground-badge", children: [_jsx(FlaskConical, { "aria-hidden": true }), "Playground"] }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=playground-badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playground-badge.js","sourceRoot":"","sources":["../../src/components/playground-badge.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAA;AAEpE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAChC,2GAA2G,CAAA;AAE7G;;;;;;GAMG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,IAAI,CAAA;IACpC,OAAO,CACL,MAAC,KAAK,IAAC,OAAO,EAAC,SAAS,EAAC,KAAK,EAAE,qBAAqB,iBAAc,kBAAkB,aACnF,KAAC,YAAY,0BAAe,kBAEtB,CACT,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SectionState } from '@elytracms/studio-core';
|
|
2
|
+
export interface ProjectLauncherProps {
|
|
3
|
+
/** Force a deterministic list state for browser verification (?state=…). */
|
|
4
|
+
forcedState?: SectionState | null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Studio launcher / project list (brief §4.3, §8.1; reframed by EC-154). The
|
|
8
|
+
* Studio's front door: lists the workspace's projects and routes into a
|
|
9
|
+
* project's shell. With a workspace config the list is config-driven
|
|
10
|
+
* (configured projects ∩ grants, plus explicit "not provisioned" states);
|
|
11
|
+
* project *creation* is code-first — `elytra.config.ts` + `builder init
|
|
12
|
+
* --project <slug>` — so there is no in-UI create flow. Without a config the
|
|
13
|
+
* adapter-backed list (and the starter-kit gallery) behaves as before.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ProjectLauncher({ forcedState }: ProjectLauncherProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router';
|
|
3
|
+
import { Globe, LogIn, TerminalSquare } from 'lucide-react';
|
|
4
|
+
import { Badge, Button, Card, Code, Heading, Row, Spacer, Stack, Text } from '@elytracms/studio/ui';
|
|
5
|
+
import { hasProjectSession } from '@elytracms/studio/lib/auth';
|
|
6
|
+
import { PlaygroundBadge } from './playground-badge';
|
|
7
|
+
import { SectionStateView } from './section-state';
|
|
8
|
+
import { useStudio } from './studio-context';
|
|
9
|
+
import { useSwitcherEntries } from './workspace-projects';
|
|
10
|
+
/**
|
|
11
|
+
* Studio launcher / project list (brief §4.3, §8.1; reframed by EC-154). The
|
|
12
|
+
* Studio's front door: lists the workspace's projects and routes into a
|
|
13
|
+
* project's shell. With a workspace config the list is config-driven
|
|
14
|
+
* (configured projects ∩ grants, plus explicit "not provisioned" states);
|
|
15
|
+
* project *creation* is code-first — `elytra.config.ts` + `builder init
|
|
16
|
+
* --project <slug>` — so there is no in-UI create flow. Without a config the
|
|
17
|
+
* adapter-backed list (and the starter-kit gallery) behaves as before.
|
|
18
|
+
*/
|
|
19
|
+
export function ProjectLauncher({ forcedState }) {
|
|
20
|
+
const studio = useStudio();
|
|
21
|
+
const { entries, workspace } = useSwitcherEntries();
|
|
22
|
+
const hasConfig = workspace.kind === 'config';
|
|
23
|
+
const visible = entries;
|
|
24
|
+
const recents = studio.context.recentProjectIds
|
|
25
|
+
.map((id) => studio.getProject(id))
|
|
26
|
+
.filter((p) => Boolean(p))
|
|
27
|
+
.filter((p) => entries.some((e) => e.kind === 'project' && e.project.id === p.id))
|
|
28
|
+
.slice(0, 4);
|
|
29
|
+
const forced = forcedState && forcedState !== 'working' ? forcedState : null;
|
|
30
|
+
return (_jsxs("div", { className: "mx-auto w-full max-w-6xl px-6 py-8", children: [_jsxs(Row, { gap: "3", className: "mb-6", children: [_jsxs(Stack, { gap: "1", children: [_jsxs(Row, { gap: "2", children: [_jsx(Heading, { size: "display", children: "Projects" }), _jsx(PlaygroundBadge, {}), hasConfig ? (
|
|
31
|
+
// EC-154: this workspace is defined in code.
|
|
32
|
+
_jsxs(Badge, { variant: "outline", children: [_jsx(TerminalSquare, { className: "size-3" }), " ", workspace.source] })) : null] }), _jsx(Text, { tone: "muted", children: hasConfig
|
|
33
|
+
? 'Projects are defined in code. Add entries to elytra.config.ts and provision them with the CLI.'
|
|
34
|
+
: 'Open and manage your Elytra projects.' })] }), _jsx(Spacer, {})] }), recents.length > 0 && !forced ? (_jsxs(Stack, { gap: "2", className: "mb-6", children: [_jsx(Text, { size: "xs", tone: "muted", mono: true, children: "RECENT" }), _jsx(Row, { gap: "2", wrap: true, children: recents.map((p) => (_jsxs(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId: p.id, _splat: studioPath.index() }, onClick: () => studio.activate(p.id), className: "inline-flex items-center gap-2 rounded-md border border-border bg-card px-3 py-1.5 text-sm transition-colors hover:border-primary/40 hover:bg-muted", children: [_jsx("span", { className: "grid size-4 place-items-center rounded-[4px] bg-primary text-[0.6rem] font-bold text-primary-foreground", children: p.name.charAt(0).toUpperCase() }), p.name] }, p.id))) })] })) : null, forced ? (_jsx(SectionStateView, { state: forced, title: forced === 'empty' ? 'No projects' : undefined })) : visible.length === 0 ? (_jsx(SectionStateView, { state: "empty", title: "No projects", description: hasConfig
|
|
35
|
+
? 'The workspace config declares no visible projects. Add an entry to elytra.config.ts, or ask an admin to grant you access.'
|
|
36
|
+
: 'No active projects. Create one from the CLI: run `builder init` in your repo to scaffold elytra.config.ts, then `builder init --project <slug>`.' })) : (_jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: visible.map((entry) => entry.kind === 'project' ? (_jsx(ProjectCard, { project: entry.project }, entry.project.id)) : (_jsx(UnprovisionedCard, { config: entry.config }, `config:${entry.config.slug}`))) }))] }));
|
|
37
|
+
}
|
|
38
|
+
function ProjectCard({ project }) {
|
|
39
|
+
const studio = useStudio();
|
|
40
|
+
// Per-backend sign-in state (EC-179): one project per backend, so a project on
|
|
41
|
+
// a deployment the user hasn't authenticated into shows "Sign in", not "Open".
|
|
42
|
+
const authed = hasProjectSession(project.slug);
|
|
43
|
+
return (_jsxs(Card, { className: "flex flex-col gap-3 p-4 transition-colors hover:border-primary/30", children: [_jsxs(Row, { gap: "2", children: [_jsx("span", { className: "grid size-8 shrink-0 place-items-center rounded-lg bg-primary text-sm font-bold text-primary-foreground", children: project.name.charAt(0).toUpperCase() }), _jsxs(Stack, { gap: "1", className: "min-w-0", children: [_jsx(Text, { weight: "semibold", className: "truncate", children: project.name }), _jsx(Code, { tone: "muted", className: "w-fit max-w-full truncate", children: project.slug })] }), _jsx(Spacer, {}), authed ? null : (_jsxs(Badge, { variant: "warning", children: [_jsx(LogIn, { className: "size-3" }), " Sign in"] }))] }), _jsxs(Row, { gap: "2", className: "text-muted-foreground", children: [_jsxs(Badge, { variant: "outline", children: [_jsx(Globe, { className: "size-3" }), " ", project.settings.locales.length] }), _jsx(Spacer, {})] }), _jsx(Button, { variant: authed ? 'secondary' : 'default', size: "sm", asChild: true, className: "mt-1", children: _jsx(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId: project.id, _splat: studioPath.index() }, onClick: () => studio.activate(project.id), children: authed ? 'Open project' : (_jsxs(_Fragment, { children: [_jsx(LogIn, {}), " Sign in"] })) }) })] }));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A configured project that has no backend project yet (EC-154): an explicit,
|
|
47
|
+
* deterministic state pointing at the CLI provisioning flow — never an error.
|
|
48
|
+
*/
|
|
49
|
+
function UnprovisionedCard({ config }) {
|
|
50
|
+
return (_jsxs(Card, { className: "flex flex-col gap-3 border-dashed p-4", children: [_jsxs(Row, { gap: "2", children: [_jsx("span", { className: "grid size-8 shrink-0 place-items-center rounded-lg border border-border bg-muted text-sm font-bold text-muted-foreground", children: config.name.charAt(0).toUpperCase() }), _jsxs(Stack, { gap: "1", className: "min-w-0", children: [_jsx(Text, { weight: "semibold", className: "truncate", children: config.name }), _jsx(Code, { tone: "muted", className: "w-fit max-w-full truncate", children: config.slug })] }), _jsx(Spacer, {}), _jsx(Badge, { variant: "outline", children: "not provisioned" })] }), _jsx(Text, { size: "sm", tone: "muted", children: "Declared in the workspace config, but no backend project exists yet. Provision it from your repo:" }), _jsxs(Code, { className: "block w-fit max-w-full truncate text-xs", children: ["builder init --project ", config.slug] })] }));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=project-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-list.js","sourceRoot":"","sources":["../../src/components/project-list.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { HydratedCms, HydratedProjectSession, OperationResult } from '@elytracms/studio/lib/operations';
|
|
3
|
+
/**
|
|
4
|
+
* Project-session hydration gate (Milestone B sign-off fix, EC-177 gap 1).
|
|
5
|
+
*
|
|
6
|
+
* In Convex mode every project session must BOOT from persistence: the
|
|
7
|
+
* builder from the latest persisted graph revision, the CMS from the saved
|
|
8
|
+
* schema + documents, publishing from the persisted environment states.
|
|
9
|
+
* This provider runs the `@elytracms/operations` hydration queries
|
|
10
|
+
* (`lib/operations/session-hydration`) and — like `BackendGate` — gates its
|
|
11
|
+
* children on a deterministic loading state, so fixture content never
|
|
12
|
+
* flashes (and is never editable) before the persisted state arrives.
|
|
13
|
+
*
|
|
14
|
+
* Playground mode renders children synchronously with `session: null`
|
|
15
|
+
* (fixtures), byte-identical to the pre-hydration behavior — the EC-138
|
|
16
|
+
* determinism contract.
|
|
17
|
+
*
|
|
18
|
+
* Side effect on hydration: the content preview engine
|
|
19
|
+
* (`lib/data/collection-content`) is pointed at the hydrated documents
|
|
20
|
+
* BEFORE children render, so "Preview with" lists and section previews show
|
|
21
|
+
* live entries, not fixture titles.
|
|
22
|
+
*/
|
|
23
|
+
export interface ProjectSessionStore {
|
|
24
|
+
/** Hydrated persisted state (Convex mode); `null` in playground (fixtures). */
|
|
25
|
+
session: HydratedProjectSession | null;
|
|
26
|
+
/**
|
|
27
|
+
* Load the CURRENT persisted CMS state (fresh query — the CMS section
|
|
28
|
+
* remounts per visit and must show edits persisted since project open).
|
|
29
|
+
* Playground resolves `null` immediately (fixtures).
|
|
30
|
+
*/
|
|
31
|
+
loadCms(): Promise<OperationResult<HydratedCms | null>>;
|
|
32
|
+
}
|
|
33
|
+
export declare function ProjectSessionProvider({ projectId, children, }: {
|
|
34
|
+
projectId: string;
|
|
35
|
+
children: ReactNode;
|
|
36
|
+
}): import("react").JSX.Element;
|
|
37
|
+
export declare function useProjectSession(): ProjectSessionStore;
|
|
38
|
+
/**
|
|
39
|
+
* Gate one CMS surface mount on a FRESH persisted CMS load (Convex mode).
|
|
40
|
+
* Render-prop: hands the hydrated content (or `null` → fixture fallback,
|
|
41
|
+
* first-run) to the caller once it resolved. Playground renders synchronously
|
|
42
|
+
* with `null`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function CmsSessionGate({ children, }: {
|
|
45
|
+
children: (cms: HydratedCms | null) => ReactNode;
|
|
46
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
3
|
+
import { Button, Stack, Text } from '@elytracms/studio/ui';
|
|
4
|
+
import { getStudioOperations, loadHydratedCms, loadProjectSession } from '@elytracms/studio/lib/operations';
|
|
5
|
+
import { isPlaygroundMode } from '@elytracms/studio/lib/persistence';
|
|
6
|
+
import { configureContentSession } from '@elytracms/studio/lib/data';
|
|
7
|
+
import { OperationErrorBanner } from './operation-error';
|
|
8
|
+
const ProjectSessionContext = createContext(null);
|
|
9
|
+
export function ProjectSessionProvider({ projectId, children, }) {
|
|
10
|
+
const playground = isPlaygroundMode();
|
|
11
|
+
// Playground renders children on the FIRST render (no effect round-trip):
|
|
12
|
+
// fixture boots stay synchronous and deterministic.
|
|
13
|
+
const [phase, setPhase] = useState(() => playground ? { kind: 'ready', session: null } : { kind: 'loading' });
|
|
14
|
+
const [attempt, setAttempt] = useState(0);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (playground) {
|
|
17
|
+
configureContentSession(null);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
let cancelled = false;
|
|
21
|
+
setPhase({ kind: 'loading' });
|
|
22
|
+
void getStudioOperations()
|
|
23
|
+
.then(({ operations }) => loadProjectSession(operations, projectId))
|
|
24
|
+
.then((result) => {
|
|
25
|
+
if (cancelled)
|
|
26
|
+
return;
|
|
27
|
+
if (!result.ok) {
|
|
28
|
+
setPhase({ kind: 'error', error: result.error });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Point the preview content engine at the hydrated documents before
|
|
32
|
+
// any child renders (panels read it module-level, synchronously).
|
|
33
|
+
configureContentSession(result.value.cms);
|
|
34
|
+
setPhase({ kind: 'ready', session: result.value });
|
|
35
|
+
});
|
|
36
|
+
return () => {
|
|
37
|
+
cancelled = true;
|
|
38
|
+
};
|
|
39
|
+
}, [projectId, playground, attempt]);
|
|
40
|
+
// Leaving the project resets the preview engine to fixtures; the next
|
|
41
|
+
// project's gate reconfigures it before rendering its own children.
|
|
42
|
+
useEffect(() => () => configureContentSession(null), []);
|
|
43
|
+
const loadCms = useCallback(async () => {
|
|
44
|
+
if (playground)
|
|
45
|
+
return { ok: true, value: null };
|
|
46
|
+
const { operations } = await getStudioOperations();
|
|
47
|
+
const result = await loadHydratedCms(operations, projectId);
|
|
48
|
+
// Keep the preview engine in sync with the freshest persisted content.
|
|
49
|
+
if (result.ok && result.value !== null)
|
|
50
|
+
configureContentSession(result.value);
|
|
51
|
+
return result;
|
|
52
|
+
}, [playground, projectId]);
|
|
53
|
+
if (phase.kind === 'loading')
|
|
54
|
+
return _jsx(SessionHydrating, {});
|
|
55
|
+
if (phase.kind === 'error') {
|
|
56
|
+
return (_jsx(SessionHydrationError, { error: phase.error, onRetry: () => setAttempt((n) => n + 1) }));
|
|
57
|
+
}
|
|
58
|
+
return (_jsx(ProjectSessionContext.Provider, { value: { session: phase.session, loadCms }, children: children }));
|
|
59
|
+
}
|
|
60
|
+
export function useProjectSession() {
|
|
61
|
+
const store = useContext(ProjectSessionContext);
|
|
62
|
+
if (!store) {
|
|
63
|
+
throw new Error('useProjectSession must be used within a <ProjectSessionProvider>.');
|
|
64
|
+
}
|
|
65
|
+
return store;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Gate one CMS surface mount on a FRESH persisted CMS load (Convex mode).
|
|
69
|
+
* Render-prop: hands the hydrated content (or `null` → fixture fallback,
|
|
70
|
+
* first-run) to the caller once it resolved. Playground renders synchronously
|
|
71
|
+
* with `null`.
|
|
72
|
+
*/
|
|
73
|
+
export function CmsSessionGate({ children, }) {
|
|
74
|
+
const { loadCms } = useProjectSession();
|
|
75
|
+
const playground = isPlaygroundMode();
|
|
76
|
+
const [phase, setPhase] = useState(() => (playground ? { kind: 'ready', cms: null } : { kind: 'loading' }));
|
|
77
|
+
const [attempt, setAttempt] = useState(0);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (playground)
|
|
80
|
+
return;
|
|
81
|
+
let cancelled = false;
|
|
82
|
+
setPhase({ kind: 'loading' });
|
|
83
|
+
void loadCms().then((result) => {
|
|
84
|
+
if (cancelled)
|
|
85
|
+
return;
|
|
86
|
+
setPhase(result.ok ? { kind: 'ready', cms: result.value } : { kind: 'error', error: result.error });
|
|
87
|
+
});
|
|
88
|
+
return () => {
|
|
89
|
+
cancelled = true;
|
|
90
|
+
};
|
|
91
|
+
}, [playground, loadCms, attempt]);
|
|
92
|
+
if (phase.kind === 'loading')
|
|
93
|
+
return _jsx(SessionHydrating, {});
|
|
94
|
+
if (phase.kind === 'error') {
|
|
95
|
+
return (_jsx(SessionHydrationError, { error: phase.error, onRetry: () => setAttempt((n) => n + 1) }));
|
|
96
|
+
}
|
|
97
|
+
return _jsx(_Fragment, { children: children(phase.cms) });
|
|
98
|
+
}
|
|
99
|
+
/** Deterministic loading frame while persisted state is fetched (mirrors BackendGate). */
|
|
100
|
+
function SessionHydrating() {
|
|
101
|
+
return (_jsx("div", { className: "grid h-full min-h-64 flex-1 place-items-center p-8", "data-testid": "session-hydrating", children: _jsx(Text, { size: "sm", tone: "muted", children: "Loading project\u2026" }) }));
|
|
102
|
+
}
|
|
103
|
+
/** A failed hydration is a visible, retryable state — never a fixture fallback. */
|
|
104
|
+
function SessionHydrationError({ error, onRetry, }) {
|
|
105
|
+
return (_jsx("div", { className: "grid h-full min-h-64 flex-1 place-items-center p-8", children: _jsxs(Stack, { gap: "3", className: "w-full max-w-xl", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Couldn\u2019t load this project\u2019s saved state" }), _jsx(OperationErrorBanner, { error: error }), _jsx(Text, { size: "xs", tone: "muted", children: "The studio never falls back to sample content against a live backend \u2014 your data is safe; retry once the backend is reachable." }), _jsx(Button, { variant: "outline", size: "sm", onClick: onRetry, className: "self-start", children: "Retry" })] }) }));
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=project-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-session.js","sourceRoot":"","sources":["../../src/components/project-session.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Project } from '@elytracms/studio-core';
|
|
2
|
+
/**
|
|
3
|
+
* The project switcher (EC-033, reframed by EC-154): with a workspace config
|
|
4
|
+
* the list is config-driven — configured projects ∩ the user's grants, plus
|
|
5
|
+
* explicit "not provisioned" states for config entries that have no backend
|
|
6
|
+
* project yet. Without a config it lists the adapter-backed projects exactly
|
|
7
|
+
* as before. Project *creation* lives in code + CLI (`builder init`), not here.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ProjectSwitcher({ activeProject }: {
|
|
10
|
+
activeProject: Project;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { STUDIO_PROJECT_ROUTE, studioPath, useNavigate } from '@elytracms/studio/router';
|
|
3
|
+
import { Check, ChevronsUpDown, FolderOpen, LogIn } from 'lucide-react';
|
|
4
|
+
import { hasProjectSession } from '@elytracms/studio/lib/auth';
|
|
5
|
+
import { Badge, Button, Code, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Row, Spacer, Stack, Text, } from '@elytracms/studio/ui';
|
|
6
|
+
import { useStudio } from './studio-context';
|
|
7
|
+
import { useSwitcherEntries } from './workspace-projects';
|
|
8
|
+
/**
|
|
9
|
+
* The project switcher (EC-033, reframed by EC-154): with a workspace config
|
|
10
|
+
* the list is config-driven — configured projects ∩ the user's grants, plus
|
|
11
|
+
* explicit "not provisioned" states for config entries that have no backend
|
|
12
|
+
* project yet. Without a config it lists the adapter-backed projects exactly
|
|
13
|
+
* as before. Project *creation* lives in code + CLI (`builder init`), not here.
|
|
14
|
+
*/
|
|
15
|
+
export function ProjectSwitcher({ activeProject }) {
|
|
16
|
+
const studio = useStudio();
|
|
17
|
+
const navigate = useNavigate();
|
|
18
|
+
const { entries } = useSwitcherEntries();
|
|
19
|
+
const activeEntries = entries;
|
|
20
|
+
const recents = studio.context.recentProjectIds
|
|
21
|
+
.map((id) => studio.getProject(id))
|
|
22
|
+
.filter((p) => Boolean(p) && p.id !== activeProject.id)
|
|
23
|
+
.filter((p) => activeEntries.some((entry) => entry.kind === 'project' && entry.project.id === p.id))
|
|
24
|
+
.slice(0, 4);
|
|
25
|
+
function open(project) {
|
|
26
|
+
studio.activate(project.id);
|
|
27
|
+
navigate({ to: STUDIO_PROJECT_ROUTE, params: { projectId: project.id, _splat: studioPath.index() } });
|
|
28
|
+
}
|
|
29
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-2 px-2.5", children: [_jsx("span", { className: "grid size-4 place-items-center rounded-[4px] bg-primary text-[0.6rem] font-bold text-primary-foreground", children: activeProject.name.charAt(0).toUpperCase() }), _jsx("span", { className: "max-w-[12rem] truncate font-medium", children: activeProject.name }), _jsx(ChevronsUpDown, { className: "size-3.5 text-muted-foreground" })] }) }), _jsxs(DropdownMenuContent, { className: "w-80", align: "start", children: [recents.length > 0 ? (_jsxs(_Fragment, { children: [_jsx(DropdownMenuLabel, { children: "Recent" }), recents.map((p) => (_jsx(ProjectMenuItem, { project: p, active: false, onSelect: () => open(p) }, p.id))), _jsx(DropdownMenuSeparator, {})] })) : null, _jsx(DropdownMenuLabel, { children: "Projects" }), activeEntries.map((entry) => entry.kind === 'project' ? (_jsx(ProjectMenuItem, { project: entry.project, active: entry.project.id === activeProject.id, onSelect: () => open(entry.project) }, entry.project.id)) : (_jsx(UnprovisionedMenuItem, { config: entry.config }, `config:${entry.config.slug}`))), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => navigate({ to: '/' }), children: [_jsx(FolderOpen, {}), " Browse all projects"] })] })] }));
|
|
30
|
+
}
|
|
31
|
+
function ProjectMenuItem({ project, active, onSelect, }) {
|
|
32
|
+
// Per-backend sign-in state (EC-179): the active project is signed-in by
|
|
33
|
+
// definition; others wear a "Sign in" badge when their backend has no session.
|
|
34
|
+
const needsSignIn = !active && !hasProjectSession(project.slug);
|
|
35
|
+
return (_jsx(DropdownMenuItem, { onSelect: onSelect, className: "gap-2", children: _jsxs(Row, { gap: "2", className: "min-w-0 flex-1", children: [_jsx(Text, { size: "sm", className: "truncate", children: project.name }), _jsx(Code, { tone: "muted", className: "shrink-0", children: project.slug }), _jsx(Spacer, {}), needsSignIn ? (_jsxs(Badge, { variant: "warning", children: [_jsx(LogIn, { className: "size-3" }), " Sign in"] })) : null, active ? _jsx(Check, { className: "size-4 text-primary" }) : null] }) }));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A configured project with no backend project yet (EC-154): a clear,
|
|
39
|
+
* non-navigating state pointing at the CLI provisioning flow — never an error.
|
|
40
|
+
*/
|
|
41
|
+
function UnprovisionedMenuItem({ config }) {
|
|
42
|
+
return (_jsx(DropdownMenuItem, { disabled: true, className: "gap-2 opacity-100", children: _jsxs(Stack, { gap: "1", className: "min-w-0 flex-1 py-0.5", children: [_jsxs(Row, { gap: "2", className: "min-w-0", children: [_jsx(Text, { size: "sm", tone: "muted", className: "truncate", children: config.name }), _jsx(Spacer, {}), _jsx(Badge, { variant: "outline", children: "not provisioned" })] }), _jsxs(Code, { tone: "muted", className: "w-fit max-w-full truncate text-[0.7rem]", children: ["builder init --project ", config.slug] })] }) }));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=project-switcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-switcher.js","sourceRoot":"","sources":["../../src/components/project-switcher.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Param-driven builder selection (EC-172). Reference-panel entries deep-link
|
|
3
|
+
* to `/$projectId/builder?page=<pageId>&node=<nodeId>`; this headless
|
|
4
|
+
* component applies those params to the builder store — switching the active
|
|
5
|
+
* page, selecting the node (falling back to the page root when the node has
|
|
6
|
+
* drifted away), and scrolling the canvas wrapper (`data-ec-node-id`) into
|
|
7
|
+
* view. Pure selection state: nothing here mutates the graph.
|
|
8
|
+
*/
|
|
9
|
+
export declare function BuilderDeepLink({ pageId, nodeId }: {
|
|
10
|
+
pageId?: string;
|
|
11
|
+
nodeId?: string;
|
|
12
|
+
}): null;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { getNode } from '@elytracms/project-graph';
|
|
3
|
+
import { useBuilder } from '../builder/builder-store';
|
|
4
|
+
/**
|
|
5
|
+
* Param-driven builder selection (EC-172). Reference-panel entries deep-link
|
|
6
|
+
* to `/$projectId/builder?page=<pageId>&node=<nodeId>`; this headless
|
|
7
|
+
* component applies those params to the builder store — switching the active
|
|
8
|
+
* page, selecting the node (falling back to the page root when the node has
|
|
9
|
+
* drifted away), and scrolling the canvas wrapper (`data-ec-node-id`) into
|
|
10
|
+
* view. Pure selection state: nothing here mutates the graph.
|
|
11
|
+
*/
|
|
12
|
+
export function BuilderDeepLink({ pageId, nodeId }) {
|
|
13
|
+
const builder = useBuilder();
|
|
14
|
+
const { dispatch } = builder;
|
|
15
|
+
const graphRef = useRef(builder.present);
|
|
16
|
+
graphRef.current = builder.present;
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (pageId === undefined && nodeId === undefined)
|
|
19
|
+
return;
|
|
20
|
+
const graph = graphRef.current;
|
|
21
|
+
const page = (pageId !== undefined ? graph.pages.find((p) => p.id === pageId) : undefined) ??
|
|
22
|
+
(nodeId !== undefined
|
|
23
|
+
? graph.pages.find((p) => getNode(p.root, nodeId) !== undefined)
|
|
24
|
+
: undefined);
|
|
25
|
+
if (!page)
|
|
26
|
+
return;
|
|
27
|
+
const selectedId = nodeId !== undefined && getNode(page.root, nodeId) ? nodeId : page.root.id;
|
|
28
|
+
dispatch({ type: 'select', id: selectedId, pageId: page.id });
|
|
29
|
+
// The canvas marks every rendered node with `data-ec-node-id`; scroll the
|
|
30
|
+
// selection into view once the page has rendered (bounded retries — the
|
|
31
|
+
// canvas may need a frame or two after a page switch).
|
|
32
|
+
let cancelled = false;
|
|
33
|
+
let attempts = 0;
|
|
34
|
+
const tryScroll = () => {
|
|
35
|
+
if (cancelled)
|
|
36
|
+
return;
|
|
37
|
+
const element = document.querySelector(`[data-ec-node-id="${CSS.escape(selectedId)}"]`);
|
|
38
|
+
if (element) {
|
|
39
|
+
element.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
40
|
+
}
|
|
41
|
+
else if (attempts < 10) {
|
|
42
|
+
attempts += 1;
|
|
43
|
+
window.setTimeout(tryScroll, 60);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
window.setTimeout(tryScroll, 60);
|
|
47
|
+
return () => {
|
|
48
|
+
cancelled = true;
|
|
49
|
+
};
|
|
50
|
+
}, [pageId, nodeId, dispatch]);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=builder-deep-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder-deep-link.js","sourceRoot":"","sources":["../../../src/components/references/builder-deep-link.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAErD;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAwC;IACtF,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAElC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;YAAE,OAAM;QACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAA;QAC9B,MAAM,IAAI,GACR,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7E,CAAC,MAAM,KAAK,SAAS;gBACnB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC;gBAChE,CAAC,CAAC,SAAS,CAAC,CAAA;QAChB,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,MAAM,UAAU,GAAG,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;QAC7F,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;QAE7D,0EAA0E;QAC1E,wEAAwE;QACxE,uDAAuD;QACvD,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,SAAS;gBAAE,OAAM;YACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,qBAAqB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YACvF,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;YACjE,CAAC;iBAAM,IAAI,QAAQ,GAAG,EAAE,EAAE,CAAC;gBACzB,QAAQ,IAAI,CAAC,CAAA;gBACb,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;YAClC,CAAC;QACH,CAAC,CAAA;QACD,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QAChC,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;QAClB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE9B,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReferenceSource, ReferenceTarget } from '@elytracms/persistence';
|
|
2
|
+
/**
|
|
3
|
+
* The shared "References / Used by" panel (EC-172) — one generic component,
|
|
4
|
+
* three hosts (CMS document detail, asset library, component detail). Entries
|
|
5
|
+
* are served entirely by `@elytracms/operations` reference queries over the
|
|
6
|
+
* EC-155 index; every entry deep-links to the exact field control or graph
|
|
7
|
+
* node its index path identifies, and draft-only entries are visibly
|
|
8
|
+
* distinguished from published (live) ones.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ReferencesPanel({ projectId, source, target, className, }: {
|
|
11
|
+
projectId: string;
|
|
12
|
+
/** The holding entity — enables the outbound "References" section. */
|
|
13
|
+
source?: ReferenceSource;
|
|
14
|
+
/** The referenced entity — enables the inbound "Used by" section. */
|
|
15
|
+
target?: ReferenceTarget;
|
|
16
|
+
className?: string;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router';
|
|
3
|
+
import { AlertTriangle, ArrowDownLeft, ArrowUpRight, Link2, RotateCcw } from 'lucide-react';
|
|
4
|
+
import { useReferencePanel } from '@elytracms/studio/lib/references';
|
|
5
|
+
import { Badge, Button, Panel, PanelHeader, Row, Spacer, Stack, Text } from '@elytracms/studio/ui';
|
|
6
|
+
/**
|
|
7
|
+
* The shared "References / Used by" panel (EC-172) — one generic component,
|
|
8
|
+
* three hosts (CMS document detail, asset library, component detail). Entries
|
|
9
|
+
* are served entirely by `@elytracms/operations` reference queries over the
|
|
10
|
+
* EC-155 index; every entry deep-links to the exact field control or graph
|
|
11
|
+
* node its index path identifies, and draft-only entries are visibly
|
|
12
|
+
* distinguished from published (live) ones.
|
|
13
|
+
*/
|
|
14
|
+
export function ReferencesPanel({ projectId, source, target, className, }) {
|
|
15
|
+
const panel = useReferencePanel({ projectId, source, target });
|
|
16
|
+
const total = panel.data === null ? null : panel.data.outbound.length + panel.data.inbound.length;
|
|
17
|
+
return (_jsxs(Panel, { className: className, "data-testid": "references-panel", children: [_jsxs(PanelHeader, { children: [_jsx(Link2, { className: "size-4 text-primary" }), _jsx(Text, { size: "sm", weight: "semibold", children: "References" }), total !== null ? _jsx(Badge, { variant: "outline", children: total }) : null, _jsx(Spacer, {})] }), _jsx(Stack, { gap: "4", className: "p-4", children: panel.status === 'loading' ? (_jsx(ReferencesLoading, {})) : panel.status === 'error' ? (_jsx(ReferencesError, { message: panel.errorMessage, onRetry: panel.refresh })) : (_jsxs(_Fragment, { children: [source ? (_jsx(ReferenceSection, { title: "References", icon: _jsx(ArrowUpRight, { className: "size-3.5" }), hint: "What this entry points at \u2014 click to jump to the target, or to the exact field.", direction: "outbound", projectId: projectId, entries: panel.data?.outbound ?? [], error: panel.data?.outboundError ?? null, emptyLabel: "No outbound references." })) : null, target ? (_jsx(ReferenceSection, { title: "Used by", icon: _jsx(ArrowDownLeft, { className: "size-3.5" }), hint: "Everything referencing this entry \u2014 click to jump to the exact field or node.", direction: "inbound", projectId: projectId, entries: panel.data?.inbound ?? [], error: panel.data?.inboundError ?? null, emptyLabel: "Not referenced anywhere." })) : null] })) })] }));
|
|
18
|
+
}
|
|
19
|
+
/** Named loading state, consistent with existing studio panels. */
|
|
20
|
+
function ReferencesLoading() {
|
|
21
|
+
return (_jsx(Text, { size: "sm", tone: "muted", "data-testid": "references-loading", children: "Loading references\u2026" }));
|
|
22
|
+
}
|
|
23
|
+
/** Named error state with retry — never a silent failure. */
|
|
24
|
+
function ReferencesError({ message, onRetry, }) {
|
|
25
|
+
return (_jsxs(Stack, { gap: "2", "data-testid": "references-error", children: [_jsxs(Row, { gap: "2", children: [_jsx(AlertTriangle, { className: "size-4 text-destructive" }), _jsx(Text, { size: "sm", weight: "semibold", children: "References failed to load" })] }), _jsx(Text, { size: "xs", tone: "muted", children: message ?? 'The reference index is unreachable.' }), _jsx(Row, { children: _jsxs(Button, { variant: "outline", size: "sm", onClick: onRetry, children: [_jsx(RotateCcw, {}), " Retry"] }) })] }));
|
|
26
|
+
}
|
|
27
|
+
function ReferenceSection({ title, icon, hint, direction, projectId, entries, error, emptyLabel, }) {
|
|
28
|
+
return (_jsxs(Stack, { gap: "2", "data-testid": `references-${direction}`, children: [_jsxs(Row, { gap: "2", children: [_jsx("span", { className: "text-muted-foreground", children: icon }), _jsx(Text, { size: "xs", weight: "semibold", tone: "muted", className: "uppercase tracking-wide", children: title }), _jsx(Badge, { variant: "outline", children: entries.length })] }), error ? (_jsxs(Row, { gap: "2", "data-testid": `references-${direction}-error`, children: [_jsx(AlertTriangle, { className: "size-3.5 shrink-0 text-destructive" }), _jsxs(Text, { size: "xs", tone: "muted", children: ["Couldn\u2019t load this section: ", error] })] })) : entries.length === 0 ? (_jsx(Text, { size: "sm", tone: "muted", "data-testid": `references-${direction}-empty`, children: emptyLabel })) : (_jsx(Stack, { gap: "2", title: hint, children: entries.map((entry) => (_jsx(ReferenceEntryRow, { entry: entry, direction: direction, projectId: projectId }, entry.key))) }))] }));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* One entry row. Inbound rows lead with the *source* (where it is used) and
|
|
32
|
+
* deep-link to the exact location; outbound rows lead with the *target* and
|
|
33
|
+
* keep the exact-field link on the location line.
|
|
34
|
+
*/
|
|
35
|
+
function ReferenceEntryRow({ entry, direction, projectId, }) {
|
|
36
|
+
const primary = direction === 'inbound'
|
|
37
|
+
? { label: entry.sourceLabel, link: entry.sourceLink }
|
|
38
|
+
: { label: entry.targetLabel, link: entry.targetLink };
|
|
39
|
+
return (_jsxs(Row, { gap: "2", className: "rounded-md border border-border/70 bg-background/40 px-2.5 py-2", "data-testid": "reference-entry", children: [_jsxs(Stack, { gap: "1", className: "min-w-0 flex-1", children: [_jsx(Row, { gap: "2", className: "min-w-0", children: _jsx(DeepLinkText, { projectId: projectId, link: primary.link, label: primary.label, primary: true }) }), _jsxs(Row, { gap: "1", className: "min-w-0", children: [_jsx(Text, { size: "xs", tone: "muted", className: "shrink-0", children: "at" }), _jsx(DeepLinkText, { projectId: projectId, link: entry.sourceLink, label: entry.locationLabel })] })] }), _jsx(Badge, { variant: "outline", className: "shrink-0", children: entry.kindLabel }), _jsx(VariantBadges, { draft: entry.draft, published: entry.published })] }));
|
|
40
|
+
}
|
|
41
|
+
/** Draft/published visibility (the Sanity hidden-draft-reference case, AD-6). */
|
|
42
|
+
function VariantBadges({ draft, published }) {
|
|
43
|
+
return (_jsxs(Row, { gap: "1", className: "shrink-0", "data-testid": "reference-variants", children: [draft ? _jsx(Badge, { variant: "warning", children: "draft" }) : null, published ? _jsx(Badge, { variant: "success", children: "published" }) : null] }));
|
|
44
|
+
}
|
|
45
|
+
/** Render a deep-link descriptor as a router link (plain text when unresolvable). */
|
|
46
|
+
function DeepLinkText({ projectId, link, label, primary = false, }) {
|
|
47
|
+
const className = primary
|
|
48
|
+
? 'min-w-0 truncate text-sm font-medium text-foreground hover:text-primary hover:underline'
|
|
49
|
+
: 'min-w-0 truncate text-xs text-muted-foreground hover:text-primary hover:underline';
|
|
50
|
+
if (link === null) {
|
|
51
|
+
return primary ? (_jsx(Text, { size: "sm", weight: "medium", className: "min-w-0 truncate", children: label })) : (_jsx(Text, { size: "xs", tone: "muted", className: "min-w-0 truncate", children: label }));
|
|
52
|
+
}
|
|
53
|
+
switch (link.kind) {
|
|
54
|
+
case 'cms-field':
|
|
55
|
+
return (_jsx(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.cmsDocument(link.collectionId, link.documentId) }, search: link.fieldPath !== undefined ? { field: link.fieldPath } : {}, className: className, "data-testid": "reference-link-cms", children: label }));
|
|
56
|
+
case 'builder-node':
|
|
57
|
+
// The builder redirect (EC-187) only reads `?page=`; the page-graph-only
|
|
58
|
+
// `node` has no home in the document editor and is dropped.
|
|
59
|
+
return (_jsx(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.builder() }, search: link.pageId !== undefined ? { page: link.pageId } : {}, className: className, "data-testid": "reference-link-builder", children: label }));
|
|
60
|
+
case 'component':
|
|
61
|
+
return (_jsx(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.component(link.componentId) }, className: className, "data-testid": "reference-link-component", children: label }));
|
|
62
|
+
case 'asset':
|
|
63
|
+
return (_jsx(Link, { to: STUDIO_PROJECT_ROUTE, params: { projectId, _splat: studioPath.assets() }, search: { asset: link.assetId }, className: className, "data-testid": "reference-link-asset", children: label }));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=references-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"references-panel.js","sourceRoot":"","sources":["../../../src/components/references/references-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RedirectResolution } from '@elytracms/cms-core';
|
|
2
|
+
/**
|
|
3
|
+
* Visualizes a redirect chain from the engine's {@link RedirectResolution}:
|
|
4
|
+
* every hop in order, with the loop entry point highlighted when the chain
|
|
5
|
+
* closes a loop (EC-170).
|
|
6
|
+
*/
|
|
7
|
+
export declare function RedirectChain({ resolution }: {
|
|
8
|
+
resolution: RedirectResolution;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
|
+
import { ArrowRight, RotateCw } from 'lucide-react';
|
|
4
|
+
import { Badge, Code, Row } from '@elytracms/studio/ui';
|
|
5
|
+
/**
|
|
6
|
+
* Visualizes a redirect chain from the engine's {@link RedirectResolution}:
|
|
7
|
+
* every hop in order, with the loop entry point highlighted when the chain
|
|
8
|
+
* closes a loop (EC-170).
|
|
9
|
+
*/
|
|
10
|
+
export function RedirectChain({ resolution }) {
|
|
11
|
+
return (_jsxs(Row, { gap: "1", wrap: true, "data-testid": "redirect-chain", "data-loop": resolution.loop, children: [resolution.chain.map((hop, index) => {
|
|
12
|
+
const isLoopEntry = resolution.loop && hop === resolution.target;
|
|
13
|
+
return (_jsxs(Fragment, { children: [index > 0 ? _jsx(ArrowRight, { className: "size-3 shrink-0 text-muted-foreground" }) : null, _jsx(Code, { className: isLoopEntry ? 'border-destructive/50 bg-destructive/10 text-destructive' : undefined, children: hop })] }, `${hop}-${index}`));
|
|
14
|
+
}), resolution.loop ? (_jsxs(Badge, { variant: "error", "data-testid": "loop-badge", children: [_jsx(RotateCw, {}), " loop"] })) : null] }));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=redirect-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect-chain.js","sourceRoot":"","sources":["../../../src/components/routes/redirect-chain.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEnD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAEvD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,UAAU,EAAsC;IAC9E,OAAO,CACL,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,IAAI,uBAAa,gBAAgB,eAAY,UAAU,CAAC,IAAI,aACtE,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBACnC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,IAAI,GAAG,KAAK,UAAU,CAAC,MAAM,CAAA;gBAChE,OAAO,CACL,MAAC,QAAQ,eACN,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAC,UAAU,IAAC,SAAS,EAAC,uCAAuC,GAAG,CAAC,CAAC,CAAC,IAAI,EACpF,KAAC,IAAI,IACH,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,0DAA0D,CAAC,CAAC,CAAC,SAAS,YAE9F,GAAG,GACC,KANM,GAAG,GAAG,IAAI,KAAK,EAAE,CAOrB,CACZ,CAAA;YACH,CAAC,CAAC,EACD,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CACjB,MAAC,KAAK,IAAC,OAAO,EAAC,OAAO,iBAAa,YAAY,aAC7C,KAAC,QAAQ,KAAG,aACN,CACT,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RedirectRecord, RedirectResolution } from '@elytracms/cms-core';
|
|
2
|
+
export interface RedirectManagerProps {
|
|
3
|
+
redirects: readonly RedirectRecord[];
|
|
4
|
+
/** The live router's chain resolver (engine API, EC-020). */
|
|
5
|
+
followRedirects: (from: string) => RedirectResolution;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The redirect list (EC-170), read-only (EC-207 "routes as code"): every
|
|
9
|
+
* 301/302 redirect of the project. Each row shows its resolved chain from the
|
|
10
|
+
* live engine; loops render as explicit errors. Redirects are authored in
|
|
11
|
+
* `elytra.config.ts`; this surface only views them.
|
|
12
|
+
*/
|
|
13
|
+
export declare function RedirectManager({ redirects, followRedirects }: RedirectManagerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowRight } from 'lucide-react';
|
|
3
|
+
import { Badge, Code, Row, Spacer, Stack, Text } from '@elytracms/studio/ui';
|
|
4
|
+
import { statusCodeOf } from '@elytracms/studio/lib/routing';
|
|
5
|
+
import { RedirectChain } from './redirect-chain';
|
|
6
|
+
/**
|
|
7
|
+
* The redirect list (EC-170), read-only (EC-207 "routes as code"): every
|
|
8
|
+
* 301/302 redirect of the project. Each row shows its resolved chain from the
|
|
9
|
+
* live engine; loops render as explicit errors. Redirects are authored in
|
|
10
|
+
* `elytra.config.ts`; this surface only views them.
|
|
11
|
+
*/
|
|
12
|
+
export function RedirectManager({ redirects, followRedirects }) {
|
|
13
|
+
const sorted = [...redirects].sort((a, b) => a.from.localeCompare(b.from));
|
|
14
|
+
return (_jsxs(Stack, { gap: "none", className: "min-h-0", children: [_jsxs(Row, { gap: "2", className: "h-12 shrink-0 border-b border-border px-4", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Redirects" }), _jsx(Text, { size: "xs", tone: "subtle", mono: true, children: redirects.length })] }), _jsxs(Stack, { gap: "3", className: "p-4", children: [sorted.length === 0 ? (_jsx(Text, { size: "sm", tone: "muted", children: "No redirects defined. Add redirects in elytra.config.ts to forward old URLs to new ones." })) : null, _jsx("ul", { className: "flex flex-col gap-2", "data-testid": "redirect-list", children: sorted.map((redirect) => (_jsx(RedirectRow, { redirect: redirect, resolution: followRedirects(redirect.from) }, redirect.id))) })] })] }));
|
|
15
|
+
}
|
|
16
|
+
function RedirectRow({ redirect, resolution, }) {
|
|
17
|
+
// More hops than `from → to` means this redirect chains onward (or loops).
|
|
18
|
+
const chains = resolution.loop || resolution.chain.length > 2;
|
|
19
|
+
return (_jsxs("li", { "data-testid": `redirect-row-${redirect.id}`, className: 'rounded-md border p-3 ' +
|
|
20
|
+
(resolution.loop ? 'border-destructive/40 bg-destructive/5' : 'border-border bg-card/40'), children: [_jsxs(Row, { gap: "2", wrap: true, children: [_jsx(Code, { children: redirect.from }), _jsx(ArrowRight, { className: "size-3 shrink-0 text-muted-foreground" }), _jsx(Code, { children: redirect.to }), _jsx(Badge, { variant: redirect.permanent ? 'primary' : 'info', "data-testid": `redirect-status-${redirect.id}`, children: statusCodeOf(redirect) }), resolution.loop ? _jsx(Badge, { variant: "error", children: "loop" }) : null, _jsx(Spacer, {})] }), chains ? (_jsxs(Stack, { gap: "1", className: "mt-2", children: [_jsx(Text, { size: "xs", tone: "muted", children: resolution.loop
|
|
21
|
+
? 'This redirect is part of a loop:'
|
|
22
|
+
: `Chains to ${resolution.target}:` }), _jsx(RedirectChain, { resolution: resolution })] })) : null] }));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=redirect-manager.js.map
|