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,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook for managing internal group state
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { useState, useEffect, useCallback } from 'react'
|
|
6
|
-
import type { InternalGroup, CanopyGroupId, CanopyUserId } from '../types'
|
|
7
|
-
|
|
8
|
-
export interface UseGroupStateOptions {
|
|
9
|
-
initialGroups: InternalGroup[]
|
|
10
|
-
onSave?: (groups: InternalGroup[]) => Promise<void>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface UseGroupStateResult {
|
|
14
|
-
groups: InternalGroup[]
|
|
15
|
-
isDirty: boolean
|
|
16
|
-
isSaving: boolean
|
|
17
|
-
error: string | null
|
|
18
|
-
setError: (error: string | null) => void
|
|
19
|
-
createGroup: (name: string, description: string) => void
|
|
20
|
-
updateGroup: (groupId: CanopyGroupId, name: string, description: string) => void
|
|
21
|
-
deleteGroup: (groupId: CanopyGroupId) => void
|
|
22
|
-
addMember: (groupId: CanopyGroupId, userId: CanopyUserId) => void
|
|
23
|
-
removeMember: (groupId: CanopyGroupId, userId: CanopyUserId) => void
|
|
24
|
-
save: () => Promise<void>
|
|
25
|
-
discard: () => void
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function useGroupState({
|
|
29
|
-
initialGroups,
|
|
30
|
-
onSave,
|
|
31
|
-
}: UseGroupStateOptions): UseGroupStateResult {
|
|
32
|
-
const [groups, setGroups] = useState<InternalGroup[]>(initialGroups)
|
|
33
|
-
const [isDirty, setIsDirty] = useState(false)
|
|
34
|
-
const [isSaving, setIsSaving] = useState(false)
|
|
35
|
-
const [error, setError] = useState<string | null>(null)
|
|
36
|
-
|
|
37
|
-
// Sync groups when prop changes
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
setGroups(initialGroups)
|
|
40
|
-
setIsDirty(false)
|
|
41
|
-
}, [initialGroups])
|
|
42
|
-
|
|
43
|
-
const createGroup = useCallback((name: string, description: string) => {
|
|
44
|
-
const newGroup: InternalGroup = {
|
|
45
|
-
id: '' as CanopyGroupId,
|
|
46
|
-
name,
|
|
47
|
-
description,
|
|
48
|
-
members: [],
|
|
49
|
-
}
|
|
50
|
-
setGroups((prev) => [...prev, newGroup])
|
|
51
|
-
setIsDirty(true)
|
|
52
|
-
}, [])
|
|
53
|
-
|
|
54
|
-
const updateGroup = useCallback((groupId: CanopyGroupId, name: string, description: string) => {
|
|
55
|
-
setGroups((prev) => prev.map((g) => (g.id === groupId ? { ...g, name, description } : g)))
|
|
56
|
-
setIsDirty(true)
|
|
57
|
-
}, [])
|
|
58
|
-
|
|
59
|
-
const deleteGroup = useCallback((groupId: CanopyGroupId) => {
|
|
60
|
-
setGroups((prev) => prev.filter((g) => g.id !== groupId))
|
|
61
|
-
setIsDirty(true)
|
|
62
|
-
}, [])
|
|
63
|
-
|
|
64
|
-
const addMember = useCallback((groupId: CanopyGroupId, userId: CanopyUserId) => {
|
|
65
|
-
setGroups((prev) =>
|
|
66
|
-
prev.map((g) => {
|
|
67
|
-
if (g.id === groupId) {
|
|
68
|
-
const members = g.members || []
|
|
69
|
-
if (!members.includes(userId)) {
|
|
70
|
-
return { ...g, members: [...members, userId] }
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return g
|
|
74
|
-
}),
|
|
75
|
-
)
|
|
76
|
-
setIsDirty(true)
|
|
77
|
-
}, [])
|
|
78
|
-
|
|
79
|
-
const removeMember = useCallback((groupId: CanopyGroupId, userId: CanopyUserId) => {
|
|
80
|
-
setGroups((prev) =>
|
|
81
|
-
prev.map((g) => {
|
|
82
|
-
if (g.id === groupId) {
|
|
83
|
-
const members = (g.members || []).filter((m) => m !== userId)
|
|
84
|
-
return { ...g, members }
|
|
85
|
-
}
|
|
86
|
-
return g
|
|
87
|
-
}),
|
|
88
|
-
)
|
|
89
|
-
setIsDirty(true)
|
|
90
|
-
}, [])
|
|
91
|
-
|
|
92
|
-
const save = useCallback(async () => {
|
|
93
|
-
if (!onSave) return
|
|
94
|
-
|
|
95
|
-
// Validate that Admins group is not empty
|
|
96
|
-
const adminsGroup = groups.find((g) => g.id === 'Admins')
|
|
97
|
-
if (!adminsGroup || !adminsGroup.members || adminsGroup.members.length === 0) {
|
|
98
|
-
setError('Cannot remove the last admin. At least one admin is required.')
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
setIsSaving(true)
|
|
103
|
-
setError(null)
|
|
104
|
-
try {
|
|
105
|
-
await onSave(groups)
|
|
106
|
-
setIsDirty(false)
|
|
107
|
-
} catch (err) {
|
|
108
|
-
setError(err instanceof Error ? err.message : 'Failed to save groups')
|
|
109
|
-
} finally {
|
|
110
|
-
setIsSaving(false)
|
|
111
|
-
}
|
|
112
|
-
}, [onSave, groups])
|
|
113
|
-
|
|
114
|
-
const discard = useCallback(() => {
|
|
115
|
-
setGroups(initialGroups)
|
|
116
|
-
setIsDirty(false)
|
|
117
|
-
setError(null)
|
|
118
|
-
}, [initialGroups])
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
groups,
|
|
122
|
-
isDirty,
|
|
123
|
-
isSaving,
|
|
124
|
-
error,
|
|
125
|
-
setError,
|
|
126
|
-
createGroup,
|
|
127
|
-
updateGroup,
|
|
128
|
-
deleteGroup,
|
|
129
|
-
addMember,
|
|
130
|
-
removeMember,
|
|
131
|
-
save,
|
|
132
|
-
discard,
|
|
133
|
-
}
|
|
134
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook for user search functionality
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { useState, useEffect, useCallback } from 'react'
|
|
6
|
-
import type { UserSearchResult } from '../types'
|
|
7
|
-
|
|
8
|
-
export interface UseUserSearchOptions {
|
|
9
|
-
onSearchUsers?: (query: string, limit?: number) => Promise<UserSearchResult[]>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface UseUserSearchResult {
|
|
13
|
-
searchQuery: string
|
|
14
|
-
searchResults: UserSearchResult[]
|
|
15
|
-
isSearching: boolean
|
|
16
|
-
searchError: string | null
|
|
17
|
-
activeGroupId: string | null
|
|
18
|
-
setSearchQuery: (query: string) => void
|
|
19
|
-
showSearch: (groupId: string) => void
|
|
20
|
-
hideSearch: () => void
|
|
21
|
-
clearSearch: () => void
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function useUserSearch({ onSearchUsers }: UseUserSearchOptions): UseUserSearchResult {
|
|
25
|
-
const [searchQuery, setSearchQuery] = useState('')
|
|
26
|
-
const [searchResults, setSearchResults] = useState<UserSearchResult[]>([])
|
|
27
|
-
const [isSearching, setIsSearching] = useState(false)
|
|
28
|
-
const [searchError, setSearchError] = useState<string | null>(null)
|
|
29
|
-
const [activeGroupId, setActiveGroupId] = useState<string | null>(null)
|
|
30
|
-
|
|
31
|
-
// Debounced user search
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (!activeGroupId || !searchQuery.trim()) return
|
|
34
|
-
|
|
35
|
-
const timer = setTimeout(() => {
|
|
36
|
-
if (onSearchUsers) {
|
|
37
|
-
setIsSearching(true)
|
|
38
|
-
setSearchError(null)
|
|
39
|
-
onSearchUsers(searchQuery, 10)
|
|
40
|
-
.then((results) => {
|
|
41
|
-
setSearchResults(results)
|
|
42
|
-
setSearchError(null)
|
|
43
|
-
})
|
|
44
|
-
.catch((err) => {
|
|
45
|
-
console.error('User search failed:', err)
|
|
46
|
-
setSearchError('Failed to search users. Please try again.')
|
|
47
|
-
setSearchResults([])
|
|
48
|
-
})
|
|
49
|
-
.finally(() => setIsSearching(false))
|
|
50
|
-
}
|
|
51
|
-
}, 300)
|
|
52
|
-
|
|
53
|
-
return () => clearTimeout(timer)
|
|
54
|
-
}, [searchQuery, onSearchUsers, activeGroupId])
|
|
55
|
-
|
|
56
|
-
const showSearch = useCallback((groupId: string) => {
|
|
57
|
-
setActiveGroupId(groupId)
|
|
58
|
-
}, [])
|
|
59
|
-
|
|
60
|
-
const hideSearch = useCallback(() => {
|
|
61
|
-
setActiveGroupId(null)
|
|
62
|
-
setSearchQuery('')
|
|
63
|
-
setSearchResults([])
|
|
64
|
-
setSearchError(null)
|
|
65
|
-
}, [])
|
|
66
|
-
|
|
67
|
-
const clearSearch = useCallback(() => {
|
|
68
|
-
setSearchQuery('')
|
|
69
|
-
setSearchResults([])
|
|
70
|
-
setSearchError(null)
|
|
71
|
-
}, [])
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
searchQuery,
|
|
75
|
-
searchResults,
|
|
76
|
-
isSearching,
|
|
77
|
-
searchError,
|
|
78
|
-
activeGroupId,
|
|
79
|
-
setSearchQuery,
|
|
80
|
-
showSearch,
|
|
81
|
-
hideSearch,
|
|
82
|
-
clearSearch,
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* GroupManager - Main component for managing internal and external groups.
|
|
5
|
-
*
|
|
6
|
-
* This component provides a tabbed UI for managing internal groups with
|
|
7
|
-
* member assignment, and browsing external groups from the organization.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import React, { useState, useCallback } from 'react'
|
|
11
|
-
import { Alert, Button, Group, Loader, Stack, Tabs, Text } from '@mantine/core'
|
|
12
|
-
import { IconAlertCircle } from '@tabler/icons-react'
|
|
13
|
-
import type { GroupManagerProps, InternalGroup, GroupFormData } from './types'
|
|
14
|
-
import { useGroupState } from './hooks/useGroupState'
|
|
15
|
-
import { useUserSearch } from './hooks/useUserSearch'
|
|
16
|
-
import { useExternalGroupSearch } from './hooks/useExternalGroupSearch'
|
|
17
|
-
import { InternalGroupsTab } from './InternalGroupsTab'
|
|
18
|
-
import { ExternalGroupsTab } from './ExternalGroupsTab'
|
|
19
|
-
import { GroupForm } from './GroupForm'
|
|
20
|
-
|
|
21
|
-
export const GroupManager: React.FC<GroupManagerProps> = ({
|
|
22
|
-
internalGroups: initialInternalGroups,
|
|
23
|
-
loading = false,
|
|
24
|
-
canEdit,
|
|
25
|
-
onSave,
|
|
26
|
-
onSearchUsers,
|
|
27
|
-
onGetUserMetadata,
|
|
28
|
-
onSearchExternalGroups,
|
|
29
|
-
onClose: _,
|
|
30
|
-
}) => {
|
|
31
|
-
// Group state management
|
|
32
|
-
const {
|
|
33
|
-
groups,
|
|
34
|
-
isDirty,
|
|
35
|
-
isSaving,
|
|
36
|
-
error,
|
|
37
|
-
setError,
|
|
38
|
-
createGroup,
|
|
39
|
-
updateGroup,
|
|
40
|
-
deleteGroup,
|
|
41
|
-
addMember,
|
|
42
|
-
removeMember,
|
|
43
|
-
save,
|
|
44
|
-
discard,
|
|
45
|
-
} = useGroupState({
|
|
46
|
-
initialGroups: initialInternalGroups,
|
|
47
|
-
onSave,
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
// User search for adding members
|
|
51
|
-
const userSearch = useUserSearch({ onSearchUsers })
|
|
52
|
-
|
|
53
|
-
// External group search
|
|
54
|
-
const externalGroupSearch = useExternalGroupSearch({ onSearchExternalGroups })
|
|
55
|
-
|
|
56
|
-
// Modal state for creating/editing groups
|
|
57
|
-
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
58
|
-
const [editingGroup, setEditingGroup] = useState<InternalGroup | null>(null)
|
|
59
|
-
const [formData, setFormData] = useState<GroupFormData>({
|
|
60
|
-
name: '',
|
|
61
|
-
description: '',
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const handleCreateGroup = useCallback(() => {
|
|
65
|
-
setEditingGroup(null)
|
|
66
|
-
setFormData({ name: '', description: '' })
|
|
67
|
-
setIsModalOpen(true)
|
|
68
|
-
}, [])
|
|
69
|
-
|
|
70
|
-
const handleEditGroup = useCallback((group: InternalGroup) => {
|
|
71
|
-
setEditingGroup(group)
|
|
72
|
-
setFormData({ name: group.name, description: group.description || '' })
|
|
73
|
-
setIsModalOpen(true)
|
|
74
|
-
}, [])
|
|
75
|
-
|
|
76
|
-
const handleSaveModal = useCallback(() => {
|
|
77
|
-
if (!formData.name.trim()) {
|
|
78
|
-
setError('Group name is required')
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (editingGroup) {
|
|
83
|
-
updateGroup(editingGroup.id, formData.name, formData.description)
|
|
84
|
-
} else {
|
|
85
|
-
createGroup(formData.name, formData.description)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
setIsModalOpen(false)
|
|
89
|
-
setError(null)
|
|
90
|
-
}, [formData, editingGroup, updateGroup, createGroup, setError])
|
|
91
|
-
|
|
92
|
-
const handleFormChange = useCallback((data: Partial<GroupFormData>) => {
|
|
93
|
-
setFormData((prev) => ({ ...prev, ...data }))
|
|
94
|
-
}, [])
|
|
95
|
-
|
|
96
|
-
const handleAddMember = useCallback(
|
|
97
|
-
(groupId: string, userId: string) => {
|
|
98
|
-
addMember(
|
|
99
|
-
groupId as Parameters<typeof addMember>[0],
|
|
100
|
-
userId as Parameters<typeof addMember>[1],
|
|
101
|
-
)
|
|
102
|
-
userSearch.hideSearch()
|
|
103
|
-
},
|
|
104
|
-
[addMember, userSearch],
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<Stack h="100%" style={{ display: 'flex', flexDirection: 'column' }} gap={0}>
|
|
109
|
-
{!canEdit && (
|
|
110
|
-
<Alert icon={<IconAlertCircle size={16} />} color="yellow" mb="sm" title="Read-only">
|
|
111
|
-
You need admin access to manage groups.
|
|
112
|
-
</Alert>
|
|
113
|
-
)}
|
|
114
|
-
|
|
115
|
-
{error && (
|
|
116
|
-
<Alert
|
|
117
|
-
icon={<IconAlertCircle size={16} />}
|
|
118
|
-
color="red"
|
|
119
|
-
mb="sm"
|
|
120
|
-
title="Error"
|
|
121
|
-
withCloseButton
|
|
122
|
-
onClose={() => setError(null)}
|
|
123
|
-
>
|
|
124
|
-
{error}
|
|
125
|
-
</Alert>
|
|
126
|
-
)}
|
|
127
|
-
|
|
128
|
-
{loading ? (
|
|
129
|
-
<Group justify="center" py="xl">
|
|
130
|
-
<Loader size="md" />
|
|
131
|
-
<Text size="sm" c="dimmed">
|
|
132
|
-
Loading groups...
|
|
133
|
-
</Text>
|
|
134
|
-
</Group>
|
|
135
|
-
) : (
|
|
136
|
-
<Tabs defaultValue="internal" style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
|
|
137
|
-
<Tabs.List>
|
|
138
|
-
<Tabs.Tab value="internal">Internal Groups</Tabs.Tab>
|
|
139
|
-
<Tabs.Tab value="external">External Groups</Tabs.Tab>
|
|
140
|
-
</Tabs.List>
|
|
141
|
-
|
|
142
|
-
<Tabs.Panel value="internal" style={{ flex: 1, overflow: 'auto' }}>
|
|
143
|
-
<InternalGroupsTab
|
|
144
|
-
groups={groups}
|
|
145
|
-
canEdit={canEdit}
|
|
146
|
-
onCreateGroup={handleCreateGroup}
|
|
147
|
-
onEditGroup={handleEditGroup}
|
|
148
|
-
onDeleteGroup={deleteGroup}
|
|
149
|
-
onAddMember={handleAddMember}
|
|
150
|
-
onRemoveMember={removeMember}
|
|
151
|
-
onGetUserMetadata={onGetUserMetadata}
|
|
152
|
-
activeSearchGroupId={userSearch.activeGroupId}
|
|
153
|
-
searchQuery={userSearch.searchQuery}
|
|
154
|
-
searchResults={userSearch.searchResults}
|
|
155
|
-
isSearching={userSearch.isSearching}
|
|
156
|
-
searchError={userSearch.searchError}
|
|
157
|
-
onSearchQueryChange={userSearch.setSearchQuery}
|
|
158
|
-
onShowSearch={userSearch.showSearch}
|
|
159
|
-
onHideSearch={userSearch.hideSearch}
|
|
160
|
-
canSearch={!!onSearchUsers}
|
|
161
|
-
/>
|
|
162
|
-
</Tabs.Panel>
|
|
163
|
-
|
|
164
|
-
<Tabs.Panel value="external" style={{ flex: 1, overflow: 'auto' }}>
|
|
165
|
-
<ExternalGroupsTab
|
|
166
|
-
canEdit={canEdit}
|
|
167
|
-
searchQuery={externalGroupSearch.searchQuery}
|
|
168
|
-
searchResults={externalGroupSearch.searchResults}
|
|
169
|
-
isSearching={externalGroupSearch.isSearching}
|
|
170
|
-
searchError={externalGroupSearch.searchError}
|
|
171
|
-
onSearchQueryChange={externalGroupSearch.setSearchQuery}
|
|
172
|
-
canSearch={!!onSearchExternalGroups}
|
|
173
|
-
/>
|
|
174
|
-
</Tabs.Panel>
|
|
175
|
-
</Tabs>
|
|
176
|
-
)}
|
|
177
|
-
|
|
178
|
-
{canEdit && isDirty && (
|
|
179
|
-
<Group
|
|
180
|
-
justify="flex-end"
|
|
181
|
-
py="sm"
|
|
182
|
-
gap="sm"
|
|
183
|
-
style={{ borderTop: '1px solid var(--mantine-color-gray-3)' }}
|
|
184
|
-
>
|
|
185
|
-
<Button variant="subtle" color="neutral" onClick={discard} disabled={isSaving}>
|
|
186
|
-
Discard Changes
|
|
187
|
-
</Button>
|
|
188
|
-
<Button onClick={save} loading={isSaving} disabled={isSaving}>
|
|
189
|
-
Save Groups
|
|
190
|
-
</Button>
|
|
191
|
-
</Group>
|
|
192
|
-
)}
|
|
193
|
-
|
|
194
|
-
<GroupForm
|
|
195
|
-
isOpen={isModalOpen}
|
|
196
|
-
editingGroup={editingGroup}
|
|
197
|
-
formData={formData}
|
|
198
|
-
onFormChange={handleFormChange}
|
|
199
|
-
onSave={handleSaveModal}
|
|
200
|
-
onClose={() => setIsModalOpen(false)}
|
|
201
|
-
/>
|
|
202
|
-
</Stack>
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Re-export types and hooks for external use
|
|
207
|
-
export type { GroupManagerProps, InternalGroup } from './types'
|
|
208
|
-
export { useGroupState } from './hooks/useGroupState'
|
|
209
|
-
export { useUserSearch } from './hooks/useUserSearch'
|
|
210
|
-
export { useExternalGroupSearch } from './hooks/useExternalGroupSearch'
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for GroupManager module
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { UserSearchResult, GroupMetadata } from '../../auth/types'
|
|
6
|
-
import type { CanopyGroupId, CanopyUserId } from '../../types'
|
|
7
|
-
import type { InternalGroup } from '../../authorization'
|
|
8
|
-
import type { ExternalGroup } from '../../api/groups'
|
|
9
|
-
|
|
10
|
-
// Re-export commonly used types for convenience
|
|
11
|
-
export type { UserSearchResult, GroupMetadata, InternalGroup, ExternalGroup }
|
|
12
|
-
export type { CanopyGroupId, CanopyUserId }
|
|
13
|
-
|
|
14
|
-
export interface GroupManagerProps {
|
|
15
|
-
internalGroups: InternalGroup[]
|
|
16
|
-
loading?: boolean
|
|
17
|
-
canEdit: boolean
|
|
18
|
-
onSave?: (groups: InternalGroup[]) => Promise<void>
|
|
19
|
-
onSearchUsers?: (query: string, limit?: number) => Promise<UserSearchResult[]>
|
|
20
|
-
onGetUserMetadata?: (userId: string) => Promise<UserSearchResult | null>
|
|
21
|
-
onSearchExternalGroups?: (query: string) => Promise<ExternalGroup[]>
|
|
22
|
-
onClose?: () => void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface GroupFormData {
|
|
26
|
-
name: string
|
|
27
|
-
description: string
|
|
28
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Editor Hooks Architecture
|
|
2
|
-
|
|
3
|
-
## Decoupled Reactive Pattern
|
|
4
|
-
|
|
5
|
-
Hooks independently manage their data lifecycle using `useEffect` to watch `branchName`.
|
|
6
|
-
|
|
7
|
-
### Principles
|
|
8
|
-
|
|
9
|
-
- Each hook owns its data loading via `useEffect([branchName])`
|
|
10
|
-
- No callback orchestration between hooks
|
|
11
|
-
- State flows down from `useBranchManager.branchNameState`
|
|
12
|
-
- Effects fire in parallel when `branchName` changes
|
|
13
|
-
|
|
14
|
-
### Flow
|
|
15
|
-
|
|
16
|
-
Branch switch → `branchName` state changes → 3 parallel effects:
|
|
17
|
-
|
|
18
|
-
- `useBranchManager` → `loadBranches()`
|
|
19
|
-
- `useEntryManager` → `refreshEntries()`
|
|
20
|
-
- `useCommentSystem` → `loadComments()`
|
|
21
|
-
|
|
22
|
-
### Benefits
|
|
23
|
-
|
|
24
|
-
- Self-contained hooks (easier testing)
|
|
25
|
-
- Parallel data loading (better performance)
|
|
26
|
-
- No duplicate requests (each hook loads once)
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared test utilities for hook tests.
|
|
3
|
-
*
|
|
4
|
-
* This file provides common setup patterns and helpers to reduce duplication
|
|
5
|
-
* across hook test files.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react'
|
|
9
|
-
import { vi } from 'vitest'
|
|
10
|
-
import { createMockApiClient, type MockApiClient } from '../../../api/__test__/mock-client'
|
|
11
|
-
import { ApiClientProvider } from '../../context'
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Setup mock API client for hook tests.
|
|
15
|
-
*
|
|
16
|
-
* This helper handles the common pattern of:
|
|
17
|
-
* 1. Creating a mock API client
|
|
18
|
-
* 2. Injecting it into the createApiClient factory
|
|
19
|
-
*
|
|
20
|
-
* @returns The mock API client instance
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* let mockClient: MockApiClient
|
|
25
|
-
*
|
|
26
|
-
* beforeEach(async () => {
|
|
27
|
-
* mockClient = await setupMockApiClient()
|
|
28
|
-
* })
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export async function setupMockApiClient(): Promise<MockApiClient> {
|
|
32
|
-
const { createApiClient } = await import('../../../api')
|
|
33
|
-
const mockClient = createMockApiClient()
|
|
34
|
-
vi.mocked(createApiClient).mockReturnValue(mockClient as any)
|
|
35
|
-
return mockClient
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Create a wrapper component that provides the mock API client via context.
|
|
40
|
-
*
|
|
41
|
-
* Use this with renderHook to provide the ApiClientContext:
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* ```ts
|
|
45
|
-
* const mockClient = await setupMockApiClient()
|
|
46
|
-
* const wrapper = createApiClientWrapper(mockClient)
|
|
47
|
-
* const { result } = renderHook(() => useSomeHook(), { wrapper })
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
export function createApiClientWrapper(mockClient: MockApiClient) {
|
|
51
|
-
return function Wrapper({ children }: { children: React.ReactNode }) {
|
|
52
|
-
return <ApiClientProvider client={mockClient as any}>{children}</ApiClientProvider>
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Setup mock window.location for tests that need to manipulate browser location.
|
|
58
|
-
*
|
|
59
|
-
* Automatically restores the original location after the test.
|
|
60
|
-
*
|
|
61
|
-
* @param options - Initial location values
|
|
62
|
-
* @returns Cleanup function (called automatically in afterEach if used with setupTestEnvironment)
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```ts
|
|
66
|
-
* beforeEach(() => {
|
|
67
|
-
* setupMockLocation({ href: 'http://localhost/', search: '' })
|
|
68
|
-
* })
|
|
69
|
-
* ```
|
|
70
|
-
*/
|
|
71
|
-
export function setupMockLocation(options: { href?: string; search?: string } = {}) {
|
|
72
|
-
const originalLocation = window.location as Location
|
|
73
|
-
|
|
74
|
-
delete (window as any).location
|
|
75
|
-
;(window as any).location = {
|
|
76
|
-
href: options.href ?? 'http://localhost/',
|
|
77
|
-
search: options.search ?? '',
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return () => {
|
|
81
|
-
;(window as any).location = originalLocation
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Setup mock window.history.replaceState for tests.
|
|
87
|
-
*
|
|
88
|
-
* @returns The mock function
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```ts
|
|
92
|
-
* beforeEach(() => {
|
|
93
|
-
* setupMockHistory()
|
|
94
|
-
* })
|
|
95
|
-
* ```
|
|
96
|
-
*/
|
|
97
|
-
export function setupMockHistory() {
|
|
98
|
-
const mockReplaceState = vi.fn()
|
|
99
|
-
window.history.replaceState = mockReplaceState
|
|
100
|
-
return mockReplaceState
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Setup mock console methods with automatic cleanup.
|
|
105
|
-
*
|
|
106
|
-
* @param methods - Console methods to mock ('error', 'warn', 'log', etc.)
|
|
107
|
-
* @returns Object with spy methods and restore function
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```ts
|
|
111
|
-
* it('handles errors silently', async () => {
|
|
112
|
-
* const { error, restore } = setupMockConsole(['error'])
|
|
113
|
-
*
|
|
114
|
-
* // ... test code that logs errors
|
|
115
|
-
*
|
|
116
|
-
* expect(error).toHaveBeenCalled()
|
|
117
|
-
* restore()
|
|
118
|
-
* })
|
|
119
|
-
* ```
|
|
120
|
-
*/
|
|
121
|
-
export function setupMockConsole(
|
|
122
|
-
methods: Array<'error' | 'warn' | 'log' | 'info' | 'debug'> = ['error'],
|
|
123
|
-
) {
|
|
124
|
-
const spies: any = {}
|
|
125
|
-
|
|
126
|
-
for (const method of methods) {
|
|
127
|
-
spies[method] = vi.spyOn(console, method).mockImplementation(() => {})
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const restore = () => {
|
|
131
|
-
for (const spy of Object.values(spies)) {
|
|
132
|
-
;(spy as any)?.mockRestore()
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
...spies,
|
|
138
|
-
restore,
|
|
139
|
-
} as Record<'error' | 'warn' | 'log' | 'info' | 'debug', ReturnType<typeof vi.spyOn>> & {
|
|
140
|
-
restore: () => void
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Complete test environment setup for hook tests.
|
|
146
|
-
*
|
|
147
|
-
* Sets up:
|
|
148
|
-
* - Mock API client
|
|
149
|
-
* - Mock window.location
|
|
150
|
-
* - Mock window.history
|
|
151
|
-
*
|
|
152
|
-
* @param options - Configuration options
|
|
153
|
-
* @returns Object with mock client and cleanup functions
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```ts
|
|
157
|
-
* let mockClient: MockApiClient
|
|
158
|
-
*
|
|
159
|
-
* beforeEach(async () => {
|
|
160
|
-
* const setup = await setupTestEnvironment()
|
|
161
|
-
* mockClient = setup.mockClient
|
|
162
|
-
* })
|
|
163
|
-
* ```
|
|
164
|
-
*/
|
|
165
|
-
export async function setupTestEnvironment(
|
|
166
|
-
options: {
|
|
167
|
-
location?: { href?: string; search?: string }
|
|
168
|
-
setupHistory?: boolean
|
|
169
|
-
} = {},
|
|
170
|
-
) {
|
|
171
|
-
const mockClient = await setupMockApiClient()
|
|
172
|
-
|
|
173
|
-
const cleanupLocation = setupMockLocation(options.location)
|
|
174
|
-
const mockHistory = options.setupHistory !== false ? setupMockHistory() : undefined
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
mockClient,
|
|
178
|
-
mockHistory,
|
|
179
|
-
cleanup: () => {
|
|
180
|
-
cleanupLocation()
|
|
181
|
-
},
|
|
182
|
-
}
|
|
183
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// Barrel export for all custom hooks
|
|
2
|
-
// Export hooks as they are created
|
|
3
|
-
// Note: resetApiClient functions are not exported - they're test-only utilities
|
|
4
|
-
|
|
5
|
-
export * from './useEditorLayout'
|
|
6
|
-
export { useBranchManager, type UseBranchManagerOptions } from './useBranchManager'
|
|
7
|
-
export { useEntryManager } from './useEntryManager'
|
|
8
|
-
export * from './useDraftManager'
|
|
9
|
-
export { useCommentSystem } from './useCommentSystem'
|
|
10
|
-
export { useGroupManager } from './useGroupManager'
|
|
11
|
-
export { usePermissionManager } from './usePermissionManager'
|
|
12
|
-
export { useBranchActions } from './useBranchActions'
|
|
13
|
-
export { useUserContext, type UseUserContextReturn } from './useUserContext'
|
|
14
|
-
export {
|
|
15
|
-
useReferenceResolution,
|
|
16
|
-
type UseReferenceResolutionOptions,
|
|
17
|
-
type UseReferenceResolutionResult,
|
|
18
|
-
} from './useReferenceResolution'
|
|
19
|
-
export {
|
|
20
|
-
useSchemaManager,
|
|
21
|
-
type UseSchemaManagerOptions,
|
|
22
|
-
type UseSchemaManagerReturn,
|
|
23
|
-
} from './useSchemaManager'
|