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,525 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React, { useState, useMemo, useEffect, useRef } from 'react'
|
|
4
|
-
import { ActionIcon, Alert, Button, Group, Paper, Stack, Text, Textarea } from '@mantine/core'
|
|
5
|
-
import { IconChevronLeft, IconChevronRight, IconAlertCircle } from '@tabler/icons-react'
|
|
6
|
-
import type { CommentThread } from '../../comment-store'
|
|
7
|
-
import type { UserSearchResult } from '../../auth/types'
|
|
8
|
-
import { InlineCommentThread } from './InlineCommentThread'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* ThreadCarousel - Horizontal comment thread navigation component
|
|
12
|
-
*
|
|
13
|
-
* ## Purpose
|
|
14
|
-
* Provides a horizontal carousel UI for navigating between multiple comment threads
|
|
15
|
-
* on fields, entries, or branches. Supports both keyboard navigation (arrow buttons)
|
|
16
|
-
* and displays a visual "peekaboo" preview of adjacent threads.
|
|
17
|
-
*
|
|
18
|
-
* ## Key Behaviors
|
|
19
|
-
*
|
|
20
|
-
* ### Layout & Sizing
|
|
21
|
-
* - **Active thread width**: `calc(100% - 72px)` - fills container minus peekaboo space
|
|
22
|
-
* - **Single thread width**: `calc(100% - 72px)` - same as active (for consistency)
|
|
23
|
-
* - **Inactive thread width**: `400px` - fixed width when not in view
|
|
24
|
-
* - **Peekaboo size**: `60px` - sliver of next thread shown on right edge
|
|
25
|
-
* - **Gap between threads**: `12px`
|
|
26
|
-
*
|
|
27
|
-
* ### Peekaboo Preview
|
|
28
|
-
* - Shows 60px of the next thread on the right edge (when not viewing last thread)
|
|
29
|
-
* - Gradient fade overlay applied to peekaboo area for visual polish
|
|
30
|
-
* - **Last thread behavior**: Invisible 60px spacer ensures last thread stays left-aligned
|
|
31
|
-
* without showing previous threads on the left
|
|
32
|
-
* - Peekaboo helps users discover there are more threads to navigate
|
|
33
|
-
*
|
|
34
|
-
* ### Thread Sorting
|
|
35
|
-
* - **Unresolved threads first** (primary sort)
|
|
36
|
-
* - **Newest first within same resolved state** (secondary sort by createdAt)
|
|
37
|
-
* - This ensures urgent unresolved feedback appears first
|
|
38
|
-
*
|
|
39
|
-
* ### Navigation
|
|
40
|
-
* - **Arrow buttons**: `← 2/5 →` counter with disabled states at boundaries
|
|
41
|
-
* - **Smooth scrolling**: CSS `scroll-behavior: smooth` with programmatic scroll
|
|
42
|
-
* - **Auto-scroll**: When `autoFocus` is true, automatically scrolls to first unresolved thread
|
|
43
|
-
* - **Mouse scrolling disabled**: `overflowX: 'hidden'` - only button navigation allowed
|
|
44
|
-
* - **Scroll calculation**: Accounts for active thread width + gaps when navigating
|
|
45
|
-
*
|
|
46
|
-
* ### Always-Visible Design
|
|
47
|
-
* - Component renders even with 0 threads (shows "No comments yet" message)
|
|
48
|
-
* - "New" button always accessible in header
|
|
49
|
-
* - Header shows thread count when threads exist: "Comments (3)"
|
|
50
|
-
* - Navigation arrows only appear when multiple threads exist
|
|
51
|
-
*
|
|
52
|
-
* ### Vertical Resizing
|
|
53
|
-
* - **Default height**: 400px
|
|
54
|
-
* - **Resize range**: 200px (min) to 600px (max)
|
|
55
|
-
* - **Resize handle**: Bottom edge with visual feedback on hover/drag
|
|
56
|
-
* - User can drag to adjust carousel height for their workflow
|
|
57
|
-
*
|
|
58
|
-
* ### New Thread Creation
|
|
59
|
-
* - "New" button in header toggles inline thread creation box
|
|
60
|
-
* - `autoOpenNewThread` prop auto-opens box (used when clicking "New comment" button)
|
|
61
|
-
* - New thread box appears above carousel, with textarea and Create/Cancel buttons
|
|
62
|
-
*
|
|
63
|
-
* ## Usage Context
|
|
64
|
-
* Used by:
|
|
65
|
-
* - **FieldWrapper**: Inline comments beneath form fields
|
|
66
|
-
* - **EntryComments**: Comments at top of entry form
|
|
67
|
-
* - **BranchComments**: Comments at top of BranchManager
|
|
68
|
-
*
|
|
69
|
-
* ## Design Decisions
|
|
70
|
-
*
|
|
71
|
-
* ### Why calc(100% - 72px)?
|
|
72
|
-
* - 60px for peekaboo preview + 12px gap = 72px total
|
|
73
|
-
* - Active thread fills remaining space for maximum readability
|
|
74
|
-
* - Consistent sizing between single thread and active thread in multi-thread scenarios
|
|
75
|
-
*
|
|
76
|
-
* ### Why invisible spacer at end?
|
|
77
|
-
* - Without spacer: last thread would align to right edge, showing previous threads on left
|
|
78
|
-
* - With spacer: last thread stays left-aligned with blank space on right (matching peekaboo size)
|
|
79
|
-
* - Creates consistent left-alignment across all thread positions
|
|
80
|
-
*
|
|
81
|
-
* ### Why disable mouse scrolling?
|
|
82
|
-
* - Prevents accidental scroll-wheel navigation that could be jarring
|
|
83
|
-
* - Forces deliberate button-based navigation for better UX
|
|
84
|
-
* - Scroll-snap still works programmatically for smooth transitions
|
|
85
|
-
*
|
|
86
|
-
* ### Why sort unresolved first?
|
|
87
|
-
* - Unresolved threads require action, so they should be most visible
|
|
88
|
-
* - Resolved threads are less urgent and can appear later in carousel
|
|
89
|
-
* - Newest-first secondary sort ensures recent feedback is prioritized
|
|
90
|
-
*/
|
|
91
|
-
|
|
92
|
-
export interface ThreadCarouselProps {
|
|
93
|
-
/** All threads for this context */
|
|
94
|
-
threads: CommentThread[]
|
|
95
|
-
/** Label for the comment section (e.g., "Comments", "Entry Comments") */
|
|
96
|
-
label?: string
|
|
97
|
-
/** Context type for creating new threads */
|
|
98
|
-
contextType: 'field' | 'entry' | 'branch'
|
|
99
|
-
/** Current user ID */
|
|
100
|
-
currentUserId: string
|
|
101
|
-
/** Whether user can resolve threads */
|
|
102
|
-
canResolve: boolean
|
|
103
|
-
/** Handler to add a new comment (creates new thread or adds to existing) */
|
|
104
|
-
onAddComment: (text: string, threadId?: string) => Promise<void>
|
|
105
|
-
/** Handler to resolve a thread */
|
|
106
|
-
onResolveThread: (threadId: string) => Promise<void>
|
|
107
|
-
/** Auto-focus and expand (from preview click) */
|
|
108
|
-
autoFocus?: boolean
|
|
109
|
-
/** Auto-open new thread box */
|
|
110
|
-
autoOpenNewThread?: boolean
|
|
111
|
-
/** Thread ID to highlight and scroll to */
|
|
112
|
-
highlightThreadId?: string
|
|
113
|
-
/** Optional function to fetch user metadata for displaying user badges */
|
|
114
|
-
onGetUserMetadata?: (userId: string) => Promise<UserSearchResult | null>
|
|
115
|
-
}
|
|
116
|
-
export const ThreadCarousel: React.FC<ThreadCarouselProps> = ({
|
|
117
|
-
threads,
|
|
118
|
-
label = 'Comments',
|
|
119
|
-
contextType: _,
|
|
120
|
-
currentUserId,
|
|
121
|
-
canResolve,
|
|
122
|
-
onAddComment,
|
|
123
|
-
onResolveThread,
|
|
124
|
-
autoFocus,
|
|
125
|
-
autoOpenNewThread,
|
|
126
|
-
highlightThreadId,
|
|
127
|
-
onGetUserMetadata,
|
|
128
|
-
}) => {
|
|
129
|
-
const [currentIndex, setCurrentIndex] = useState(0)
|
|
130
|
-
const [showNewThreadBox, setShowNewThreadBox] = useState(false)
|
|
131
|
-
const [newThreadText, setNewThreadText] = useState('')
|
|
132
|
-
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
133
|
-
const [carouselHeight, setCarouselHeight] = useState(400)
|
|
134
|
-
const [isResizing, setIsResizing] = useState(false)
|
|
135
|
-
const [highlightedThreadId, setHighlightedThreadId] = useState<string | undefined>(undefined)
|
|
136
|
-
const [error, setError] = useState<string | null>(null)
|
|
137
|
-
const scrollContainerRef = useRef<HTMLDivElement>(null)
|
|
138
|
-
const resizeStartY = useRef<number>(0)
|
|
139
|
-
const resizeStartHeight = useRef<number>(0)
|
|
140
|
-
|
|
141
|
-
// Sort: unresolved first, then resolved
|
|
142
|
-
const sortedThreads = useMemo(
|
|
143
|
-
() =>
|
|
144
|
-
[...threads].sort((a, b) => {
|
|
145
|
-
if (a.resolved === b.resolved) {
|
|
146
|
-
// Same resolved state: sort by createdAt (newest first)
|
|
147
|
-
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
|
148
|
-
}
|
|
149
|
-
return a.resolved ? 1 : -1
|
|
150
|
-
}),
|
|
151
|
-
[threads],
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
// Auto-scroll to first unresolved thread when autoFocus is true
|
|
155
|
-
|
|
156
|
-
useEffect(() => {
|
|
157
|
-
if (autoFocus && sortedThreads.length > 0) {
|
|
158
|
-
const firstUnresolved = sortedThreads.find((t) => !t.resolved)
|
|
159
|
-
if (firstUnresolved) {
|
|
160
|
-
const index = sortedThreads.findIndex((t) => t.id === firstUnresolved.id)
|
|
161
|
-
setCurrentIndex(index)
|
|
162
|
-
// Scroll to thread
|
|
163
|
-
scrollToIndex(index)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- scrollToIndex is stable
|
|
167
|
-
}, [autoFocus, sortedThreads])
|
|
168
|
-
|
|
169
|
-
// Scroll to and highlight specific thread when highlightThreadId changes
|
|
170
|
-
|
|
171
|
-
useEffect(() => {
|
|
172
|
-
if (highlightThreadId && sortedThreads.length > 0) {
|
|
173
|
-
const threadIndex = sortedThreads.findIndex((t) => t.id === highlightThreadId)
|
|
174
|
-
if (threadIndex !== -1) {
|
|
175
|
-
setCurrentIndex(threadIndex)
|
|
176
|
-
scrollToIndex(threadIndex)
|
|
177
|
-
setHighlightedThreadId(highlightThreadId)
|
|
178
|
-
// Clear highlight after 2 seconds
|
|
179
|
-
const timer = window.setTimeout(() => {
|
|
180
|
-
setHighlightedThreadId(undefined)
|
|
181
|
-
}, 2000)
|
|
182
|
-
return () => window.clearTimeout(timer)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps -- scrollToIndex is stable
|
|
186
|
-
}, [highlightThreadId, sortedThreads])
|
|
187
|
-
|
|
188
|
-
// Auto-open new thread box when autoOpenNewThread is true
|
|
189
|
-
useEffect(() => {
|
|
190
|
-
if (autoOpenNewThread) {
|
|
191
|
-
setShowNewThreadBox(true)
|
|
192
|
-
}
|
|
193
|
-
}, [autoOpenNewThread])
|
|
194
|
-
|
|
195
|
-
// Handle resize dragging
|
|
196
|
-
useEffect(() => {
|
|
197
|
-
const handleMouseMove = (e: MouseEvent) => {
|
|
198
|
-
if (!isResizing) return
|
|
199
|
-
const delta = e.clientY - resizeStartY.current
|
|
200
|
-
const newHeight = Math.max(200, Math.min(600, resizeStartHeight.current + delta))
|
|
201
|
-
setCarouselHeight(newHeight)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const handleMouseUp = () => {
|
|
205
|
-
setIsResizing(false)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (isResizing) {
|
|
209
|
-
document.addEventListener('mousemove', handleMouseMove)
|
|
210
|
-
document.addEventListener('mouseup', handleMouseUp)
|
|
211
|
-
return () => {
|
|
212
|
-
document.removeEventListener('mousemove', handleMouseMove)
|
|
213
|
-
document.removeEventListener('mouseup', handleMouseUp)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}, [isResizing])
|
|
217
|
-
|
|
218
|
-
const handleResizeStart = (e: React.MouseEvent) => {
|
|
219
|
-
e.preventDefault()
|
|
220
|
-
setIsResizing(true)
|
|
221
|
-
resizeStartY.current = e.clientY
|
|
222
|
-
resizeStartHeight.current = carouselHeight
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const scrollToIndex = (index: number) => {
|
|
226
|
-
if (scrollContainerRef.current) {
|
|
227
|
-
const container = scrollContainerRef.current
|
|
228
|
-
// Calculate scroll position based on container width
|
|
229
|
-
// Active thread takes most space, others are 400px + gap
|
|
230
|
-
let scrollLeft = 0
|
|
231
|
-
for (let i = 0; i < index; i++) {
|
|
232
|
-
if (sortedThreads.length > 1) {
|
|
233
|
-
// Each previous thread was the active one when visible, so use full width
|
|
234
|
-
scrollLeft += container.clientWidth - 72 + 12 // width - peekaboo + gap
|
|
235
|
-
} else {
|
|
236
|
-
scrollLeft += 400 + 12
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
container.scrollTo({
|
|
240
|
-
left: scrollLeft,
|
|
241
|
-
behavior: 'smooth',
|
|
242
|
-
})
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const handlePrevious = () => {
|
|
247
|
-
if (currentIndex > 0) {
|
|
248
|
-
const newIndex = currentIndex - 1
|
|
249
|
-
setCurrentIndex(newIndex)
|
|
250
|
-
scrollToIndex(newIndex)
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const handleNext = () => {
|
|
255
|
-
if (currentIndex < sortedThreads.length - 1) {
|
|
256
|
-
const newIndex = currentIndex + 1
|
|
257
|
-
setCurrentIndex(newIndex)
|
|
258
|
-
scrollToIndex(newIndex)
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const handleAddReply = async (threadId: string, text: string) => {
|
|
263
|
-
try {
|
|
264
|
-
setError(null)
|
|
265
|
-
await onAddComment(text, threadId)
|
|
266
|
-
} catch (err) {
|
|
267
|
-
setError(err instanceof Error ? err.message : 'Failed to add reply')
|
|
268
|
-
throw err // Re-throw so InlineCommentThread can handle it
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const handleCreateNewThread = async () => {
|
|
273
|
-
if (!newThreadText.trim()) return
|
|
274
|
-
|
|
275
|
-
setIsSubmitting(true)
|
|
276
|
-
setError(null)
|
|
277
|
-
try {
|
|
278
|
-
await onAddComment(newThreadText)
|
|
279
|
-
setNewThreadText('')
|
|
280
|
-
setShowNewThreadBox(false)
|
|
281
|
-
} catch (err) {
|
|
282
|
-
setError(err instanceof Error ? err.message : 'Failed to create comment')
|
|
283
|
-
} finally {
|
|
284
|
-
setIsSubmitting(false)
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const unresolvedCount = sortedThreads.filter((t) => !t.resolved).length
|
|
289
|
-
|
|
290
|
-
return (
|
|
291
|
-
<Paper p="sm" bg="gray.0" style={{ marginTop: 8 }}>
|
|
292
|
-
<Stack gap="xs">
|
|
293
|
-
{/* Header: always visible */}
|
|
294
|
-
<Group justify="space-between" align="center">
|
|
295
|
-
<Group gap="xs">
|
|
296
|
-
<Text size="sm" fw={600}>
|
|
297
|
-
{label}
|
|
298
|
-
{sortedThreads.length > 0 && ` (${sortedThreads.length})`}
|
|
299
|
-
</Text>
|
|
300
|
-
{unresolvedCount > 0 && (
|
|
301
|
-
<Text size="xs" c="orange" fw={600}>
|
|
302
|
-
{unresolvedCount} unresolved
|
|
303
|
-
</Text>
|
|
304
|
-
)}
|
|
305
|
-
</Group>
|
|
306
|
-
|
|
307
|
-
<Group gap="xs">
|
|
308
|
-
{/* Navigation arrows (only if multiple threads) */}
|
|
309
|
-
{sortedThreads.length > 1 && (
|
|
310
|
-
<>
|
|
311
|
-
<ActionIcon
|
|
312
|
-
size="sm"
|
|
313
|
-
variant="subtle"
|
|
314
|
-
onClick={handlePrevious}
|
|
315
|
-
disabled={currentIndex === 0}
|
|
316
|
-
>
|
|
317
|
-
<IconChevronLeft size={16} />
|
|
318
|
-
</ActionIcon>
|
|
319
|
-
<Text size="xs" fw={500}>
|
|
320
|
-
{currentIndex + 1}/{sortedThreads.length}
|
|
321
|
-
</Text>
|
|
322
|
-
<ActionIcon
|
|
323
|
-
size="sm"
|
|
324
|
-
variant="subtle"
|
|
325
|
-
onClick={handleNext}
|
|
326
|
-
disabled={currentIndex === sortedThreads.length - 1}
|
|
327
|
-
>
|
|
328
|
-
<IconChevronRight size={16} />
|
|
329
|
-
</ActionIcon>
|
|
330
|
-
<div
|
|
331
|
-
style={{
|
|
332
|
-
width: 1,
|
|
333
|
-
height: 16,
|
|
334
|
-
background: 'var(--mantine-color-gray-4)',
|
|
335
|
-
}}
|
|
336
|
-
/>
|
|
337
|
-
</>
|
|
338
|
-
)}
|
|
339
|
-
|
|
340
|
-
{/* New button (always visible) */}
|
|
341
|
-
<Button
|
|
342
|
-
size="xs"
|
|
343
|
-
variant="light"
|
|
344
|
-
onClick={() => setShowNewThreadBox(!showNewThreadBox)}
|
|
345
|
-
>
|
|
346
|
-
+ New
|
|
347
|
-
</Button>
|
|
348
|
-
</Group>
|
|
349
|
-
</Group>
|
|
350
|
-
|
|
351
|
-
{/* Error display */}
|
|
352
|
-
{error && (
|
|
353
|
-
<Alert
|
|
354
|
-
icon={<IconAlertCircle size={16} />}
|
|
355
|
-
color="red"
|
|
356
|
-
variant="light"
|
|
357
|
-
onClose={() => setError(null)}
|
|
358
|
-
withCloseButton
|
|
359
|
-
>
|
|
360
|
-
{error}
|
|
361
|
-
</Alert>
|
|
362
|
-
)}
|
|
363
|
-
|
|
364
|
-
{/* New thread box */}
|
|
365
|
-
{showNewThreadBox && (
|
|
366
|
-
<Paper withBorder p="sm" bg="white">
|
|
367
|
-
<Stack gap="xs">
|
|
368
|
-
<Textarea
|
|
369
|
-
placeholder="Start a new thread..."
|
|
370
|
-
value={newThreadText}
|
|
371
|
-
onChange={(e) => setNewThreadText(e.target.value)}
|
|
372
|
-
minRows={2}
|
|
373
|
-
disabled={isSubmitting}
|
|
374
|
-
autoFocus
|
|
375
|
-
data-testid="new-thread-textarea"
|
|
376
|
-
/>
|
|
377
|
-
<Group gap="xs">
|
|
378
|
-
<Button
|
|
379
|
-
size="xs"
|
|
380
|
-
onClick={handleCreateNewThread}
|
|
381
|
-
loading={isSubmitting}
|
|
382
|
-
disabled={!newThreadText.trim()}
|
|
383
|
-
data-testid="create-thread-button"
|
|
384
|
-
>
|
|
385
|
-
Create Thread
|
|
386
|
-
</Button>
|
|
387
|
-
<Button size="xs" variant="subtle" onClick={() => setShowNewThreadBox(false)}>
|
|
388
|
-
Cancel
|
|
389
|
-
</Button>
|
|
390
|
-
</Group>
|
|
391
|
-
</Stack>
|
|
392
|
-
</Paper>
|
|
393
|
-
)}
|
|
394
|
-
|
|
395
|
-
{/* Thread carousel */}
|
|
396
|
-
{sortedThreads.length > 0 && (
|
|
397
|
-
<div
|
|
398
|
-
style={{
|
|
399
|
-
position: 'relative',
|
|
400
|
-
width: '100%',
|
|
401
|
-
}}
|
|
402
|
-
>
|
|
403
|
-
<div
|
|
404
|
-
ref={scrollContainerRef}
|
|
405
|
-
style={{
|
|
406
|
-
display: 'flex',
|
|
407
|
-
gap: 12,
|
|
408
|
-
overflowX: 'hidden', // Disable mouse scrolling
|
|
409
|
-
scrollSnapType: 'x mandatory',
|
|
410
|
-
scrollBehavior: 'smooth',
|
|
411
|
-
maxHeight: carouselHeight,
|
|
412
|
-
position: 'relative',
|
|
413
|
-
width: '100%', // Ensure container respects parent width boundary
|
|
414
|
-
}}
|
|
415
|
-
>
|
|
416
|
-
{sortedThreads.map((thread, idx) => {
|
|
417
|
-
const isActive = idx === currentIndex
|
|
418
|
-
const isHighlighted = thread.id === highlightedThreadId
|
|
419
|
-
|
|
420
|
-
return (
|
|
421
|
-
<div
|
|
422
|
-
key={thread.id}
|
|
423
|
-
style={{
|
|
424
|
-
scrollSnapAlign: 'start',
|
|
425
|
-
flexShrink: 0,
|
|
426
|
-
// Active thread or single thread stretches to fill space minus peekaboo
|
|
427
|
-
width:
|
|
428
|
-
isActive || sortedThreads.length === 1
|
|
429
|
-
? 'calc(100% - 72px)' // Active or single: leave room for peekaboo/spacing
|
|
430
|
-
: 400, // Non-active: fixed width
|
|
431
|
-
maxWidth: isActive || sortedThreads.length === 1 ? 'calc(100% - 72px)' : 400,
|
|
432
|
-
// Add highlight animation
|
|
433
|
-
outline: isHighlighted ? '3px solid var(--mantine-color-blue-5)' : undefined,
|
|
434
|
-
outlineOffset: isHighlighted ? 2 : undefined,
|
|
435
|
-
borderRadius: isHighlighted ? 8 : undefined,
|
|
436
|
-
transition: 'outline 0.3s ease, outline-offset 0.3s ease',
|
|
437
|
-
}}
|
|
438
|
-
>
|
|
439
|
-
<InlineCommentThread
|
|
440
|
-
thread={thread}
|
|
441
|
-
onAddReply={(text) => handleAddReply(thread.id, text)}
|
|
442
|
-
onResolve={() => onResolveThread(thread.id)}
|
|
443
|
-
currentUserId={currentUserId}
|
|
444
|
-
canResolve={canResolve}
|
|
445
|
-
onGetUserMetadata={onGetUserMetadata}
|
|
446
|
-
/>
|
|
447
|
-
</div>
|
|
448
|
-
)
|
|
449
|
-
})}
|
|
450
|
-
|
|
451
|
-
{/* Invisible spacer at end to maintain left alignment for last thread */}
|
|
452
|
-
{sortedThreads.length > 1 && (
|
|
453
|
-
<div
|
|
454
|
-
style={{
|
|
455
|
-
flexShrink: 0,
|
|
456
|
-
width: 60, // Match peekaboo size
|
|
457
|
-
visibility: 'hidden',
|
|
458
|
-
}}
|
|
459
|
-
/>
|
|
460
|
-
)}
|
|
461
|
-
</div>
|
|
462
|
-
|
|
463
|
-
{/* Peekaboo gradient fade overlay */}
|
|
464
|
-
{sortedThreads.length > 1 && currentIndex < sortedThreads.length - 1 && (
|
|
465
|
-
<div
|
|
466
|
-
style={{
|
|
467
|
-
position: 'absolute',
|
|
468
|
-
top: 0,
|
|
469
|
-
right: 0,
|
|
470
|
-
width: 60,
|
|
471
|
-
height: '100%',
|
|
472
|
-
background:
|
|
473
|
-
'linear-gradient(to left, var(--mantine-color-gray-0) 0%, transparent 100%)',
|
|
474
|
-
pointerEvents: 'none',
|
|
475
|
-
}}
|
|
476
|
-
/>
|
|
477
|
-
)}
|
|
478
|
-
|
|
479
|
-
{/* Resize handle */}
|
|
480
|
-
<div
|
|
481
|
-
onMouseDown={handleResizeStart}
|
|
482
|
-
style={{
|
|
483
|
-
position: 'absolute',
|
|
484
|
-
bottom: 0,
|
|
485
|
-
left: 0,
|
|
486
|
-
right: 0,
|
|
487
|
-
height: 8,
|
|
488
|
-
cursor: 'ns-resize',
|
|
489
|
-
background: isResizing ? 'var(--mantine-color-blue-5)' : 'transparent',
|
|
490
|
-
transition: 'background 0.2s',
|
|
491
|
-
display: 'flex',
|
|
492
|
-
alignItems: 'center',
|
|
493
|
-
justifyContent: 'center',
|
|
494
|
-
}}
|
|
495
|
-
onMouseEnter={(e) => {
|
|
496
|
-
e.currentTarget.style.background = 'var(--mantine-color-gray-3)'
|
|
497
|
-
}}
|
|
498
|
-
onMouseLeave={(e) => {
|
|
499
|
-
if (!isResizing) {
|
|
500
|
-
e.currentTarget.style.background = 'transparent'
|
|
501
|
-
}
|
|
502
|
-
}}
|
|
503
|
-
>
|
|
504
|
-
<div
|
|
505
|
-
style={{
|
|
506
|
-
width: 40,
|
|
507
|
-
height: 3,
|
|
508
|
-
borderRadius: 2,
|
|
509
|
-
background: 'var(--mantine-color-gray-5)',
|
|
510
|
-
}}
|
|
511
|
-
/>
|
|
512
|
-
</div>
|
|
513
|
-
</div>
|
|
514
|
-
)}
|
|
515
|
-
|
|
516
|
-
{/* Empty state */}
|
|
517
|
-
{sortedThreads.length === 0 && !showNewThreadBox && (
|
|
518
|
-
<Text size="xs" c="dimmed" ta="center" py="xs">
|
|
519
|
-
No comments yet. Click "+ New" to start a thread.
|
|
520
|
-
</Text>
|
|
521
|
-
)}
|
|
522
|
-
</Stack>
|
|
523
|
-
</Paper>
|
|
524
|
-
)
|
|
525
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Modal, Button, Text, Group, Stack } from '@mantine/core'
|
|
4
|
-
|
|
5
|
-
export interface ConfirmDeleteModalProps {
|
|
6
|
-
isOpen: boolean
|
|
7
|
-
title: string
|
|
8
|
-
message: string
|
|
9
|
-
confirmLabel?: string
|
|
10
|
-
onConfirm: () => void
|
|
11
|
-
onClose: () => void
|
|
12
|
-
loading?: boolean
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Confirmation modal for delete operations.
|
|
17
|
-
* Provides a clear warning UI with red/danger theme.
|
|
18
|
-
*/
|
|
19
|
-
export function ConfirmDeleteModal({
|
|
20
|
-
isOpen,
|
|
21
|
-
title,
|
|
22
|
-
message,
|
|
23
|
-
confirmLabel = 'Delete',
|
|
24
|
-
onConfirm,
|
|
25
|
-
onClose,
|
|
26
|
-
loading = false,
|
|
27
|
-
}: ConfirmDeleteModalProps) {
|
|
28
|
-
return (
|
|
29
|
-
<Modal opened={isOpen} onClose={onClose} title={title} centered size="md">
|
|
30
|
-
<Stack gap="md" data-testid="confirm-delete-modal">
|
|
31
|
-
<Text size="sm">{message}</Text>
|
|
32
|
-
|
|
33
|
-
<Group justify="flex-end" gap="sm">
|
|
34
|
-
<Button variant="default" onClick={onClose} disabled={loading}>
|
|
35
|
-
Cancel
|
|
36
|
-
</Button>
|
|
37
|
-
<Button
|
|
38
|
-
color="red"
|
|
39
|
-
onClick={onConfirm}
|
|
40
|
-
loading={loading}
|
|
41
|
-
data-testid="confirm-delete-submit"
|
|
42
|
-
>
|
|
43
|
-
{confirmLabel}
|
|
44
|
-
</Button>
|
|
45
|
-
</Group>
|
|
46
|
-
</Stack>
|
|
47
|
-
</Modal>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from 'react'
|
|
2
|
-
import type { CommentThread } from '../../comment-store'
|
|
3
|
-
import type { EditorEntry } from '../Editor'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* EditorContext provides shared state for deeply nested components
|
|
7
|
-
* to avoid prop drilling through 5+ component levels.
|
|
8
|
-
*
|
|
9
|
-
* Contains:
|
|
10
|
-
* - Core navigation state (branchName, selectedPath, currentEntry)
|
|
11
|
-
* - Global busy state
|
|
12
|
-
* - Comment system state (for FormRenderer, FieldWrapper, CommentsPanel)
|
|
13
|
-
* - User context for permissions
|
|
14
|
-
*/
|
|
15
|
-
export interface EditorContextValue {
|
|
16
|
-
// Core navigation (used by 5+ components)
|
|
17
|
-
branchName: string
|
|
18
|
-
selectedPath: string
|
|
19
|
-
currentEntry: EditorEntry | undefined
|
|
20
|
-
busy: boolean
|
|
21
|
-
|
|
22
|
-
// Comments (used by FormRenderer, FieldWrapper, CommentsPanel)
|
|
23
|
-
comments: CommentThread[]
|
|
24
|
-
focusedFieldPath: string | undefined
|
|
25
|
-
highlightThreadId: string | undefined
|
|
26
|
-
|
|
27
|
-
// User context
|
|
28
|
-
currentUser: string
|
|
29
|
-
canResolveComments: boolean
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const EditorContext = createContext<EditorContextValue | undefined>(undefined)
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Hook to access EditorContext.
|
|
36
|
-
* Throws an error if used outside of EditorContext.Provider.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```tsx
|
|
40
|
-
* const { branchName, selectedPath, currentEntry } = useEditorContext()
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
export function useEditorContext(): EditorContextValue {
|
|
44
|
-
const context = useContext(EditorContext)
|
|
45
|
-
if (context === undefined) {
|
|
46
|
-
throw new Error('useEditorContext must be used within EditorContext.Provider')
|
|
47
|
-
}
|
|
48
|
-
return context
|
|
49
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Group, Paper, Text } from '@mantine/core'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Props for the EditorFooter component.
|
|
5
|
-
*/
|
|
6
|
-
export interface EditorFooterProps {
|
|
7
|
-
/**
|
|
8
|
-
* Optional custom footer content.
|
|
9
|
-
*/
|
|
10
|
-
children?: React.ReactNode
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Footer component for the Editor.
|
|
15
|
-
* Displays static links (Terms, Privacy) and copyright notice.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* <EditorFooter />
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export function EditorFooter({ children }: EditorFooterProps) {
|
|
23
|
-
return (
|
|
24
|
-
<Paper
|
|
25
|
-
withBorder
|
|
26
|
-
radius={0}
|
|
27
|
-
shadow="sm"
|
|
28
|
-
px="md"
|
|
29
|
-
py="xs"
|
|
30
|
-
style={{ position: 'fixed', left: 0, right: 0, bottom: 0, zIndex: 40 }}
|
|
31
|
-
>
|
|
32
|
-
{children ?? (
|
|
33
|
-
<Group gap="md" justify="center">
|
|
34
|
-
<Text size="xs" c="dimmed">
|
|
35
|
-
Terms
|
|
36
|
-
</Text>
|
|
37
|
-
<Text size="xs" c="dimmed">
|
|
38
|
-
Privacy
|
|
39
|
-
</Text>
|
|
40
|
-
<Text size="xs" c="dimmed">
|
|
41
|
-
© CanopyCMS
|
|
42
|
-
</Text>
|
|
43
|
-
</Group>
|
|
44
|
-
)}
|
|
45
|
-
</Paper>
|
|
46
|
-
)
|
|
47
|
-
}
|