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,51 +1,80 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import useSWR, { useSWRConfig } from 'swr';
|
|
3
|
+
import { isSystemUserId } from '../../system-users.js';
|
|
4
|
+
import { SYSTEM_USER_LABEL } from '../user-display.js';
|
|
5
|
+
const ANONYMOUS_USER = { id: 'anonymous', name: 'Anonymous', email: 'public' };
|
|
6
|
+
/** A bot has no directory entry to look up; it is answered here, by name. */
|
|
7
|
+
const systemUser = (userId) => ({
|
|
8
|
+
id: userId,
|
|
9
|
+
name: SYSTEM_USER_LABEL,
|
|
10
|
+
email: '',
|
|
11
|
+
});
|
|
12
|
+
const userMetadataKey = (userId) => `canopy:user:${userId}`;
|
|
13
|
+
const isUserRecord = (value) => typeof value === 'object' &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
'id' in value &&
|
|
16
|
+
typeof value.id === 'string' &&
|
|
17
|
+
'name' in value &&
|
|
18
|
+
typeof value.name === 'string';
|
|
19
|
+
const cachedRecord = (cache, key) => {
|
|
20
|
+
const data = cache.get(key)?.data;
|
|
21
|
+
return isUserRecord(data) ? data : null;
|
|
22
|
+
};
|
|
2
23
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
24
|
+
* Caches profiles a response carried, keeping a cached record's email. A profile matching the
|
|
25
|
+
* cached record is not written: any write makes SWR discard a lookup in flight, email included. A
|
|
26
|
+
* user with no record, or whose written record still has no email, is refetched once the writes
|
|
27
|
+
* settle, since the seed may have discarded a lookup; that refetch is detached, so the caller
|
|
28
|
+
* never waits on the directory.
|
|
6
29
|
*/
|
|
7
|
-
export function
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// Special case: anonymous user
|
|
15
|
-
if (userId === 'anonymous') {
|
|
16
|
-
setUserMetadata({
|
|
17
|
-
id: 'anonymous',
|
|
18
|
-
name: 'Anonymous',
|
|
19
|
-
email: 'public',
|
|
20
|
-
});
|
|
21
|
-
setIsLoading(false);
|
|
30
|
+
export async function seedUserProfiles(swr, users) {
|
|
31
|
+
const { cache, mutate } = swr;
|
|
32
|
+
const emailless = new Set();
|
|
33
|
+
await Promise.all(users.map(async (user) => {
|
|
34
|
+
const key = userMetadataKey(user.id);
|
|
35
|
+
const record = cachedRecord(cache, key);
|
|
36
|
+
if (record && record.name === user.name && record.avatarUrl === user.avatarUrl)
|
|
22
37
|
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
const merged = { email: '', ...record, ...user };
|
|
39
|
+
if (!record || !merged.email)
|
|
40
|
+
emailless.add(key);
|
|
41
|
+
await mutate(key, merged, { revalidate: false });
|
|
42
|
+
}));
|
|
43
|
+
for (const key of emailless)
|
|
44
|
+
void mutate(key);
|
|
45
|
+
}
|
|
46
|
+
/** Answers from the cache with no request and no email, for a reader who may not look users up. */
|
|
47
|
+
export function useSeededUserResolver() {
|
|
48
|
+
const { cache } = useSWRConfig();
|
|
49
|
+
return useCallback((userId) => {
|
|
50
|
+
const record = cachedRecord(cache, userMetadataKey(userId));
|
|
51
|
+
return Promise.resolve(record ? { ...record, email: '' } : null);
|
|
52
|
+
}, [cache]);
|
|
53
|
+
}
|
|
54
|
+
/** One user's metadata under a per-user SWR key, so every badge for that user shares a fetch. */
|
|
55
|
+
export function useUserMetadata(userId, getUserMetadata, cachedUser) {
|
|
56
|
+
const skip = cachedUser !== undefined || userId === 'anonymous' || isSystemUserId(userId);
|
|
57
|
+
const { cache } = useSWRConfig();
|
|
58
|
+
const key = userMetadataKey(userId);
|
|
59
|
+
const { data, error, isLoading } = useSWR(skip ? null : key,
|
|
60
|
+
// A lookup that answers null keeps the record already cached, such as a seeded name.
|
|
61
|
+
async () => (await getUserMetadata(userId)) ?? cachedRecord(cache, key));
|
|
62
|
+
if (cachedUser)
|
|
63
|
+
return { userMetadata: cachedUser, isLoading: false, error: null };
|
|
64
|
+
if (userId === 'anonymous')
|
|
65
|
+
return { userMetadata: ANONYMOUS_USER, isLoading: false, error: null };
|
|
66
|
+
if (isSystemUserId(userId)) {
|
|
67
|
+
return { userMetadata: systemUser(userId), isLoading: false, error: null };
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
userMetadata: data ?? null,
|
|
71
|
+
// A seed can land while the lookup is in flight; SWR still reports that lookup as loading.
|
|
72
|
+
isLoading: isLoading && data === undefined,
|
|
73
|
+
// A record to show outranks a failed lookup, so a seeded name survives it.
|
|
74
|
+
error: error === undefined || data
|
|
75
|
+
? null
|
|
76
|
+
: error instanceof Error
|
|
77
|
+
? error
|
|
78
|
+
: new Error('Failed to fetch user'),
|
|
79
|
+
};
|
|
51
80
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ApiClient } from '../context/index.js';
|
|
2
|
+
import type { UserSearchResult } from '../../auth/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Sends the ids asked for within one window as one `POST /users/batch`, split at the cap. Pass
|
|
5
|
+
* it to useUserMetadata, whose per-user SWR key is the cache. A failed request rejects every id
|
|
6
|
+
* in it, so SWR keeps the last good record; an id a successful response omits resolves `null`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createUserMetadataBatcher(apiClient: ApiClient): (userId: string) => Promise<UserSearchResult | null>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import DataLoader from 'dataloader';
|
|
2
|
+
import { MAX_USER_METADATA_BATCH } from '../../api/users-constants.js';
|
|
3
|
+
/** Long enough to gather every badge one render mounts. */
|
|
4
|
+
const BATCH_WINDOW_MS = 10;
|
|
5
|
+
/**
|
|
6
|
+
* Sends the ids asked for within one window as one `POST /users/batch`, split at the cap. Pass
|
|
7
|
+
* it to useUserMetadata, whose per-user SWR key is the cache. A failed request rejects every id
|
|
8
|
+
* in it, so SWR keeps the last good record; an id a successful response omits resolves `null`.
|
|
9
|
+
*/
|
|
10
|
+
export function createUserMetadataBatcher(apiClient) {
|
|
11
|
+
const loader = new DataLoader(async (userIds) => {
|
|
12
|
+
let result;
|
|
13
|
+
try {
|
|
14
|
+
result = await apiClient.permissions.batchGetUserMetadata({ userIds: [...userIds] });
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error('Batch get user metadata failed:', err);
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
if (!result.ok) {
|
|
21
|
+
const reason = result.error ?? `status ${result.status}`;
|
|
22
|
+
console.error('Batch get user metadata failed:', reason);
|
|
23
|
+
throw new Error(`Batch get user metadata failed: ${reason}`);
|
|
24
|
+
}
|
|
25
|
+
const byId = new Map((result.data?.users ?? []).map((u) => [u.id, u]));
|
|
26
|
+
return userIds.map((id) => byId.get(id) ?? null);
|
|
27
|
+
}, {
|
|
28
|
+
cache: false,
|
|
29
|
+
maxBatchSize: MAX_USER_METADATA_BATCH,
|
|
30
|
+
batchScheduleFn: (dispatch) => setTimeout(dispatch, BATCH_WINDOW_MS),
|
|
31
|
+
});
|
|
32
|
+
return (userId) => loader.load(userId);
|
|
33
|
+
}
|
|
@@ -2,18 +2,17 @@ import React from 'react';
|
|
|
2
2
|
import type { AssetRecord } from '../../api/index.js';
|
|
3
3
|
export interface AssetCardProps {
|
|
4
4
|
asset: AssetRecord;
|
|
5
|
-
/** `
|
|
5
|
+
/** `useAssetContext().baseUrl`, the authenticated raw route - see AssetContext. */
|
|
6
6
|
baseUrl?: string;
|
|
7
7
|
/** Present in picker mode - clicking the card selects the asset. */
|
|
8
8
|
onSelect?: (asset: AssetRecord) => void;
|
|
9
|
-
/** Present only
|
|
9
|
+
/** Present only where the viewer may remove the asset (manage mode) - renders the trash button. */
|
|
10
10
|
onDelete?: (asset: AssetRecord) => void;
|
|
11
|
+
/** `compact` shrinks the thumbnail and drops the date line. */
|
|
12
|
+
density?: 'grid' | 'compact';
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
|
-
* One thumbnail card in the MediaLibrary grid.
|
|
14
|
-
*
|
|
15
|
-
* `assetUrl` ignores the `width` option and just applies `baseUrl`, which is
|
|
16
|
-
* exactly the behavior wanted here. PDFs have no image to preview, so they
|
|
17
|
-
* render a file-type icon instead.
|
|
15
|
+
* One thumbnail card in the MediaLibrary grid. PDFs have no image to preview, so they render a
|
|
16
|
+
* file-type icon instead.
|
|
18
17
|
*/
|
|
19
18
|
export declare const AssetCard: React.FC<AssetCardProps>;
|
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from 'react';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
4
3
|
import { ActionIcon, Card, Text, Tooltip } from '@mantine/core';
|
|
5
4
|
import { IconFileTypePdf, IconPhotoOff, IconTrash } from '@tabler/icons-react';
|
|
6
|
-
import {
|
|
5
|
+
import { formatRelativeTime } from '../relative-time.js';
|
|
6
|
+
import { editorImageSrc } from './editor-image-src.js';
|
|
7
|
+
import { CARD_THUMBNAIL_HEIGHT } from './media-library-view.js';
|
|
8
|
+
import { useThumbnailFailure } from './useThumbnailFailure.js';
|
|
7
9
|
const THUMBNAIL_WIDTH = 160;
|
|
8
10
|
/**
|
|
9
|
-
* One thumbnail card in the MediaLibrary grid.
|
|
10
|
-
*
|
|
11
|
-
* `assetUrl` ignores the `width` option and just applies `baseUrl`, which is
|
|
12
|
-
* exactly the behavior wanted here. PDFs have no image to preview, so they
|
|
13
|
-
* render a file-type icon instead.
|
|
11
|
+
* One thumbnail card in the MediaLibrary grid. PDFs have no image to preview, so they render a
|
|
12
|
+
* file-type icon instead.
|
|
14
13
|
*/
|
|
15
|
-
export const AssetCard = ({ asset, baseUrl, onSelect, onDelete }) => {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
// thumbnail that failed earlier gets another chance to load. Adjusting state
|
|
21
|
-
// during render (rather than in a useEffect) avoids an extra render pass -
|
|
22
|
-
// see https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes
|
|
23
|
-
const [prevThumbnailSrc, setPrevThumbnailSrc] = useState(thumbnailSrc);
|
|
24
|
-
if (thumbnailSrc !== prevThumbnailSrc) {
|
|
25
|
-
setPrevThumbnailSrc(thumbnailSrc);
|
|
26
|
-
setThumbnailFailed(false);
|
|
27
|
-
}
|
|
14
|
+
export const AssetCard = ({ asset, baseUrl, onSelect, onDelete, density = 'grid', }) => {
|
|
15
|
+
const compact = density === 'compact';
|
|
16
|
+
const thumbnailHeight = CARD_THUMBNAIL_HEIGHT[density];
|
|
17
|
+
const thumbnailSrc = editorImageSrc(asset.src, baseUrl ?? '', { width: THUMBNAIL_WIDTH });
|
|
18
|
+
const [thumbnailFailed, markThumbnailFailed] = useThumbnailFailure(thumbnailSrc);
|
|
28
19
|
const handleKeyDown = (event) => {
|
|
29
20
|
if (!onSelect)
|
|
30
21
|
return;
|
|
@@ -38,23 +29,25 @@ export const AssetCard = ({ asset, baseUrl, onSelect, onDelete }) => {
|
|
|
38
29
|
// element, unreachable from the keyboard - role="button" + tabIndex
|
|
39
30
|
// makes it focusable and announced correctly, and onKeyDown mirrors
|
|
40
31
|
// native <button> Enter/Space activation.
|
|
41
|
-
role: onSelect ? 'button' : undefined, tabIndex: onSelect ? 0 : undefined, onKeyDown: onSelect ? handleKeyDown : undefined,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
role: onSelect ? 'button' : undefined, tabIndex: onSelect ? 0 : undefined, onKeyDown: onSelect ? handleKeyDown : undefined,
|
|
33
|
+
// Mantine draws its focus ring only on its own controls or this class; a bare Card gets none.
|
|
34
|
+
className: onSelect ? 'mantine-focus-auto' : undefined, "aria-label": onSelect ? `Select ${asset.filename}` : undefined, children: [onDelete && (_jsx(Tooltip, { label: "Remove from library", children: _jsx(ActionIcon, { variant: "default", c: "var(--canopy-danger-text)", radius: "xl", style: { position: 'absolute', top: 4, right: 4, zIndex: 1 }, "aria-label": `Remove ${asset.filename} from library`, "data-testid": `asset-card-delete-${asset.hash32}`, onClick: (event) => {
|
|
35
|
+
event.stopPropagation();
|
|
36
|
+
onDelete(asset);
|
|
37
|
+
}, children: _jsx(IconTrash, { size: 14 }) }) })), _jsx(Card.Section, { children: asset.kind === 'pdf' ? (_jsx("div", { style: {
|
|
38
|
+
height: thumbnailHeight,
|
|
46
39
|
display: 'flex',
|
|
47
40
|
alignItems: 'center',
|
|
48
41
|
justifyContent: 'center',
|
|
49
|
-
background: 'var(--
|
|
50
|
-
}, children: _jsx(IconFileTypePdf, { size: 40, stroke: 1.5 }) })) : thumbnailFailed ? (_jsxs("div", { "data-testid": `asset-card-thumbnail-fallback-${asset.hash32}`, style: {
|
|
51
|
-
height:
|
|
42
|
+
background: 'var(--canopy-surface-muted)',
|
|
43
|
+
}, children: _jsx(IconFileTypePdf, { size: compact ? 28 : 40, stroke: 1.5 }) })) : thumbnailFailed ? (_jsxs("div", { "data-testid": `asset-card-thumbnail-fallback-${asset.hash32}`, style: {
|
|
44
|
+
height: thumbnailHeight,
|
|
52
45
|
width: '100%',
|
|
53
46
|
display: 'flex',
|
|
54
47
|
flexDirection: 'column',
|
|
55
48
|
alignItems: 'center',
|
|
56
49
|
justifyContent: 'center',
|
|
57
50
|
gap: 4,
|
|
58
|
-
background: 'var(--
|
|
59
|
-
}, children: [_jsx(IconPhotoOff, { size: 28, stroke: 1.5, color: "var(--mantine-color-
|
|
51
|
+
background: 'var(--canopy-surface-muted)',
|
|
52
|
+
}, children: [_jsx(IconPhotoOff, { size: compact ? 20 : 28, stroke: 1.5, color: "var(--mantine-color-dimmed)" }), _jsx(Text, { size: "xs", c: "dimmed", children: "Preview unavailable" })] })) : (_jsx("img", { src: thumbnailSrc, alt: asset.filename, style: { width: '100%', height: thumbnailHeight, objectFit: 'cover', display: 'block' }, onError: markThumbnailFailed })) }), _jsx(Tooltip, { multiline: true, w: 260, openDelay: 400, label: _jsxs(_Fragment, { children: [_jsx("div", { style: { overflowWrap: 'anywhere' }, children: asset.filename }), _jsxs("div", { style: { overflowWrap: 'anywhere' }, children: ["Slug: ", asset.slug] })] }), children: _jsx(Text, { size: "xs", fw: 500, truncate: true, mt: 4, children: asset.filename }) }), !compact && (_jsx(Tooltip, { label: new Date(asset.uploadedAt).toLocaleString(), children: _jsx(Text, { size: "xs", c: "dimmed", w: "fit-content", children: formatRelativeTime(asset.uploadedAt) }) }))] }));
|
|
60
53
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AssetRecord } from '../../api/index.js';
|
|
3
|
+
export interface AssetListRowProps {
|
|
4
|
+
asset: AssetRecord;
|
|
5
|
+
/** `useAssetContext().baseUrl`, the authenticated raw route - see AssetContext. */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Present in picker mode - the whole row is then a button that selects the asset. A button
|
|
9
|
+
* cannot hold another, so a selectable row renders no remove control.
|
|
10
|
+
*/
|
|
11
|
+
onSelect?: (asset: AssetRecord) => void;
|
|
12
|
+
/** Present only where the viewer may remove the asset - renders the trash button. */
|
|
13
|
+
onDelete?: (asset: AssetRecord) => void;
|
|
14
|
+
}
|
|
15
|
+
/** One asset as a row in the list layout: thumbnail, name, dimensions, size and upload date. */
|
|
16
|
+
export declare const AssetListRow: React.FC<AssetListRowProps>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { ActionIcon, Group, Text, Tooltip, UnstyledButton } from '@mantine/core';
|
|
4
|
+
import { IconFileTypePdf, IconPhotoOff, IconTrash } from '@tabler/icons-react';
|
|
5
|
+
import { formatRelativeTime } from '../relative-time.js';
|
|
6
|
+
import { editorImageSrc } from './editor-image-src.js';
|
|
7
|
+
import { formatBytes } from './format-bytes.js';
|
|
8
|
+
import { useThumbnailFailure } from './useThumbnailFailure.js';
|
|
9
|
+
const THUMBNAIL_SIZE = 40;
|
|
10
|
+
const THUMBNAIL_WIDTH = 80;
|
|
11
|
+
const rowStyle = {
|
|
12
|
+
width: '100%',
|
|
13
|
+
padding: 6,
|
|
14
|
+
border: '1px solid var(--mantine-color-default-border)',
|
|
15
|
+
borderRadius: 'var(--mantine-radius-md)',
|
|
16
|
+
};
|
|
17
|
+
const thumbnailBoxStyle = {
|
|
18
|
+
width: THUMBNAIL_SIZE,
|
|
19
|
+
height: THUMBNAIL_SIZE,
|
|
20
|
+
flex: `0 0 ${THUMBNAIL_SIZE}px`,
|
|
21
|
+
display: 'flex',
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
borderRadius: 'var(--mantine-radius-sm)',
|
|
25
|
+
background: 'var(--canopy-surface-muted)',
|
|
26
|
+
overflow: 'hidden',
|
|
27
|
+
};
|
|
28
|
+
/** One asset as a row in the list layout: thumbnail, name, dimensions, size and upload date. */
|
|
29
|
+
export const AssetListRow = ({ asset, baseUrl, onSelect, onDelete, }) => {
|
|
30
|
+
const thumbnailSrc = editorImageSrc(asset.src, baseUrl ?? '', { width: THUMBNAIL_WIDTH });
|
|
31
|
+
const [thumbnailFailed, markThumbnailFailed] = useThumbnailFailure(thumbnailSrc);
|
|
32
|
+
const hasDimensions = asset.width !== undefined && asset.height !== undefined;
|
|
33
|
+
const content = (_jsxs(Group, { gap: "sm", wrap: "nowrap", style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: thumbnailBoxStyle, children: asset.kind === 'pdf' ? (_jsx(IconFileTypePdf, { size: 24, stroke: 1.5, "aria-hidden": true })) : thumbnailFailed ? (_jsx(IconPhotoOff, { size: 20, stroke: 1.5, color: "var(--mantine-color-dimmed)", "data-testid": `asset-row-thumbnail-fallback-${asset.hash32}`, "aria-label": "Preview unavailable" })) : (
|
|
34
|
+
// Decorative: the filename beside it already names the row.
|
|
35
|
+
_jsx("img", { src: thumbnailSrc, alt: "", style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' }, onError: markThumbnailFailed })) }), _jsx(Tooltip, { multiline: true, w: 260, openDelay: 400, label: _jsxs(_Fragment, { children: [_jsx("div", { style: { overflowWrap: 'anywhere' }, children: asset.filename }), _jsxs("div", { style: { overflowWrap: 'anywhere' }, children: ["Slug: ", asset.slug] })] }), children: _jsx(Text, { size: "sm", fw: 500, truncate: true, style: { flex: 1, minWidth: 0 }, children: asset.filename }) }), _jsx(Text, { size: "xs", c: "dimmed", w: 84, ta: "right", visibleFrom: "sm", style: { flex: '0 0 auto' }, children: hasDimensions ? `${asset.width} × ${asset.height}` : '' }), _jsx(Text, { size: "xs", c: "dimmed", w: 52, ta: "right", visibleFrom: "sm", style: { flex: '0 0 auto' }, children: formatBytes(asset.size) }), _jsx(Tooltip, { label: new Date(asset.uploadedAt).toLocaleString(), children: _jsx(Text, { size: "xs", c: "dimmed", w: 72, ta: "right", style: { flex: '0 0 auto' }, children: formatRelativeTime(asset.uploadedAt) }) })] }));
|
|
36
|
+
const removeButton = onDelete && (_jsx(Tooltip, { label: "Remove from library", children: _jsx(ActionIcon, { variant: "subtle", color: "red", "aria-label": `Remove ${asset.filename} from library`, "data-testid": `asset-row-delete-${asset.hash32}`, onClick: () => onDelete(asset), children: _jsx(IconTrash, { size: 16 }) }) }));
|
|
37
|
+
if (onSelect) {
|
|
38
|
+
return (_jsx(UnstyledButton, { onClick: () => onSelect(asset), "data-testid": `asset-row-${asset.hash32}`, style: rowStyle, children: content }));
|
|
39
|
+
}
|
|
40
|
+
return (_jsxs(Group, { gap: "xs", wrap: "nowrap", "data-testid": `asset-row-${asset.hash32}`, style: rowStyle, children: [content, removeButton] }));
|
|
41
|
+
};
|
|
@@ -32,5 +32,10 @@ const CropStepBody = ({ imageSrc, aspect, initialCrop, onConfirm, onClose, }) =>
|
|
|
32
32
|
onConfirm(rect);
|
|
33
33
|
};
|
|
34
34
|
const initialCroppedAreaPercentages = initialCrop ? cropRectToAreaPercent(initialCrop) : undefined;
|
|
35
|
-
return (_jsxs(Stack, { gap: "md", children: [_jsx("div", { style: {
|
|
35
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx("div", { style: {
|
|
36
|
+
position: 'relative',
|
|
37
|
+
width: '100%',
|
|
38
|
+
height: 360,
|
|
39
|
+
background: 'var(--mantine-color-black)',
|
|
40
|
+
}, children: _jsx(Cropper, { image: imageSrc, crop: crop, zoom: zoom, aspect: aspect, initialCroppedAreaPercentages: initialCroppedAreaPercentages, onCropChange: setCrop, onZoomChange: setZoom, onCropComplete: (croppedArea) => setPendingArea(croppedArea) }) }), _jsxs(Group, { gap: "sm", align: "center", children: [_jsx(Text, { size: "sm", w: 50, children: "Zoom" }), _jsx(Slider, { style: { flex: 1 }, min: MIN_ZOOM, max: MAX_ZOOM, step: ZOOM_STEP, value: zoom, onChange: setZoom, label: (value) => `${value.toFixed(2)}x` })] }), _jsxs(Group, { justify: "flex-end", children: [_jsx(Button, { size: "sm", variant: "default", onClick: onClose, children: "Cancel" }), _jsx(Button, { size: "sm", onClick: handleConfirm, disabled: !pendingArea, "data-testid": "crop-step-apply", children: "Apply crop" })] })] }));
|
|
36
41
|
};
|
|
@@ -4,17 +4,18 @@ export interface MediaLibraryProps {
|
|
|
4
4
|
opened: boolean;
|
|
5
5
|
onClose: () => void;
|
|
6
6
|
/**
|
|
7
|
-
* 'manage': right-side Drawer opened from the
|
|
7
|
+
* 'manage': right-side Drawer opened from the rail's Media button.
|
|
8
8
|
* 'picker': Modal used by ImageField ("Browse library"/"Replace") and the
|
|
9
9
|
* MDX image dialog's "From library" tab.
|
|
10
10
|
*/
|
|
11
11
|
mode: 'manage' | 'picker';
|
|
12
12
|
/** Required in picker mode - called with the chosen asset when a card is clicked. */
|
|
13
13
|
onSelect?: (asset: AssetRecord) => void;
|
|
14
|
+
returnFocusTo?: () => HTMLElement | null;
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
|
-
* One component, two presentations, sharing the same grid/upload/
|
|
17
|
-
*
|
|
17
|
+
* One component, two presentations, sharing the same grid/list/upload/search/
|
|
18
|
+
* delete core (MediaLibraryBody) - see
|
|
18
19
|
* .claude/future-tasks/resolved/assets-media-system.md "MediaManager design".
|
|
19
20
|
*/
|
|
20
21
|
export declare const MediaLibrary: React.FC<MediaLibraryProps>;
|
|
@@ -2,14 +2,21 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Drawer, Modal, Text, Title } from '@mantine/core';
|
|
4
4
|
import { MediaLibraryBody } from './MediaLibraryBody.js';
|
|
5
|
+
import { focusReturnProps } from '../utils/focus-return.js';
|
|
5
6
|
/**
|
|
6
|
-
* One component, two presentations, sharing the same grid/upload/
|
|
7
|
-
*
|
|
7
|
+
* One component, two presentations, sharing the same grid/list/upload/search/
|
|
8
|
+
* delete core (MediaLibraryBody) - see
|
|
8
9
|
* .claude/future-tasks/resolved/assets-media-system.md "MediaManager design".
|
|
9
10
|
*/
|
|
10
|
-
export const MediaLibrary = ({ opened, onClose, mode, onSelect }) => {
|
|
11
|
+
export const MediaLibrary = ({ opened, onClose, mode, onSelect, returnFocusTo, }) => {
|
|
11
12
|
if (mode === 'picker') {
|
|
12
13
|
return (_jsx(Modal, { opened: opened, onClose: onClose, title: "Media library", size: "lg", overlayProps: { blur: 2 }, "data-testid": "media-library-picker", children: _jsx(MediaLibraryBody, { opened: opened, mode: "picker", onSelect: onSelect }) }));
|
|
13
14
|
}
|
|
14
|
-
return (_jsx(Drawer, { opened: opened, onClose: onClose, position: "right", title: _jsxs("div", { children: [_jsx(Title, { order: 4, children: "Media library" }), _jsx(Text, { size: "xs", c: "dimmed", children: "Upload and manage images and PDFs" })] }), padding: "md", size: 700,
|
|
15
|
+
return (_jsx(Drawer, { opened: opened, onClose: onClose, position: "right", title: _jsxs("div", { children: [_jsx(Title, { order: 4, children: "Media library" }), _jsx(Text, { size: "xs", c: "dimmed", children: "Upload and manage images and PDFs" })] }), padding: "md", size: 700,
|
|
16
|
+
// The body fills the drawer and the library's own ScrollArea scrolls, so the toolbar stays put
|
|
17
|
+
// and the list's IntersectionObserver sees a real clipping viewport.
|
|
18
|
+
styles: {
|
|
19
|
+
content: { display: 'flex', flexDirection: 'column' },
|
|
20
|
+
body: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' },
|
|
21
|
+
}, overlayProps: { blur: 2 }, "data-testid": "media-library-manage", ...focusReturnProps(returnFocusTo), children: _jsx(MediaLibraryBody, { opened: opened, mode: "manage" }) }));
|
|
15
22
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { AssetRecord } from '../../api/index.js';
|
|
3
3
|
export interface MediaLibraryBodyProps {
|
|
4
|
-
/** Whether the enclosing Drawer/Modal is open -
|
|
4
|
+
/** Whether the enclosing Drawer/Modal is open - the library (re)loads from page 1 on each open and stops loading on close. */
|
|
5
5
|
opened: boolean;
|
|
6
6
|
mode: 'manage' | 'picker';
|
|
7
|
-
/** Present in picker mode - clicking a card
|
|
7
|
+
/** Present in picker mode - clicking a card or row selects the asset; an upload is pinned first, not selected. */
|
|
8
8
|
onSelect?: (asset: AssetRecord) => void;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Shared grid/upload/
|
|
11
|
+
* Shared grid/list/upload/search/delete core for both MediaLibrary
|
|
12
12
|
* presentations (Drawer "manage" mode, Modal "picker" mode) - see
|
|
13
13
|
* MediaLibrary.tsx for the two wrappers.
|
|
14
14
|
*/
|