canopycms 0.0.68-int.98 → 0.1.0
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/CHANGELOG.md +2131 -0
- package/README.md +47 -63
- package/dist/ai/generate.d.ts +5 -0
- package/dist/ai/generate.js +244 -115
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/json-to-markdown.d.ts +21 -1
- package/dist/ai/json-to-markdown.js +120 -57
- package/dist/ai/references.d.ts +72 -0
- package/dist/ai/references.js +223 -0
- package/dist/ai/resolve-branch.js +9 -2
- package/dist/ai/to-plain-text.d.ts +17 -8
- package/dist/ai/to-plain-text.js +18 -15
- package/dist/ai/types.d.ts +84 -3
- package/dist/api/admin-branch-health.d.ts +24 -1
- package/dist/api/admin-branch-health.js +52 -20
- package/dist/api/admin.d.ts +23 -5
- package/dist/api/admin.js +36 -1
- package/dist/api/assets.js +88 -78
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch-merge.js +1 -1
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +16 -7
- package/dist/api/branch-status.d.ts +16 -6
- package/dist/api/branch-status.js +57 -12
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +8 -3
- package/dist/api/branch.d.ts +25 -12
- package/dist/api/branch.js +164 -103
- package/dist/api/client.d.ts +78 -58
- package/dist/api/client.js +150 -117
- package/dist/api/comments.d.ts +12 -3
- package/dist/api/comments.js +118 -9
- package/dist/api/content.d.ts +9 -9
- package/dist/api/content.js +131 -22
- package/dist/api/entries-constants.d.ts +14 -3
- package/dist/api/entries-constants.js +14 -3
- package/dist/api/entries.d.ts +40 -2
- package/dist/api/entries.js +102 -6
- package/dist/api/github-sync.d.ts +19 -0
- package/dist/api/github-sync.js +50 -3
- package/dist/api/groups.d.ts +4 -4
- package/dist/api/groups.js +2 -1
- package/dist/api/guards.js +23 -3
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +1 -0
- package/dist/api/permissions.d.ts +21 -2
- package/dist/api/permissions.js +50 -3
- package/dist/api/request-deadline.d.ts +59 -0
- package/dist/api/request-deadline.js +73 -0
- package/dist/api/resolve-references.js +8 -7
- package/dist/api/route-builder.d.ts +14 -0
- package/dist/api/route-builder.js +14 -1
- package/dist/api/schema.d.ts +11 -9
- package/dist/api/schema.js +2 -0
- package/dist/api/settings-helpers.d.ts +5 -1
- package/dist/api/settings-helpers.js +10 -2
- package/dist/api/types.d.ts +18 -0
- package/dist/api/users-constants.d.ts +6 -0
- package/dist/api/users-constants.js +6 -0
- package/dist/assets/asset-url.d.ts +28 -16
- package/dist/assets/asset-url.js +51 -25
- package/dist/assets/finalize.js +3 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +153 -0
- package/dist/assets/materialize.js +402 -0
- package/dist/assets/store-local.d.ts +19 -5
- package/dist/assets/store-local.js +69 -10
- package/dist/assets/store-s3.d.ts +38 -7
- package/dist/assets/store-s3.js +128 -22
- package/dist/assets/transform-directives.d.ts +52 -13
- package/dist/assets/transform-directives.js +87 -27
- package/dist/assets/transform.d.ts +3 -3
- package/dist/assets/transform.js +13 -8
- package/dist/assets/types.d.ts +31 -4
- package/dist/auth/cache.d.ts +1 -1
- package/dist/auth/cache.js +1 -1
- package/dist/auth/caching-auth-plugin.d.ts +2 -0
- package/dist/auth/caching-auth-plugin.js +12 -2
- package/dist/auth/file-based-auth-cache.d.ts +8 -0
- package/dist/auth/file-based-auth-cache.js +18 -8
- package/dist/auth/person-name.d.ts +5 -0
- package/dist/auth/person-name.js +8 -0
- package/dist/auth/plugin.d.ts +10 -1
- package/dist/auth/types.d.ts +2 -0
- package/dist/auth/user-metadata-lookup.d.ts +21 -0
- package/dist/auth/user-metadata-lookup.js +116 -0
- package/dist/authorization/branch.d.ts +1 -1
- package/dist/authorization/branch.js +12 -13
- package/dist/authorization/groups/schema.d.ts +4 -4
- package/dist/authorization/helpers.d.ts +8 -0
- package/dist/authorization/helpers.js +8 -0
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/protected-branch.d.ts +5 -4
- package/dist/authorization/protected-branch.js +7 -5
- package/dist/branch-health.d.ts +35 -8
- package/dist/branch-health.js +54 -18
- package/dist/branch-metadata-error.d.ts +27 -0
- package/dist/branch-metadata-error.js +23 -0
- package/dist/branch-metadata-file.d.ts +205 -24
- package/dist/branch-metadata-file.js +126 -25
- package/dist/branch-metadata.d.ts +45 -6
- package/dist/branch-metadata.js +142 -50
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-registry.d.ts +8 -0
- package/dist/branch-registry.js +61 -9
- package/dist/branch-schema-cache.d.ts +29 -12
- package/dist/branch-schema-cache.js +64 -21
- package/dist/branch-sparse.d.ts +23 -0
- package/dist/branch-sparse.js +118 -0
- package/dist/branch-workspace.d.ts +42 -3
- package/dist/branch-workspace.js +239 -100
- package/dist/build/asset-refs.d.ts +94 -0
- package/dist/build/asset-refs.js +267 -0
- package/dist/build/generate-ai-content.js +5 -0
- package/dist/build/inline-flight.d.ts +37 -0
- package/dist/build/inline-flight.js +142 -0
- package/dist/cli/asset-refs.d.ts +52 -0
- package/dist/cli/asset-refs.js +194 -0
- package/dist/cli/cli.d.ts +15 -1
- package/dist/cli/cli.js +8543 -3193
- package/dist/cli/configured-asset-store.d.ts +12 -0
- package/dist/cli/configured-asset-store.js +46 -0
- package/dist/cli/generate-ai-content.js +4244 -1072
- package/dist/cli/init.js +217 -126
- package/dist/cli/project-detect.d.ts +2 -0
- package/dist/cli/project-detect.js +2 -0
- package/dist/cli/template-files/Dockerfile.cms.template +13 -5
- package/dist/cli/template-files/cms-stack.ts.template +16 -13
- package/dist/client.d.ts +1 -2
- package/dist/client.js +1 -2
- package/dist/comment-store.d.ts +25 -0
- package/dist/comment-store.js +43 -8
- package/dist/config/flatten.js +2 -0
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schemas/config.d.ts +12 -29
- package/dist/config/schemas/config.js +9 -12
- package/dist/config/schemas/field.d.ts +3 -0
- package/dist/config/schemas/field.js +58 -4
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +2 -20
- package/dist/config/schemas/url.js +2 -25
- package/dist/config/types.d.ts +116 -22
- package/dist/config/types.js +3 -9
- package/dist/config/validation.d.ts +25 -4
- package/dist/config/validation.js +116 -3
- package/dist/content-id-index.js +2 -2
- package/dist/content-index-generation.d.ts +1 -1
- package/dist/content-index-generation.js +1 -1
- package/dist/content-listing.d.ts +10 -1
- package/dist/content-listing.js +22 -5
- package/dist/content-reader.d.ts +9 -0
- package/dist/content-reader.js +16 -11
- package/dist/content-store.d.ts +75 -12
- package/dist/content-store.js +249 -86
- package/dist/content-tree.js +2 -2
- package/dist/context.js +5 -2
- package/dist/dangling-reference-log.d.ts +17 -0
- package/dist/dangling-reference-log.js +29 -0
- package/dist/dev-content-watcher.d.ts +1 -1
- package/dist/dev-content-watcher.js +1 -1
- package/dist/editor/BranchManager.d.ts +23 -7
- package/dist/editor/BranchManager.js +119 -54
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CommentsPanel.d.ts +14 -0
- package/dist/editor/CommentsPanel.js +68 -43
- package/dist/editor/Editor.d.ts +11 -5
- package/dist/editor/Editor.js +891 -218
- package/dist/editor/EditorAuthGate.d.ts +7 -1
- package/dist/editor/EditorAuthGate.js +41 -9
- package/dist/editor/EntryNavigator.d.ts +22 -0
- package/dist/editor/EntryNavigator.js +353 -105
- package/dist/editor/FormHeader.d.ts +25 -0
- package/dist/editor/FormHeader.js +82 -0
- package/dist/editor/FormRenderer.d.ts +27 -3
- package/dist/editor/FormRenderer.js +171 -76
- package/dist/editor/PreviewFrame.d.ts +40 -0
- package/dist/editor/PreviewFrame.js +215 -0
- package/dist/editor/PreviewPane.d.ts +47 -0
- package/dist/editor/PreviewPane.js +147 -0
- package/dist/editor/PreviewToolbarTools.d.ts +22 -0
- package/dist/editor/PreviewToolbarTools.js +73 -0
- package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
- package/dist/editor/admin/SystemHealthPanel.js +163 -33
- package/dist/editor/admin/useSystemHealth.d.ts +18 -0
- package/dist/editor/admin/useSystemHealth.js +70 -1
- package/dist/editor/branch-status.d.ts +17 -0
- package/dist/editor/branch-status.js +29 -0
- package/dist/editor/canopy-path.d.ts +9 -6
- package/dist/editor/canopy-path.js +8 -11
- package/dist/editor/client-reference-resolver.d.ts +43 -16
- package/dist/editor/client-reference-resolver.js +155 -64
- package/dist/editor/comments/BranchComments.d.ts +1 -1
- package/dist/editor/comments/BranchComments.js +2 -2
- package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
- package/dist/editor/comments/CloseRefusedNotice.js +7 -0
- package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
- package/dist/editor/comments/CommentThreadsPopover.js +274 -0
- package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
- package/dist/editor/comments/CommentWriteAlert.js +13 -0
- package/dist/editor/comments/EntryComments.d.ts +10 -4
- package/dist/editor/comments/EntryComments.js +14 -17
- package/dist/editor/comments/FieldWrapper.d.ts +18 -4
- package/dist/editor/comments/FieldWrapper.js +62 -28
- package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
- package/dist/editor/comments/InlineCommentThread.js +11 -47
- package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
- package/dist/editor/comments/ThreadCarousel.js +18 -21
- package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
- package/dist/editor/comments/ThreadReplyControls.js +92 -0
- package/dist/editor/comments/field-comment-context.d.ts +14 -0
- package/dist/editor/comments/field-comment-context.js +14 -0
- package/dist/editor/comments/form-comments.d.ts +48 -0
- package/dist/editor/comments/form-comments.js +178 -0
- package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
- package/dist/editor/comments/item-anchor-copy.js +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
- package/dist/editor/comments/popover-placement.d.ts +18 -0
- package/dist/editor/comments/popover-placement.js +58 -0
- package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
- package/dist/editor/comments/use-tracked-writes.js +53 -0
- package/dist/editor/components/BranchAccessList.d.ts +15 -0
- package/dist/editor/components/BranchAccessList.js +52 -0
- package/dist/editor/components/BranchLockBanner.d.ts +22 -0
- package/dist/editor/components/BranchLockBanner.js +39 -0
- package/dist/editor/components/BranchPill.d.ts +32 -0
- package/dist/editor/components/BranchPill.js +33 -0
- package/dist/editor/components/BranchesDrawer.d.ts +11 -0
- package/dist/editor/components/BranchesDrawer.js +5 -0
- package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
- package/dist/editor/components/ConfirmDeleteModal.js +3 -2
- package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
- package/dist/editor/components/DestructiveMenuItem.js +8 -0
- package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
- package/dist/editor/components/EditorCrashScreen.js +22 -0
- package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
- package/dist/editor/components/EditorErrorBoundary.js +40 -0
- package/dist/editor/components/EditorHeader.d.ts +56 -106
- package/dist/editor/components/EditorHeader.js +130 -131
- package/dist/editor/components/EditorRail.d.ts +49 -0
- package/dist/editor/components/EditorRail.js +65 -0
- package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
- package/dist/editor/components/EntryBreadcrumb.js +56 -0
- package/dist/editor/components/EntryCreateModal.d.ts +12 -7
- package/dist/editor/components/EntryCreateModal.js +51 -57
- package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
- package/dist/editor/components/NoEditPermissionNotice.js +5 -4
- package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
- package/dist/editor/components/QuickOpenPalette.js +66 -0
- package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
- package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
- package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
- package/dist/editor/components/ReasonedMenuItem.js +15 -0
- package/dist/editor/components/ReferencedByList.d.ts +11 -0
- package/dist/editor/components/ReferencedByList.js +28 -0
- package/dist/editor/components/RelativeTime.d.ts +10 -0
- package/dist/editor/components/RelativeTime.js +10 -0
- package/dist/editor/components/RenameEntryModal.d.ts +9 -1
- package/dist/editor/components/RenameEntryModal.js +19 -31
- package/dist/editor/components/RetryToastMessage.d.ts +9 -0
- package/dist/editor/components/RetryToastMessage.js +6 -0
- package/dist/editor/components/SaveAllResult.d.ts +25 -0
- package/dist/editor/components/SaveAllResult.js +86 -0
- package/dist/editor/components/SaveSplitButton.d.ts +30 -0
- package/dist/editor/components/SaveSplitButton.js +108 -0
- package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
- package/dist/editor/components/StagedChangesDrawer.js +92 -0
- package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
- package/dist/editor/components/UnavailableEntryNotice.js +9 -0
- package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
- package/dist/editor/components/UnavailableTypeMessage.js +9 -0
- package/dist/editor/components/UndoToastMessage.d.ts +18 -0
- package/dist/editor/components/UndoToastMessage.js +10 -0
- package/dist/editor/components/UserBadge.d.ts +2 -5
- package/dist/editor/components/UserBadge.js +62 -33
- package/dist/editor/components/ValidationSummary.d.ts +14 -0
- package/dist/editor/components/ValidationSummary.js +24 -0
- package/dist/editor/components/index.d.ts +2 -2
- package/dist/editor/components/index.js +2 -2
- package/dist/editor/context/ApiClientContext.d.ts +8 -2
- package/dist/editor/context/ApiClientContext.js +19 -8
- package/dist/editor/context/AssetContext.d.ts +13 -35
- package/dist/editor/context/AssetContext.js +12 -31
- package/dist/editor/context/EditorStateContext.d.ts +4 -4
- package/dist/editor/context/EditorStateContext.js +4 -4
- package/dist/editor/context/SWRProvider.d.ts +3 -3
- package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
- package/dist/editor/context/SiteMdxAllowContext.js +7 -0
- package/dist/editor/context/index.d.ts +2 -1
- package/dist/editor/context/index.js +2 -1
- package/dist/editor/contrast.d.ts +19 -0
- package/dist/editor/contrast.js +41 -0
- package/dist/editor/copy.d.ts +18 -0
- package/dist/editor/copy.js +18 -0
- package/dist/editor/editor-config.js +16 -0
- package/dist/editor/editor-utils.d.ts +34 -8
- package/dist/editor/editor-utils.js +42 -20
- package/dist/editor/entry-search.d.ts +20 -0
- package/dist/editor/entry-search.js +34 -0
- package/dist/editor/field-breadcrumb.d.ts +12 -0
- package/dist/editor/field-breadcrumb.js +85 -0
- package/dist/editor/field-props.d.ts +86 -0
- package/dist/editor/field-props.js +27 -0
- package/dist/editor/field-target.d.ts +30 -0
- package/dist/editor/field-target.js +77 -0
- package/dist/editor/fields/BlockField.d.ts +12 -0
- package/dist/editor/fields/BlockField.js +89 -73
- package/dist/editor/fields/CodeField.d.ts +2 -0
- package/dist/editor/fields/CodeField.js +6 -2
- package/dist/editor/fields/DateTimeField.d.ts +4 -29
- package/dist/editor/fields/DateTimeField.js +79 -41
- package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
- package/dist/editor/fields/ExpandAllButton.js +4 -0
- package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
- package/dist/editor/fields/FieldCrashFallback.js +30 -0
- package/dist/editor/fields/FieldLabel.d.ts +37 -0
- package/dist/editor/fields/FieldLabel.js +19 -0
- package/dist/editor/fields/ImageField.d.ts +4 -0
- package/dist/editor/fields/ImageField.js +29 -14
- package/dist/editor/fields/InlineGroupField.js +4 -3
- package/dist/editor/fields/ItemList.d.ts +42 -0
- package/dist/editor/fields/ItemList.js +130 -0
- package/dist/editor/fields/MarkdownField.d.ts +32 -0
- package/dist/editor/fields/MarkdownField.js +223 -46
- package/dist/editor/fields/MdxImageDialog.js +1 -1
- package/dist/editor/fields/NumberField.d.ts +2 -0
- package/dist/editor/fields/NumberField.js +8 -5
- package/dist/editor/fields/NumberListField.d.ts +2 -0
- package/dist/editor/fields/NumberListField.js +19 -16
- package/dist/editor/fields/ObjectField.d.ts +2 -7
- package/dist/editor/fields/ObjectField.js +15 -5
- package/dist/editor/fields/ObjectListField.d.ts +29 -0
- package/dist/editor/fields/ObjectListField.js +57 -0
- package/dist/editor/fields/ReferenceField.d.ts +2 -0
- package/dist/editor/fields/ReferenceField.js +34 -9
- package/dist/editor/fields/SelectField.d.ts +2 -0
- package/dist/editor/fields/SelectField.js +11 -2
- package/dist/editor/fields/StringListField.d.ts +4 -1
- package/dist/editor/fields/StringListField.js +22 -8
- package/dist/editor/fields/TextField.d.ts +2 -0
- package/dist/editor/fields/TextField.js +6 -2
- package/dist/editor/fields/ToggleField.d.ts +2 -0
- package/dist/editor/fields/ToggleField.js +8 -3
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
- package/dist/editor/fields/form-expansion.d.ts +9 -0
- package/dist/editor/fields/form-expansion.js +2 -0
- package/dist/editor/fields/item-expansion.d.ts +15 -0
- package/dist/editor/fields/item-expansion.js +60 -0
- package/dist/editor/fields/list-item-keys.d.ts +8 -0
- package/dist/editor/fields/list-item-keys.js +50 -0
- package/dist/editor/fields/list-item-title.d.ts +20 -0
- package/dist/editor/fields/list-item-title.js +85 -0
- package/dist/editor/fields/markdown-export-options.d.ts +2 -0
- package/dist/editor/fields/markdown-export-options.js +8 -0
- package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
- package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
- package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
- package/dist/editor/fields/mdx-jsx-support.js +157 -69
- package/dist/editor/fields/rich-text-failures.d.ts +5 -0
- package/dist/editor/fields/rich-text-failures.js +26 -0
- package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
- package/dist/editor/fields/toolbar-wrap.js +35 -0
- package/dist/editor/form-outline.d.ts +13 -0
- package/dist/editor/form-outline.js +70 -0
- package/dist/editor/group-manager/GroupCard.d.ts +4 -1
- package/dist/editor/group-manager/GroupCard.js +12 -3
- package/dist/editor/group-manager/GroupForm.js +1 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
- package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
- package/dist/editor/group-manager/MemberList.d.ts +2 -1
- package/dist/editor/group-manager/MemberList.js +15 -4
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
- package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
- package/dist/editor/group-manager/index.js +34 -5
- package/dist/editor/group-manager/types.d.ts +5 -2
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +54 -0
- package/dist/editor/hooks/save-all.d.ts +68 -0
- package/dist/editor/hooks/save-all.js +61 -0
- package/dist/editor/hooks/useBranchActions.d.ts +11 -1
- package/dist/editor/hooks/useBranchActions.js +42 -19
- package/dist/editor/hooks/useBranchManager.d.ts +21 -0
- package/dist/editor/hooks/useBranchManager.js +321 -125
- package/dist/editor/hooks/useBranchesData.d.ts +8 -4
- package/dist/editor/hooks/useBranchesData.js +9 -5
- package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
- package/dist/editor/hooks/useCommentSystem.js +79 -55
- package/dist/editor/hooks/useCommentsData.d.ts +11 -7
- package/dist/editor/hooks/useCommentsData.js +20 -19
- package/dist/editor/hooks/useDraftManager.d.ts +77 -3
- package/dist/editor/hooks/useDraftManager.js +887 -94
- package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
- package/dist/editor/hooks/useEditorLayout.js +98 -20
- package/dist/editor/hooks/useEntriesData.d.ts +2 -1
- package/dist/editor/hooks/useEntriesData.js +18 -4
- package/dist/editor/hooks/useEntryManager.d.ts +41 -2
- package/dist/editor/hooks/useEntryManager.js +227 -41
- package/dist/editor/hooks/useGroupManager.js +13 -16
- package/dist/editor/hooks/usePermissionManager.js +14 -6
- package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
- package/dist/editor/hooks/usePreviewMarks.js +33 -0
- package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
- package/dist/editor/hooks/useReferenceResolution.js +34 -177
- package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
- package/dist/editor/hooks/useSchemaManager.js +97 -39
- package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
- package/dist/editor/hooks/useUserMetadata.js +76 -47
- package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
- package/dist/editor/hooks/user-metadata-batcher.js +33 -0
- package/dist/editor/media/AssetCard.d.ts +6 -7
- package/dist/editor/media/AssetCard.js +24 -31
- package/dist/editor/media/AssetListRow.d.ts +16 -0
- package/dist/editor/media/AssetListRow.js +41 -0
- package/dist/editor/media/CropStep.js +6 -1
- package/dist/editor/media/MediaLibrary.d.ts +4 -3
- package/dist/editor/media/MediaLibrary.js +11 -4
- package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
- package/dist/editor/media/MediaLibraryBody.js +195 -80
- package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
- package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
- package/dist/editor/media/crop-math.d.ts +3 -4
- package/dist/editor/media/crop-math.js +11 -22
- package/dist/editor/media/editor-image-src.d.ts +8 -0
- package/dist/editor/media/editor-image-src.js +10 -0
- package/dist/editor/media/format-bytes.d.ts +2 -0
- package/dist/editor/media/format-bytes.js +23 -0
- package/dist/editor/media/media-library-prefs.d.ts +23 -0
- package/dist/editor/media/media-library-prefs.js +49 -0
- package/dist/editor/media/media-library-view.d.ts +34 -0
- package/dist/editor/media/media-library-view.js +40 -0
- package/dist/editor/media/useAssetLibrary.d.ts +30 -0
- package/dist/editor/media/useAssetLibrary.js +126 -0
- package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
- package/dist/editor/media/useStableAssetOrder.js +37 -0
- package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
- package/dist/editor/media/useThumbnailFailure.js +16 -0
- package/dist/editor/permission-manager/GroupSelector.js +2 -2
- package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
- package/dist/editor/permission-manager/PermissionEditor.js +15 -4
- package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.js +3 -3
- package/dist/editor/permission-manager/index.js +12 -3
- package/dist/editor/permission-manager/types.d.ts +5 -2
- package/dist/editor/platform.d.ts +3 -0
- package/dist/editor/platform.js +9 -0
- package/dist/editor/preview-asset-base.d.ts +9 -0
- package/dist/editor/preview-asset-base.js +17 -0
- package/dist/editor/preview-bridge.d.ts +51 -27
- package/dist/editor/preview-bridge.js +103 -144
- package/dist/editor/preview-marks.d.ts +15 -0
- package/dist/editor/preview-marks.js +74 -0
- package/dist/editor/preview-path.d.ts +12 -0
- package/dist/editor/preview-path.js +45 -1
- package/dist/editor/preview-scale.d.ts +27 -0
- package/dist/editor/preview-scale.js +34 -0
- package/dist/editor/raw-asset-base.d.ts +5 -0
- package/dist/editor/raw-asset-base.js +14 -0
- package/dist/editor/relative-time.d.ts +4 -4
- package/dist/editor/relative-time.js +16 -8
- package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
- package/dist/editor/schema-editor/CollectionEditor.js +361 -62
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
- package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
- package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
- package/dist/editor/schema-editor/collection-draft.js +40 -0
- package/dist/editor/schema-editor/index.d.ts +1 -1
- package/dist/editor/schema-label.d.ts +10 -0
- package/dist/editor/schema-label.js +17 -0
- package/dist/editor/settings-conflict.d.ts +5 -0
- package/dist/editor/settings-conflict.js +8 -0
- package/dist/editor/shell/ActivityRail.d.ts +37 -0
- package/dist/editor/shell/ActivityRail.js +91 -0
- package/dist/editor/shell/EditorShell.d.ts +17 -0
- package/dist/editor/shell/EditorShell.js +31 -0
- package/dist/editor/shell/PaneLayout.d.ts +28 -0
- package/dist/editor/shell/PaneLayout.js +116 -0
- package/dist/editor/shell/SidePanelHost.d.ts +35 -0
- package/dist/editor/shell/SidePanelHost.js +184 -0
- package/dist/editor/shell/TopBar.d.ts +12 -0
- package/dist/editor/shell/TopBar.js +14 -0
- package/dist/editor/shell/host-chrome.d.ts +16 -0
- package/dist/editor/shell/host-chrome.js +69 -0
- package/dist/editor/slug.d.ts +16 -0
- package/dist/editor/slug.js +43 -0
- package/dist/editor/theme.d.ts +2 -1
- package/dist/editor/theme.js +314 -13
- package/dist/editor/unanswered.d.ts +17 -0
- package/dist/editor/unanswered.js +26 -0
- package/dist/editor/unavailable-entry-type.d.ts +20 -0
- package/dist/editor/unavailable-entry-type.js +28 -0
- package/dist/editor/undo-removal.d.ts +57 -0
- package/dist/editor/undo-removal.js +163 -0
- package/dist/editor/user-display.d.ts +4 -0
- package/dist/editor/user-display.js +5 -0
- package/dist/editor/utils/confirm-modal.d.ts +8 -0
- package/dist/editor/utils/confirm-modal.js +12 -0
- package/dist/editor/utils/editor-errors.d.ts +19 -0
- package/dist/editor/utils/editor-errors.js +32 -0
- package/dist/editor/utils/focus-return.d.ts +56 -0
- package/dist/editor/utils/focus-return.js +106 -0
- package/dist/entry-link-resolver.d.ts +11 -1
- package/dist/entry-link-resolver.js +65 -5
- package/dist/entry-schema-registry.d.ts +3 -3
- package/dist/entry-schema-registry.js +7 -4
- package/dist/entry-schema.d.ts +49 -3
- package/dist/entry-schema.js +18 -0
- package/dist/git-manager.d.ts +172 -10
- package/dist/git-manager.js +449 -107
- package/dist/github-service.d.ts +39 -2
- package/dist/github-service.js +101 -7
- package/dist/http/handler.js +74 -9
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +9 -4
- package/dist/http/worker-not-ready.js +59 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/item-keys.d.ts +46 -0
- package/dist/item-keys.js +235 -0
- package/dist/operating-mode/editor-mode-check.d.ts +15 -0
- package/dist/operating-mode/editor-mode-check.js +24 -0
- package/dist/operating-mode/mode-env.d.ts +13 -14
- package/dist/operating-mode/mode-env.js +13 -14
- package/dist/operating-mode/types.d.ts +2 -2
- package/dist/paths/branch.d.ts +0 -1
- package/dist/paths/branch.js +1 -8
- package/dist/paths/index.d.ts +1 -1
- package/dist/paths/index.js +1 -1
- package/dist/paths/validation.js +0 -2
- package/dist/preview.d.ts +8 -0
- package/dist/preview.js +7 -0
- package/dist/reference-resolver.js +1 -0
- package/dist/resolve-canopy-user.d.ts +1 -1
- package/dist/resolve-canopy-user.js +1 -1
- package/dist/schema/meta-loader.d.ts +18 -8
- package/dist/schema/meta-loader.js +42 -9
- package/dist/schema/registry-fingerprint.d.ts +14 -0
- package/dist/schema/registry-fingerprint.js +63 -0
- package/dist/schema/resolver.d.ts +7 -4
- package/dist/schema/resolver.js +7 -6
- package/dist/schema/schema-store.d.ts +7 -10
- package/dist/schema/schema-store.js +13 -11
- package/dist/schema/schema-unavailable-error.d.ts +11 -0
- package/dist/schema/schema-unavailable-error.js +15 -0
- package/dist/schema/types.d.ts +22 -0
- package/dist/schema-registry-record.d.ts +35 -0
- package/dist/schema-registry-record.js +134 -0
- package/dist/server.d.ts +79 -9
- package/dist/server.js +62 -8
- package/dist/services.d.ts +33 -5
- package/dist/services.js +155 -37
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +159 -45
- package/dist/stamp-on-publish.d.ts +36 -0
- package/dist/stamp-on-publish.js +71 -0
- package/dist/static/index.d.ts +58 -5
- package/dist/static/index.js +133 -3
- package/dist/static/seo.d.ts +5 -5
- package/dist/static/seo.js +5 -5
- package/dist/submission-attribution.d.ts +8 -0
- package/dist/submission-attribution.js +22 -0
- package/dist/system-users.d.ts +12 -0
- package/dist/system-users.js +12 -0
- package/dist/task-queue/cms-task-queue.d.ts +1 -1
- package/dist/task-queue/cms-task-queue.js +1 -1
- package/dist/task-queue/index.d.ts +1 -1
- package/dist/task-queue/index.js +1 -1
- package/dist/task-queue/task-queue.d.ts +6 -0
- package/dist/task-queue/task-queue.js +29 -0
- package/dist/task-queue/worker-status.d.ts +35 -9
- package/dist/task-queue/worker-status.js +84 -17
- package/dist/types.d.ts +90 -9
- package/dist/url-collision.js +3 -3
- package/dist/url-exclusivity-fixtures.d.ts +8 -1
- package/dist/url-exclusivity-fixtures.js +11 -1
- package/dist/user.js +2 -1
- package/dist/utils/atomic-write.js +2 -1
- package/dist/utils/base-branch.d.ts +13 -0
- package/dist/utils/base-branch.js +23 -0
- package/dist/utils/content-serialize.d.ts +15 -7
- package/dist/utils/content-serialize.js +353 -51
- package/dist/utils/content-write-lock.d.ts +6 -1
- package/dist/utils/content-write-lock.js +21 -6
- package/dist/utils/debug.d.ts +1 -1
- package/dist/utils/debug.js +5 -3
- package/dist/utils/error.js +13 -2
- package/dist/utils/escape-text.d.ts +7 -0
- package/dist/utils/escape-text.js +27 -0
- package/dist/utils/fs.d.ts +12 -4
- package/dist/utils/fs.js +18 -5
- package/dist/utils/git.d.ts +21 -1
- package/dist/utils/git.js +63 -8
- package/dist/utils/json-source-splice.d.ts +14 -0
- package/dist/utils/json-source-splice.js +120 -0
- package/dist/utils/markdown-body-splice.d.ts +39 -0
- package/dist/utils/markdown-body-splice.js +421 -0
- package/dist/utils/occ-json-write.js +18 -12
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +32 -1
- package/dist/utils/provisioning-lock.js +78 -32
- package/dist/utils/sanitize-href.d.ts +9 -23
- package/dist/utils/sanitize-href.js +14 -28
- package/dist/utils/title-field.d.ts +10 -0
- package/dist/utils/title-field.js +47 -0
- package/dist/utils/yaml-source-splice.d.ts +58 -0
- package/dist/utils/yaml-source-splice.js +515 -0
- package/dist/validation/block-structural-keys.d.ts +1 -1
- package/dist/validation/block-structural-keys.js +1 -1
- package/dist/validation/deletion-checker.d.ts +21 -29
- package/dist/validation/deletion-checker.js +41 -117
- package/dist/validation/entry-validator.d.ts +6 -10
- package/dist/validation/entry-validator.js +19 -26
- package/dist/validation/field-traversal.d.ts +22 -0
- package/dist/validation/field-traversal.js +39 -8
- package/dist/validation/markdown-safety.d.ts +68 -0
- package/dist/validation/markdown-safety.js +596 -0
- package/dist/validation/mdx-allowlist.d.ts +55 -0
- package/dist/validation/mdx-allowlist.js +183 -0
- package/dist/validation/reference-validator.d.ts +2 -0
- package/dist/validation/reference-validator.js +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/branch-policy.d.ts +124 -0
- package/dist/worker/branch-policy.js +243 -0
- package/dist/worker/bundle-header.d.ts +117 -0
- package/dist/worker/bundle-header.js +253 -0
- package/dist/worker/cms-worker.d.ts +236 -142
- package/dist/worker/cms-worker.js +772 -285
- package/dist/worker/gateway-egress.d.ts +43 -0
- package/dist/worker/gateway-egress.js +209 -0
- package/dist/worker/gateway-instance.d.ts +42 -0
- package/dist/worker/gateway-instance.js +129 -0
- package/dist/worker/git-process.d.ts +81 -0
- package/dist/worker/git-process.js +234 -0
- package/dist/worker/git-sync.d.ts +34 -17
- package/dist/worker/git-sync.js +394 -131
- package/dist/worker/github-auth.d.ts +9 -9
- package/dist/worker/github-auth.js +13 -15
- package/dist/worker/github-gateway-http.d.ts +62 -0
- package/dist/worker/github-gateway-http.js +977 -0
- package/dist/worker/github-gateway-wire.d.ts +590 -0
- package/dist/worker/github-gateway-wire.js +488 -0
- package/dist/worker/github-gateway.d.ts +238 -0
- package/dist/worker/github-gateway.js +726 -0
- package/dist/worker/github-mirror-upkeep.d.ts +75 -0
- package/dist/worker/github-mirror-upkeep.js +266 -0
- package/dist/worker/github-mirror.d.ts +364 -0
- package/dist/worker/github-mirror.js +1030 -0
- package/dist/worker/github-transfer.d.ts +56 -0
- package/dist/worker/github-transfer.js +444 -0
- package/dist/worker/history-rewrite.d.ts +4 -5
- package/dist/worker/history-rewrite.js +12 -17
- package/dist/worker/provisioned-workspace.d.ts +5 -5
- package/dist/worker/provisioned-workspace.js +5 -5
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +58 -54
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +12 -0
- package/dist/worker/schema-gate.d.ts +49 -0
- package/dist/worker/schema-gate.js +226 -0
- package/dist/worker/self-checks.d.ts +107 -0
- package/dist/worker/self-checks.js +358 -0
- package/dist/worker/shared-repo-git.d.ts +96 -0
- package/dist/worker/shared-repo-git.js +459 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +136 -0
- package/dist/worker/stale-mirror.d.ts +82 -0
- package/dist/worker/stale-mirror.js +130 -0
- package/dist/worker/task-runner.d.ts +5 -3
- package/dist/worker/task-runner.js +287 -186
- package/dist/worker/worker-context.d.ts +36 -37
- package/package.json +35 -7
- package/dist/editor/EditorPanes.d.ts +0 -10
- package/dist/editor/EditorPanes.js +0 -98
- package/dist/editor/components/EditorFooter.d.ts +0 -11
- package/dist/editor/components/EditorFooter.js +0 -9
- package/dist/editor/components/EditorSidebar.d.ts +0 -67
- package/dist/editor/components/EditorSidebar.js +0 -22
|
@@ -1,10 +1,127 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useMemo, useRef,
|
|
4
|
-
import { ActionIcon, Badge, Box, Group, Loader, Menu, ScrollArea, Stack, Text, Tooltip, Tree, useTree, rem, } from '@mantine/core';
|
|
5
|
-
import { IconArrowDown, IconArrowUp, IconDots, IconEdit, IconFolderPlus, IconPlus, IconTrash, } from '@tabler/icons-react';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { ActionIcon, Badge, Box, Button, CloseButton, Group, Highlight, Loader, Menu, ScrollArea, Stack, Text, TextInput, Tooltip, Tree, useTree, rem, } from '@mantine/core';
|
|
5
|
+
import { IconArrowDown, IconAlertTriangle, IconArrowUp, IconDots, IconEdit, IconFolderPlus, IconLock, IconPlus, IconSearch, IconTrash, } from '@tabler/icons-react';
|
|
6
6
|
import { calculatePathToEntry } from './editor-utils.js';
|
|
7
|
-
|
|
7
|
+
import { matchesEntryQuery } from './entry-search.js';
|
|
8
|
+
import { DestructiveMenuItem } from './components/DestructiveMenuItem.js';
|
|
9
|
+
import { ReasonedMenuItem } from './components/ReasonedMenuItem.js';
|
|
10
|
+
import { UnavailableTypeMessage } from './components/UnavailableTypeMessage.js';
|
|
11
|
+
const UnavailableTypeRow = ({ schemaRefs }) => (_jsxs(Group, { gap: 6, wrap: "nowrap", align: "flex-start", mt: 4, "data-testid": "unavailable-type-message", children: [_jsx(Box, { c: "orange", style: { display: 'flex', flexShrink: 0, paddingTop: 2 }, children: _jsx(IconAlertTriangle, { size: 14, "aria-hidden": true }) }), _jsx(Text, { size: "xs", c: "orange", children: _jsx(UnavailableTypeMessage, { schemaRefs: schemaRefs }) })] }));
|
|
12
|
+
/** Where path rules refuse new entries, one line says so in place of the "…" menus they hide. */
|
|
13
|
+
const AddRefusedRow = () => (_jsx(Text, { size: "xs", c: "dimmed", mt: 4, "data-testid": "add-refused-message", children: "You can't add entries here." }));
|
|
14
|
+
const lastSegment = (path) => path.split('/').filter(Boolean).pop() ?? path;
|
|
15
|
+
/** A collection's node value; a single-entry collection's node is its entry. */
|
|
16
|
+
const collectionNodeValue = (nodes, path) => {
|
|
17
|
+
for (const node of nodes) {
|
|
18
|
+
if (node.value === `collection:${path}` || node.nodeProps?.collectionPath === path) {
|
|
19
|
+
return node.value;
|
|
20
|
+
}
|
|
21
|
+
const inner = node.children && collectionNodeValue(node.children, path);
|
|
22
|
+
if (inner)
|
|
23
|
+
return inner;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
};
|
|
27
|
+
/** The collection values below `nodes` that have children, as an all-expanded state. */
|
|
28
|
+
const expandedStateFor = (nodes, acc = {}) => {
|
|
29
|
+
for (const node of nodes) {
|
|
30
|
+
if (node.children?.length) {
|
|
31
|
+
acc[node.value] = true;
|
|
32
|
+
expandedStateFor(node.children, acc);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return acc;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The nodes of `nodes` that match `query`. An entry matches on label or slug; a collection whose
|
|
39
|
+
* label matches keeps its whole subtree, and any other collection survives only with its matching
|
|
40
|
+
* descendants. Nodes keep the position data (`childIndex`, `totalChildrenCount`) of the full tree.
|
|
41
|
+
*/
|
|
42
|
+
const filterTree = (nodes, query) => {
|
|
43
|
+
const kept = [];
|
|
44
|
+
for (const node of nodes) {
|
|
45
|
+
const label = String(node.label ?? '');
|
|
46
|
+
if (node.nodeProps?.isEntry) {
|
|
47
|
+
if (matchesEntryQuery({ label, slug: node.nodeProps.slug }, query)) {
|
|
48
|
+
kept.push(node);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (matchesEntryQuery({ label }, query)) {
|
|
52
|
+
kept.push(node);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const children = filterTree(node.children ?? [], query);
|
|
56
|
+
if (children.length > 0)
|
|
57
|
+
kept.push({ ...node, children });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return kept;
|
|
61
|
+
};
|
|
62
|
+
/** The first entry in tree order that matches `query`, else the first entry of any kind. */
|
|
63
|
+
const firstEntryPath = (nodes, query) => {
|
|
64
|
+
const entries = [];
|
|
65
|
+
const walk = (list) => {
|
|
66
|
+
for (const node of list) {
|
|
67
|
+
if (node.nodeProps?.isEntry)
|
|
68
|
+
entries.push(node);
|
|
69
|
+
else
|
|
70
|
+
walk(node.children ?? []);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
walk(nodes);
|
|
74
|
+
const match = entries.find((node) => matchesEntryQuery({ label: String(node.label ?? ''), slug: node.nodeProps?.slug }, query));
|
|
75
|
+
return (match ?? entries[0])?.value;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* A row's title, truncated with an ellipsis. Its full text shows in a tooltip, and only while the
|
|
79
|
+
* text is cut: the width is measured when the pointer or focus enters the row, not on every render.
|
|
80
|
+
*/
|
|
81
|
+
const TruncatedLabel = ({ label, highlight, fw, }) => {
|
|
82
|
+
const elementRef = useRef(null);
|
|
83
|
+
const [truncated, setTruncated] = useState(false);
|
|
84
|
+
const setElement = useCallback((node) => {
|
|
85
|
+
elementRef.current = node;
|
|
86
|
+
}, []);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const row = elementRef.current?.closest('[data-nav-row]');
|
|
89
|
+
if (!row)
|
|
90
|
+
return;
|
|
91
|
+
// Read at measure time: the label swaps between Text and Highlight as a filter starts and stops.
|
|
92
|
+
const measure = () => {
|
|
93
|
+
const element = elementRef.current;
|
|
94
|
+
setTruncated(!!element && element.scrollWidth > element.clientWidth);
|
|
95
|
+
};
|
|
96
|
+
row.addEventListener('mouseenter', measure);
|
|
97
|
+
row.addEventListener('focusin', measure);
|
|
98
|
+
return () => {
|
|
99
|
+
row.removeEventListener('mouseenter', measure);
|
|
100
|
+
row.removeEventListener('focusin', measure);
|
|
101
|
+
};
|
|
102
|
+
}, []);
|
|
103
|
+
return (_jsx(Tooltip, { label: label, openDelay: 400, withinPortal: true, disabled: !truncated, children: highlight ? (_jsx(Highlight, { ref: setElement, highlight: highlight, size: "sm", fw: fw, truncate: "end", style: { minWidth: 0 }, children: label })) : (_jsx(Text, { ref: setElement, size: "sm", fw: fw, truncate: "end", style: { minWidth: 0 }, children: label })) }));
|
|
104
|
+
};
|
|
105
|
+
/** The keys Mantine's tree acts on, matched as it matches them, by `code`. */
|
|
106
|
+
const TREE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space']);
|
|
107
|
+
/**
|
|
108
|
+
* A row menu's dropdown is portaled, but React still bubbles its key events to the row, where the
|
|
109
|
+
* tree's arrow keys would take focus out of the open menu. Only those keys stop: React's
|
|
110
|
+
* stopPropagation stops the native event too, and every other key must still reach the document,
|
|
111
|
+
* where the Mod+P shortcut and the focus traps' Tab handling listen.
|
|
112
|
+
*/
|
|
113
|
+
const stopTreeKeys = (event) => {
|
|
114
|
+
if (TREE_KEYS.has(event.nativeEvent.code))
|
|
115
|
+
event.stopPropagation();
|
|
116
|
+
};
|
|
117
|
+
const UnsavedDot = ({ label }) => (_jsx(Tooltip, { label: label, withinPortal: true, children: _jsx(Box, { component: "span", role: "img", "aria-label": label, "data-testid": "unsaved-dot", style: {
|
|
118
|
+
flexShrink: 0,
|
|
119
|
+
width: 8,
|
|
120
|
+
height: 8,
|
|
121
|
+
borderRadius: '50%',
|
|
122
|
+
backgroundColor: 'var(--mantine-color-brand-6)',
|
|
123
|
+
} }) }));
|
|
124
|
+
export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onTreeControllerReady, expandedStateRef, onExpandedStateChange, onDeleteEntry: onDeleteEntryProp, onRenameEntry: onRenameEntryProp, onReorderEntry: onReorderEntryProp, hiddenRootPath, loading, readOnly = false, dirtyPaths, revealCollection, onRevealed, }) => {
|
|
8
125
|
// Shadow the entry-mutation callbacks with undefined when readOnly, so every
|
|
9
126
|
// downstream reference (hasEntryMenu, canReorder, the menu items themselves)
|
|
10
127
|
// sees them as absent rather than threading a readOnly check through each
|
|
@@ -16,7 +133,32 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
16
133
|
const hasScrolledRef = useRef(false);
|
|
17
134
|
// Track expanded state synchronously to avoid race conditions on unmount
|
|
18
135
|
const localExpandedStateRef = useRef(expandedStateRef?.current ?? {});
|
|
136
|
+
const [query, setQuery] = useState('');
|
|
137
|
+
const filterInputRef = useRef(null);
|
|
138
|
+
const filtering = query.trim() !== '';
|
|
139
|
+
// Read from the tree's expand/collapse callbacks, which fire from state updaters.
|
|
140
|
+
const filteringRef = useRef(false);
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
filteringRef.current = filtering;
|
|
143
|
+
}, [filtering]);
|
|
19
144
|
const treeData = useMemo(() => {
|
|
145
|
+
const entryNode = (entry, parent, childIndex, totalChildren) => ({
|
|
146
|
+
value: entry.path,
|
|
147
|
+
label: entry.label,
|
|
148
|
+
nodeProps: {
|
|
149
|
+
status: entry.status,
|
|
150
|
+
isEntry: true,
|
|
151
|
+
entryPath: entry.path,
|
|
152
|
+
slug: entry.slug ?? lastSegment(entry.path),
|
|
153
|
+
contentId: entry.contentId,
|
|
154
|
+
conflictNotice: entry.conflictNotice,
|
|
155
|
+
unavailable: entry.unavailable,
|
|
156
|
+
itemReadOnly: entry.readOnly,
|
|
157
|
+
parentCollectionPath: parent.path,
|
|
158
|
+
childIndex,
|
|
159
|
+
totalChildrenCount: totalChildren,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
20
162
|
if (collections?.length) {
|
|
21
163
|
const toTree = (col) => {
|
|
22
164
|
if (col.type === 'entry') {
|
|
@@ -28,6 +170,9 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
28
170
|
status: entry?.status,
|
|
29
171
|
isEntry: true,
|
|
30
172
|
entryPath: entry?.path,
|
|
173
|
+
collectionPath: col.path,
|
|
174
|
+
slug: entry ? (entry.slug ?? lastSegment(entry.path)) : undefined,
|
|
175
|
+
itemReadOnly: entry?.readOnly,
|
|
31
176
|
},
|
|
32
177
|
children: [],
|
|
33
178
|
};
|
|
@@ -38,51 +183,39 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
38
183
|
const order = col.order ?? [];
|
|
39
184
|
const entryNodesByContentId = new Map();
|
|
40
185
|
entries.forEach((entry) => {
|
|
41
|
-
const node = {
|
|
42
|
-
value: entry.path,
|
|
43
|
-
label: entry.label,
|
|
44
|
-
nodeProps: {
|
|
45
|
-
status: entry.status,
|
|
46
|
-
isEntry: true,
|
|
47
|
-
entryPath: entry.path,
|
|
48
|
-
contentId: entry.contentId,
|
|
49
|
-
conflictNotice: entry.conflictNotice,
|
|
50
|
-
parentCollectionPath: col.path,
|
|
51
|
-
childIndex: 0, // Will be set below
|
|
52
|
-
totalChildrenCount: totalChildren,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
186
|
if (entry.contentId) {
|
|
56
|
-
entryNodesByContentId.set(entry.contentId,
|
|
187
|
+
entryNodesByContentId.set(entry.contentId, entryNode(entry, col, 0, totalChildren));
|
|
57
188
|
}
|
|
58
189
|
});
|
|
59
|
-
const
|
|
60
|
-
childCollections.forEach((child) => {
|
|
190
|
+
const withPosition = (child, childIndex) => {
|
|
61
191
|
const childTree = toTree(child);
|
|
62
|
-
|
|
192
|
+
return {
|
|
63
193
|
...childTree,
|
|
64
194
|
nodeProps: {
|
|
65
195
|
...childTree.nodeProps,
|
|
66
196
|
contentId: child.contentId,
|
|
67
197
|
parentCollectionPath: col.path,
|
|
68
|
-
childIndex
|
|
198
|
+
childIndex,
|
|
69
199
|
totalChildrenCount: totalChildren,
|
|
70
200
|
},
|
|
71
201
|
};
|
|
202
|
+
};
|
|
203
|
+
const childNodesByContentId = new Map();
|
|
204
|
+
childCollections.forEach((child) => {
|
|
72
205
|
if (child.contentId) {
|
|
73
|
-
childNodesByContentId.set(child.contentId,
|
|
206
|
+
childNodesByContentId.set(child.contentId, withPosition(child, 0));
|
|
74
207
|
}
|
|
75
208
|
});
|
|
76
209
|
const allChildren = [];
|
|
77
210
|
const usedContentIds = new Set();
|
|
78
211
|
for (const contentId of order) {
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
...
|
|
212
|
+
const orderedEntry = entryNodesByContentId.get(contentId);
|
|
213
|
+
if (orderedEntry) {
|
|
214
|
+
orderedEntry.nodeProps = {
|
|
215
|
+
...orderedEntry.nodeProps,
|
|
83
216
|
childIndex: allChildren.length,
|
|
84
217
|
};
|
|
85
|
-
allChildren.push(
|
|
218
|
+
allChildren.push(orderedEntry);
|
|
86
219
|
usedContentIds.add(contentId);
|
|
87
220
|
continue;
|
|
88
221
|
}
|
|
@@ -100,38 +233,13 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
100
233
|
.filter((e) => !e.contentId || !usedContentIds.has(e.contentId))
|
|
101
234
|
.sort((a, b) => (a.label ?? '').localeCompare(b.label ?? ''));
|
|
102
235
|
for (const entry of unorderedEntries) {
|
|
103
|
-
|
|
104
|
-
value: entry.path,
|
|
105
|
-
label: entry.label,
|
|
106
|
-
nodeProps: {
|
|
107
|
-
status: entry.status,
|
|
108
|
-
isEntry: true,
|
|
109
|
-
entryPath: entry.path,
|
|
110
|
-
contentId: entry.contentId,
|
|
111
|
-
conflictNotice: entry.conflictNotice,
|
|
112
|
-
parentCollectionPath: col.path,
|
|
113
|
-
childIndex: allChildren.length,
|
|
114
|
-
totalChildrenCount: totalChildren,
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
allChildren.push(node);
|
|
236
|
+
allChildren.push(entryNode(entry, col, allChildren.length, totalChildren));
|
|
118
237
|
}
|
|
119
238
|
const unorderedChildren = childCollections
|
|
120
239
|
.filter((c) => !c.contentId || !usedContentIds.has(c.contentId))
|
|
121
240
|
.sort((a, b) => (a.label ?? '').localeCompare(b.label ?? ''));
|
|
122
241
|
for (const child of unorderedChildren) {
|
|
123
|
-
|
|
124
|
-
const node = {
|
|
125
|
-
...childTree,
|
|
126
|
-
nodeProps: {
|
|
127
|
-
...childTree.nodeProps,
|
|
128
|
-
contentId: child.contentId,
|
|
129
|
-
parentCollectionPath: col.path,
|
|
130
|
-
childIndex: allChildren.length,
|
|
131
|
-
totalChildrenCount: totalChildren,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
allChildren.push(node);
|
|
242
|
+
allChildren.push(withPosition(child, allChildren.length));
|
|
135
243
|
}
|
|
136
244
|
// Collections should always have children array (even if empty) to show chevron
|
|
137
245
|
// This matches standard file tree UI behavior where folders always show expand/collapse
|
|
@@ -143,6 +251,8 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
143
251
|
type: col.type,
|
|
144
252
|
collectionPath: col.path,
|
|
145
253
|
conflictNotice: col.conflictNotice,
|
|
254
|
+
unavailableSchemaRefs: col.unavailableSchemaRefs,
|
|
255
|
+
addRefused: col.addRefused,
|
|
146
256
|
onAdd: col.onAdd,
|
|
147
257
|
onEdit: col.onEdit,
|
|
148
258
|
onAddSubCollection: col.onAddSubCollection,
|
|
@@ -163,12 +273,56 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
163
273
|
return flatItems.map((item) => ({
|
|
164
274
|
value: item.path,
|
|
165
275
|
label: item.label,
|
|
166
|
-
nodeProps: {
|
|
276
|
+
nodeProps: {
|
|
277
|
+
status: item.status,
|
|
278
|
+
isEntry: true,
|
|
279
|
+
entryPath: item.path,
|
|
280
|
+
slug: item.slug ?? lastSegment(item.path),
|
|
281
|
+
itemReadOnly: item.readOnly,
|
|
282
|
+
},
|
|
167
283
|
}));
|
|
168
284
|
}, [collections, items, hiddenRootPath]);
|
|
285
|
+
// Filtered from the finished tree, so each node keeps its position in the whole collection and
|
|
286
|
+
// Move up / Move down stay correct while a filter is on.
|
|
287
|
+
const filteredTree = useMemo(() => (filtering ? filterTree(treeData, query) : treeData), [filtering, treeData, query]);
|
|
288
|
+
// Collections that hold an entry with unsaved changes, found over the whole tree so a filter
|
|
289
|
+
// never hides the reason for a dot.
|
|
290
|
+
const dirtyCollections = useMemo(() => {
|
|
291
|
+
const dirty = new Set();
|
|
292
|
+
if (!dirtyPaths?.size)
|
|
293
|
+
return dirty;
|
|
294
|
+
const walk = (nodes) => {
|
|
295
|
+
let any = false;
|
|
296
|
+
for (const node of nodes) {
|
|
297
|
+
if (node.nodeProps?.isEntry) {
|
|
298
|
+
if (dirtyPaths.has(node.value))
|
|
299
|
+
any = true;
|
|
300
|
+
}
|
|
301
|
+
else if (walk(node.children ?? [])) {
|
|
302
|
+
dirty.add(node.value);
|
|
303
|
+
any = true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return any;
|
|
307
|
+
};
|
|
308
|
+
walk(treeData);
|
|
309
|
+
return dirty;
|
|
310
|
+
}, [treeData, dirtyPaths]);
|
|
311
|
+
// The hidden root's own row never renders, so its message is shown once above the tree.
|
|
312
|
+
const hiddenRootAddRefused = !readOnly &&
|
|
313
|
+
!!hiddenRootPath &&
|
|
314
|
+
collections?.length === 1 &&
|
|
315
|
+
collections[0].path === hiddenRootPath &&
|
|
316
|
+
!!collections[0].addRefused;
|
|
317
|
+
const hiddenRootUnavailableRefs = hiddenRootPath && collections?.length === 1 && collections[0].path === hiddenRootPath
|
|
318
|
+
? collections[0].unavailableSchemaRefs
|
|
319
|
+
: undefined;
|
|
169
320
|
const tree = useTree({
|
|
170
321
|
initialExpandedState: expandedStateRef?.current ?? {},
|
|
322
|
+
// A filter expands and collapses nodes only for as long as it is on, so none of it is saved.
|
|
171
323
|
onNodeExpand: (value) => {
|
|
324
|
+
if (filteringRef.current)
|
|
325
|
+
return;
|
|
172
326
|
localExpandedStateRef.current = {
|
|
173
327
|
...localExpandedStateRef.current,
|
|
174
328
|
[value]: true,
|
|
@@ -176,6 +330,8 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
176
330
|
onExpandedStateChange?.(localExpandedStateRef.current);
|
|
177
331
|
},
|
|
178
332
|
onNodeCollapse: (value) => {
|
|
333
|
+
if (filteringRef.current)
|
|
334
|
+
return;
|
|
179
335
|
localExpandedStateRef.current = {
|
|
180
336
|
...localExpandedStateRef.current,
|
|
181
337
|
[value]: false,
|
|
@@ -194,8 +350,26 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
194
350
|
};
|
|
195
351
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
196
352
|
}, []);
|
|
353
|
+
// The expanded state from before the filter started, put back exactly when it clears. The tree
|
|
354
|
+
// drops the state of nodes it no longer renders, so it cannot be recovered from the tree itself.
|
|
355
|
+
const expandedBeforeFilterRef = useRef(null);
|
|
197
356
|
useEffect(() => {
|
|
198
|
-
if (
|
|
357
|
+
if (filtering) {
|
|
358
|
+
expandedBeforeFilterRef.current ??= tree.expandedState;
|
|
359
|
+
tree.setExpandedState(expandedStateFor(filteredTree));
|
|
360
|
+
}
|
|
361
|
+
else if (expandedBeforeFilterRef.current) {
|
|
362
|
+
// Plus the ancestors of an entry picked while filtering, so it stays in view.
|
|
363
|
+
tree.setExpandedState({
|
|
364
|
+
...expandedBeforeFilterRef.current,
|
|
365
|
+
...calculatePathToEntry(selectedPath, treeData),
|
|
366
|
+
});
|
|
367
|
+
expandedBeforeFilterRef.current = null;
|
|
368
|
+
}
|
|
369
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- runs when the filter or the filtered tree changes; `tree` is a fresh object each render
|
|
370
|
+
}, [filtering, filteredTree]);
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
if (!selectedPath || !treeData || filtering)
|
|
199
373
|
return;
|
|
200
374
|
const savedState = expandedStateRef?.current ?? {};
|
|
201
375
|
const pathToEntry = calculatePathToEntry(selectedPath, treeData);
|
|
@@ -228,7 +402,65 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
228
402
|
useEffect(() => {
|
|
229
403
|
hasScrolledRef.current = false;
|
|
230
404
|
}, []);
|
|
231
|
-
const
|
|
405
|
+
const treeBoxRef = useRef(null);
|
|
406
|
+
const servedRevealRef = useRef();
|
|
407
|
+
// Runs again as the filter clears and the expansion lands, then focuses the row a frame later.
|
|
408
|
+
useEffect(() => {
|
|
409
|
+
if (!revealCollection || !treeData || servedRevealRef.current === revealCollection.seq)
|
|
410
|
+
return;
|
|
411
|
+
const served = () => {
|
|
412
|
+
servedRevealRef.current = revealCollection.seq;
|
|
413
|
+
onRevealed?.();
|
|
414
|
+
};
|
|
415
|
+
if (query) {
|
|
416
|
+
setQuery('');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const value = collectionNodeValue(treeData, revealCollection.path);
|
|
420
|
+
if (!value) {
|
|
421
|
+
served();
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const wanted = { ...calculatePathToEntry(value, treeData), [value]: true };
|
|
425
|
+
if (Object.keys(wanted).some((key) => !tree.expandedState[key])) {
|
|
426
|
+
const next = { ...tree.expandedState, ...wanted };
|
|
427
|
+
tree.setExpandedState(next);
|
|
428
|
+
localExpandedStateRef.current = next;
|
|
429
|
+
onExpandedStateChange?.(next);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const frame = requestAnimationFrame(() => {
|
|
433
|
+
const row = Array.from(treeBoxRef.current?.querySelectorAll('[role="treeitem"]') ?? []).find((item) => item.dataset.value === value);
|
|
434
|
+
row?.scrollIntoView({ block: 'nearest' });
|
|
435
|
+
row?.focus();
|
|
436
|
+
served();
|
|
437
|
+
});
|
|
438
|
+
return () => cancelAnimationFrame(frame);
|
|
439
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- `tree` and the callbacks are fresh each render
|
|
440
|
+
}, [revealCollection, treeData, query, tree.expandedState]);
|
|
441
|
+
const clearFilter = () => {
|
|
442
|
+
setQuery('');
|
|
443
|
+
filterInputRef.current?.focus();
|
|
444
|
+
};
|
|
445
|
+
const handleFilterKeyDown = (event) => {
|
|
446
|
+
// Enter and Escape during IME composition commit or cancel the composition, nothing more.
|
|
447
|
+
if (event.nativeEvent.isComposing)
|
|
448
|
+
return;
|
|
449
|
+
if (event.key === 'Escape' && query) {
|
|
450
|
+
// Clears the filter and nothing else: the surrounding drawer stays open.
|
|
451
|
+
event.preventDefault();
|
|
452
|
+
event.stopPropagation();
|
|
453
|
+
setQuery('');
|
|
454
|
+
}
|
|
455
|
+
else if (event.key === 'Enter' && filtering) {
|
|
456
|
+
const path = firstEntryPath(filteredTree, query);
|
|
457
|
+
if (path) {
|
|
458
|
+
event.preventDefault();
|
|
459
|
+
onSelect(path);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
const Chevron = ({ expanded, visible }) => (_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", style: { flexShrink: 0, opacity: visible ? 0.9 : 0 }, children: expanded ? (_jsx("path", { d: "M7.41 8.59 12 13.17 16.59 8.59 18 10l-6 6-6-6z" })) : (_jsx("path", { d: "M10 6 8.59 7.41 13.17 12 8.59 16.59 10 18l6-6z" })) }));
|
|
232
464
|
const renderNode = ({ node, elementProps, hasChildren, expanded, level, }) => {
|
|
233
465
|
const status = node.nodeProps?.status;
|
|
234
466
|
// Collection-level mutation callbacks are nulled when readOnly, same as
|
|
@@ -248,8 +480,13 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
248
480
|
const isCollection = node.nodeProps?.isCollection;
|
|
249
481
|
const isEntry = node.nodeProps?.isEntry;
|
|
250
482
|
const conflictNotice = node.nodeProps?.conflictNotice;
|
|
483
|
+
const unavailableSchemaRefs = node.nodeProps?.unavailableSchemaRefs;
|
|
484
|
+
// A read-only navigator already says so once, in the branch banner.
|
|
485
|
+
const addRefused = !readOnly && !!node.nodeProps?.addRefused;
|
|
251
486
|
const isLeaf = !hasChildren || isEntry;
|
|
252
487
|
const selected = node.value === selectedPath;
|
|
488
|
+
const label = String(node.label ?? '');
|
|
489
|
+
const testIdSuffix = label.toLowerCase().replace(/\s+/g, '-');
|
|
253
490
|
// For collections, always show chevron (even if empty) to match standard tree UI
|
|
254
491
|
// Mantine only provides hasChildren=true if children.length > 0, but we want
|
|
255
492
|
// collections to always be expandable
|
|
@@ -259,10 +496,21 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
259
496
|
const canMoveDown = canReorder && typeof totalChildrenCount === 'number' && childIndex < totalChildrenCount - 1;
|
|
260
497
|
// Collections show menu for add/edit/delete actions OR for reordering (subcollections)
|
|
261
498
|
const hasCollectionMenu = isCollection && (onAdd || onEdit || onAddSubCollection || onDelete || canReorder);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
499
|
+
// An unavailable entry cannot be written, so its menu (rename, delete, reorder) is not offered.
|
|
500
|
+
const entryUnavailable = node.nodeProps?.unavailable;
|
|
501
|
+
// The same holds for an entry this user may not edit. A read-only navigator already says so
|
|
502
|
+
// once, in the branch banner, so only a lone read-only entry gets its own lock.
|
|
503
|
+
const entryLocked = !readOnly && !!node.nodeProps?.itemReadOnly;
|
|
504
|
+
const hasEntryMenu = isEntry &&
|
|
505
|
+
entryPath &&
|
|
506
|
+
!entryUnavailable &&
|
|
507
|
+
!entryLocked &&
|
|
508
|
+
(onDeleteEntry || onRenameEntry || onReorderEntry);
|
|
509
|
+
const showEntryDirtyDot = isEntry && !!entryPath && !!dirtyPaths?.has(entryPath);
|
|
510
|
+
const showCollectionDirtyDot = !isEntry && dirtyCollections.has(node.value);
|
|
511
|
+
const adminItems = onAddSubCollection || onEdit || onDelete;
|
|
512
|
+
const hasCollectionContentItems = onAdd || canReorder;
|
|
513
|
+
return (_jsxs(Box, { ...elementProps, ref: selected ? selectedNodeRef : undefined, "data-nav-row": true, "data-testid": `entry-nav-item-${testIdSuffix}`, onClick: (event) => {
|
|
266
514
|
elementProps.onClick(event);
|
|
267
515
|
if (isLeaf && isEntry) {
|
|
268
516
|
onSelect(node.value);
|
|
@@ -274,49 +522,49 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
|
|
|
274
522
|
paddingInline: 10,
|
|
275
523
|
paddingBlock: 6,
|
|
276
524
|
paddingLeft: `calc(${rem(8)} + ${rem(level * 12)})`,
|
|
277
|
-
backgroundColor: selected ? 'var(--mantine-color-
|
|
278
|
-
|
|
525
|
+
backgroundColor: selected ? 'var(--mantine-primary-color-light)' : undefined,
|
|
526
|
+
color: selected ? 'var(--mantine-primary-color-light-color)' : undefined,
|
|
527
|
+
border: selected
|
|
528
|
+
? '1px solid var(--mantine-primary-color-light-color)'
|
|
529
|
+
: '1px solid transparent',
|
|
279
530
|
transition: 'background-color 120ms ease, border-color 120ms ease',
|
|
280
|
-
}, children: _jsxs(Group, { gap: "xs", justify: "space-between", wrap: "nowrap", children: [_jsxs(Group, { gap: 6, wrap: "nowrap", children: [_jsx(Box, { w: 18, h: 18, style: {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
event.stopPropagation();
|
|
317
|
-
onDeleteEntry(entryPath);
|
|
318
|
-
}, "data-testid": "delete-entry-menu-item", children: "Delete Entry" }))] })] }))] })] }) }));
|
|
531
|
+
}, children: [_jsxs(Group, { gap: "xs", justify: "space-between", wrap: "nowrap", style: { width: '100%' }, children: [_jsxs(Group, { gap: 6, wrap: "nowrap", style: { flex: 1, minWidth: 0 }, children: [_jsx(Box, { w: 18, h: 18, style: {
|
|
532
|
+
display: 'flex',
|
|
533
|
+
flexShrink: 0,
|
|
534
|
+
alignItems: 'center',
|
|
535
|
+
justifyContent: 'center',
|
|
536
|
+
}, children: _jsx(Chevron, { expanded: expanded, visible: showChevron }) }), _jsx(TruncatedLabel, { label: label, highlight: filtering ? query.trim() : '', fw: selected ? 600 : 500 }), showEntryDirtyDot && _jsx(UnsavedDot, { label: "Unsaved changes" }), showCollectionDirtyDot && _jsx(UnsavedDot, { label: "Contains unsaved changes" }), status && (_jsx(Badge, { size: "xs", variant: "light", color: "gray", style: { flexShrink: 0, maxWidth: 96 }, children: status })), conflictNotice && (_jsx(Tooltip, { label: "This content was updated on the base branch \u2014 a reviewer will reconcile", withArrow: true, children: _jsx(Badge, { size: "xs", variant: "light", color: "orange", "data-testid": "conflict-badge", style: { flexShrink: 0 }, children: "Conflict" }) })), entryLocked && (_jsx(Tooltip, { label: "You can't edit this entry", withinPortal: true, children: _jsx(Box, { component: "span", role: "img", "aria-label": "You can't edit this entry", "data-testid": "entry-lock", c: "dimmed", style: { display: 'inline-flex', flexShrink: 0 }, children: _jsx(IconLock, { size: 14, "aria-hidden": true }) }) }))] }), _jsxs(Group, { gap: 4, wrap: "nowrap", style: { flexShrink: 0 }, children: [hasCollectionMenu && (_jsxs(Menu, { shadow: "md", width: 200, withinPortal: true, position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { size: "xs", variant: "subtle", color: "gray", onClick: (event) => event.stopPropagation(), "aria-label": "Collection actions", "data-testid": `collection-menu-${testIdSuffix}`, children: _jsx(IconDots, { size: 14 }) }) }), _jsxs(Menu.Dropdown, { onKeyDown: stopTreeKeys, children: [onAdd && (_jsx(Menu.Item, { leftSection: _jsx(IconPlus, { size: 14 }), onClick: (event) => {
|
|
537
|
+
event.stopPropagation();
|
|
538
|
+
onAdd();
|
|
539
|
+
}, "data-testid": "add-entry-menu-item", children: "Add entry\u2026" })), canReorder && (_jsxs(_Fragment, { children: [_jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowUp, { size: 14 }), blockedReason: canMoveUp ? undefined : 'Already first', onClick: (event) => {
|
|
540
|
+
event.stopPropagation();
|
|
541
|
+
onReorderEntry?.(parentCollectionPath, contentId, 'up');
|
|
542
|
+
}, children: "Move up" }), _jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowDown, { size: 14 }), blockedReason: canMoveDown ? undefined : 'Already last', onClick: (event) => {
|
|
543
|
+
event.stopPropagation();
|
|
544
|
+
onReorderEntry?.(parentCollectionPath, contentId, 'down');
|
|
545
|
+
}, children: "Move down" })] })), adminItems && (_jsxs(_Fragment, { children: [hasCollectionContentItems && _jsx(Menu.Divider, {}), _jsx(Menu.Label, { children: "Admin" })] })), onAddSubCollection && (_jsx(Menu.Item, { leftSection: _jsx(IconFolderPlus, { size: 14 }), onClick: (event) => {
|
|
546
|
+
event.stopPropagation();
|
|
547
|
+
onAddSubCollection();
|
|
548
|
+
}, children: "Add sub-collection\u2026" })), onEdit && (_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 14 }), onClick: (event) => {
|
|
549
|
+
event.stopPropagation();
|
|
550
|
+
onEdit();
|
|
551
|
+
}, children: "Edit collection\u2026" })), onDelete && (_jsx(DestructiveMenuItem, { leftSection: _jsx(IconTrash, { size: 14 }), onClick: (event) => {
|
|
552
|
+
event.stopPropagation();
|
|
553
|
+
onDelete();
|
|
554
|
+
}, children: "Delete collection" }))] })] })), hasEntryMenu && (_jsxs(Menu, { shadow: "md", width: 180, withinPortal: true, position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { size: "xs", variant: "subtle", color: "gray", onClick: (event) => event.stopPropagation(), "aria-label": "Entry actions", "data-testid": `entry-menu-${testIdSuffix}`, children: _jsx(IconDots, { size: 14 }) }) }), _jsxs(Menu.Dropdown, { onKeyDown: stopTreeKeys, children: [onRenameEntry && (_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 14 }), onClick: (event) => {
|
|
555
|
+
event.stopPropagation();
|
|
556
|
+
onRenameEntry(entryPath);
|
|
557
|
+
}, "data-testid": "rename-entry-menu-item", children: "Rename\u2026" })), onReorderEntry && contentId && parentCollectionPath && (_jsxs(_Fragment, { children: [_jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowUp, { size: 14 }), blockedReason: canMoveUp ? undefined : 'Already first', onClick: (event) => {
|
|
558
|
+
event.stopPropagation();
|
|
559
|
+
onReorderEntry(parentCollectionPath, contentId, 'up');
|
|
560
|
+
}, children: "Move up" }), _jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowDown, { size: 14 }), blockedReason: canMoveDown ? undefined : 'Already last', onClick: (event) => {
|
|
561
|
+
event.stopPropagation();
|
|
562
|
+
onReorderEntry(parentCollectionPath, contentId, 'down');
|
|
563
|
+
}, children: "Move down" })] })), onDeleteEntry && (_jsxs(_Fragment, { children: [(onRenameEntry || (onReorderEntry && contentId && parentCollectionPath)) && (_jsx(Menu.Divider, {})), _jsx(DestructiveMenuItem, { leftSection: _jsx(IconTrash, { size: 14 }), onClick: (event) => {
|
|
564
|
+
event.stopPropagation();
|
|
565
|
+
onDeleteEntry(entryPath);
|
|
566
|
+
}, "data-testid": "delete-entry-menu-item", children: "Delete entry" })] }))] })] }))] })] }), isCollection && unavailableSchemaRefs && unavailableSchemaRefs.length > 0 && (_jsx(UnavailableTypeRow, { schemaRefs: unavailableSchemaRefs })), isCollection && addRefused && _jsx(AddRefusedRow, {})] }));
|
|
319
567
|
};
|
|
320
|
-
return (
|
|
568
|
+
return (_jsxs(Stack, { h: "100%", style: { display: 'flex', flexDirection: 'column' }, gap: 0, "data-testid": "entry-navigator", children: [treeData.length > 0 && (_jsx(TextInput, { ref: filterInputRef, size: "sm", py: 4, "aria-label": "Filter entries", spellCheck: false, "data-autofocus": true, placeholder: "Filter by title or slug", value: query, onChange: (event) => setQuery(event.currentTarget.value), onKeyDown: handleFilterKeyDown, leftSection: _jsx(IconSearch, { size: 14, "aria-hidden": true }), rightSection: query ? _jsx(CloseButton, { size: "sm", "aria-label": "Clear filter", onClick: clearFilter }) : null, "data-mantine-stop-propagation": query ? 'true' : undefined, "data-testid": "entry-nav-filter" })), _jsxs(ScrollArea, { type: "auto", scrollbars: "y", offsetScrollbars: true, style: { flex: 1 }, children: [hiddenRootUnavailableRefs && hiddenRootUnavailableRefs.length > 0 && (_jsx(Box, { pt: "sm", children: _jsx(UnavailableTypeRow, { schemaRefs: hiddenRootUnavailableRefs }) })), hiddenRootAddRefused && (_jsx(Box, { pt: "sm", children: _jsx(AddRefusedRow, {}) })), treeData.length === 0 ? (loading ? (_jsxs(Group, { gap: "xs", py: "sm", children: [_jsx(Loader, { size: "xs" }), _jsx(Text, { size: "xs", c: "dimmed", children: "Loading content\u2026" })] })) : (_jsx(Text, { size: "xs", c: "dimmed", py: "sm", children: "No content" }))) : filteredTree.length === 0 ? (_jsxs(Stack, { gap: 4, py: "sm", align: "flex-start", "data-testid": "entry-nav-filter-empty", children: [_jsxs(Text, { size: "sm", c: "dimmed", children: ["No entries match \u201C", query, "\u201D."] }), _jsx(Button, { size: "compact-sm", variant: "subtle", onClick: clearFilter, children: "Clear filter" })] })) : (_jsx(Box, { py: "sm", ref: treeBoxRef, children: _jsx(Tree, { data: filteredTree, tree: tree, renderNode: renderNode, selectOnClick: false, levelOffset: "sm" }) }))] })] }));
|
|
321
569
|
};
|
|
322
570
|
export default EntryNavigator;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/** A field in the outline, holding its rows, or an inline group holding its fields. */
|
|
3
|
+
export interface OutlineNode {
|
|
4
|
+
label: string;
|
|
5
|
+
/** The canopy path to focus; absent for an inline group, which is not a field. */
|
|
6
|
+
path?: string;
|
|
7
|
+
/** A row's second value, shown dimmed beside its label. */
|
|
8
|
+
secondary?: string;
|
|
9
|
+
children?: OutlineNode[];
|
|
10
|
+
}
|
|
11
|
+
export interface FormHeaderProps {
|
|
12
|
+
title: string;
|
|
13
|
+
/** The entry type's label, shown as a badge. */
|
|
14
|
+
typeLabel?: string;
|
|
15
|
+
outline: OutlineNode[];
|
|
16
|
+
/** Scrolls to and focuses the field at `path`. */
|
|
17
|
+
onSelect: (path: string) => void;
|
|
18
|
+
/** Set when the form has a list or block field, so expanding and collapsing has a target. */
|
|
19
|
+
onExpandAll?: (expanded: boolean) => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The form's sticky header: which entry this is, an outline of its fields to jump to, and
|
|
23
|
+
* Expand all / Collapse all for every list and block field in it.
|
|
24
|
+
*/
|
|
25
|
+
export declare const FormHeader: React.FC<FormHeaderProps>;
|