canopycms 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/plugin.d.ts +8 -0
- package/dist/auth/plugin.d.ts.map +1 -1
- package/dist/build-mode.d.ts +15 -5
- package/dist/build-mode.d.ts.map +1 -1
- package/dist/build-mode.js +18 -8
- package/dist/build-mode.js.map +1 -1
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +37 -36
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/template-files/ai-config.ts.template +21 -0
- package/dist/cli/template-files/ai-route.ts.template +10 -0
- package/dist/cli/template-files/canopy.ts.template +24 -0
- package/dist/cli/templates.d.ts +5 -1
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +9 -2
- package/dist/cli/templates.js.map +1 -1
- package/dist/config/schemas/config.d.ts +4 -0
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +2 -0
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/types.d.ts +5 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/content-reader.js +2 -2
- package/dist/content-reader.js.map +1 -1
- package/dist/context.js +5 -5
- package/dist/context.js.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.js +15 -18
- package/dist/operating-mode/client-unsafe-strategy.js.map +1 -1
- package/dist/operating-mode/types.d.ts +8 -0
- package/dist/operating-mode/types.d.ts.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/package.json +5 -4
- package/src/cli/init.ts +43 -38
- package/dist/__integration__/fixtures/content-seeds.d.ts +0 -43
- package/dist/__integration__/fixtures/content-seeds.d.ts.map +0 -1
- package/dist/__integration__/fixtures/content-seeds.js +0 -99
- package/dist/__integration__/fixtures/content-seeds.js.map +0 -1
- package/dist/__integration__/fixtures/schemas.d.ts +0 -12
- package/dist/__integration__/fixtures/schemas.d.ts.map +0 -1
- package/dist/__integration__/fixtures/schemas.js +0 -65
- package/dist/__integration__/fixtures/schemas.js.map +0 -1
- package/dist/__integration__/test-utils/api-client.d.ts +0 -123
- package/dist/__integration__/test-utils/api-client.d.ts.map +0 -1
- package/dist/__integration__/test-utils/api-client.js +0 -118
- package/dist/__integration__/test-utils/api-client.js.map +0 -1
- package/dist/__integration__/test-utils/multi-user.d.ts +0 -25
- package/dist/__integration__/test-utils/multi-user.d.ts.map +0 -1
- package/dist/__integration__/test-utils/multi-user.js +0 -105
- package/dist/__integration__/test-utils/multi-user.js.map +0 -1
- package/dist/__integration__/test-utils/test-workspace.d.ts +0 -25
- package/dist/__integration__/test-utils/test-workspace.d.ts.map +0 -1
- package/dist/__integration__/test-utils/test-workspace.js +0 -102
- package/dist/__integration__/test-utils/test-workspace.js.map +0 -1
- package/dist/editor/BranchManager.stories.d.ts +0 -8
- package/dist/editor/BranchManager.stories.d.ts.map +0 -1
- package/dist/editor/BranchManager.stories.js +0 -74
- package/dist/editor/BranchManager.stories.js.map +0 -1
- package/dist/editor/CanopyEditor.stories.d.ts +0 -7
- package/dist/editor/CanopyEditor.stories.d.ts.map +0 -1
- package/dist/editor/CanopyEditor.stories.js +0 -99
- package/dist/editor/CanopyEditor.stories.js.map +0 -1
- package/dist/editor/CommentsPanel.stories.d.ts +0 -10
- package/dist/editor/CommentsPanel.stories.d.ts.map +0 -1
- package/dist/editor/CommentsPanel.stories.js +0 -175
- package/dist/editor/CommentsPanel.stories.js.map +0 -1
- package/dist/editor/Editor.stories.d.ts +0 -7
- package/dist/editor/Editor.stories.d.ts.map +0 -1
- package/dist/editor/Editor.stories.js +0 -95
- package/dist/editor/Editor.stories.js.map +0 -1
- package/dist/editor/EditorPanes.stories.d.ts +0 -7
- package/dist/editor/EditorPanes.stories.d.ts.map +0 -1
- package/dist/editor/EditorPanes.stories.js +0 -116
- package/dist/editor/EditorPanes.stories.js.map +0 -1
- package/dist/editor/EntryNavigator.stories.d.ts +0 -8
- package/dist/editor/EntryNavigator.stories.d.ts.map +0 -1
- package/dist/editor/EntryNavigator.stories.js +0 -42
- package/dist/editor/EntryNavigator.stories.js.map +0 -1
- package/dist/editor/FormRenderer.stories.d.ts +0 -7
- package/dist/editor/FormRenderer.stories.d.ts.map +0 -1
- package/dist/editor/FormRenderer.stories.js +0 -115
- package/dist/editor/FormRenderer.stories.js.map +0 -1
- package/dist/editor/GroupManager.stories.d.ts +0 -19
- package/dist/editor/GroupManager.stories.d.ts.map +0 -1
- package/dist/editor/GroupManager.stories.js +0 -265
- package/dist/editor/GroupManager.stories.js.map +0 -1
- package/dist/editor/PermissionManager.stories.d.ts +0 -20
- package/dist/editor/PermissionManager.stories.d.ts.map +0 -1
- package/dist/editor/PermissionManager.stories.js +0 -506
- package/dist/editor/PermissionManager.stories.js.map +0 -1
- package/dist/editor/comments/FieldWrapper.stories.d.ts +0 -10
- package/dist/editor/comments/FieldWrapper.stories.d.ts.map +0 -1
- package/dist/editor/comments/FieldWrapper.stories.js +0 -173
- package/dist/editor/comments/FieldWrapper.stories.js.map +0 -1
- package/dist/editor/fields/BlockField.stories.d.ts +0 -7
- package/dist/editor/fields/BlockField.stories.d.ts.map +0 -1
- package/dist/editor/fields/BlockField.stories.js +0 -50
- package/dist/editor/fields/BlockField.stories.js.map +0 -1
- package/dist/editor/fields/fields.stories.d.ts +0 -8
- package/dist/editor/fields/fields.stories.d.ts.map +0 -1
- package/dist/editor/fields/fields.stories.js +0 -34
- package/dist/editor/fields/fields.stories.js.map +0 -1
- package/dist/test-utils/api-test-helpers.d.ts +0 -238
- package/dist/test-utils/api-test-helpers.d.ts.map +0 -1
- package/dist/test-utils/api-test-helpers.js +0 -347
- package/dist/test-utils/api-test-helpers.js.map +0 -1
- package/dist/test-utils/console-spy.d.ts +0 -56
- package/dist/test-utils/console-spy.d.ts.map +0 -1
- package/dist/test-utils/console-spy.js +0 -81
- package/dist/test-utils/console-spy.js.map +0 -1
- package/dist/test-utils/git-helpers.d.ts +0 -21
- package/dist/test-utils/git-helpers.d.ts.map +0 -1
- package/dist/test-utils/git-helpers.js +0 -23
- package/dist/test-utils/git-helpers.js.map +0 -1
- package/dist/test-utils/index.d.ts +0 -5
- package/dist/test-utils/index.d.ts.map +0 -1
- package/dist/test-utils/index.js +0 -4
- package/dist/test-utils/index.js.map +0 -1
- package/src/__integration__/errors/invalid-content.test.ts +0 -238
- package/src/__integration__/errors/permission-denied.test.ts +0 -220
- package/src/__integration__/fixtures/content-seeds.ts +0 -105
- package/src/__integration__/fixtures/schemas.ts +0 -67
- package/src/__integration__/initialization/prod-sim-init.test.ts +0 -139
- package/src/__integration__/permissions/path-permissions.test.ts +0 -314
- package/src/__integration__/permissions/role-permissions.test.ts +0 -354
- package/src/__integration__/permissions/settings-branch-isolation.test.ts +0 -317
- package/src/__integration__/settings/groups-api.test.ts +0 -403
- package/src/__integration__/test-utils/api-client.ts +0 -167
- package/src/__integration__/test-utils/multi-user.ts +0 -129
- package/src/__integration__/test-utils/test-workspace.ts +0 -130
- package/src/__integration__/user/user-context.test.ts +0 -174
- package/src/__integration__/validation/input-validation.test.ts +0 -166
- package/src/__integration__/workflows/api-editing-workflow.test.ts +0 -244
- package/src/__integration__/workflows/conflict-resolution.test.ts +0 -259
- package/src/__integration__/workflows/editing-workflow.test.ts +0 -205
- package/src/__integration__/workflows/review-workflow.test.ts +0 -260
- package/src/ai/__tests__/build.integration.test.ts +0 -224
- package/src/ai/__tests__/generate.integration.test.ts +0 -495
- package/src/ai/__tests__/handler.integration.test.ts +0 -212
- package/src/ai/__tests__/json-to-markdown.test.ts +0 -553
- package/src/ai/generate.ts +0 -410
- package/src/ai/handler.ts +0 -123
- package/src/ai/index.ts +0 -26
- package/src/ai/json-to-markdown.ts +0 -424
- package/src/ai/resolve-branch.ts +0 -34
- package/src/ai/types.ts +0 -160
- package/src/api/AGENTS.md +0 -81
- package/src/api/__test__/mock-client.ts +0 -404
- package/src/api/assets.test.ts +0 -140
- package/src/api/assets.ts +0 -154
- package/src/api/branch-merge.test.ts +0 -163
- package/src/api/branch-merge.ts +0 -113
- package/src/api/branch-review.test.ts +0 -297
- package/src/api/branch-review.ts +0 -136
- package/src/api/branch-status.test.ts +0 -85
- package/src/api/branch-status.ts +0 -153
- package/src/api/branch-withdraw.test.ts +0 -146
- package/src/api/branch-withdraw.ts +0 -81
- package/src/api/branch-workflow.integration.test.ts +0 -578
- package/src/api/branch.test.ts +0 -620
- package/src/api/branch.ts +0 -492
- package/src/api/client.test.ts +0 -349
- package/src/api/client.ts +0 -506
- package/src/api/comments.test.ts +0 -285
- package/src/api/comments.ts +0 -210
- package/src/api/content.test.ts +0 -345
- package/src/api/content.ts +0 -454
- package/src/api/entries.test.ts +0 -1339
- package/src/api/entries.ts +0 -650
- package/src/api/github-sync.ts +0 -144
- package/src/api/groups.test.ts +0 -1013
- package/src/api/groups.ts +0 -375
- package/src/api/guards.test.ts +0 -533
- package/src/api/guards.ts +0 -271
- package/src/api/index.ts +0 -87
- package/src/api/permissions.test.ts +0 -766
- package/src/api/permissions.ts +0 -334
- package/src/api/reference-options.ts +0 -118
- package/src/api/resolve-references.ts +0 -107
- package/src/api/route-builder.ts +0 -289
- package/src/api/schema.test.ts +0 -840
- package/src/api/schema.ts +0 -936
- package/src/api/security.test.ts +0 -233
- package/src/api/settings-helpers.ts +0 -84
- package/src/api/types.ts +0 -40
- package/src/api/user.test.ts +0 -127
- package/src/api/user.ts +0 -42
- package/src/api/validators.test.ts +0 -275
- package/src/api/validators.ts +0 -176
- package/src/asset-store.test.ts +0 -37
- package/src/asset-store.ts +0 -110
- package/src/auth/cache.ts +0 -7
- package/src/auth/caching-auth-plugin.test.ts +0 -154
- package/src/auth/caching-auth-plugin.ts +0 -109
- package/src/auth/context-helpers.ts +0 -75
- package/src/auth/file-based-auth-cache.test.ts +0 -257
- package/src/auth/file-based-auth-cache.ts +0 -279
- package/src/auth/index.ts +0 -12
- package/src/auth/plugin.ts +0 -51
- package/src/auth/types.ts +0 -38
- package/src/authorization/__tests__/branch.test.ts +0 -260
- package/src/authorization/__tests__/content.test.ts +0 -142
- package/src/authorization/__tests__/path.test.ts +0 -133
- package/src/authorization/__tests__/permissions-loader.test.ts +0 -200
- package/src/authorization/branch.ts +0 -94
- package/src/authorization/content.ts +0 -93
- package/src/authorization/groups/index.ts +0 -11
- package/src/authorization/groups/loader.ts +0 -127
- package/src/authorization/groups/schema.ts +0 -48
- package/src/authorization/helpers.ts +0 -48
- package/src/authorization/index.ts +0 -84
- package/src/authorization/path.ts +0 -112
- package/src/authorization/permissions/index.ts +0 -11
- package/src/authorization/permissions/loader.ts +0 -116
- package/src/authorization/permissions/schema.ts +0 -66
- package/src/authorization/test-utils.ts +0 -15
- package/src/authorization/types.ts +0 -66
- package/src/authorization/validation.test.ts +0 -100
- package/src/authorization/validation.ts +0 -62
- package/src/branch-metadata.test.ts +0 -168
- package/src/branch-metadata.ts +0 -166
- package/src/branch-registry.test.ts +0 -248
- package/src/branch-registry.ts +0 -152
- package/src/branch-schema-cache.test.ts +0 -275
- package/src/branch-schema-cache.ts +0 -189
- package/src/branch-workspace.test.ts +0 -183
- package/src/branch-workspace.ts +0 -124
- package/src/build/generate-ai-content.ts +0 -78
- package/src/build/index.ts +0 -8
- package/src/build-mode.ts +0 -27
- package/src/cli/generate-ai-content.ts +0 -100
- package/src/cli/init.test.ts +0 -240
- package/src/cli/templates/canopy.ts.template +0 -55
- package/src/cli/templates.ts +0 -47
- package/src/client.ts +0 -12
- package/src/comment-store.test.ts +0 -442
- package/src/comment-store.ts +0 -301
- package/src/config/__tests__/config.test.ts +0 -513
- package/src/config/flatten.ts +0 -174
- package/src/config/helpers.ts +0 -167
- package/src/config/index.ts +0 -86
- package/src/config/schemas/collection.ts +0 -67
- package/src/config/schemas/config.ts +0 -77
- package/src/config/schemas/field.ts +0 -108
- package/src/config/schemas/media.ts +0 -27
- package/src/config/schemas/permissions.ts +0 -21
- package/src/config/types.ts +0 -321
- package/src/config/validation.ts +0 -70
- package/src/config-test.ts +0 -65
- package/src/config.ts +0 -11
- package/src/content-id-index.test.ts +0 -512
- package/src/content-id-index.ts +0 -479
- package/src/content-reader.test.ts +0 -478
- package/src/content-reader.ts +0 -214
- package/src/content-store.test.ts +0 -1126
- package/src/content-store.ts +0 -793
- package/src/context.ts +0 -111
- package/src/editor/BranchManager.stories.tsx +0 -80
- package/src/editor/BranchManager.test.tsx +0 -324
- package/src/editor/BranchManager.tsx +0 -461
- package/src/editor/CanopyEditor.stories.tsx +0 -128
- package/src/editor/CanopyEditor.test.tsx +0 -81
- package/src/editor/CanopyEditor.tsx +0 -73
- package/src/editor/CanopyEditorPage.test.tsx +0 -59
- package/src/editor/CanopyEditorPage.tsx +0 -25
- package/src/editor/CommentsPanel.stories.tsx +0 -184
- package/src/editor/CommentsPanel.tsx +0 -338
- package/src/editor/Editor.integration.test.tsx +0 -227
- package/src/editor/Editor.stories.tsx +0 -119
- package/src/editor/Editor.tsx +0 -1221
- package/src/editor/EditorPanes.stories.tsx +0 -256
- package/src/editor/EditorPanes.test.tsx +0 -77
- package/src/editor/EditorPanes.tsx +0 -180
- package/src/editor/EntryNavigator.stories.tsx +0 -65
- package/src/editor/EntryNavigator.test.tsx +0 -598
- package/src/editor/EntryNavigator.tsx +0 -665
- package/src/editor/FormRenderer.stories.tsx +0 -212
- package/src/editor/FormRenderer.test.tsx +0 -194
- package/src/editor/FormRenderer.tsx +0 -432
- package/src/editor/GroupManager.stories.tsx +0 -301
- package/src/editor/GroupManager.test.tsx +0 -682
- package/src/editor/GroupManager.tsx +0 -9
- package/src/editor/PermissionManager.stories.tsx +0 -539
- package/src/editor/PermissionManager.test.tsx +0 -864
- package/src/editor/PermissionManager.tsx +0 -12
- package/src/editor/canopy-path.test.ts +0 -23
- package/src/editor/canopy-path.ts +0 -52
- package/src/editor/client-reference-resolver.ts +0 -118
- package/src/editor/comments/BranchComments.tsx +0 -93
- package/src/editor/comments/EntryComments.tsx +0 -94
- package/src/editor/comments/FieldWrapper.stories.tsx +0 -210
- package/src/editor/comments/FieldWrapper.tsx +0 -129
- package/src/editor/comments/InlineCommentThread.test.tsx +0 -384
- package/src/editor/comments/InlineCommentThread.tsx +0 -246
- package/src/editor/comments/ThreadCarousel.test.tsx +0 -393
- package/src/editor/comments/ThreadCarousel.tsx +0 -525
- package/src/editor/components/ConfirmDeleteModal.tsx +0 -49
- package/src/editor/components/EditorContext.tsx +0 -49
- package/src/editor/components/EditorFooter.tsx +0 -47
- package/src/editor/components/EditorHeader.tsx +0 -492
- package/src/editor/components/EditorSidebar.tsx +0 -193
- package/src/editor/components/EntryCreateModal.tsx +0 -193
- package/src/editor/components/RenameEntryModal.tsx +0 -152
- package/src/editor/components/UserBadge.test.tsx +0 -274
- package/src/editor/components/UserBadge.tsx +0 -240
- package/src/editor/components/index.ts +0 -6
- package/src/editor/context/ApiClientContext.tsx +0 -56
- package/src/editor/context/EditorStateContext.tsx +0 -221
- package/src/editor/context/index.ts +0 -40
- package/src/editor/editor-config.test.ts +0 -385
- package/src/editor/editor-config.ts +0 -94
- package/src/editor/editor-utils.test.ts +0 -772
- package/src/editor/editor-utils.ts +0 -303
- package/src/editor/env.ts +0 -4
- package/src/editor/fields/BlockField.stories.tsx +0 -79
- package/src/editor/fields/BlockField.tsx +0 -267
- package/src/editor/fields/CodeField.tsx +0 -41
- package/src/editor/fields/MarkdownField.tsx +0 -205
- package/src/editor/fields/ObjectField.tsx +0 -71
- package/src/editor/fields/ReferenceField.tsx +0 -138
- package/src/editor/fields/SelectField.tsx +0 -76
- package/src/editor/fields/TextField.tsx +0 -35
- package/src/editor/fields/ToggleField.tsx +0 -37
- package/src/editor/fields/fields.stories.tsx +0 -40
- package/src/editor/group-manager/ExternalGroupsTab.tsx +0 -114
- package/src/editor/group-manager/GroupCard.tsx +0 -102
- package/src/editor/group-manager/GroupForm.tsx +0 -66
- package/src/editor/group-manager/InternalGroupsTab.tsx +0 -147
- package/src/editor/group-manager/MemberList.tsx +0 -184
- package/src/editor/group-manager/hooks/useExternalGroupSearch.ts +0 -63
- package/src/editor/group-manager/hooks/useGroupState.ts +0 -134
- package/src/editor/group-manager/hooks/useUserSearch.ts +0 -84
- package/src/editor/group-manager/index.tsx +0 -210
- package/src/editor/group-manager/types.ts +0 -28
- package/src/editor/hooks/README.md +0 -26
- package/src/editor/hooks/__test__/test-utils.tsx +0 -183
- package/src/editor/hooks/index.ts +0 -23
- package/src/editor/hooks/useBranchActions.test.tsx +0 -267
- package/src/editor/hooks/useBranchActions.tsx +0 -121
- package/src/editor/hooks/useBranchManager.test.tsx +0 -391
- package/src/editor/hooks/useBranchManager.tsx +0 -326
- package/src/editor/hooks/useCommentSystem.test.ts +0 -615
- package/src/editor/hooks/useCommentSystem.ts +0 -347
- package/src/editor/hooks/useDraftManager.test.ts +0 -375
- package/src/editor/hooks/useDraftManager.ts +0 -259
- package/src/editor/hooks/useEditorLayout.test.ts +0 -147
- package/src/editor/hooks/useEditorLayout.ts +0 -67
- package/src/editor/hooks/useEntryManager.test.ts +0 -588
- package/src/editor/hooks/useEntryManager.ts +0 -387
- package/src/editor/hooks/useGroupManager.test.ts +0 -277
- package/src/editor/hooks/useGroupManager.ts +0 -139
- package/src/editor/hooks/usePermissionManager.test.ts +0 -211
- package/src/editor/hooks/usePermissionManager.ts +0 -113
- package/src/editor/hooks/useReferenceResolution.ts +0 -248
- package/src/editor/hooks/useSchemaManager.test.ts +0 -370
- package/src/editor/hooks/useSchemaManager.ts +0 -310
- package/src/editor/hooks/useUserContext.tsx +0 -57
- package/src/editor/hooks/useUserMetadata.test.ts +0 -191
- package/src/editor/hooks/useUserMetadata.ts +0 -71
- package/src/editor/permission-manager/GroupSelector.tsx +0 -73
- package/src/editor/permission-manager/PermissionEditor.tsx +0 -321
- package/src/editor/permission-manager/PermissionLevelBadge.tsx +0 -53
- package/src/editor/permission-manager/PermissionTree.tsx +0 -237
- package/src/editor/permission-manager/UserSelector.tsx +0 -95
- package/src/editor/permission-manager/constants.tsx +0 -18
- package/src/editor/permission-manager/hooks/useGroupsAndUsers.ts +0 -153
- package/src/editor/permission-manager/hooks/usePermissionTree.ts +0 -200
- package/src/editor/permission-manager/index.tsx +0 -294
- package/src/editor/permission-manager/types.ts +0 -58
- package/src/editor/permission-manager/utils.ts +0 -179
- package/src/editor/preview-bridge.test.tsx +0 -50
- package/src/editor/preview-bridge.tsx +0 -294
- package/src/editor/schema-editor/CollectionEditor.test.tsx +0 -238
- package/src/editor/schema-editor/CollectionEditor.tsx +0 -520
- package/src/editor/schema-editor/EntryTypeEditor.test.tsx +0 -215
- package/src/editor/schema-editor/EntryTypeEditor.tsx +0 -367
- package/src/editor/schema-editor/index.ts +0 -19
- package/src/editor/setup-test-dom.ts +0 -10
- package/src/editor/test-setup.ts +0 -33
- package/src/editor/theme.tsx +0 -119
- package/src/editor/utils/env.ts +0 -39
- package/src/entry-schema-registry.test.ts +0 -281
- package/src/entry-schema-registry.ts +0 -121
- package/src/entry-schema.ts +0 -84
- package/src/git-manager.test.ts +0 -552
- package/src/git-manager.ts +0 -667
- package/src/github-service.test.ts +0 -312
- package/src/github-service.ts +0 -295
- package/src/http/handler.test.ts +0 -275
- package/src/http/handler.ts +0 -280
- package/src/http/index.ts +0 -11
- package/src/http/router.ts +0 -164
- package/src/http/types.ts +0 -44
- package/src/id.test.ts +0 -48
- package/src/id.ts +0 -22
- package/src/index.ts +0 -26
- package/src/operating-mode/__tests__/strategies.test.ts +0 -511
- package/src/operating-mode/client-safe-strategy.ts +0 -184
- package/src/operating-mode/client-unsafe-strategy.ts +0 -303
- package/src/operating-mode/client.ts +0 -13
- package/src/operating-mode/index.ts +0 -34
- package/src/operating-mode/types.ts +0 -186
- package/src/paths/__tests__/branch.test.ts +0 -53
- package/src/paths/__tests__/normalize.test.ts +0 -141
- package/src/paths/__tests__/resolve.test.ts +0 -207
- package/src/paths/__tests__/validation.test.ts +0 -61
- package/src/paths/branch.ts +0 -115
- package/src/paths/index.ts +0 -73
- package/src/paths/normalize-server.ts +0 -40
- package/src/paths/normalize.ts +0 -107
- package/src/paths/resolve.ts +0 -61
- package/src/paths/test-utils.ts +0 -37
- package/src/paths/types.ts +0 -68
- package/src/paths/validation.test.ts +0 -480
- package/src/paths/validation.ts +0 -391
- package/src/reference-resolver.test.ts +0 -107
- package/src/reference-resolver.ts +0 -157
- package/src/schema/index.ts +0 -29
- package/src/schema/meta-loader.ts +0 -366
- package/src/schema/resolver.ts +0 -83
- package/src/schema/schema-store-types.ts +0 -56
- package/src/schema/schema-store.test.ts +0 -816
- package/src/schema/schema-store.ts +0 -795
- package/src/schema/types.ts +0 -33
- package/src/schema-meta-loader.test.ts +0 -447
- package/src/server.ts +0 -15
- package/src/services.test.ts +0 -559
- package/src/services.ts +0 -373
- package/src/settings-branch-utils.ts +0 -53
- package/src/settings-workspace.ts +0 -156
- package/src/task-queue/README.md +0 -144
- package/src/task-queue/index.ts +0 -14
- package/src/task-queue/task-queue.test.ts +0 -524
- package/src/task-queue/task-queue.ts +0 -514
- package/src/task-queue/types.ts +0 -41
- package/src/test-utils/api-test-helpers.ts +0 -445
- package/src/test-utils/console-spy.test.ts +0 -14
- package/src/test-utils/console-spy.ts +0 -125
- package/src/test-utils/git-helpers.ts +0 -31
- package/src/test-utils/index.ts +0 -4
- package/src/types.ts +0 -54
- package/src/user.ts +0 -118
- package/src/utils/debug.test.ts +0 -114
- package/src/utils/debug.ts +0 -127
- package/src/utils/error.test.ts +0 -92
- package/src/utils/error.ts +0 -83
- package/src/utils/format.ts +0 -12
- package/src/validation/__tests__/field-traversal.test.ts +0 -263
- package/src/validation/deletion-checker.ts +0 -234
- package/src/validation/field-traversal.ts +0 -146
- package/src/validation/reference-validator.ts +0 -168
- package/src/worker/cms-worker-rebase.test.ts +0 -473
- package/src/worker/cms-worker.ts +0 -777
- package/src/worker/integration.test.ts +0 -289
- package/src/worker/task-queue-config.ts +0 -25
- package/src/worker/task-queue.test.ts +0 -452
- package/src/worker/task-queue.ts +0 -58
- /package/{src/cli/templates → dist/cli/template-files}/Dockerfile.cms.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/canopycms.config.ts.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/deploy-cms.yml.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/edit-page.tsx.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/route.ts.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/schemas.ts.template +0 -0
|
@@ -1,665 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React, { useMemo, useRef, useEffect } from 'react'
|
|
4
|
-
import type { ContentId, LogicalPath } from '../paths/types'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
ActionIcon,
|
|
8
|
-
Badge,
|
|
9
|
-
Box,
|
|
10
|
-
Group,
|
|
11
|
-
Menu,
|
|
12
|
-
ScrollArea,
|
|
13
|
-
Stack,
|
|
14
|
-
Text,
|
|
15
|
-
Tooltip,
|
|
16
|
-
Tree,
|
|
17
|
-
useTree,
|
|
18
|
-
type RenderTreeNodePayload,
|
|
19
|
-
type TreeNodeData,
|
|
20
|
-
rem,
|
|
21
|
-
} from '@mantine/core'
|
|
22
|
-
import {
|
|
23
|
-
IconArrowDown,
|
|
24
|
-
IconArrowUp,
|
|
25
|
-
IconDots,
|
|
26
|
-
IconEdit,
|
|
27
|
-
IconFolderPlus,
|
|
28
|
-
IconPlus,
|
|
29
|
-
IconTrash,
|
|
30
|
-
} from '@tabler/icons-react'
|
|
31
|
-
|
|
32
|
-
import { calculatePathToEntry } from './editor-utils'
|
|
33
|
-
|
|
34
|
-
// TreeController type from Mantine's useTree hook
|
|
35
|
-
type TreeController = ReturnType<typeof useTree>
|
|
36
|
-
|
|
37
|
-
export interface EntryNavItem {
|
|
38
|
-
path: LogicalPath
|
|
39
|
-
label: string
|
|
40
|
-
status?: string
|
|
41
|
-
collectionPath?: LogicalPath
|
|
42
|
-
contentId?: ContentId // 12-char embedded ID for ordering
|
|
43
|
-
/** True when this entry's file conflicted during rebase */
|
|
44
|
-
conflictNotice?: boolean
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface EntryNavCollection {
|
|
48
|
-
path: LogicalPath
|
|
49
|
-
label: string
|
|
50
|
-
type: 'collection' | 'entry'
|
|
51
|
-
contentId?: ContentId // 12-char embedded ID for ordering
|
|
52
|
-
order?: readonly string[] // Order array for interleaving entries and children
|
|
53
|
-
entries?: EntryNavItem[]
|
|
54
|
-
children?: EntryNavCollection[]
|
|
55
|
-
/** True when this collection's .collection.json conflicted during rebase */
|
|
56
|
-
conflictNotice?: boolean
|
|
57
|
-
onAdd?: () => void
|
|
58
|
-
onEdit?: () => void
|
|
59
|
-
onAddSubCollection?: () => void
|
|
60
|
-
onDelete?: () => void
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface EntryNavigatorProps {
|
|
64
|
-
items?: EntryNavItem[]
|
|
65
|
-
collections?: EntryNavCollection[]
|
|
66
|
-
selectedPath?: string
|
|
67
|
-
onSelect: (id: string) => void
|
|
68
|
-
onTreeControllerReady?: (controller: TreeController) => void
|
|
69
|
-
expandedStateRef?: React.MutableRefObject<Record<string, boolean>>
|
|
70
|
-
onExpandedStateChange?: (state: Record<string, boolean>) => void
|
|
71
|
-
/** Called when user requests to delete an entry */
|
|
72
|
-
onDeleteEntry?: (path: LogicalPath) => void
|
|
73
|
-
/** Called when user requests to rename an entry */
|
|
74
|
-
onRenameEntry?: (path: LogicalPath) => void
|
|
75
|
-
/** Called when user reorders an entry within a collection */
|
|
76
|
-
onReorderEntry?: (
|
|
77
|
-
collectionPath: LogicalPath,
|
|
78
|
-
contentId: string,
|
|
79
|
-
direction: 'up' | 'down',
|
|
80
|
-
) => void
|
|
81
|
-
/** If provided, this collection path's node is hidden but its children are rendered at the top level */
|
|
82
|
-
hiddenRootPath?: string
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export const EntryNavigator: React.FC<EntryNavigatorProps> = ({
|
|
86
|
-
items,
|
|
87
|
-
collections,
|
|
88
|
-
selectedPath,
|
|
89
|
-
onSelect,
|
|
90
|
-
onTreeControllerReady,
|
|
91
|
-
expandedStateRef,
|
|
92
|
-
onExpandedStateChange,
|
|
93
|
-
onDeleteEntry,
|
|
94
|
-
onRenameEntry,
|
|
95
|
-
onReorderEntry,
|
|
96
|
-
hiddenRootPath,
|
|
97
|
-
}) => {
|
|
98
|
-
const selectedNodeRef = useRef<HTMLDivElement>(null)
|
|
99
|
-
const hasScrolledRef = useRef(false)
|
|
100
|
-
// Track expanded state synchronously to avoid race conditions on unmount
|
|
101
|
-
const localExpandedStateRef = useRef<Record<string, boolean>>(expandedStateRef?.current ?? {})
|
|
102
|
-
const treeData = useMemo<TreeNodeData[]>(() => {
|
|
103
|
-
if (collections?.length) {
|
|
104
|
-
const toTree = (col: EntryNavCollection): TreeNodeData => {
|
|
105
|
-
if (col.type === 'entry') {
|
|
106
|
-
const entry = col.entries?.[0]
|
|
107
|
-
return {
|
|
108
|
-
value: entry?.path ?? `collection:${col.path}`,
|
|
109
|
-
label: entry?.label ?? col.label,
|
|
110
|
-
nodeProps: {
|
|
111
|
-
status: entry?.status,
|
|
112
|
-
isEntry: true,
|
|
113
|
-
entryPath: entry?.path,
|
|
114
|
-
},
|
|
115
|
-
children: [],
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const entries = col.entries ?? []
|
|
119
|
-
const childCollections = col.children ?? []
|
|
120
|
-
const totalChildren = entries.length + childCollections.length
|
|
121
|
-
const order = col.order ?? []
|
|
122
|
-
|
|
123
|
-
// Build entry nodes keyed by contentId
|
|
124
|
-
const entryNodesByContentId = new Map<string, TreeNodeData>()
|
|
125
|
-
entries.forEach((entry) => {
|
|
126
|
-
const node: TreeNodeData = {
|
|
127
|
-
value: entry.path,
|
|
128
|
-
label: entry.label,
|
|
129
|
-
nodeProps: {
|
|
130
|
-
status: entry.status,
|
|
131
|
-
isEntry: true,
|
|
132
|
-
entryPath: entry.path,
|
|
133
|
-
contentId: entry.contentId,
|
|
134
|
-
conflictNotice: entry.conflictNotice,
|
|
135
|
-
parentCollectionPath: col.path,
|
|
136
|
-
childIndex: 0, // Will be set below
|
|
137
|
-
totalChildrenCount: totalChildren,
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
if (entry.contentId) {
|
|
141
|
-
entryNodesByContentId.set(entry.contentId, node)
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
// Build child collection nodes keyed by contentId
|
|
146
|
-
const childNodesByContentId = new Map<string, TreeNodeData>()
|
|
147
|
-
childCollections.forEach((child) => {
|
|
148
|
-
const childTree = toTree(child)
|
|
149
|
-
const node: TreeNodeData = {
|
|
150
|
-
...childTree,
|
|
151
|
-
nodeProps: {
|
|
152
|
-
...childTree.nodeProps,
|
|
153
|
-
contentId: child.contentId,
|
|
154
|
-
parentCollectionPath: col.path,
|
|
155
|
-
childIndex: 0, // Will be set below
|
|
156
|
-
totalChildrenCount: totalChildren,
|
|
157
|
-
},
|
|
158
|
-
}
|
|
159
|
-
if (child.contentId) {
|
|
160
|
-
childNodesByContentId.set(child.contentId, node)
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
// Interleave entries and children based on order array
|
|
165
|
-
const allChildren: TreeNodeData[] = []
|
|
166
|
-
const usedContentIds = new Set<string>()
|
|
167
|
-
|
|
168
|
-
// First, add items in order
|
|
169
|
-
for (const contentId of order) {
|
|
170
|
-
const entryNode = entryNodesByContentId.get(contentId)
|
|
171
|
-
if (entryNode) {
|
|
172
|
-
entryNode.nodeProps = {
|
|
173
|
-
...entryNode.nodeProps,
|
|
174
|
-
childIndex: allChildren.length,
|
|
175
|
-
}
|
|
176
|
-
allChildren.push(entryNode)
|
|
177
|
-
usedContentIds.add(contentId)
|
|
178
|
-
continue
|
|
179
|
-
}
|
|
180
|
-
const childNode = childNodesByContentId.get(contentId)
|
|
181
|
-
if (childNode) {
|
|
182
|
-
childNode.nodeProps = {
|
|
183
|
-
...childNode.nodeProps,
|
|
184
|
-
childIndex: allChildren.length,
|
|
185
|
-
}
|
|
186
|
-
allChildren.push(childNode)
|
|
187
|
-
usedContentIds.add(contentId)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Add any entries not in order (alphabetically)
|
|
192
|
-
const unorderedEntries = entries
|
|
193
|
-
.filter((e) => !e.contentId || !usedContentIds.has(e.contentId))
|
|
194
|
-
.sort((a, b) => (a.label ?? '').localeCompare(b.label ?? ''))
|
|
195
|
-
for (const entry of unorderedEntries) {
|
|
196
|
-
const node: TreeNodeData = {
|
|
197
|
-
value: entry.path,
|
|
198
|
-
label: entry.label,
|
|
199
|
-
nodeProps: {
|
|
200
|
-
status: entry.status,
|
|
201
|
-
isEntry: true,
|
|
202
|
-
entryPath: entry.path,
|
|
203
|
-
contentId: entry.contentId,
|
|
204
|
-
conflictNotice: entry.conflictNotice,
|
|
205
|
-
parentCollectionPath: col.path,
|
|
206
|
-
childIndex: allChildren.length,
|
|
207
|
-
totalChildrenCount: totalChildren,
|
|
208
|
-
},
|
|
209
|
-
}
|
|
210
|
-
allChildren.push(node)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Add any child collections not in order (alphabetically)
|
|
214
|
-
const unorderedChildren = childCollections
|
|
215
|
-
.filter((c) => !c.contentId || !usedContentIds.has(c.contentId))
|
|
216
|
-
.sort((a, b) => (a.label ?? '').localeCompare(b.label ?? ''))
|
|
217
|
-
for (const child of unorderedChildren) {
|
|
218
|
-
const childTree = toTree(child)
|
|
219
|
-
const node: TreeNodeData = {
|
|
220
|
-
...childTree,
|
|
221
|
-
nodeProps: {
|
|
222
|
-
...childTree.nodeProps,
|
|
223
|
-
contentId: child.contentId,
|
|
224
|
-
parentCollectionPath: col.path,
|
|
225
|
-
childIndex: allChildren.length,
|
|
226
|
-
totalChildrenCount: totalChildren,
|
|
227
|
-
},
|
|
228
|
-
}
|
|
229
|
-
allChildren.push(node)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Collections should always have children array (even if empty) to show chevron
|
|
233
|
-
// This matches standard file tree UI behavior where folders always show expand/collapse
|
|
234
|
-
return {
|
|
235
|
-
value: `collection:${col.path}`,
|
|
236
|
-
label: col.label,
|
|
237
|
-
nodeProps: {
|
|
238
|
-
isCollection: true,
|
|
239
|
-
type: col.type,
|
|
240
|
-
collectionPath: col.path,
|
|
241
|
-
conflictNotice: col.conflictNotice,
|
|
242
|
-
onAdd: col.onAdd,
|
|
243
|
-
onEdit: col.onEdit,
|
|
244
|
-
onAddSubCollection: col.onAddSubCollection,
|
|
245
|
-
onDelete: col.onDelete,
|
|
246
|
-
},
|
|
247
|
-
children: allChildren,
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// If hiddenRootPath is set and matches a single root collection, return its children directly
|
|
252
|
-
// This allows the root collection's order/context to be used for top-level item reordering
|
|
253
|
-
if (hiddenRootPath && collections.length === 1 && collections[0].path === hiddenRootPath) {
|
|
254
|
-
const rootNode = toTree(collections[0])
|
|
255
|
-
return rootNode.children ?? []
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return collections.map(toTree)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const flatItems = items ?? []
|
|
262
|
-
return flatItems.map((item) => ({
|
|
263
|
-
value: item.path,
|
|
264
|
-
label: item.label,
|
|
265
|
-
nodeProps: { status: item.status, isEntry: true, entryPath: item.path },
|
|
266
|
-
}))
|
|
267
|
-
}, [collections, items, hiddenRootPath])
|
|
268
|
-
|
|
269
|
-
// Initialize tree controller
|
|
270
|
-
const tree = useTree({
|
|
271
|
-
initialExpandedState: expandedStateRef?.current ?? {},
|
|
272
|
-
onNodeExpand: (value) => {
|
|
273
|
-
// Update local state synchronously
|
|
274
|
-
localExpandedStateRef.current = {
|
|
275
|
-
...localExpandedStateRef.current,
|
|
276
|
-
[value]: true,
|
|
277
|
-
}
|
|
278
|
-
// Notify parent immediately
|
|
279
|
-
onExpandedStateChange?.(localExpandedStateRef.current)
|
|
280
|
-
},
|
|
281
|
-
onNodeCollapse: (value) => {
|
|
282
|
-
// Update local state synchronously
|
|
283
|
-
localExpandedStateRef.current = {
|
|
284
|
-
...localExpandedStateRef.current,
|
|
285
|
-
[value]: false,
|
|
286
|
-
}
|
|
287
|
-
// Notify parent immediately
|
|
288
|
-
onExpandedStateChange?.(localExpandedStateRef.current)
|
|
289
|
-
},
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
// Forward tree controller to parent for collapse/expand all functionality
|
|
293
|
-
|
|
294
|
-
useEffect(() => {
|
|
295
|
-
onTreeControllerReady?.(tree)
|
|
296
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- fire only when callback ref changes, not on tree state
|
|
297
|
-
}, [onTreeControllerReady])
|
|
298
|
-
|
|
299
|
-
// Cleanup: save current state when component unmounts
|
|
300
|
-
// Empty dependency array ensures this only runs on mount/unmount, not on re-renders
|
|
301
|
-
useEffect(() => {
|
|
302
|
-
return () => {
|
|
303
|
-
onExpandedStateChange?.(localExpandedStateRef.current)
|
|
304
|
-
}
|
|
305
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
306
|
-
}, [])
|
|
307
|
-
|
|
308
|
-
// Restore state on mount and when selectedPath changes
|
|
309
|
-
useEffect(() => {
|
|
310
|
-
if (!selectedPath || !treeData) return
|
|
311
|
-
|
|
312
|
-
const savedState = expandedStateRef?.current ?? {}
|
|
313
|
-
|
|
314
|
-
// Calculate path to current entry and merge with saved state
|
|
315
|
-
const pathToEntry = calculatePathToEntry(selectedPath, treeData)
|
|
316
|
-
const baseState = { ...savedState, ...pathToEntry }
|
|
317
|
-
|
|
318
|
-
// Only update if state actually changed to avoid infinite loops
|
|
319
|
-
const currentStateJson = JSON.stringify(tree.expandedState)
|
|
320
|
-
const newStateJson = JSON.stringify(baseState)
|
|
321
|
-
if (currentStateJson !== newStateJson) {
|
|
322
|
-
tree.setExpandedState(baseState)
|
|
323
|
-
localExpandedStateRef.current = baseState
|
|
324
|
-
// Notify parent of the merged state
|
|
325
|
-
onExpandedStateChange?.(baseState)
|
|
326
|
-
}
|
|
327
|
-
// Dependencies limited to data changes only to prevent infinite update loops
|
|
328
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
329
|
-
}, [selectedPath, treeData])
|
|
330
|
-
|
|
331
|
-
// Auto-scroll to selected entry when drawer opens
|
|
332
|
-
useEffect(() => {
|
|
333
|
-
if (selectedPath && selectedNodeRef.current && !hasScrolledRef.current) {
|
|
334
|
-
// Small delay to ensure tree expansion completes first
|
|
335
|
-
const timeoutId = setTimeout(() => {
|
|
336
|
-
selectedNodeRef.current?.scrollIntoView({
|
|
337
|
-
behavior: 'smooth',
|
|
338
|
-
block: 'center',
|
|
339
|
-
inline: 'nearest',
|
|
340
|
-
})
|
|
341
|
-
hasScrolledRef.current = true
|
|
342
|
-
}, 100)
|
|
343
|
-
|
|
344
|
-
return () => clearTimeout(timeoutId)
|
|
345
|
-
}
|
|
346
|
-
}, [selectedPath, tree.expandedState])
|
|
347
|
-
|
|
348
|
-
// Reset scroll flag when component mounts (drawer opens)
|
|
349
|
-
useEffect(() => {
|
|
350
|
-
hasScrolledRef.current = false
|
|
351
|
-
}, [])
|
|
352
|
-
|
|
353
|
-
const Chevron = ({ expanded, visible }: { expanded: boolean; visible: boolean }) => (
|
|
354
|
-
<svg
|
|
355
|
-
width="18"
|
|
356
|
-
height="18"
|
|
357
|
-
viewBox="0 0 24 24"
|
|
358
|
-
fill="currentColor"
|
|
359
|
-
aria-hidden="true"
|
|
360
|
-
style={{ opacity: visible ? 0.9 : 0 }}
|
|
361
|
-
>
|
|
362
|
-
{expanded ? (
|
|
363
|
-
<path d="M7.41 8.59 12 13.17 16.59 8.59 18 10l-6 6-6-6z" />
|
|
364
|
-
) : (
|
|
365
|
-
<path d="M10 6 8.59 7.41 13.17 12 8.59 16.59 10 18l6-6z" />
|
|
366
|
-
)}
|
|
367
|
-
</svg>
|
|
368
|
-
)
|
|
369
|
-
|
|
370
|
-
const renderNode = ({
|
|
371
|
-
node,
|
|
372
|
-
elementProps,
|
|
373
|
-
hasChildren,
|
|
374
|
-
expanded,
|
|
375
|
-
level,
|
|
376
|
-
}: RenderTreeNodePayload) => {
|
|
377
|
-
const status = node.nodeProps?.status as string | undefined
|
|
378
|
-
const onAdd = node.nodeProps?.onAdd as (() => void) | undefined
|
|
379
|
-
const onEdit = node.nodeProps?.onEdit as (() => void) | undefined
|
|
380
|
-
const onAddSubCollection = node.nodeProps?.onAddSubCollection as (() => void) | undefined
|
|
381
|
-
const onDelete = node.nodeProps?.onDelete as (() => void) | undefined
|
|
382
|
-
const entryPath = node.nodeProps?.entryPath as LogicalPath | undefined
|
|
383
|
-
const contentId = node.nodeProps?.contentId as string | undefined
|
|
384
|
-
const parentCollectionPath = node.nodeProps?.parentCollectionPath as LogicalPath | undefined
|
|
385
|
-
const childIndex = node.nodeProps?.childIndex as number | undefined
|
|
386
|
-
const totalChildrenCount = node.nodeProps?.totalChildrenCount as number | undefined
|
|
387
|
-
const isCollection = node.nodeProps?.isCollection as boolean | undefined
|
|
388
|
-
const isEntry = node.nodeProps?.isEntry as boolean | undefined
|
|
389
|
-
const conflictNotice = node.nodeProps?.conflictNotice as boolean | undefined
|
|
390
|
-
const isLeaf = !hasChildren || isEntry
|
|
391
|
-
const selected = node.value === selectedPath
|
|
392
|
-
|
|
393
|
-
// For collections, always show chevron (even if empty) to match standard tree UI
|
|
394
|
-
// Mantine only provides hasChildren=true if children.length > 0, but we want
|
|
395
|
-
// collections to always be expandable
|
|
396
|
-
const showChevron = hasChildren || Boolean(isCollection)
|
|
397
|
-
|
|
398
|
-
// Reordering is available for both entries and collections that have contentId and parent path
|
|
399
|
-
const canReorder =
|
|
400
|
-
onReorderEntry && contentId && parentCollectionPath && typeof childIndex === 'number'
|
|
401
|
-
const canMoveUp = canReorder && childIndex > 0
|
|
402
|
-
const canMoveDown =
|
|
403
|
-
canReorder && typeof totalChildrenCount === 'number' && childIndex < totalChildrenCount - 1
|
|
404
|
-
|
|
405
|
-
// Determine if we should show a context menu
|
|
406
|
-
// Collections show menu for add/edit/delete actions OR for reordering (subcollections)
|
|
407
|
-
const hasCollectionMenu =
|
|
408
|
-
isCollection && (onAdd || onEdit || onAddSubCollection || onDelete || canReorder)
|
|
409
|
-
const hasEntryMenu = isEntry && entryPath && (onDeleteEntry || onRenameEntry || onReorderEntry)
|
|
410
|
-
|
|
411
|
-
return (
|
|
412
|
-
<Box
|
|
413
|
-
{...elementProps}
|
|
414
|
-
ref={selected ? selectedNodeRef : undefined}
|
|
415
|
-
data-testid={`entry-nav-item-${String(node.label ?? '')
|
|
416
|
-
.toLowerCase()
|
|
417
|
-
.replace(/\s+/g, '-')}`}
|
|
418
|
-
onClick={(event) => {
|
|
419
|
-
elementProps.onClick(event)
|
|
420
|
-
if (isLeaf && isEntry) {
|
|
421
|
-
onSelect(node.value)
|
|
422
|
-
}
|
|
423
|
-
}}
|
|
424
|
-
style={{
|
|
425
|
-
...elementProps.style,
|
|
426
|
-
marginBottom: 4,
|
|
427
|
-
borderRadius: 10,
|
|
428
|
-
paddingInline: 10,
|
|
429
|
-
paddingBlock: 6,
|
|
430
|
-
paddingLeft: `calc(${rem(8)} + ${rem(level * 12)})`,
|
|
431
|
-
backgroundColor: selected ? 'var(--mantine-color-brand-0)' : undefined,
|
|
432
|
-
border: selected ? '1px solid var(--mantine-color-brand-3)' : '1px solid transparent',
|
|
433
|
-
transition: 'background-color 120ms ease, border-color 120ms ease',
|
|
434
|
-
}}
|
|
435
|
-
>
|
|
436
|
-
<Group gap="xs" justify="space-between" wrap="nowrap">
|
|
437
|
-
<Group gap={6} wrap="nowrap">
|
|
438
|
-
<Box
|
|
439
|
-
w={18}
|
|
440
|
-
h={18}
|
|
441
|
-
style={{
|
|
442
|
-
display: 'flex',
|
|
443
|
-
alignItems: 'center',
|
|
444
|
-
justifyContent: 'center',
|
|
445
|
-
}}
|
|
446
|
-
>
|
|
447
|
-
<Chevron expanded={expanded} visible={showChevron} />
|
|
448
|
-
</Box>
|
|
449
|
-
<Text size="sm" fw={selected ? 600 : 500} truncate="end">
|
|
450
|
-
{node.label}
|
|
451
|
-
</Text>
|
|
452
|
-
{status && (
|
|
453
|
-
<Badge size="xs" variant="light" color="gray">
|
|
454
|
-
{status}
|
|
455
|
-
</Badge>
|
|
456
|
-
)}
|
|
457
|
-
{conflictNotice && (
|
|
458
|
-
<Tooltip
|
|
459
|
-
label="This content was updated on the base branch — a reviewer will reconcile"
|
|
460
|
-
withArrow
|
|
461
|
-
>
|
|
462
|
-
<Badge size="xs" variant="light" color="orange" data-testid="conflict-badge">
|
|
463
|
-
conflict
|
|
464
|
-
</Badge>
|
|
465
|
-
</Tooltip>
|
|
466
|
-
)}
|
|
467
|
-
</Group>
|
|
468
|
-
<Group gap={4} wrap="nowrap">
|
|
469
|
-
{hasCollectionMenu && (
|
|
470
|
-
<Menu shadow="md" width={200} withinPortal position="bottom-end">
|
|
471
|
-
<Menu.Target>
|
|
472
|
-
<ActionIcon
|
|
473
|
-
size="xs"
|
|
474
|
-
variant="subtle"
|
|
475
|
-
color="gray"
|
|
476
|
-
onClick={(event) => event.stopPropagation()}
|
|
477
|
-
aria-label="Collection actions"
|
|
478
|
-
data-testid={`collection-menu-${String(node.label ?? '')
|
|
479
|
-
.toLowerCase()
|
|
480
|
-
.replace(/\s+/g, '-')}`}
|
|
481
|
-
>
|
|
482
|
-
<IconDots size={14} />
|
|
483
|
-
</ActionIcon>
|
|
484
|
-
</Menu.Target>
|
|
485
|
-
<Menu.Dropdown>
|
|
486
|
-
{canReorder && (
|
|
487
|
-
<>
|
|
488
|
-
<Menu.Item
|
|
489
|
-
leftSection={<IconArrowUp size={14} />}
|
|
490
|
-
disabled={!canMoveUp}
|
|
491
|
-
onClick={(event) => {
|
|
492
|
-
event.stopPropagation()
|
|
493
|
-
onReorderEntry?.(parentCollectionPath!, contentId!, 'up')
|
|
494
|
-
}}
|
|
495
|
-
>
|
|
496
|
-
Move Up
|
|
497
|
-
</Menu.Item>
|
|
498
|
-
<Menu.Item
|
|
499
|
-
leftSection={<IconArrowDown size={14} />}
|
|
500
|
-
disabled={!canMoveDown}
|
|
501
|
-
onClick={(event) => {
|
|
502
|
-
event.stopPropagation()
|
|
503
|
-
onReorderEntry?.(parentCollectionPath!, contentId!, 'down')
|
|
504
|
-
}}
|
|
505
|
-
>
|
|
506
|
-
Move Down
|
|
507
|
-
</Menu.Item>
|
|
508
|
-
{(onAdd || onAddSubCollection || onEdit || onDelete) && <Menu.Divider />}
|
|
509
|
-
</>
|
|
510
|
-
)}
|
|
511
|
-
{onAdd && (
|
|
512
|
-
<Menu.Item
|
|
513
|
-
leftSection={<IconPlus size={14} />}
|
|
514
|
-
onClick={(event) => {
|
|
515
|
-
event.stopPropagation()
|
|
516
|
-
onAdd()
|
|
517
|
-
}}
|
|
518
|
-
data-testid="add-entry-menu-item"
|
|
519
|
-
>
|
|
520
|
-
Add Entry
|
|
521
|
-
</Menu.Item>
|
|
522
|
-
)}
|
|
523
|
-
{onAddSubCollection && (
|
|
524
|
-
<Menu.Item
|
|
525
|
-
leftSection={<IconFolderPlus size={14} />}
|
|
526
|
-
onClick={(event) => {
|
|
527
|
-
event.stopPropagation()
|
|
528
|
-
onAddSubCollection()
|
|
529
|
-
}}
|
|
530
|
-
>
|
|
531
|
-
Add Sub-Collection
|
|
532
|
-
</Menu.Item>
|
|
533
|
-
)}
|
|
534
|
-
{(onAdd || onAddSubCollection) && (onEdit || onDelete) && <Menu.Divider />}
|
|
535
|
-
{onEdit && (
|
|
536
|
-
<Menu.Item
|
|
537
|
-
leftSection={<IconEdit size={14} />}
|
|
538
|
-
onClick={(event) => {
|
|
539
|
-
event.stopPropagation()
|
|
540
|
-
onEdit()
|
|
541
|
-
}}
|
|
542
|
-
>
|
|
543
|
-
Edit Collection
|
|
544
|
-
</Menu.Item>
|
|
545
|
-
)}
|
|
546
|
-
{onDelete && (
|
|
547
|
-
<Menu.Item
|
|
548
|
-
leftSection={<IconTrash size={14} />}
|
|
549
|
-
color="red"
|
|
550
|
-
onClick={(event) => {
|
|
551
|
-
event.stopPropagation()
|
|
552
|
-
onDelete()
|
|
553
|
-
}}
|
|
554
|
-
>
|
|
555
|
-
Delete Collection
|
|
556
|
-
</Menu.Item>
|
|
557
|
-
)}
|
|
558
|
-
</Menu.Dropdown>
|
|
559
|
-
</Menu>
|
|
560
|
-
)}
|
|
561
|
-
{hasEntryMenu && (
|
|
562
|
-
<Menu shadow="md" width={150} withinPortal position="bottom-end">
|
|
563
|
-
<Menu.Target>
|
|
564
|
-
<ActionIcon
|
|
565
|
-
size="xs"
|
|
566
|
-
variant="subtle"
|
|
567
|
-
color="gray"
|
|
568
|
-
onClick={(event) => event.stopPropagation()}
|
|
569
|
-
aria-label="Entry actions"
|
|
570
|
-
data-testid={`entry-menu-${String(node.label ?? '')
|
|
571
|
-
.toLowerCase()
|
|
572
|
-
.replace(/\s+/g, '-')}`}
|
|
573
|
-
>
|
|
574
|
-
<IconDots size={14} />
|
|
575
|
-
</ActionIcon>
|
|
576
|
-
</Menu.Target>
|
|
577
|
-
<Menu.Dropdown>
|
|
578
|
-
{onReorderEntry && contentId && parentCollectionPath && (
|
|
579
|
-
<>
|
|
580
|
-
<Menu.Item
|
|
581
|
-
leftSection={<IconArrowUp size={14} />}
|
|
582
|
-
disabled={!canMoveUp}
|
|
583
|
-
onClick={(event) => {
|
|
584
|
-
event.stopPropagation()
|
|
585
|
-
onReorderEntry(parentCollectionPath, contentId, 'up')
|
|
586
|
-
}}
|
|
587
|
-
>
|
|
588
|
-
Move Up
|
|
589
|
-
</Menu.Item>
|
|
590
|
-
<Menu.Item
|
|
591
|
-
leftSection={<IconArrowDown size={14} />}
|
|
592
|
-
disabled={!canMoveDown}
|
|
593
|
-
onClick={(event) => {
|
|
594
|
-
event.stopPropagation()
|
|
595
|
-
onReorderEntry(parentCollectionPath, contentId, 'down')
|
|
596
|
-
}}
|
|
597
|
-
>
|
|
598
|
-
Move Down
|
|
599
|
-
</Menu.Item>
|
|
600
|
-
{(onRenameEntry || onDeleteEntry) && <Menu.Divider />}
|
|
601
|
-
</>
|
|
602
|
-
)}
|
|
603
|
-
{onRenameEntry && (
|
|
604
|
-
<Menu.Item
|
|
605
|
-
leftSection={<IconEdit size={14} />}
|
|
606
|
-
onClick={(event) => {
|
|
607
|
-
event.stopPropagation()
|
|
608
|
-
onRenameEntry(entryPath)
|
|
609
|
-
}}
|
|
610
|
-
data-testid="rename-entry-menu-item"
|
|
611
|
-
>
|
|
612
|
-
Rename Entry
|
|
613
|
-
</Menu.Item>
|
|
614
|
-
)}
|
|
615
|
-
{onDeleteEntry && (
|
|
616
|
-
<Menu.Item
|
|
617
|
-
leftSection={<IconTrash size={14} />}
|
|
618
|
-
color="red"
|
|
619
|
-
onClick={(event) => {
|
|
620
|
-
event.stopPropagation()
|
|
621
|
-
onDeleteEntry(entryPath)
|
|
622
|
-
}}
|
|
623
|
-
data-testid="delete-entry-menu-item"
|
|
624
|
-
>
|
|
625
|
-
Delete Entry
|
|
626
|
-
</Menu.Item>
|
|
627
|
-
)}
|
|
628
|
-
</Menu.Dropdown>
|
|
629
|
-
</Menu>
|
|
630
|
-
)}
|
|
631
|
-
</Group>
|
|
632
|
-
</Group>
|
|
633
|
-
</Box>
|
|
634
|
-
)
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
return (
|
|
638
|
-
<Stack
|
|
639
|
-
h="100%"
|
|
640
|
-
style={{ display: 'flex', flexDirection: 'column' }}
|
|
641
|
-
gap={0}
|
|
642
|
-
data-testid="entry-navigator"
|
|
643
|
-
>
|
|
644
|
-
<ScrollArea type="auto" offsetScrollbars style={{ flex: 1 }}>
|
|
645
|
-
{treeData.length === 0 ? (
|
|
646
|
-
<Text size="xs" c="dimmed" py="sm">
|
|
647
|
-
No content
|
|
648
|
-
</Text>
|
|
649
|
-
) : (
|
|
650
|
-
<Box py="sm">
|
|
651
|
-
<Tree
|
|
652
|
-
data={treeData}
|
|
653
|
-
tree={tree}
|
|
654
|
-
renderNode={renderNode}
|
|
655
|
-
selectOnClick={false}
|
|
656
|
-
levelOffset="sm"
|
|
657
|
-
/>
|
|
658
|
-
</Box>
|
|
659
|
-
)}
|
|
660
|
-
</ScrollArea>
|
|
661
|
-
</Stack>
|
|
662
|
-
)
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
export default EntryNavigator
|