@taskforcehq/taskforce 0.3.170 → 0.3.300
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/README.md +52 -21
- package/dist/Taskforce.module.css +3394 -5981
- package/dist/TaskforceCore.CategoryFallback.test.js +5 -2
- package/dist/TaskforceCore.filter-persistence.test.js +402 -0
- package/dist/TaskforceCore.js +388 -71
- package/dist/TaskforceCore.routing.test.js +311 -0
- package/dist/TaskforceCore.test.js +3344 -615
- package/dist/TaskforceWidget.js +3 -2
- package/dist/__tests__/localizationCatalogs.test.js +48 -31
- package/dist/__tests__/workflowSimulation.test.js +2 -2
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.d.ts +60 -0
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +324 -0
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.js +278 -0
- package/dist/annotatedAttachments/payload.d.ts +2 -0
- package/dist/annotatedAttachments/payload.js +54 -0
- package/dist/annotatedAttachments/payload.test.js +67 -0
- package/dist/annotatedAttachments/service.d.ts +49 -0
- package/dist/annotatedAttachments/service.js +121 -0
- package/dist/annotatedAttachments/types.d.ts +86 -0
- package/dist/cli.js +74 -25
- package/dist/compat/deploymentCompat.d.ts +12 -0
- package/dist/compat/deploymentCompat.js +43 -0
- package/dist/compat/workspaceSyncCompat.d.ts +6 -0
- package/dist/compat/workspaceSyncCompat.js +79 -0
- package/dist/compat/workspaceSyncCompat.test.js +87 -0
- package/dist/components/features/AgentsModule.d.ts +5 -0
- package/dist/components/features/AgentsModule.js +131 -0
- package/dist/components/features/AgentsModule.test.js +102 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +24 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +1942 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +2831 -0
- package/dist/components/features/DocumentGenerateModal.js +8 -16
- package/dist/components/features/DocumentIndex.d.ts +3 -4
- package/dist/components/features/DocumentIndex.js +22 -10
- package/dist/components/features/DocumentViewer.d.ts +6 -2
- package/dist/components/features/DocumentViewer.js +1000 -18
- package/dist/components/features/DocumentWorkspace.d.ts +40 -2
- package/dist/components/features/DocumentWorkspace.js +96 -16
- package/dist/components/features/DocumentWorkspace.test.js +1202 -0
- package/dist/components/features/InitiativesModule.d.ts +22 -0
- package/dist/components/features/InitiativesModule.js +33 -0
- package/dist/components/features/TaskSettings.d.ts +41 -32
- package/dist/components/features/TaskSettings.js +798 -313
- package/dist/components/features/TaskSettings.test.js +1221 -47
- package/dist/components/features/WorkflowsModule.d.ts +27 -0
- package/dist/components/features/WorkflowsModule.js +21 -0
- package/dist/components/features/documentWorkspaceFilters.d.ts +10 -0
- package/dist/components/features/documentWorkspaceFilters.js +11 -0
- package/dist/components/features/settings/CategoryManager.d.ts +2 -0
- package/dist/components/features/settings/CategoryManager.js +15 -8
- package/dist/components/features/settings/PriorityManager.d.ts +18 -0
- package/dist/components/features/settings/PriorityManager.js +51 -0
- package/dist/components/features/settings/TaxonomyEditor.d.ts +2 -1
- package/dist/components/features/settings/TaxonomyEditor.js +41 -18
- package/dist/components/features/settings/TaxonomyLibraryManager.d.ts +26 -0
- package/dist/components/features/settings/TaxonomyLibraryManager.js +301 -0
- package/dist/components/features/settings/TaxonomyLibraryManager.test.js +141 -0
- package/dist/components/features/settings/TaxonomyManager.d.ts +35 -12
- package/dist/components/features/settings/TaxonomyManager.js +59 -27
- package/dist/components/features/settings/TypeManager.d.ts +11 -0
- package/dist/components/features/settings/TypeManager.js +48 -11
- package/dist/components/features/settings/{WorkflowEditorPrototype.d.ts → WorkflowEditor.d.ts} +2 -2
- package/dist/components/features/settings/{WorkflowEditorPrototype.js → WorkflowEditor.js} +3 -3
- package/dist/components/task/TaskActionHeader.d.ts +12 -2
- package/dist/components/task/TaskActionHeader.js +64 -8
- package/dist/components/task/TaskActionHeader.test.js +73 -0
- package/dist/components/task/TaskCard.d.ts +14 -16
- package/dist/components/task/TaskCard.js +144 -174
- package/dist/components/task/TaskCard.test.js +416 -64
- package/dist/components/task/TaskContextUpload.d.ts +6 -5
- package/dist/components/task/TaskContextUpload.js +199 -64
- package/dist/components/task/TaskContextUpload.test.js +331 -14
- package/dist/components/task/TaskForm.d.ts +23 -29
- package/dist/components/task/TaskForm.js +348 -169
- package/dist/components/task/TaskForm.test.js +419 -23
- package/dist/components/task/TaskKanban.d.ts +20 -21
- package/dist/components/task/TaskKanban.js +176 -316
- package/dist/components/task/TaskKanban.planning-drop.test.js +93 -0
- package/dist/components/task/TaskList.d.ts +22 -11
- package/dist/components/task/TaskList.js +98 -12
- package/dist/components/task/TaskList.test.js +206 -7
- package/dist/components/task/TaskReferenceBadge.d.ts +12 -0
- package/dist/components/task/TaskReferenceBadge.js +5 -0
- package/dist/components/task/TaskStatusActions.d.ts +12 -0
- package/dist/components/task/TaskStatusActions.js +18 -0
- package/dist/components/task/TaskStatusActions.test.js +45 -0
- package/dist/components/ui/ImageReferenceBadge.d.ts +12 -0
- package/dist/components/ui/ImageReferenceBadge.js +5 -0
- package/dist/components/ui/LevelSelector.d.ts +2 -1
- package/dist/components/ui/LevelSelector.js +2 -2
- package/dist/components/ui/Markdown.d.ts +1 -2
- package/dist/components/ui/Markdown.js +2 -13
- package/dist/components/ui/Modal.d.ts +3 -2
- package/dist/components/ui/Modal.js +4 -3
- package/dist/components/ui/MultiSelectFilter.d.ts +3 -1
- package/dist/components/ui/MultiSelectFilter.js +2 -2
- package/dist/components/ui/ReferenceBadgeButton.d.ts +13 -0
- package/dist/components/ui/ReferenceBadgeButton.js +6 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +7 -1
- package/dist/components/ui/TaxonomyDropdown.js +58 -23
- package/dist/components/ui/TopNoticeLayer.d.ts +7 -0
- package/dist/components/ui/TopNoticeLayer.js +14 -0
- package/dist/components/ui/TopNoticeLayer.test.js +25 -0
- package/dist/components/views/AppShellHeader.d.ts +13 -0
- package/dist/components/views/AppShellHeader.js +19 -0
- package/dist/components/views/AppShellHeader.test.js +21 -0
- package/dist/components/views/PlanComparisonPage.d.ts +73 -0
- package/dist/components/views/PlanComparisonPage.js +196 -0
- package/dist/components/views/PlanComparisonPage.test.js +251 -0
- package/dist/components/views/PlansPage.d.ts +14 -0
- package/dist/components/views/PlansPage.js +355 -0
- package/dist/components/views/StandaloneLayout.d.ts +2 -2
- package/dist/components/views/StandaloneLayout.js +2212 -1194
- package/dist/components/views/WidgetView.d.ts +2 -2
- package/dist/components/views/WidgetView.js +149 -43
- package/dist/components/views/chrome/WorkspaceChromeSections.d.ts +57 -0
- package/dist/components/views/chrome/WorkspaceChromeSections.js +38 -0
- package/dist/components/views/chrome/WorkspaceChromeSections.test.js +54 -0
- package/dist/components/views/chrome/workspaceChrome.d.ts +31 -0
- package/dist/components/views/chrome/workspaceChrome.js +108 -0
- package/dist/components/views/chrome/workspaceChrome.test.js +52 -0
- package/dist/components/views/panels/DocumentFilterToolbar.d.ts +10 -0
- package/dist/components/views/panels/DocumentFilterToolbar.js +7 -0
- package/dist/components/views/panels/DocumentFilterToolbar.test.js +19 -0
- package/dist/components/views/panels/FilterToolbar.d.ts +66 -0
- package/dist/components/views/panels/FilterToolbar.js +21 -0
- package/dist/components/views/panels/FilterToolbar.test.d.ts +1 -0
- package/dist/components/views/panels/FilterToolbar.test.js +45 -0
- package/dist/components/views/panels/FilterToolbarControls.d.ts +46 -0
- package/dist/components/views/panels/FilterToolbarControls.js +61 -0
- package/dist/components/views/panels/PlanningDrawer.d.ts +115 -0
- package/dist/components/views/panels/PlanningDrawer.js +220 -0
- package/dist/components/views/panels/ScheduleSidebar.d.ts +52 -0
- package/dist/components/views/panels/ScheduleSidebar.js +127 -0
- package/dist/components/views/panels/scheduleUtils.d.ts +14 -0
- package/dist/components/views/panels/scheduleUtils.js +79 -0
- package/dist/components/views/teamManagementAccess.d.ts +6 -0
- package/dist/components/views/teamManagementAccess.js +18 -0
- package/dist/components/views/teamManagementAccess.test.d.ts +1 -0
- package/dist/components/views/teamManagementAccess.test.js +44 -0
- package/dist/config/clientDeployment.d.ts +2 -0
- package/dist/config/clientDeployment.js +13 -0
- package/dist/config/cloudEnvironment.d.ts +15 -0
- package/dist/config/cloudEnvironment.js +60 -0
- package/dist/config/deployment.d.ts +20 -0
- package/dist/config/deployment.js +67 -0
- package/dist/config/deployment.test.d.ts +1 -0
- package/dist/config/deployment.test.js +88 -0
- package/dist/config/envSchema.js +36 -8
- package/dist/config/envSchema.test.js +28 -0
- package/dist/core/AiProfileService.d.ts +66 -0
- package/dist/core/AiProfileService.js +320 -0
- package/dist/core/AiProfileService.test.d.ts +1 -0
- package/dist/core/AiProfileService.test.js +164 -0
- package/dist/core/AiProfiles.test.d.ts +1 -0
- package/dist/core/AiProfiles.test.js +449 -0
- package/dist/core/AttachmentLinkService.d.ts +15 -0
- package/dist/core/AttachmentLinkService.js +157 -0
- package/dist/core/AuthTokenService.d.ts +44 -0
- package/dist/core/AuthTokenService.js +207 -0
- package/dist/core/CreatedBy.test.js +134 -6
- package/dist/core/DeletedTaskLifecycleService.d.ts +33 -0
- package/dist/core/DeletedTaskLifecycleService.js +158 -0
- package/dist/core/DeletedTaskTrash.test.d.ts +1 -0
- package/dist/core/DeletedTaskTrash.test.js +104 -0
- package/dist/core/EntitlementsPolicy.test.js +78 -5
- package/dist/core/GlobalSettingsService.d.ts +16 -0
- package/dist/core/GlobalSettingsService.js +370 -0
- package/dist/core/JsonBackupRuntime.test.d.ts +1 -0
- package/dist/core/JsonBackupRuntime.test.js +155 -0
- package/dist/core/McpTokenService.d.ts +118 -0
- package/dist/core/McpTokenService.js +921 -0
- package/dist/core/PlanEntitlementService.d.ts +201 -0
- package/dist/core/PlanEntitlementService.js +1442 -0
- package/dist/core/PlanVersionPolicy.test.d.ts +1 -0
- package/dist/core/PlanVersionPolicy.test.js +178 -0
- package/dist/core/PlanningEntities.test.d.ts +1 -0
- package/dist/core/PlanningEntities.test.js +95 -0
- package/dist/core/ScheduleFields.test.js +15 -19
- package/dist/core/SignupMonetizationSettings.test.d.ts +1 -0
- package/dist/core/SignupMonetizationSettings.test.js +159 -0
- package/dist/core/Stats.test.d.ts +1 -0
- package/dist/core/Stats.test.js +36 -0
- package/dist/core/SyncReconciliationService.d.ts +93 -0
- package/dist/core/SyncReconciliationService.js +406 -0
- package/dist/core/SystemAdmin.test.js +578 -13
- package/dist/core/TaskActivityService.d.ts +21 -0
- package/dist/core/TaskActivityService.js +130 -0
- package/dist/core/TaskAttachmentsCanonical.test.d.ts +1 -0
- package/dist/core/TaskAttachmentsCanonical.test.js +306 -0
- package/dist/core/TaskAuditTimeline.test.d.ts +1 -0
- package/dist/core/TaskAuditTimeline.test.js +132 -0
- package/dist/core/TaskTaxonomyValidation.test.js +338 -15
- package/dist/core/Taskforce.d.ts +930 -183
- package/dist/core/Taskforce.ids.test.js +252 -0
- package/dist/core/Taskforce.js +3848 -2532
- package/dist/core/Taskforce.mcpAuth.test.d.ts +1 -0
- package/dist/core/Taskforce.mcpAuth.test.js +343 -0
- package/dist/core/Taskforce.realtimeMutation.test.js +57 -2
- package/dist/core/TaxonomySettingsService.d.ts +18 -0
- package/dist/core/TaxonomySettingsService.js +162 -0
- package/dist/core/WorkspaceDelete.test.js +32 -13
- package/dist/core/WorkspaceLifecycleService.d.ts +11 -0
- package/dist/core/WorkspaceLifecycleService.js +88 -0
- package/dist/core/WorkspacePermissions.test.js +95 -0
- package/dist/core/WorkspacePlanMode.test.js +114 -1
- package/dist/core/WorkspacePreferenceService.d.ts +41 -0
- package/dist/core/WorkspacePreferenceService.js +246 -0
- package/dist/core/WorkspaceSyncSettings.test.d.ts +1 -0
- package/dist/core/WorkspaceSyncSettings.test.js +65 -0
- package/dist/core/__tests__/TaskAttachmentsCanonical.test.d.ts +1 -0
- package/dist/core/__tests__/TaskAttachmentsCanonical.test.js +212 -0
- package/dist/core/shared.d.ts +36 -0
- package/dist/core/shared.js +128 -0
- package/dist/core/types.d.ts +614 -0
- package/dist/core/types.js +27 -0
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +56 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +230 -0
- package/dist/documentReviews/DocumentReviewSessionStore.d.ts +52 -0
- package/dist/documentReviews/DocumentReviewSessionStore.js +193 -0
- package/dist/documentReviews/DocumentReviewSessionStore.test.d.ts +1 -0
- package/dist/documentReviews/DocumentReviewSessionStore.test.js +127 -0
- package/dist/documentReviews/service.d.ts +68 -0
- package/dist/documentReviews/service.js +210 -0
- package/dist/documentReviews/types.d.ts +58 -0
- package/dist/documentReviews/types.js +1 -0
- package/dist/hooks/auth/useAuthGuardPolicy.d.ts +2 -0
- package/dist/hooks/auth/useAuthGuardPolicy.js +1 -0
- package/dist/hooks/tasks/useCurrentTaskRelations.d.ts +15 -0
- package/dist/hooks/tasks/useCurrentTaskRelations.js +37 -0
- package/dist/hooks/tasks/useTaskActions.d.ts +3 -0
- package/dist/hooks/tasks/useTaskActions.js +2 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +65 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.js +235 -0
- package/dist/hooks/tasks/useTaskFilters.d.ts +2 -0
- package/dist/hooks/tasks/useTaskFilters.js +2 -0
- package/dist/hooks/tasks/useTaskFormActions.d.ts +58 -0
- package/dist/hooks/tasks/useTaskFormActions.js +365 -0
- package/dist/hooks/tasks/useTaskRelationships.d.ts +16 -0
- package/dist/hooks/tasks/useTaskRelationships.js +64 -0
- package/dist/hooks/ui/useResourceExport.d.ts +19 -0
- package/dist/hooks/ui/useResourceExport.js +84 -0
- package/dist/hooks/ui/useSettingsModel.d.ts +203 -0
- package/dist/hooks/ui/useSettingsModel.js +125 -0
- package/dist/hooks/ui/useSettingsPersistence.d.ts +36 -0
- package/dist/hooks/ui/useSettingsPersistence.js +254 -0
- package/dist/hooks/ui/useSettingsTaxonomyManagement.d.ts +119 -0
- package/dist/hooks/ui/useSettingsTaxonomyManagement.js +536 -0
- package/dist/hooks/ui/useUiNotice.d.ts +1 -0
- package/dist/hooks/ui/useUiNotice.js +1 -0
- package/dist/hooks/ui/useWorkflowTemplates.d.ts +37 -0
- package/dist/hooks/ui/useWorkflowTemplates.js +111 -0
- package/dist/hooks/ui/useZenMode.d.ts +5 -0
- package/dist/hooks/ui/useZenMode.js +32 -0
- package/dist/hooks/useFilterSort.d.ts +60 -0
- package/dist/hooks/useFilterSort.js +362 -0
- package/dist/hooks/useFilterSort.test.d.ts +1 -0
- package/dist/hooks/useFilterSort.test.js +333 -0
- package/dist/hooks/useRealtimeSync.d.ts +1 -0
- package/dist/hooks/useRealtimeSync.js +24 -9
- package/dist/hooks/useRealtimeSync.test.js +28 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.d.ts +1 -0
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +34 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +65 -103
- package/dist/hooks/useSyncOrchestrator.js +1538 -670
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +700 -174
- package/dist/hooks/useTaskData.d.ts +35 -0
- package/dist/hooks/useTaskData.js +239 -0
- package/dist/hooks/useTaskData.test.d.ts +1 -0
- package/dist/hooks/useTaskData.test.js +119 -0
- package/dist/hooks/useTaskMutations.d.ts +46 -0
- package/dist/hooks/useTaskMutations.js +472 -0
- package/dist/hooks/useTaskMutations.test.d.ts +1 -0
- package/dist/hooks/useTaskMutations.test.js +80 -0
- package/dist/hooks/useTaskforce.contract.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.contract.test.js +7 -0
- package/dist/hooks/useTaskforce.d.ts +260 -295
- package/dist/hooks/useTaskforce.js +1954 -2623
- package/dist/hooks/useTaskforce.priority-filters.test.js +6 -11
- package/dist/hooks/useTaskforce.sync-behavior.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +1120 -0
- package/dist/hooks/useUiNotice.d.ts +16 -0
- package/dist/hooks/useUiNotice.js +49 -0
- package/dist/hooks/useWorkspaceSyncController.d.ts +23 -46
- package/dist/hooks/useWorkspaceSyncController.js +280 -461
- package/dist/hooks/useWorkspaceSyncController.test.js +106 -199
- package/dist/hooks/workspace/useTaskforceApiRouting.d.ts +8 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.js +91 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.test.d.ts +1 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.test.js +60 -0
- package/dist/hooks/workspace/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/workspace/useWorkspaceSyncController.js +1 -0
- package/dist/hooks/workspace/workspaceLocalState.d.ts +30 -0
- package/dist/hooks/workspace/workspaceLocalState.js +101 -0
- package/dist/localization/locales/en-US.d.ts +1 -8
- package/dist/localization/locales/en-US.js +4 -11
- package/dist/localization/locales/es-419.js +2 -9
- package/dist/localization/locales/pt-BR.js +2 -9
- package/dist/localization/localizationCatalogs.test.d.ts +1 -0
- package/dist/localization/localizationCatalogs.test.js +37 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +9 -15
- package/dist/mcp/clientIntegrations.d.ts +33 -0
- package/dist/mcp/clientIntegrations.js +199 -0
- package/dist/mcp/clientIntegrations.test.d.ts +1 -0
- package/dist/mcp/clientIntegrations.test.js +110 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/optionResolution.test.js +6 -2
- package/dist/mcp/runtime.d.ts +120 -0
- package/dist/mcp/runtime.js +5668 -0
- package/dist/mcp/runtime.test.d.ts +1 -0
- package/dist/mcp/runtime.test.js +3293 -0
- package/dist/mcp/server.js +2 -1793
- package/dist/mcp/structuredCommentValidation.test.d.ts +1 -0
- package/dist/{__tests__ → mcp}/structuredCommentValidation.test.js +1 -1
- package/dist/mcp/structuredDocValidation.js +1 -2
- package/dist/mcp/structuredDocValidation.test.d.ts +1 -0
- package/dist/{__tests__ → mcp}/structuredDocValidation.test.js +9 -4
- package/dist/mcp/toolRegistry.d.ts +570 -0
- package/dist/mcp/toolRegistry.js +90 -0
- package/dist/mcp/toolRegistry.test.d.ts +1 -0
- package/dist/mcp/toolRegistry.test.js +30 -0
- package/dist/migrations/billingSchemaParity.test.js +111 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
- package/dist/migrations/taskSchemaMigrations.js +681 -39
- package/dist/migrations/taskSchemaMigrations.test.d.ts +1 -0
- package/dist/migrations/taskSchemaMigrations.test.js +210 -0
- package/dist/plugins/vite.js +13 -7
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/archive/phoenix/apple-touch-icon.png +0 -0
- package/dist/public/archive/phoenix/favicon.ico +0 -0
- package/dist/public/archive/phoenix/site.webmanifest +1 -0
- package/dist/public/favicon-96x96.png +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/favicon.svg +17 -0
- package/dist/public/site.webmanifest +21 -1
- package/dist/public/web-app-manifest-192x192.png +0 -0
- package/dist/public/web-app-manifest-512x512.png +0 -0
- package/dist/releaseVersion.test.d.ts +1 -0
- package/dist/{__tests__/releaseVersion.test.js → releaseVersion.test.js} +1 -1
- package/dist/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
- package/dist/resources/templates/workflows/collaborate.yaml +11 -5
- package/dist/resources/templates/workflows/do.yaml +8 -2
- package/dist/resources/templates/workflows/evaluate.yaml +13 -7
- package/dist/resources/templates/workflows/execute.yaml +40 -23
- package/dist/resources/templates/workflows/plan.yaml +15 -8
- package/dist/resources/templates/workflows/review.yaml +14 -8
- package/dist/runtime/appGateDefinitions.d.ts +32 -0
- package/dist/runtime/appGateDefinitions.js +32 -0
- package/dist/runtime/appGates.d.ts +29 -0
- package/dist/runtime/appGates.js +53 -0
- package/dist/runtime/appGates.test.d.ts +1 -0
- package/dist/runtime/appGates.test.js +42 -0
- package/dist/runtime/migrationFlags.d.ts +1 -0
- package/dist/runtime/migrationFlags.js +1 -0
- package/dist/server/annotatedAttachmentsRoutes.test.d.ts +1 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +473 -0
- package/dist/server/auth.js +14 -2
- package/dist/server/auth.test.js +21 -1
- package/dist/server/cors.js +11 -5
- package/dist/server/cors.test.js +6 -0
- package/dist/server/documentReviewRoutes.test.d.ts +1 -0
- package/dist/server/documentReviewRoutes.test.js +157 -0
- package/dist/server/index.cookieProxy.test.js +46 -1
- package/dist/server/index.d.ts +20 -0
- package/dist/server/index.js +168 -41
- package/dist/server/index.rateLimit.test.js +6 -0
- package/dist/server/index.test.js +133 -2
- package/dist/server/mockStripe.d.ts +72 -0
- package/dist/server/mockStripe.js +357 -0
- package/dist/server/realtimeSyncWs.js +4 -0
- package/dist/server/routes/admin.d.ts +114 -0
- package/dist/server/routes/admin.js +2226 -0
- package/dist/server/routes/annotatedAttachments.d.ts +24 -0
- package/dist/server/routes/annotatedAttachments.js +235 -0
- package/dist/server/routes/auth.d.ts +61 -0
- package/dist/server/routes/auth.js +1296 -0
- package/dist/server/{routes.billing.d.ts → routes/billing.d.ts} +3 -2
- package/dist/server/routes/billing.js +2001 -0
- package/dist/server/routes/billing.test.d.ts +1 -0
- package/dist/server/routes/billing.test.js +1631 -0
- package/dist/server/routes/documentReviews.d.ts +11 -0
- package/dist/server/routes/documentReviews.js +191 -0
- package/dist/server/routes/documents.d.ts +118 -0
- package/dist/server/routes/documents.js +1113 -0
- package/dist/server/routes/resources.d.ts +25 -0
- package/dist/server/routes/resources.js +225 -0
- package/dist/server/routes/shared.d.ts +35 -0
- package/dist/server/routes/shared.js +305 -0
- package/dist/server/routes/shared.test.d.ts +1 -0
- package/dist/server/routes/shared.test.js +32 -0
- package/dist/server/{routes.sync.d.ts → routes/sync.d.ts} +5 -5
- package/dist/server/routes/sync.integration.test.d.ts +1 -0
- package/dist/server/routes/sync.integration.test.js +2003 -0
- package/dist/server/routes/sync.js +3143 -0
- package/dist/server/routes/tasks.d.ts +72 -0
- package/dist/server/routes/tasks.js +1252 -0
- package/dist/server/routes/workspaces.d.ts +32 -0
- package/dist/server/routes/workspaces.js +307 -0
- package/dist/server/routes.d.ts +8 -9
- package/dist/server/routes.js +968 -4092
- package/dist/server/routes.test.js +9043 -2415
- package/dist/server/runtimeMode.d.ts +1 -1
- package/dist/server/runtimeMode.js +3 -18
- package/dist/server/runtimeMode.test.js +3 -3
- package/dist/server/securityHeaders.d.ts +1 -1
- package/dist/server/securityHeaders.js +65 -6
- package/dist/server/securityHeaders.test.js +40 -2
- package/dist/services/templateEngine.test.d.ts +1 -0
- package/dist/{__tests__ → services}/templateEngine.test.js +1 -1
- package/dist/services/templates.test.d.ts +1 -0
- package/dist/{__tests__ → services}/templates.test.js +1 -1
- package/dist/services/workflowDocumentFixtures.test.d.ts +1 -0
- package/dist/{__tests__ → services}/workflowDocumentFixtures.test.js +4 -4
- package/dist/services/workflowExportMatrix.test.d.ts +1 -0
- package/dist/{__tests__ → services}/workflowExportMatrix.test.js +1 -1
- package/dist/services/workflowExportSnapshots.test.d.ts +1 -0
- package/dist/services/workflowGeneration.test.d.ts +1 -0
- package/dist/services/workflowSimulation.test.d.ts +1 -0
- package/dist/services/workflowSimulation.test.js +113 -0
- package/dist/services/workflowV2Policy.test.d.ts +1 -0
- package/dist/{__tests__ → services}/workflowV2Policy.test.js +2 -2
- package/dist/shared/aiProfileSurfaceType.d.ts +9 -0
- package/dist/shared/aiProfileSurfaceType.js +49 -0
- package/dist/shared/customTaxonomyLibrary.d.ts +11 -0
- package/dist/shared/customTaxonomyLibrary.js +276 -0
- package/dist/shared/customTaxonomyLibrary.test.d.ts +1 -0
- package/dist/shared/customTaxonomyLibrary.test.js +20 -0
- package/dist/shared/taxonomyCatalog.d.ts +19 -0
- package/dist/shared/taxonomyCatalog.js +36 -0
- package/dist/shared/taxonomyDefaults.d.ts +29 -0
- package/dist/shared/taxonomyDefaults.js +26 -0
- package/dist/shared/taxonomyLibrary.d.ts +15 -0
- package/dist/shared/taxonomyLibrary.js +98 -0
- package/dist/shared/taxonomyLibrary.test.d.ts +1 -0
- package/dist/shared/taxonomyLibrary.test.js +26 -0
- package/dist/shared/taxonomyState.d.ts +36 -0
- package/dist/shared/taxonomyState.js +73 -0
- package/dist/shared/taxonomyState.test.d.ts +1 -0
- package/dist/shared/taxonomyState.test.js +71 -0
- package/dist/shared/workflowDefaults.d.ts +9 -0
- package/dist/shared/workflowDefaults.js +11 -0
- package/dist/storage/documentIntegrity.d.ts +2 -0
- package/dist/storage/documentIntegrity.js +34 -17
- package/dist/storage/documentPurge.d.ts +2 -1
- package/dist/storage/documentPurge.js +35 -8
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/objectStorage.d.ts +1 -1
- package/dist/storage/objectStorageClient.d.ts +6 -4
- package/dist/storage/objectStorageClient.js +77 -29
- package/dist/storage/objectStorageClient.test.d.ts +1 -0
- package/dist/storage/objectStorageClient.test.js +57 -0
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.d.ts +1 -0
- package/dist/storage/objectStorageConfig.test.js +38 -0
- package/dist/storage/postgresAdapter.d.ts +5 -0
- package/dist/storage/postgresAdapter.js +2 -2
- package/dist/storage/postgresAdapter.test.d.ts +1 -0
- package/dist/storage/postgresAdapter.test.js +29 -0
- package/dist/storage/taskAssetStore.d.ts +7 -4
- package/dist/storage/taskAssetStore.js +65 -60
- package/dist/storage/workspaceAssetStore.d.ts +122 -0
- package/dist/storage/workspaceAssetStore.js +496 -0
- package/dist/storage/workspaceAssetStore.test.d.ts +1 -0
- package/dist/storage/workspaceAssetStore.test.js +501 -0
- package/dist/sync/cloudSyncApi.d.ts +33 -2
- package/dist/sync/cloudSyncApi.js +37 -15
- package/dist/sync/cloudSyncApi.test.js +60 -3
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/syncService.d.ts +25 -0
- package/dist/sync/syncService.js +184 -16
- package/dist/sync/syncService.test.js +289 -25
- package/dist/sync/workspaceRepair.d.ts +114 -0
- package/dist/sync/workspaceRepair.js +566 -0
- package/dist/sync/workspaceSyncModel.d.ts +230 -2
- package/dist/sync/workspaceSyncModel.js +456 -17
- package/dist/sync/workspaceSyncModel.test.js +642 -0
- package/dist/sync/workspaceSyncState.d.ts +12 -0
- package/dist/sync/workspaceSyncState.js +12 -0
- package/dist/sync/workspaceSyncSurface.d.ts +33 -0
- package/dist/sync/workspaceSyncSurface.js +74 -0
- package/dist/types.d.ts +143 -18
- package/dist/types.js +9 -24
- package/dist/ui/assets/AgentsModule-TVmCgizS.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CAyhnPeR.js +3 -0
- package/dist/ui/assets/DocumentWorkspace-BOCw5e4D.js +250 -0
- package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +1 -0
- package/dist/ui/assets/InitiativesModule-CN0r02Oi.js +1 -0
- package/dist/ui/assets/PlansPage-BlVC_lRq.css +1 -0
- package/dist/ui/assets/PlansPage-FcQSNLZd.js +1 -0
- package/dist/ui/assets/TaskSettings-BwB9NtmJ.css +1 -0
- package/dist/ui/assets/TaskSettings-Cw5zYD1L.js +8 -0
- package/dist/ui/assets/WorkflowsModule-CY9R2zPB.js +5 -0
- package/dist/ui/assets/index-Bzqy5QGm.js +6 -0
- package/dist/ui/assets/index-DxRiI3tY.css +1 -0
- package/dist/ui/assets/vendor-dnd-DRzYolkg.js +5 -0
- package/dist/ui/assets/{vendor-icons-ZFG3SGwo.js → vendor-icons-QZyhEwgT.js} +1 -1
- package/dist/ui/assets/{vendor-markdown-CKYkQHfj.js → vendor-markdown-BUxTU7dS.js} +1 -1
- package/dist/ui/assets/vendor-react-CKJs5o3c.js +61 -0
- package/dist/ui/assets/vendor-router-BbWMxlnO.js +3 -0
- package/dist/ui/branding/logos/logo.png +0 -0
- package/dist/ui/branding/logos/logo_dark.svg +27 -0
- package/dist/ui/branding/logos/logo_favicon.svg +35 -0
- package/dist/ui/branding/logos/logo_light.svg +27 -0
- package/dist/ui/favicon/apple-touch-icon.png +0 -0
- package/dist/ui/favicon/archive/phoenix/apple-touch-icon.png +0 -0
- package/dist/ui/favicon/archive/phoenix/favicon.ico +0 -0
- package/dist/ui/favicon/archive/phoenix/site.webmanifest +1 -0
- package/dist/ui/favicon/favicon-96x96.png +0 -0
- package/dist/ui/favicon/favicon.ico +0 -0
- package/dist/ui/favicon/favicon.svg +17 -0
- package/dist/ui/favicon/site.webmanifest +21 -1
- package/dist/ui/favicon/web-app-manifest-192x192.png +0 -0
- package/dist/ui/favicon/web-app-manifest-512x512.png +0 -0
- package/dist/ui/index.html +10 -7
- package/dist/ui/product/screen_01.png +0 -0
- package/dist/ui/product/screen_02.png +0 -0
- package/dist/ui/product/screen_03.png +0 -0
- package/dist/utils/annotatedAttachments.d.ts +20 -0
- package/dist/utils/annotatedAttachments.js +74 -0
- package/dist/utils/annotatedAttachments.test.d.ts +1 -0
- package/dist/utils/annotatedAttachments.test.js +108 -0
- package/dist/utils/assignees.d.ts +26 -0
- package/dist/utils/assignees.js +132 -0
- package/dist/utils/canonicalAssetKind.d.ts +16 -0
- package/dist/utils/canonicalAssetKind.js +39 -0
- package/dist/utils/canonicalAssetKind.test.d.ts +1 -0
- package/dist/utils/canonicalAssetKind.test.js +24 -0
- package/dist/utils/coalescedRefresh.d.ts +5 -0
- package/dist/utils/coalescedRefresh.js +16 -0
- package/dist/utils/coalescedRefresh.test.d.ts +1 -0
- package/dist/utils/coalescedRefresh.test.js +30 -0
- package/dist/utils/constants.d.ts +16 -3
- package/dist/utils/constants.icons.test.js +2 -1
- package/dist/utils/constants.js +70 -13
- package/dist/utils/contextAssetEvents.d.ts +7 -0
- package/dist/utils/contextAssetEvents.js +6 -0
- package/dist/utils/contextFiles.d.ts +14 -3
- package/dist/utils/contextFiles.js +40 -8
- package/dist/utils/documentManagerApi.d.ts +6 -0
- package/dist/utils/documentManagerApi.js +19 -0
- package/dist/utils/documentNames.d.ts +24 -0
- package/dist/utils/documentNames.js +91 -0
- package/dist/utils/documentReferences.d.ts +9 -0
- package/dist/utils/documentReferences.js +11 -0
- package/dist/utils/entityReferences.d.ts +9 -0
- package/dist/utils/entityReferences.js +32 -0
- package/dist/utils/imageReferences.d.ts +9 -0
- package/dist/utils/imageReferences.js +11 -0
- package/dist/utils/planParser.d.ts +2 -2
- package/dist/utils/planParser.js +11 -11
- package/dist/utils/planParser.test.d.ts +1 -0
- package/dist/{__tests__ → utils}/planParser.test.js +22 -22
- package/dist/utils/planningReferences.d.ts +17 -0
- package/dist/utils/planningReferences.js +30 -0
- package/dist/utils/planningReferences.test.d.ts +1 -0
- package/dist/utils/planningReferences.test.js +17 -0
- package/dist/utils/taskActivity.d.ts +9 -0
- package/dist/utils/taskActivity.js +147 -0
- package/dist/utils/taskActivity.test.d.ts +1 -0
- package/dist/utils/taskActivity.test.js +34 -0
- package/dist/utils/taskDraftDefaults.d.ts +21 -0
- package/dist/utils/taskDraftDefaults.js +40 -0
- package/dist/utils/taskDraftDefaults.test.d.ts +1 -0
- package/dist/utils/taskDraftDefaults.test.js +34 -0
- package/dist/utils/taskNormalization.d.ts +25 -0
- package/dist/utils/taskNormalization.js +161 -0
- package/dist/utils/taskNormalization.test.d.ts +1 -0
- package/dist/utils/taskNormalization.test.js +158 -0
- package/dist/utils/taskReferences.d.ts +5 -0
- package/dist/utils/taskReferences.js +11 -0
- package/dist/utils/taskforceApiClient.d.ts +2 -0
- package/dist/utils/taskforceApiClient.js +101 -3
- package/dist/utils/taskforceApiClient.test.d.ts +1 -0
- package/dist/utils/taskforceApiClient.test.js +44 -0
- package/dist/utils/taxonomyFilterOptions.d.ts +2 -0
- package/dist/utils/taxonomyFilterOptions.js +17 -0
- package/dist/utils/taxonomyFormDefaults.d.ts +3 -0
- package/dist/utils/taxonomyFormDefaults.js +28 -0
- package/dist/utils/taxonomyFormDefaults.test.d.ts +1 -0
- package/dist/utils/taxonomyFormDefaults.test.js +63 -0
- package/dist/utils/taxonomyLifecycle.d.ts +3 -0
- package/dist/utils/taxonomyLifecycle.js +17 -0
- package/dist/utils/taxonomySorting.d.ts +7 -0
- package/dist/utils/taxonomySorting.js +74 -0
- package/dist/utils/theme.d.ts +15 -0
- package/dist/utils/theme.js +23 -0
- package/dist/utils/uiNotice.d.ts +7 -0
- package/dist/utils/uiNotice.js +6 -0
- package/dist/utils/uiNotice.test.d.ts +1 -0
- package/dist/utils/uiNotice.test.js +18 -0
- package/dist/utils/workspaceIdentity.d.ts +14 -0
- package/dist/utils/workspaceIdentity.js +21 -0
- package/dist/utils/workspaceIdentity.test.js +30 -1
- package/dist/utils/workspaceSyncPresentation.d.ts +20 -0
- package/dist/utils/workspaceSyncPresentation.js +21 -0
- package/dist/utils/workspaceSyncPresentation.test.d.ts +1 -0
- package/dist/utils/workspaceSyncPresentation.test.js +36 -0
- package/package.json +28 -23
- package/scripts/bootstrap-playwright-auth.mjs +155 -0
- package/scripts/check-compat-boundaries.mjs +41 -0
- package/scripts/check-env.ts +9 -2
- package/scripts/debug-login.mjs +32 -0
- package/scripts/migrate-planning-model.ts +233 -0
- package/scripts/migrate-task-data-assets.mjs +408 -0
- package/scripts/playwright-auth.sh +11 -0
- package/scripts/run-dev-proxy.sh +2 -0
- package/scripts/update-homebrew-formula.sh +2 -2
- package/scripts/with-esbuild.sh +11 -0
- package/src/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
- package/src/resources/templates/workflows/collaborate.yaml +11 -5
- package/src/resources/templates/workflows/do.yaml +8 -2
- package/src/resources/templates/workflows/evaluate.yaml +13 -7
- package/src/resources/templates/workflows/execute.yaml +40 -23
- package/src/resources/templates/workflows/plan.yaml +15 -8
- package/src/resources/templates/workflows/review.yaml +14 -8
- package/dist/TaskforceScreenshot.d.ts +0 -11
- package/dist/TaskforceScreenshot.js +0 -113
- package/dist/compat/priorityCompat.d.ts +0 -2
- package/dist/compat/priorityCompat.js +0 -24
- package/dist/components/features/settings/TaxonomyManager 2.d.ts +0 -52
- package/dist/components/features/settings/TaxonomyManager 2.js +0 -75
- package/dist/components/task/TaskKanban 2.d.ts +0 -76
- package/dist/components/task/TaskKanban 2.js +0 -1004
- package/dist/components/task/TaskScreenshotSection.d.ts +0 -15
- package/dist/components/task/TaskScreenshotSection.js +0 -22
- package/dist/components/views/StandaloneLayout 2.d.ts +0 -8
- package/dist/components/views/StandaloneLayout 2.js +0 -1660
- package/dist/core/InitiativeTemplates.test.js +0 -50
- package/dist/core/ParentLifecycle.test.js +0 -98
- package/dist/migrations/clientMigrations.d.ts +0 -9
- package/dist/migrations/clientMigrations.js +0 -74
- package/dist/migrations/flags.d.ts +0 -6
- package/dist/migrations/flags.js +0 -8
- package/dist/migrations/taskMigrations.d.ts +0 -71
- package/dist/migrations/taskMigrations.js +0 -236
- package/dist/migrations/taskMigrations.test.js +0 -34
- package/dist/server/routes.billing.js +0 -991
- package/dist/server/routes.billing.test.js +0 -387
- package/dist/server/routes.sync.integration.test.js +0 -470
- package/dist/server/routes.sync.js +0 -1141
- package/dist/soak/syncSoakHarness.d.ts +0 -6
- package/dist/soak/syncSoakHarness.js +0 -10
- package/dist/ui/assets/index-0W5vyCpn.css +0 -1
- package/dist/ui/assets/index-MCZuNNfn.js +0 -23
- package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
- package/dist/ui/assets/vendor-dnd-BI1K77C1.js +0 -5
- package/dist/ui/assets/vendor-react-DdIDsh7f.js +0 -9
- package/dist/ui/assets/vendor-router-BtiNU7Dl.js +0 -3
- package/dist/utils/taskHierarchy.d.ts +0 -4
- package/dist/utils/taskHierarchy.js +0 -69
- package/dist/utils/taskHierarchy.test.js +0 -38
- package/dist/utils/taskParenting.d.ts +0 -3
- package/dist/utils/taskParenting.js +0 -24
- package/dist/utils/taskParenting.test.js +0 -21
- package/dist/utils/taskRelations.d.ts +0 -6
- package/dist/utils/taskRelations.js +0 -24
- package/dist/utils/taskRelations.test.js +0 -34
- package/scripts/check-compat-boundaries.js +0 -48
- /package/dist/{__tests__/planParser.test.d.ts → TaskforceCore.filter-persistence.test.d.ts} +0 -0
- /package/dist/{__tests__/releaseVersion.test.d.ts → TaskforceCore.routing.test.d.ts} +0 -0
- /package/dist/{__tests__/structuredCommentValidation.test.d.ts → annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts} +0 -0
- /package/dist/{__tests__/structuredDocValidation.test.d.ts → annotatedAttachments/payload.test.d.ts} +0 -0
- /package/dist/{__tests__/templateEngine.test.d.ts → annotatedAttachments/types.js} +0 -0
- /package/dist/{__tests__/templates.test.d.ts → compat/workspaceSyncCompat.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowDocumentFixtures.test.d.ts → components/features/AgentsModule.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowExportMatrix.test.d.ts → components/features/AnnotatedAttachmentWorkspace.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowExportSnapshots.test.d.ts → components/features/DocumentWorkspace.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowGeneration.test.d.ts → components/features/settings/TaxonomyLibraryManager.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowV2Policy.test.d.ts → components/task/TaskActionHeader.test.d.ts} +0 -0
- /package/dist/{core/InitiativeTemplates.test.d.ts → components/task/TaskKanban.planning-drop.test.d.ts} +0 -0
- /package/dist/{core/ParentLifecycle.test.d.ts → components/task/TaskStatusActions.test.d.ts} +0 -0
- /package/dist/{migrations/taskMigrations.test.d.ts → components/ui/TopNoticeLayer.test.d.ts} +0 -0
- /package/dist/{server/routes.billing.test.d.ts → components/views/AppShellHeader.test.d.ts} +0 -0
- /package/dist/{server/routes.sync.integration.test.d.ts → components/views/PlanComparisonPage.test.d.ts} +0 -0
- /package/dist/{utils/taskHierarchy.test.d.ts → components/views/chrome/WorkspaceChromeSections.test.d.ts} +0 -0
- /package/dist/{utils/taskParenting.test.d.ts → components/views/chrome/workspaceChrome.test.d.ts} +0 -0
- /package/dist/{utils/taskRelations.test.d.ts → components/views/panels/DocumentFilterToolbar.test.d.ts} +0 -0
- /package/dist/public/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
- /package/dist/public/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
- /package/dist/public/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
- /package/dist/public/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
- /package/dist/public/{favicon.png → archive/phoenix/favicon.png} +0 -0
- /package/dist/{__tests__ → services}/workflowExportSnapshots.test.js +0 -0
- /package/dist/{__tests__ → services}/workflowGeneration.test.js +0 -0
- /package/dist/ui/favicon/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
- /package/dist/ui/favicon/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
- /package/dist/ui/favicon/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
- /package/dist/ui/favicon/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
- /package/dist/ui/favicon/{favicon.png → archive/phoenix/favicon.png} +0 -0
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import { Sun, Moon, Sparkles,
|
|
2
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { Sun, Moon, Sparkles, Keyboard, FileText, Check, AlertTriangle, Loader2, Settings, Layers, Box, Copy, Trash2, Terminal, Bot, Codepen, Command, Wind, Github, Zap, ChevronDown, ChevronRight, Plug } from 'lucide-react';
|
|
4
4
|
import styles from '../../Taskforce.module.css';
|
|
5
|
+
import { TASKFORCE_THEME_OPTIONS } from '../../utils/theme';
|
|
6
|
+
import { MCP_CLIENT_OPTIONS, buildCloudMcpClientIntegration, buildCloudMcpServerId, sanitizeMcpId } from '../../mcp/clientIntegrations';
|
|
7
|
+
import { resolveTaskforceMcpBaseUrlFromBaseUrl } from '../../config/cloudEnvironment';
|
|
5
8
|
import { TaxonomyManager } from './settings/TaxonomyManager';
|
|
6
|
-
|
|
9
|
+
const THEME_ICON_MAP = {
|
|
10
|
+
sun: Sun,
|
|
11
|
+
wind: Wind,
|
|
12
|
+
moon: Moon,
|
|
13
|
+
sparkles: Sparkles,
|
|
14
|
+
};
|
|
7
15
|
export function TaskSettings(props) {
|
|
8
16
|
const { settingsModel, onSectionChange } = props;
|
|
9
|
-
const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled =
|
|
17
|
+
const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled = true, showTaskCardStatusLabel = true, exportWorkflowsPath, exportingResource, exportResult, initialSection, onThemeChange, onSaveTheme, onSaveGlobalTheme, onResetProjectToGlobal, onKeyShortcutChange, onJsonBackupEnabledChange, onSaveGlobalJsonBackupEnabled, onSaveGlobalWeekStartsOn, onSaveLocale, onManualComplexityEnabledChange, onChecklistDropdownEnabledChange, onShowTaskCardStatusLabelChange, onSaveSettings, onExportWorkflowsPathChange, onShowFolderBrowserChange, onBrowserTargetChange, onFetchFolders, categories, pathValidation, taxonomyDisplayLabels, onUpdateCategory, onRemoveCategory, onSaveCategory, onAddPath, onRemovePath, onUpdateCategoryIcon, onUpdateCategoryColor, types, onSaveType, onRemoveType, onUpdateType, taxonomies, onUpdateTaxonomies, priorities, onUpdatePriorities, onAnalyzeSystemTaxonomyPack, onApplySystemTaxonomyPack, onUpdateTaxonomyDisplayLabels, projectRoot, projectName, mcpHostRoot, serverHostRoot, mcpScriptPath, tenantId, workspaceId, runtimeMode = 'local', cloudAuthBaseUrl = '', cloudMcpBaseUrl = '', fetchCloudAuthApi, workspaceSwitchingEnabled = false, currentWorkspaceRole = 'member', currentWorkspaceName = '', onDeleteWorkspace, onMcpHostRootChange, isAuthenticated = false, exportEnvironment, setupState = null, buildInfo = null, onExportEnvironmentChange, onSaveSetupMode, onSaveWorkspaceProfile, availableWorkflows = [], onExportWorkflows, initiativeTemplates = [], onRefreshInitiativeTemplates, onCreateInitiativeFromTemplate, onRefreshWorkflows } = settingsModel;
|
|
18
|
+
const showJsonBackupSettings = runtimeMode !== 'cloud';
|
|
10
19
|
// Workflow Selection State
|
|
11
20
|
const [selectedWorkflows, setSelectedWorkflows] = useState([]);
|
|
12
21
|
// Initialize selection when availableWorkflows changes
|
|
@@ -26,23 +35,85 @@ export function TaskSettings(props) {
|
|
|
26
35
|
const [setupMode, setSetupMode] = useState(() => setupState?.mode === 'operations' ? 'operations' : 'core');
|
|
27
36
|
const [workspaceDisplayName, setWorkspaceDisplayName] = useState(() => String(setupState?.workspace?.name || '').trim());
|
|
28
37
|
const [workspaceDescription, setWorkspaceDescription] = useState(() => String(setupState?.workspace?.description || ''));
|
|
29
|
-
const [workspacePlanMode, setWorkspacePlanMode] = useState('personal');
|
|
30
|
-
const [workspacePlanModeLoading, setWorkspacePlanModeLoading] = useState(false);
|
|
31
|
-
const [workspacePlanModeError, setWorkspacePlanModeError] = useState(null);
|
|
32
38
|
const [selectedInitiativeTemplateId, setSelectedInitiativeTemplateId] = useState('');
|
|
33
39
|
const [initiativeTitle, setInitiativeTitle] = useState('');
|
|
34
|
-
const [initiativeParentTaskId, setInitiativeParentTaskId] = useState('');
|
|
35
|
-
const [cloneChecklistParentTaskId, setCloneChecklistParentTaskId] = useState('');
|
|
36
|
-
const [cloneChecklistDodText, setCloneChecklistDodText] = useState('');
|
|
37
|
-
const [cloneChecklistRollbackText, setCloneChecklistRollbackText] = useState('');
|
|
38
40
|
const [isCreatingInitiative, setIsCreatingInitiative] = useState(false);
|
|
39
|
-
const [isCloningChecklists, setIsCloningChecklists] = useState(false);
|
|
40
|
-
const [documentsConfigLoading, setDocumentsConfigLoading] = useState(false);
|
|
41
|
-
const [documentsStorageProvider, setDocumentsStorageProvider] = useState('unknown');
|
|
42
41
|
const [activeTab, setActiveTab] = useState('general');
|
|
42
|
+
const [appearanceExpanded, setAppearanceExpanded] = useState(true);
|
|
43
43
|
const [generalScopeTab, setGeneralScopeTab] = useState(() => {
|
|
44
44
|
return 'project';
|
|
45
45
|
});
|
|
46
|
+
const [aiProfiles, setAiProfiles] = useState([]);
|
|
47
|
+
const [aiProfilesLoading, setAiProfilesLoading] = useState(false);
|
|
48
|
+
const [aiProfileMergeState, setAiProfileMergeState] = useState(null);
|
|
49
|
+
const [aiProfileMergeStatus, setAiProfileMergeStatus] = useState(null);
|
|
50
|
+
const loadAiProfiles = React.useCallback(async () => {
|
|
51
|
+
if (!workspaceId)
|
|
52
|
+
return;
|
|
53
|
+
setAiProfilesLoading(true);
|
|
54
|
+
try {
|
|
55
|
+
const assigneeOptionsUrl = typeof window !== 'undefined'
|
|
56
|
+
? new URL(`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(workspaceId)}`, window.location.origin).toString()
|
|
57
|
+
: `/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(workspaceId)}`;
|
|
58
|
+
const res = await fetch(assigneeOptionsUrl, { credentials: 'include' });
|
|
59
|
+
if (!res.ok)
|
|
60
|
+
return;
|
|
61
|
+
const data = await res.json().catch(() => ({}));
|
|
62
|
+
const agents = Array.isArray(data?.assignees)
|
|
63
|
+
? data.assignees.filter((a) => a.kind === 'agent').map((a) => ({
|
|
64
|
+
id: String(a.value || ''),
|
|
65
|
+
name: String(a.label || ''),
|
|
66
|
+
profileToken: typeof a.profileToken === 'string' ? a.profileToken : null,
|
|
67
|
+
username: String(a.username || a.value || ''),
|
|
68
|
+
icon: String(a.icon || 'Bot'),
|
|
69
|
+
color: String(a.color || '#6B7280'),
|
|
70
|
+
kind: 'agent',
|
|
71
|
+
description: typeof a.description === 'string' ? a.description : null,
|
|
72
|
+
role: typeof a.role === 'string' ? a.role : null,
|
|
73
|
+
provider: typeof a.provider === 'string' ? a.provider : null,
|
|
74
|
+
model: typeof a.model === 'string' ? a.model : null,
|
|
75
|
+
surfaceType: typeof a.surfaceType === 'string' ? a.surfaceType : null,
|
|
76
|
+
}))
|
|
77
|
+
: [];
|
|
78
|
+
setAiProfiles(agents);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
setAiProfiles([]);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
setAiProfilesLoading(false);
|
|
85
|
+
}
|
|
86
|
+
}, [workspaceId]);
|
|
87
|
+
const doMergeAiProfiles = React.useCallback(async (keepId, mergeId) => {
|
|
88
|
+
if (!workspaceId)
|
|
89
|
+
return;
|
|
90
|
+
setAiProfileMergeStatus(null);
|
|
91
|
+
try {
|
|
92
|
+
const res = await fetch('/api/taskforce/workspace/ai-profiles/merge', {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
credentials: 'include',
|
|
95
|
+
headers: { 'Content-Type': 'application/json' },
|
|
96
|
+
body: JSON.stringify({ workspaceId, keepId, mergeId }),
|
|
97
|
+
});
|
|
98
|
+
const data = await res.json().catch(() => ({}));
|
|
99
|
+
if (!res.ok) {
|
|
100
|
+
setAiProfileMergeStatus({ type: 'error', message: data?.error || 'Merge failed.' });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
setAiProfileMergeStatus({ type: 'success', message: `Profiles merged successfully.` });
|
|
104
|
+
setAiProfileMergeState(null);
|
|
105
|
+
await loadAiProfiles();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
setAiProfileMergeStatus({ type: 'error', message: 'Network error during merge.' });
|
|
110
|
+
}
|
|
111
|
+
}, [workspaceId, loadAiProfiles]);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (activeTab === 'agents' || activeTab === 'mcp') {
|
|
114
|
+
loadAiProfiles();
|
|
115
|
+
}
|
|
116
|
+
}, [activeTab, loadAiProfiles]);
|
|
46
117
|
useEffect(() => {
|
|
47
118
|
if (initiativeTemplates.length > 0 && !selectedInitiativeTemplateId) {
|
|
48
119
|
setSelectedInitiativeTemplateId(initiativeTemplates[0].id);
|
|
@@ -61,41 +132,6 @@ export function TaskSettings(props) {
|
|
|
61
132
|
setWorkspaceDisplayName(String(setupState?.workspace?.name || '').trim());
|
|
62
133
|
setWorkspaceDescription(String(setupState?.workspace?.description || ''));
|
|
63
134
|
}, [setupState?.workspace?.name, setupState?.workspace?.description]);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
if (activeTab !== 'general' || generalScopeTab !== 'project' || !isAuthenticated)
|
|
66
|
-
return;
|
|
67
|
-
let cancelled = false;
|
|
68
|
-
(async () => {
|
|
69
|
-
setWorkspacePlanModeLoading(true);
|
|
70
|
-
setWorkspacePlanModeError(null);
|
|
71
|
-
try {
|
|
72
|
-
const res = await fetch('/api/taskforce/account/entitlements', {
|
|
73
|
-
method: 'GET',
|
|
74
|
-
credentials: 'include'
|
|
75
|
-
});
|
|
76
|
-
const payload = await res.json().catch(() => ({}));
|
|
77
|
-
if (cancelled)
|
|
78
|
-
return;
|
|
79
|
-
if (!res.ok) {
|
|
80
|
-
setWorkspacePlanModeError(String(payload?.error || 'Failed to load account entitlements.'));
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const planId = String(payload?.planId || '').trim().toLowerCase();
|
|
84
|
-
setWorkspacePlanMode(planId === 'team' ? 'team' : 'personal');
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
if (!cancelled)
|
|
88
|
-
setWorkspacePlanModeError('Failed to load account entitlements.');
|
|
89
|
-
}
|
|
90
|
-
finally {
|
|
91
|
-
if (!cancelled)
|
|
92
|
-
setWorkspacePlanModeLoading(false);
|
|
93
|
-
}
|
|
94
|
-
})();
|
|
95
|
-
return () => {
|
|
96
|
-
cancelled = true;
|
|
97
|
-
};
|
|
98
|
-
}, [activeTab, generalScopeTab, isAuthenticated]);
|
|
99
135
|
const handleThemeChange = async (theme) => {
|
|
100
136
|
onThemeChange(theme);
|
|
101
137
|
const success = await onSaveTheme(theme);
|
|
@@ -104,16 +140,235 @@ export function TaskSettings(props) {
|
|
|
104
140
|
message: success ? 'Project theme saved.' : 'Failed to save project theme.'
|
|
105
141
|
});
|
|
106
142
|
};
|
|
143
|
+
const renderThemeButton = (themeOption, activeTheme, onSelect) => {
|
|
144
|
+
const Icon = THEME_ICON_MAP[themeOption.icon];
|
|
145
|
+
return (_jsxs("button", { className: `${styles.themeBtn} tf-button-tile ${activeTheme === themeOption.id ? styles.activeTheme : ''}`, onClick: () => { void onSelect(themeOption.id); }, children: [_jsx(Icon, { size: 20 }), " ", themeOption.label] }, themeOption.id));
|
|
146
|
+
};
|
|
147
|
+
const cloudMcpAvailable = runtimeMode === 'cloud' || isAuthenticated;
|
|
148
|
+
const defaultMcpMode = runtimeMode === 'cloud'
|
|
149
|
+
? 'cloud'
|
|
150
|
+
: (isAuthenticated ? 'cloud' : 'local');
|
|
151
|
+
const [selectedMcpMode, setSelectedMcpMode] = useState(defaultMcpMode);
|
|
107
152
|
const [copiedConfig, setCopiedConfig] = useState(false);
|
|
108
153
|
const [useGlobalMcp, setUseGlobalMcp] = useState(true);
|
|
109
154
|
const [showAdvancedMcp, setShowAdvancedMcp] = useState(false);
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
155
|
+
const [showMcpConnectionTest, setShowMcpConnectionTest] = useState(false);
|
|
156
|
+
const [showMcpTokensList, setShowMcpTokensList] = useState(true);
|
|
157
|
+
const [mcpTokens, setMcpTokens] = useState([]);
|
|
158
|
+
const [mcpTokensLoading, setMcpTokensLoading] = useState(false);
|
|
159
|
+
const [mcpTokensError, setMcpTokensError] = useState(null);
|
|
160
|
+
const [mcpActionBusyId, setMcpActionBusyId] = useState(null);
|
|
161
|
+
const defaultTokenName = useMemo(() => {
|
|
162
|
+
const label = String(currentWorkspaceName
|
|
163
|
+
|| setupState?.workspace?.name
|
|
164
|
+
|| projectName
|
|
165
|
+
|| workspaceId
|
|
166
|
+
|| 'Taskforce Workspace').trim();
|
|
167
|
+
return `${label} MCP`;
|
|
168
|
+
}, [currentWorkspaceName, setupState?.workspace?.name, projectName, workspaceId]);
|
|
169
|
+
const [newTokenName, setNewTokenName] = useState(defaultTokenName);
|
|
170
|
+
const [newTokenScopes, setNewTokenScopes] = useState(['tasks:read', 'tasks:write', 'workspace:read']);
|
|
171
|
+
const [newTokenExpiresAt, setNewTokenExpiresAt] = useState('');
|
|
172
|
+
const [mcpTokenNotice, setMcpTokenNotice] = useState(null);
|
|
173
|
+
const [generatedTokenValue, setGeneratedTokenValue] = useState(null);
|
|
174
|
+
const [selectedMcpClient, setSelectedMcpClient] = useState('cursor');
|
|
175
|
+
const [automationAiName, setAutomationAiName] = useState('');
|
|
176
|
+
const [automationAiProfileToken, setAutomationAiProfileToken] = useState('');
|
|
177
|
+
const [mcpConnectionToken, setMcpConnectionToken] = useState('');
|
|
178
|
+
const [mcpConnectionBusy, setMcpConnectionBusy] = useState(false);
|
|
179
|
+
const [mcpConnectionResult, setMcpConnectionResult] = useState(null);
|
|
180
|
+
const [mcpConnectorGrants, setMcpConnectorGrants] = useState([]);
|
|
181
|
+
const [mcpConnectorsLoading, setMcpConnectorsLoading] = useState(false);
|
|
182
|
+
const [mcpConnectorsError, setMcpConnectorsError] = useState(null);
|
|
183
|
+
const [mcpConnectorBusyId, setMcpConnectorBusyId] = useState(null);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
setSelectedMcpMode(defaultMcpMode);
|
|
186
|
+
}, [defaultMcpMode]);
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
setNewTokenName((current) => current.trim().length > 0 ? current : defaultTokenName);
|
|
189
|
+
}, [defaultTokenName]);
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
if (!mcpTokenNotice)
|
|
192
|
+
return;
|
|
193
|
+
const timer = setTimeout(() => setMcpTokenNotice(null), 3500);
|
|
194
|
+
return () => clearTimeout(timer);
|
|
195
|
+
}, [mcpTokenNotice]);
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
if (!generatedTokenValue)
|
|
198
|
+
return;
|
|
199
|
+
setMcpConnectionToken(generatedTokenValue);
|
|
200
|
+
setMcpConnectionResult(null);
|
|
201
|
+
}, [generatedTokenValue]);
|
|
202
|
+
const cloudMcpEndpoint = useMemo(() => {
|
|
203
|
+
const inferredMcpBase = resolveTaskforceMcpBaseUrlFromBaseUrl(cloudMcpBaseUrl || cloudAuthBaseUrl || '');
|
|
204
|
+
const configuredBase = String(inferredMcpBase || cloudMcpBaseUrl || cloudAuthBaseUrl || '').trim().replace(/\/+$/, '');
|
|
205
|
+
if (configuredBase)
|
|
206
|
+
return `${configuredBase}/mcp`;
|
|
207
|
+
if (typeof window === 'undefined')
|
|
208
|
+
return '/mcp';
|
|
209
|
+
return `${window.location.origin.replace(/\/+$/, '')}/mcp`;
|
|
210
|
+
}, [cloudMcpBaseUrl, cloudAuthBaseUrl]);
|
|
211
|
+
const localMcpEnabled = runtimeMode !== 'cloud';
|
|
212
|
+
const showMcpModeToggle = localMcpEnabled && cloudMcpAvailable;
|
|
213
|
+
const showCloudMcp = runtimeMode === 'cloud' || selectedMcpMode === 'cloud';
|
|
214
|
+
const showLocalMcp = runtimeMode !== 'cloud' && (!cloudMcpAvailable || selectedMcpMode === 'local');
|
|
215
|
+
const sortedMcpTokens = useMemo(() => {
|
|
216
|
+
const statusRank = {
|
|
217
|
+
active: 0,
|
|
218
|
+
expired: 1,
|
|
219
|
+
revoked: 2,
|
|
220
|
+
};
|
|
221
|
+
return [...mcpTokens].sort((a, b) => {
|
|
222
|
+
const rankDiff = (statusRank[a.status] ?? 99) - (statusRank[b.status] ?? 99);
|
|
223
|
+
if (rankDiff !== 0)
|
|
224
|
+
return rankDiff;
|
|
225
|
+
return String(b.createdAt || '').localeCompare(String(a.createdAt || ''));
|
|
226
|
+
});
|
|
227
|
+
}, [mcpTokens]);
|
|
228
|
+
const cloudMcpServerId = useMemo(() => buildCloudMcpServerId(currentWorkspaceName || null, projectName || null), [currentWorkspaceName, projectName]);
|
|
229
|
+
const cloudMcpTokenValue = generatedTokenValue || '<<GENERATE_TOKEN>>';
|
|
230
|
+
const selectedAutomationProfileId = useMemo(() => {
|
|
231
|
+
if (automationAiProfileToken) {
|
|
232
|
+
const byToken = aiProfiles.find((profile) => String(profile.profileToken || '').trim() === automationAiProfileToken.trim());
|
|
233
|
+
if (byToken)
|
|
234
|
+
return byToken.id;
|
|
235
|
+
}
|
|
236
|
+
if (automationAiName) {
|
|
237
|
+
const byName = aiProfiles.find((profile) => profile.name === automationAiName.trim());
|
|
238
|
+
if (byName)
|
|
239
|
+
return byName.id;
|
|
240
|
+
}
|
|
241
|
+
return '';
|
|
242
|
+
}, [aiProfiles, automationAiName, automationAiProfileToken]);
|
|
243
|
+
const selectedAutomationProfile = useMemo(() => aiProfiles.find((profile) => profile.id === selectedAutomationProfileId) || null, [aiProfiles, selectedAutomationProfileId]);
|
|
244
|
+
const inferredAutomationProfileMetadata = useMemo(() => {
|
|
245
|
+
switch (selectedMcpClient) {
|
|
246
|
+
case 'codex':
|
|
247
|
+
return { description: 'OpenAI Codex coding agent connected through MCP.', role: 'Coding Agent', provider: 'OpenAI', model: 'Codex', surfaceType: 'coding_tool' };
|
|
248
|
+
case 'chatgpt-desktop':
|
|
249
|
+
return { description: 'ChatGPT desktop app connected through the Taskforce MCP connector.', role: 'AI Assistant', provider: 'OpenAI', model: 'ChatGPT', surfaceType: 'chat_app' };
|
|
250
|
+
case 'claude-code':
|
|
251
|
+
return { description: 'Claude Code coding agent connected through MCP.', role: 'Coding Agent', provider: 'Anthropic', model: 'Claude Code', surfaceType: 'coding_tool' };
|
|
252
|
+
case 'claude-desktop':
|
|
253
|
+
return { description: 'Claude Desktop connected through the Taskforce MCP connector.', role: 'AI Assistant', provider: 'Anthropic', model: 'Claude', surfaceType: 'chat_app' };
|
|
254
|
+
case 'gemini-cli':
|
|
255
|
+
return { description: 'Gemini CLI coding agent connected through MCP.', role: 'Coding Agent', provider: 'Google', model: 'Gemini', surfaceType: 'coding_tool' };
|
|
256
|
+
case 'vscode':
|
|
257
|
+
return { description: 'VS Code MCP-connected coding agent.', role: 'Coding Agent', provider: null, model: null, surfaceType: 'ide' };
|
|
258
|
+
case 'cline':
|
|
259
|
+
case 'windsurf':
|
|
260
|
+
case 'antigravity':
|
|
261
|
+
case 'openclaw':
|
|
262
|
+
return {
|
|
263
|
+
description: `${MCP_CLIENT_OPTIONS.find((option) => option.id === selectedMcpClient)?.label || 'MCP'} coding agent connected through MCP.`,
|
|
264
|
+
role: 'Coding Agent',
|
|
265
|
+
provider: null,
|
|
266
|
+
model: null,
|
|
267
|
+
surfaceType: 'coding_tool'
|
|
268
|
+
};
|
|
269
|
+
default:
|
|
270
|
+
return { description: null, role: null, provider: null, model: null, surfaceType: null };
|
|
271
|
+
}
|
|
272
|
+
}, [selectedMcpClient]);
|
|
273
|
+
const cloudClientIntegration = useMemo(() => buildCloudMcpClientIntegration({
|
|
274
|
+
clientId: selectedMcpClient,
|
|
275
|
+
endpoint: cloudMcpEndpoint,
|
|
276
|
+
tokenValue: cloudMcpTokenValue,
|
|
277
|
+
serverId: cloudMcpServerId,
|
|
278
|
+
aiProfileName: automationAiName,
|
|
279
|
+
aiProfileToken: automationAiProfileToken,
|
|
280
|
+
aiProfileDescription: selectedAutomationProfile?.description ?? inferredAutomationProfileMetadata.description,
|
|
281
|
+
aiProfileRole: selectedAutomationProfile?.role ?? inferredAutomationProfileMetadata.role,
|
|
282
|
+
aiProfileProvider: selectedAutomationProfile?.provider ?? inferredAutomationProfileMetadata.provider,
|
|
283
|
+
aiProfileModel: selectedAutomationProfile?.model ?? inferredAutomationProfileMetadata.model,
|
|
284
|
+
aiProfileSurfaceType: selectedAutomationProfile?.surfaceType ?? inferredAutomationProfileMetadata.surfaceType,
|
|
285
|
+
}), [
|
|
286
|
+
automationAiName,
|
|
287
|
+
automationAiProfileToken,
|
|
288
|
+
cloudMcpEndpoint,
|
|
289
|
+
cloudMcpServerId,
|
|
290
|
+
cloudMcpTokenValue,
|
|
291
|
+
inferredAutomationProfileMetadata.description,
|
|
292
|
+
inferredAutomationProfileMetadata.model,
|
|
293
|
+
inferredAutomationProfileMetadata.provider,
|
|
294
|
+
inferredAutomationProfileMetadata.role,
|
|
295
|
+
inferredAutomationProfileMetadata.surfaceType,
|
|
296
|
+
selectedAutomationProfile?.description,
|
|
297
|
+
selectedAutomationProfile?.model,
|
|
298
|
+
selectedAutomationProfile?.provider,
|
|
299
|
+
selectedAutomationProfile?.role,
|
|
300
|
+
selectedAutomationProfile?.surfaceType,
|
|
301
|
+
selectedMcpClient
|
|
302
|
+
]);
|
|
303
|
+
const cloudMcpServerConfig = cloudClientIntegration.kind === 'json'
|
|
304
|
+
? cloudClientIntegration.serverConfig ?? null
|
|
305
|
+
: null;
|
|
306
|
+
const selectedMcpClientUsesOAuth = selectedMcpClient === 'chatgpt-desktop' || selectedMcpClient === 'claude-desktop';
|
|
307
|
+
const activeChatGptConnector = useMemo(() => mcpConnectorGrants.find((grant) => grant.provider === 'chatgpt' && grant.status === 'active') || null, [mcpConnectorGrants]);
|
|
308
|
+
const activeClaudeConnector = useMemo(() => mcpConnectorGrants.find((grant) => grant.provider === 'claude' && grant.status === 'active') || null, [mcpConnectorGrants]);
|
|
309
|
+
const selectedConnectorGrant = selectedMcpClient === 'chatgpt-desktop'
|
|
310
|
+
? activeChatGptConnector
|
|
311
|
+
: (selectedMcpClient === 'claude-desktop' ? activeClaudeConnector : null);
|
|
312
|
+
const cloudMcpFullConfig = useMemo(() => {
|
|
313
|
+
if (cloudClientIntegration.kind === 'text') {
|
|
314
|
+
return cloudClientIntegration.renderedText || '';
|
|
315
|
+
}
|
|
316
|
+
let payload = {
|
|
317
|
+
[cloudClientIntegration.rootKey || 'mcpServers']: {
|
|
318
|
+
[cloudMcpServerId]: cloudClientIntegration.serverConfig
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
for (const key of [...(cloudClientIntegration.wrapperKeys || [])].reverse()) {
|
|
322
|
+
payload = { [key]: payload };
|
|
323
|
+
}
|
|
324
|
+
return JSON.stringify(payload, null, 2);
|
|
325
|
+
}, [cloudClientIntegration, cloudMcpServerId]);
|
|
326
|
+
const renderMcpConfigBlock = (serverId, serverConfig, rootKey = 'mcpServers', wrapperKeys = []) => {
|
|
327
|
+
const dimmed = { color: 'var(--text-helper)' };
|
|
328
|
+
const highlighted = { color: 'var(--brand-primary-strong)', fontWeight: 'bold' };
|
|
329
|
+
const bracketColor = { color: 'var(--text-secondary)' };
|
|
330
|
+
const normalText = { color: 'var(--text-primary, #fff)' };
|
|
331
|
+
const tokenText = cloudMcpTokenValue;
|
|
332
|
+
const containerKeys = [...wrapperKeys, rootKey];
|
|
333
|
+
const serverIndent = ' '.repeat(containerKeys.length + 1);
|
|
334
|
+
const configText = JSON.stringify(serverConfig, null, 2)
|
|
335
|
+
.split('\n')
|
|
336
|
+
.map((line, i) => i === 0 ? line : `${serverIndent}${line}`)
|
|
337
|
+
.join('\n');
|
|
338
|
+
const configSegments = configText.split(tokenText);
|
|
339
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { style: bracketColor, children: "{" }), "\n", containerKeys.map((key, index) => (_jsxs(React.Fragment, { children: [`${' '.repeat(index + 1)}`, _jsx("span", { style: dimmed, children: `"${key}"` }), _jsx("span", { style: dimmed, children: ":" }), " ", _jsx("span", { style: bracketColor, children: "{" }), "\n"] }, `mcp-container-open-${key}-${index}`))), serverIndent, _jsxs("span", { style: normalText, children: [`"${serverId}"`, ": ", configSegments.map((segment, index) => (_jsxs(React.Fragment, { children: [segment, index < configSegments.length - 1 && _jsx("span", { style: highlighted, children: tokenText })] }, `config-segment-${index}`)))] }), "\n", [...containerKeys].reverse().map((key, index) => (_jsxs(React.Fragment, { children: [`${' '.repeat(containerKeys.length - index)}`, _jsx("span", { style: bracketColor, children: "}" }), "\n"] }, `mcp-container-close-${key}-${index}`))), _jsx("span", { style: bracketColor, children: "}" })] }));
|
|
340
|
+
};
|
|
341
|
+
const renderTextConfigBlock = (text) => {
|
|
342
|
+
const normalText = { color: 'var(--text-primary, #fff)' };
|
|
343
|
+
const highlighted = { color: 'var(--brand-primary-strong)', fontWeight: 'bold' };
|
|
344
|
+
const tokenText = cloudMcpTokenValue;
|
|
345
|
+
const segments = String(text || '').split(tokenText);
|
|
346
|
+
return segments.map((segment, index) => (_jsxs(React.Fragment, { children: [_jsx("span", { style: normalText, children: segment }), index < segments.length - 1 && _jsx("span", { style: highlighted, children: tokenText })] }, `text-config-${index}`)));
|
|
347
|
+
};
|
|
348
|
+
const toggleTokenScope = (scope) => {
|
|
349
|
+
setNewTokenScopes((current) => {
|
|
350
|
+
if (current.includes(scope)) {
|
|
351
|
+
if (current.length === 1)
|
|
352
|
+
return current;
|
|
353
|
+
return current.filter((item) => item !== scope);
|
|
354
|
+
}
|
|
355
|
+
return [...current, scope];
|
|
356
|
+
});
|
|
357
|
+
};
|
|
358
|
+
const copyToClipboard = (value, mode) => {
|
|
359
|
+
navigator.clipboard.writeText(value);
|
|
360
|
+
setCopiedConfig(mode);
|
|
361
|
+
setTimeout(() => setCopiedConfig(false), 2000);
|
|
362
|
+
};
|
|
363
|
+
const handleCopyCloudMcpConfig = () => {
|
|
364
|
+
if (!selectedMcpClientUsesOAuth && !generatedTokenValue) {
|
|
365
|
+
setMcpTokenNotice({
|
|
366
|
+
type: 'error',
|
|
367
|
+
message: 'Generate a token before copying the Cloud MCP configuration.'
|
|
368
|
+
});
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
copyToClipboard(cloudMcpFullConfig, 'full');
|
|
117
372
|
};
|
|
118
373
|
const buildMcpServerConfig = () => {
|
|
119
374
|
let finalPath = mcpScriptPath || "";
|
|
@@ -166,55 +421,234 @@ export function TaskSettings(props) {
|
|
|
166
421
|
const toCopy = mode === 'full'
|
|
167
422
|
? JSON.stringify({ mcpServers: { [serverId]: serverConfig } }, null, 2)
|
|
168
423
|
: `"${serverId}": ${JSON.stringify(serverConfig, null, 2)}`;
|
|
169
|
-
|
|
170
|
-
setCopiedConfig(mode);
|
|
171
|
-
setTimeout(() => setCopiedConfig(false), 2000);
|
|
424
|
+
copyToClipboard(toCopy, mode);
|
|
172
425
|
};
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
|
|
426
|
+
const loadMcpTokens = async () => {
|
|
427
|
+
if (!cloudMcpAvailable)
|
|
428
|
+
return;
|
|
429
|
+
setMcpTokensLoading(true);
|
|
430
|
+
setMcpTokensError(null);
|
|
431
|
+
try {
|
|
432
|
+
const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/tokens', {
|
|
433
|
+
method: 'GET',
|
|
434
|
+
credentials: 'include'
|
|
435
|
+
});
|
|
436
|
+
const payload = await res.json().catch(() => ({}));
|
|
437
|
+
if (!res.ok) {
|
|
438
|
+
setMcpTokensError(String(payload?.error || 'Failed to load MCP tokens.'));
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
setMcpTokens(Array.isArray(payload?.items) ? payload.items : []);
|
|
176
442
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
443
|
+
catch {
|
|
444
|
+
setMcpTokensError('Failed to load MCP tokens.');
|
|
445
|
+
}
|
|
446
|
+
finally {
|
|
447
|
+
setMcpTokensLoading(false);
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
const loadMcpConnectors = async () => {
|
|
451
|
+
if (!cloudMcpAvailable)
|
|
180
452
|
return;
|
|
181
|
-
|
|
182
|
-
(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
453
|
+
setMcpConnectorsLoading(true);
|
|
454
|
+
setMcpConnectorsError(null);
|
|
455
|
+
try {
|
|
456
|
+
const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/connectors', {
|
|
457
|
+
method: 'GET',
|
|
458
|
+
credentials: 'include'
|
|
459
|
+
});
|
|
460
|
+
const payload = await res.json().catch(() => ({}));
|
|
461
|
+
if (!res.ok) {
|
|
462
|
+
setMcpConnectorsError(String(payload?.error || 'Failed to load MCP connectors.'));
|
|
463
|
+
return;
|
|
191
464
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
465
|
+
setMcpConnectorGrants(Array.isArray(payload?.items) ? payload.items : []);
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
setMcpConnectorsError('Failed to load MCP connectors.');
|
|
469
|
+
}
|
|
470
|
+
finally {
|
|
471
|
+
setMcpConnectorsLoading(false);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
const handleCreateMcpToken = async () => {
|
|
475
|
+
const trimmedName = newTokenName.trim();
|
|
476
|
+
if (!trimmedName) {
|
|
477
|
+
setMcpTokenNotice({ type: 'error', message: 'Token name is required.' });
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
setMcpActionBusyId('create');
|
|
481
|
+
setMcpTokenNotice(null);
|
|
482
|
+
try {
|
|
483
|
+
const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/tokens', {
|
|
484
|
+
method: 'POST',
|
|
485
|
+
credentials: 'include',
|
|
486
|
+
headers: { 'Content-Type': 'application/json' },
|
|
487
|
+
body: JSON.stringify({
|
|
488
|
+
name: trimmedName,
|
|
489
|
+
scopes: newTokenScopes,
|
|
490
|
+
expiresAt: newTokenExpiresAt ? new Date(`${newTokenExpiresAt}T00:00:00`).toISOString() : null
|
|
491
|
+
})
|
|
492
|
+
});
|
|
493
|
+
const payload = await res.json().catch(() => ({}));
|
|
494
|
+
if (!res.ok) {
|
|
495
|
+
setMcpTokenNotice({ type: 'error', message: String(payload?.error || 'Failed to create token.') });
|
|
496
|
+
return;
|
|
195
497
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
498
|
+
setGeneratedTokenValue(String(payload?.token || ''));
|
|
499
|
+
setNewTokenName(defaultTokenName);
|
|
500
|
+
setNewTokenExpiresAt('');
|
|
501
|
+
setMcpTokens((current) => {
|
|
502
|
+
const next = payload?.record ? [payload.record, ...current.filter((item) => item.id !== payload.record.id)] : current;
|
|
503
|
+
return next;
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
catch {
|
|
507
|
+
setMcpTokenNotice({ type: 'error', message: 'Failed to create token.' });
|
|
508
|
+
}
|
|
509
|
+
finally {
|
|
510
|
+
setMcpActionBusyId(null);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
const handleMcpTokenAction = async (tokenId, action) => {
|
|
514
|
+
setMcpActionBusyId(`${action}:${tokenId}`);
|
|
515
|
+
setMcpTokenNotice(null);
|
|
516
|
+
try {
|
|
517
|
+
const res = await fetchCloudAuthApi(`/api/taskforce/settings/mcp/tokens/${encodeURIComponent(tokenId)}/${action}`, {
|
|
518
|
+
method: 'POST',
|
|
519
|
+
credentials: 'include'
|
|
520
|
+
});
|
|
521
|
+
const payload = await res.json().catch(() => ({}));
|
|
522
|
+
if (!res.ok) {
|
|
523
|
+
setMcpTokenNotice({ type: 'error', message: String(payload?.error || `Failed to ${action} token.`) });
|
|
524
|
+
return;
|
|
199
525
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
526
|
+
if (action === 'regenerate') {
|
|
527
|
+
setGeneratedTokenValue(String(payload?.token || ''));
|
|
528
|
+
setMcpTokenNotice({ type: 'success', message: 'Token regenerated. Copy the new value now.' });
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
setMcpTokenNotice({ type: 'success', message: 'Token revoked.' });
|
|
532
|
+
}
|
|
533
|
+
const nextRecord = payload?.record || null;
|
|
534
|
+
if (nextRecord?.id) {
|
|
535
|
+
setMcpTokens((current) => current.map((item) => item.id === nextRecord.id ? nextRecord : item));
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
await loadMcpTokens();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
catch {
|
|
542
|
+
setMcpTokenNotice({ type: 'error', message: `Failed to ${action} token.` });
|
|
543
|
+
}
|
|
544
|
+
finally {
|
|
545
|
+
setMcpActionBusyId(null);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
const handleTestMcpConnection = async () => {
|
|
549
|
+
const trimmedToken = mcpConnectionToken.trim();
|
|
550
|
+
if (!trimmedToken) {
|
|
551
|
+
setMcpConnectionResult({
|
|
552
|
+
type: 'error',
|
|
553
|
+
message: 'Paste a token to test the MCP connection.'
|
|
554
|
+
});
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
setMcpConnectionBusy(true);
|
|
558
|
+
setMcpConnectionResult(null);
|
|
559
|
+
try {
|
|
560
|
+
const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/test-connection', {
|
|
561
|
+
method: 'POST',
|
|
562
|
+
credentials: 'include',
|
|
563
|
+
headers: { 'Content-Type': 'application/json' },
|
|
564
|
+
body: JSON.stringify({
|
|
565
|
+
token: trimmedToken,
|
|
566
|
+
requiredScopes: newTokenScopes
|
|
567
|
+
})
|
|
568
|
+
});
|
|
569
|
+
const payload = await res.json().catch(() => ({}));
|
|
570
|
+
if (!res.ok) {
|
|
571
|
+
const details = payload?.details && typeof payload.details === 'object' ? payload.details : {};
|
|
572
|
+
const missingScopes = Array.isArray(details?.missingScopes)
|
|
573
|
+
? details.missingScopes.map((scope) => String(scope))
|
|
574
|
+
: [];
|
|
575
|
+
const workspaceName = typeof details?.tokenWorkspaceId === 'string'
|
|
576
|
+
? String(details.tokenWorkspaceId)
|
|
577
|
+
: undefined;
|
|
578
|
+
const message = payload?.code === 'MCP_TOKEN_MISSING_SCOPES' && missingScopes.length > 0
|
|
579
|
+
? `Token is missing required scopes: ${missingScopes.join(', ')}.`
|
|
580
|
+
: String(payload?.error || 'Failed to test MCP connection.');
|
|
581
|
+
setMcpConnectionResult({
|
|
582
|
+
type: 'error',
|
|
583
|
+
message,
|
|
584
|
+
workspaceName,
|
|
585
|
+
});
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const result = payload?.result && typeof payload.result === 'object' ? payload.result : {};
|
|
589
|
+
setMcpConnectionResult({
|
|
590
|
+
type: 'success',
|
|
591
|
+
message: 'Connection looks good for this workspace.',
|
|
592
|
+
scopes: Array.isArray(result?.scopes) ? result.scopes.map((scope) => String(scope)) : [],
|
|
593
|
+
workspaceName: typeof result?.workspaceName === 'string' ? String(result.workspaceName) : '',
|
|
594
|
+
workspaceId: typeof result?.workspaceId === 'string' ? String(result.workspaceId) : '',
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
setMcpConnectionResult({
|
|
599
|
+
type: 'error',
|
|
600
|
+
message: 'Failed to test MCP connection.'
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
finally {
|
|
604
|
+
setMcpConnectionBusy(false);
|
|
605
|
+
}
|
|
217
606
|
};
|
|
607
|
+
const handleDisconnectConnector = async (grantId) => {
|
|
608
|
+
setMcpConnectorBusyId(grantId);
|
|
609
|
+
setMcpConnectorsError(null);
|
|
610
|
+
try {
|
|
611
|
+
const res = await fetchCloudAuthApi(`/api/taskforce/settings/mcp/connectors/${encodeURIComponent(grantId)}/disconnect`, {
|
|
612
|
+
method: 'POST',
|
|
613
|
+
credentials: 'include'
|
|
614
|
+
});
|
|
615
|
+
const payload = await res.json().catch(() => ({}));
|
|
616
|
+
if (!res.ok) {
|
|
617
|
+
setMcpConnectorsError(String(payload?.error || 'Failed to disconnect connector.'));
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
const nextRecord = payload?.record || null;
|
|
621
|
+
if (nextRecord?.id) {
|
|
622
|
+
setMcpConnectorGrants((current) => current.map((grant) => grant.id === nextRecord.id ? nextRecord : grant));
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
await loadMcpConnectors();
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
catch {
|
|
629
|
+
setMcpConnectorsError('Failed to disconnect connector.');
|
|
630
|
+
}
|
|
631
|
+
finally {
|
|
632
|
+
setMcpConnectorBusyId(null);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
useEffect(() => {
|
|
636
|
+
if (!cloudMcpAvailable)
|
|
637
|
+
return;
|
|
638
|
+
if (activeTab === 'mcp' && showCloudMcp) {
|
|
639
|
+
void loadMcpTokens();
|
|
640
|
+
void loadMcpConnectors();
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
if (activeTab === 'integrations') {
|
|
644
|
+
void loadMcpConnectors();
|
|
645
|
+
}
|
|
646
|
+
}, [activeTab, showCloudMcp, cloudMcpAvailable]);
|
|
647
|
+
useEffect(() => {
|
|
648
|
+
if (activeTab === 'initiatives' && initiativeTemplates.length === 0) {
|
|
649
|
+
onRefreshInitiativeTemplates?.();
|
|
650
|
+
}
|
|
651
|
+
}, [activeTab, initiativeTemplates.length, onRefreshInitiativeTemplates]);
|
|
218
652
|
const availableEnvironments = settingsModel.availableEnvironments || [];
|
|
219
653
|
const getIconComponent = (iconName) => {
|
|
220
654
|
switch (iconName) {
|
|
@@ -235,10 +669,19 @@ export function TaskSettings(props) {
|
|
|
235
669
|
setActiveTab('taxonomy');
|
|
236
670
|
}
|
|
237
671
|
else if (initialSection === 'documents') {
|
|
238
|
-
setActiveTab('
|
|
672
|
+
setActiveTab('general');
|
|
673
|
+
}
|
|
674
|
+
else if (initialSection === 'appearance-application') {
|
|
675
|
+
setAppearanceExpanded(true);
|
|
676
|
+
setActiveTab('appearanceApplication');
|
|
239
677
|
}
|
|
240
|
-
else if (initialSection === '
|
|
241
|
-
|
|
678
|
+
else if (initialSection === 'appearance-task-cards') {
|
|
679
|
+
setAppearanceExpanded(true);
|
|
680
|
+
setActiveTab('appearanceTaskCards');
|
|
681
|
+
}
|
|
682
|
+
else if (initialSection === 'appearance-task-forms') {
|
|
683
|
+
setAppearanceExpanded(true);
|
|
684
|
+
setActiveTab('appearanceTaskForms');
|
|
242
685
|
}
|
|
243
686
|
else if (initialSection === 'resources' || initialSection === 'commands') {
|
|
244
687
|
setActiveTab('commands');
|
|
@@ -249,11 +692,19 @@ export function TaskSettings(props) {
|
|
|
249
692
|
else if (initialSection === 'agents') {
|
|
250
693
|
setActiveTab('agents');
|
|
251
694
|
}
|
|
695
|
+
else if (initialSection === 'integrations') {
|
|
696
|
+
setActiveTab('integrations');
|
|
697
|
+
}
|
|
252
698
|
else {
|
|
253
699
|
setActiveTab(initialSection);
|
|
254
700
|
}
|
|
255
701
|
}
|
|
256
702
|
}, [initialSection]);
|
|
703
|
+
useEffect(() => {
|
|
704
|
+
if (activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') {
|
|
705
|
+
setAppearanceExpanded(true);
|
|
706
|
+
}
|
|
707
|
+
}, [activeTab]);
|
|
257
708
|
const handleBrowseFolders = (catValue) => {
|
|
258
709
|
onBrowserTargetChange({ type: 'category', value: catValue });
|
|
259
710
|
onFetchFolders('');
|
|
@@ -269,232 +720,266 @@ export function TaskSettings(props) {
|
|
|
269
720
|
}
|
|
270
721
|
return fullPath;
|
|
271
722
|
};
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return;
|
|
308
|
-
const result = await onSaveWorkspaceProfile({
|
|
309
|
-
workspaceId: setupState?.workspaceId,
|
|
310
|
-
name: workspaceDisplayName,
|
|
311
|
-
description: workspaceDescription
|
|
312
|
-
});
|
|
313
|
-
setSettingsFeedback({
|
|
314
|
-
type: result.success ? 'success' : 'error',
|
|
315
|
-
message: result.success
|
|
316
|
-
? `${setupMode === 'operations' ? 'Mission' : 'Project'} profile saved.`
|
|
317
|
-
: (result.error || 'Failed to save workspace profile.')
|
|
318
|
-
});
|
|
319
|
-
}, className: `${styles.saveSettingsBtn} ${styles.saveSettingsBtnWrapper}`, disabled: !onSaveWorkspaceProfile, children: "Save Profile" }) })] })), generalScopeTab === 'project' && isAuthenticated && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Account Plan" }), _jsx("p", { className: styles.settingHelper, children: "Effective plan state is managed by platform admin and surfaced here as read-only." }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Plan mode:" }), _jsxs("select", { className: styles.input, value: workspacePlanMode, style: { maxWidth: '220px' }, disabled: true, children: [_jsx("option", { value: "personal", children: "Personal" }), _jsx("option", { value: "team", children: "Team" })] })] }), workspacePlanModeLoading && (_jsx("p", { className: styles.settingHelper, children: "Loading current account entitlements..." })), workspacePlanModeError && (_jsx("p", { className: styles.settingHelper, style: { color: '#fda4af' }, children: workspacePlanModeError }))] })), generalScopeTab === 'project' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Theme" }), _jsxs("div", { className: styles.buttonGrid, children: [_jsxs("button", { className: `${styles.themeBtn} ${currentTheme === 'light' ? styles.activeTheme : ''}`, onClick: () => { void handleThemeChange('light'); }, children: [_jsx(Sun, { size: 20 }), " Light"] }), _jsxs("button", { className: `${styles.themeBtn} ${currentTheme === 'dark' ? styles.activeTheme : ''}`, onClick: () => { void handleThemeChange('dark'); }, children: [_jsx(Moon, { size: 20 }), " Dark"] }), _jsxs("button", { className: `${styles.themeBtn} ${currentTheme === 'midnight' ? styles.activeTheme : ''}`, onClick: () => { void handleThemeChange('midnight'); }, children: [_jsx(Sparkles, { size: 20 }), " Midnight"] })] }), _jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: jsonBackupEnabled, onChange: async (e) => {
|
|
320
|
-
const success = await onJsonBackupEnabledChange(e.target.checked);
|
|
321
|
-
setSettingsFeedback({
|
|
322
|
-
type: success ? 'success' : 'error',
|
|
323
|
-
message: success ? 'Project backup setting saved.' : 'Failed to save project backup setting.'
|
|
324
|
-
});
|
|
325
|
-
} }), _jsx("span", { children: "Enable automatic JSON backup (`.taskforce/tasks.json`)" })] }), _jsx("h3", { className: styles.settingTitle, children: "Task Form" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: checklistDropdownEnabled, onChange: async (e) => {
|
|
326
|
-
if (!onChecklistDropdownEnabledChange)
|
|
723
|
+
const settingsNavItems = [
|
|
724
|
+
{ key: 'general', label: 'General', icon: _jsx(Settings, { size: 14 }), section: 'general' },
|
|
725
|
+
{ key: 'taxonomy', label: 'Taxonomy', icon: _jsx(Layers, { size: 14 }), section: 'taxonomy' },
|
|
726
|
+
{ key: 'integrations', label: 'Integrations', icon: _jsx(Plug, { size: 14 }), section: 'integrations' },
|
|
727
|
+
{ key: 'mcp', label: 'MCP', icon: _jsx(Box, { size: 14 }), section: 'mcp' }
|
|
728
|
+
];
|
|
729
|
+
const appearanceNavItems = [
|
|
730
|
+
{ key: 'appearanceApplication', label: 'Application', section: 'appearance-application' },
|
|
731
|
+
{ key: 'appearanceTaskCards', label: 'Task cards', section: 'appearance-task-cards' },
|
|
732
|
+
{ key: 'appearanceTaskForms', label: 'Task forms', section: 'appearance-task-forms' }
|
|
733
|
+
];
|
|
734
|
+
const selectTab = (tab, section) => {
|
|
735
|
+
setActiveTab(tab);
|
|
736
|
+
onSectionChange?.(section);
|
|
737
|
+
};
|
|
738
|
+
const renderProjectThemeControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Theme" }), _jsx("div", { className: styles.buttonGrid, children: TASKFORCE_THEME_OPTIONS.map((themeOption) => renderThemeButton(themeOption, currentTheme, handleThemeChange)) })] }));
|
|
739
|
+
const renderGlobalThemeControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Theme Defaults" }), _jsx("div", { className: styles.buttonGrid, children: TASKFORCE_THEME_OPTIONS.map((themeOption) => renderThemeButton(themeOption, globalTheme, async (theme) => {
|
|
740
|
+
const success = await onSaveGlobalTheme(theme);
|
|
741
|
+
setSettingsFeedback({
|
|
742
|
+
type: success ? 'success' : 'error',
|
|
743
|
+
message: success ? 'Global theme saved.' : 'Failed to save global theme.'
|
|
744
|
+
});
|
|
745
|
+
})) })] }));
|
|
746
|
+
const renderTaskFormsControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Task Form" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: checklistDropdownEnabled, onChange: async (e) => {
|
|
747
|
+
if (!onChecklistDropdownEnabledChange)
|
|
748
|
+
return;
|
|
749
|
+
const success = await onChecklistDropdownEnabledChange(e.target.checked);
|
|
750
|
+
setSettingsFeedback({
|
|
751
|
+
type: success ? 'success' : 'error',
|
|
752
|
+
message: success ? 'Checklist dropdown setting saved.' : 'Failed to save checklist dropdown setting.'
|
|
753
|
+
});
|
|
754
|
+
}, disabled: !onChecklistDropdownEnabledChange }), _jsx("span", { children: "Enable checklist dropdown in task form" })] })] }));
|
|
755
|
+
return (_jsx("div", { className: styles.settingsTab, children: _jsxs("div", { className: styles.settingsLayout, children: [_jsxs("aside", { className: styles.settingsSidebar, children: [_jsx("div", { className: styles.settingsSidebarHeader, children: "Sections" }), _jsxs("div", { className: `${styles.settingsSidebarNav} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [settingsNavItems.filter((item) => item.key === 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key))), _jsxs("div", { className: styles.settingsSidebarGroup, children: [_jsxs("button", { className: `${styles.settingsSidebarBtn} ${styles.settingsSidebarGroupBtn} ${(activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') ? styles.settingsSidebarBtnActive : ''}`, onClick: () => setAppearanceExpanded((current) => !current), "aria-expanded": appearanceExpanded, "aria-controls": "settings-appearance-nav", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: styles.settingsSidebarGroupLabel, children: "Appearance" }), _jsx("span", { className: styles.settingsSidebarGroupChevron, children: appearanceExpanded ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 }) })] }), appearanceExpanded && (_jsx("div", { id: "settings-appearance-nav", className: styles.settingsSidebarSubnav, children: appearanceNavItems.map((item) => (_jsx("button", { className: `${styles.settingsSidebarSubBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: _jsx("span", { children: item.label }) }, item.key))) }))] }), settingsNavItems.filter((item) => item.key !== 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key)))] })] }), _jsxs("div", { className: styles.settingsContent, children: [settingsFeedback && (_jsxs("div", { className: `${styles.settingsToast} ${settingsFeedback.type === 'success' ? styles.settingsToastSuccess : styles.settingsToastError}`, children: [settingsFeedback.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsx("span", { children: settingsFeedback.message })] })), activeTab === 'general' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.settingsTabs} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }), generalScopeTab === 'project' && (_jsx("div", { className: styles.pathInputGroup, style: { justifyContent: 'flex-end' }, children: _jsx("button", { onClick: async () => {
|
|
756
|
+
const confirmed = window.confirm('Reset project Theme and Backups to global defaults?');
|
|
757
|
+
if (!confirmed)
|
|
327
758
|
return;
|
|
328
|
-
const success = await
|
|
759
|
+
const success = await onResetProjectToGlobal();
|
|
329
760
|
setSettingsFeedback({
|
|
330
761
|
type: success ? 'success' : 'error',
|
|
331
|
-
message: success ? '
|
|
762
|
+
message: success ? 'Project settings reset to global.' : 'Failed to reset project settings.'
|
|
332
763
|
});
|
|
333
|
-
},
|
|
334
|
-
if (!
|
|
764
|
+
}, className: styles.copyBtn, children: "Reset to Global" }) }))] }), generalScopeTab === 'project' && (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.pathInputGroup, children: [_jsxs("label", { className: styles.label, style: { minWidth: '110px' }, children: [setupMode === 'operations' ? 'Mission' : 'Project', " name:"] }), _jsx("input", { className: styles.input, type: "text", value: workspaceDisplayName, onChange: (event) => setWorkspaceDisplayName(event.target.value), placeholder: setupMode === 'operations' ? 'Mission name' : 'Project name' })] }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Description:" }), _jsx("textarea", { className: styles.textarea, value: workspaceDescription, onChange: (event) => setWorkspaceDescription(event.target.value), placeholder: setupMode === 'operations' ? 'Mission description (optional)' : 'Project description (optional)', rows: 3 })] }), _jsx("div", { className: styles.pathInputGroup, style: { justifyContent: 'flex-end' }, children: _jsx("button", { onClick: async () => {
|
|
765
|
+
if (!onSaveWorkspaceProfile)
|
|
335
766
|
return;
|
|
336
|
-
const
|
|
767
|
+
const result = await onSaveWorkspaceProfile({
|
|
768
|
+
workspaceId: setupState?.workspaceId,
|
|
769
|
+
name: workspaceDisplayName,
|
|
770
|
+
description: workspaceDescription
|
|
771
|
+
});
|
|
337
772
|
setSettingsFeedback({
|
|
338
|
-
type: success ? 'success' : 'error',
|
|
339
|
-
message: success
|
|
773
|
+
type: result.success ? 'success' : 'error',
|
|
774
|
+
message: result.success
|
|
775
|
+
? `${setupMode === 'operations' ? 'Mission' : 'Project'} profile saved.`
|
|
776
|
+
: (result.error || 'Failed to save workspace profile.')
|
|
340
777
|
});
|
|
341
|
-
}, disabled: !
|
|
342
|
-
|
|
343
|
-
return;
|
|
344
|
-
const success = await onSaveSetupMode(setupMode);
|
|
778
|
+
}, className: styles.copyBtn, disabled: !onSaveWorkspaceProfile, children: "Save" }) })] })), generalScopeTab === 'project' && (_jsx("div", { className: styles.settingGroup, children: showJsonBackupSettings && (_jsxs(_Fragment, { children: [_jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: jsonBackupEnabled, onChange: async (e) => {
|
|
779
|
+
const success = await onJsonBackupEnabledChange(e.target.checked);
|
|
345
780
|
setSettingsFeedback({
|
|
346
781
|
type: success ? 'success' : 'error',
|
|
347
|
-
message: success ? '
|
|
782
|
+
message: success ? 'Project backup setting saved.' : 'Failed to save project backup setting.'
|
|
348
783
|
});
|
|
349
|
-
},
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (confirmation === null)
|
|
411
|
-
return;
|
|
412
|
-
if (confirmation.trim() !== expectedName) {
|
|
413
|
-
setSettingsFeedback({
|
|
414
|
-
type: 'error',
|
|
415
|
-
message: 'Workspace name confirmation did not match.'
|
|
416
|
-
});
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
const result = await onDeleteWorkspace(normalizedWorkspaceId);
|
|
420
|
-
if (!result.success) {
|
|
784
|
+
} }), _jsx("span", { children: "Enable automatic JSON backup (`.taskforce/tasks.json`)" })] })] })) })), generalScopeTab === 'global' && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.settingGroup, children: showJsonBackupSettings && (_jsxs(_Fragment, { children: [_jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: globalJsonBackupEnabled, onChange: async (e) => {
|
|
785
|
+
const success = await onSaveGlobalJsonBackupEnabled(e.target.checked);
|
|
786
|
+
setSettingsFeedback({
|
|
787
|
+
type: success ? 'success' : 'error',
|
|
788
|
+
message: success ? 'Global backup default saved.' : 'Failed to save global backup default.'
|
|
789
|
+
});
|
|
790
|
+
} }), _jsx("span", { children: "Enable global JSON backup default" })] })] })) }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Regional" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Calendar start:" }), _jsxs("select", { className: styles.input, value: globalWeekStartsOn, onChange: async (e) => {
|
|
791
|
+
const value = e.target.value;
|
|
792
|
+
const success = await onSaveGlobalWeekStartsOn(value);
|
|
793
|
+
setSettingsFeedback({
|
|
794
|
+
type: success ? 'success' : 'error',
|
|
795
|
+
message: success
|
|
796
|
+
? `Week start saved (${value === 'sunday' ? 'Sunday' : 'Monday'}).`
|
|
797
|
+
: 'Failed to save week start.'
|
|
798
|
+
});
|
|
799
|
+
}, style: { maxWidth: '220px' }, children: [_jsx("option", { value: "sunday", children: "Sunday" }), _jsx("option", { value: "monday", children: "Monday" })] })] }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Language:" }), _jsx("select", { className: styles.input, value: locale, onChange: async (e) => {
|
|
800
|
+
const value = e.target.value;
|
|
801
|
+
if (!onSaveLocale)
|
|
802
|
+
return;
|
|
803
|
+
const success = await onSaveLocale(value);
|
|
804
|
+
setSettingsFeedback({
|
|
805
|
+
type: success ? 'success' : 'error',
|
|
806
|
+
message: success ? `Language saved (${value}).` : 'Failed to save language.'
|
|
807
|
+
});
|
|
808
|
+
}, style: { maxWidth: '220px' }, disabled: !onSaveLocale, children: supportedLocales.map((value) => (_jsx("option", { value: value, children: value }, value))) })] })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Keyboard Shortcut" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsxs("div", { className: styles.shortcutInputWrapper, children: [_jsx(Keyboard, { size: 16, className: styles.inputIcon }), _jsx("input", { type: "text", value: keyShortcut, onChange: (e) => onKeyShortcutChange(e.target.value), placeholder: "e.g. Alt+T, Ctrl+Shift+K", className: `${styles.input} ${styles.shortcutInput}` })] }), _jsx("button", { onClick: async () => {
|
|
809
|
+
const success = await onSaveSettings();
|
|
810
|
+
setSettingsFeedback({
|
|
811
|
+
type: success ? 'success' : 'error',
|
|
812
|
+
message: success ? 'Global shortcut saved.' : 'Failed to save global shortcut.'
|
|
813
|
+
});
|
|
814
|
+
}, className: `${styles.saveSettingsBtn} ${styles.saveSettingsBtnWrapper}`, children: "Save" })] }), _jsxs("p", { className: styles.settingHelper, children: ["Supported modifiers: Alt, Option, Ctrl, Shift, Meta (Cmd). Example: ", _jsx("code", { children: "Alt+T" }), " or ", _jsx("code", { children: "Ctrl+Shift+L" }), "."] })] })] })), generalScopeTab === 'project' && runtimeMode === 'cloud' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Danger Zone" }), !workspaceSwitchingEnabled ? (_jsx("p", { className: styles.settingHelper, children: "Workspace deletion is available in cloud runtime only." })) : !isAuthenticated ? (_jsx("p", { className: styles.settingHelper, children: "Sign in to manage workspace deletion." })) : currentWorkspaceRole !== 'owner' ? (_jsx("p", { className: styles.settingHelper, children: "Only workspace owners can delete a workspace." })) : (_jsx("div", { className: styles.pathInputGroup, children: _jsxs("button", { className: styles.destructiveBtn, onClick: async () => {
|
|
815
|
+
if (!onDeleteWorkspace)
|
|
816
|
+
return;
|
|
817
|
+
const normalizedWorkspaceId = String(workspaceId || '').trim();
|
|
818
|
+
if (!normalizedWorkspaceId || normalizedWorkspaceId === 'default') {
|
|
819
|
+
setSettingsFeedback({
|
|
820
|
+
type: 'error',
|
|
821
|
+
message: 'A non-default workspace is required for deletion.'
|
|
822
|
+
});
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
const expectedName = String(currentWorkspaceName || '').trim();
|
|
826
|
+
const confirmation = window.prompt(`Type "${expectedName}" to permanently delete this workspace.`);
|
|
827
|
+
if (confirmation === null)
|
|
828
|
+
return;
|
|
829
|
+
if (confirmation.trim() !== expectedName) {
|
|
830
|
+
setSettingsFeedback({
|
|
831
|
+
type: 'error',
|
|
832
|
+
message: 'Workspace name confirmation did not match.'
|
|
833
|
+
});
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const result = await onDeleteWorkspace(normalizedWorkspaceId);
|
|
837
|
+
if (!result.success) {
|
|
838
|
+
setSettingsFeedback({
|
|
839
|
+
type: 'error',
|
|
840
|
+
message: result.error || 'Failed to delete workspace.'
|
|
841
|
+
});
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const warningCount = Array.isArray(result.cleanupWarnings) ? result.cleanupWarnings.length : 0;
|
|
421
845
|
setSettingsFeedback({
|
|
422
|
-
type: 'error',
|
|
423
|
-
message:
|
|
846
|
+
type: warningCount > 0 ? 'error' : 'success',
|
|
847
|
+
message: warningCount > 0
|
|
848
|
+
? `Workspace deleted with ${warningCount} cleanup warning(s).`
|
|
849
|
+
: 'Workspace deleted.'
|
|
424
850
|
});
|
|
851
|
+
}, disabled: !onDeleteWorkspace, children: [_jsx(Trash2, { size: 14, style: { marginRight: 8 } }), "Delete Workspace"] }) }))] }))] })), activeTab === 'appearanceApplication' && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { className: `${styles.settingsTabs} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }) }), generalScopeTab === 'project' ? renderProjectThemeControls() : renderGlobalThemeControls()] })), activeTab === 'appearanceTaskCards' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Task Cards" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: showTaskCardStatusLabel, onChange: async (e) => {
|
|
852
|
+
if (!onShowTaskCardStatusLabelChange)
|
|
425
853
|
return;
|
|
426
|
-
|
|
427
|
-
const warningCount = Array.isArray(result.cleanupWarnings) ? result.cleanupWarnings.length : 0;
|
|
854
|
+
const success = await onShowTaskCardStatusLabelChange(e.target.checked);
|
|
428
855
|
setSettingsFeedback({
|
|
429
|
-
type:
|
|
430
|
-
message:
|
|
431
|
-
? `Workspace deleted with ${warningCount} cleanup warning(s).`
|
|
432
|
-
: 'Workspace deleted.'
|
|
856
|
+
type: success ? 'success' : 'error',
|
|
857
|
+
message: success ? 'Task card status label setting saved.' : 'Failed to save task card status label setting.'
|
|
433
858
|
});
|
|
434
|
-
}, disabled: !
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
setSettingsFeedback({
|
|
460
|
-
type: result.success ? 'success' : 'error',
|
|
461
|
-
message: result.success
|
|
462
|
-
? 'Initiative created from template.'
|
|
463
|
-
: (result.error || 'Failed to create initiative.')
|
|
464
|
-
});
|
|
465
|
-
}, children: [isCreatingInitiative ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(Zap, { size: 14 }), "Create Initiative"] }), _jsxs("div", { className: `${styles.exportItem} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, children: "Clone Checklists to Children" }), _jsx("input", { className: styles.input, placeholder: "Parent task ID to update children (task-...)", value: cloneChecklistParentTaskId, onChange: (e) => setCloneChecklistParentTaskId(e.target.value) }), _jsx("textarea", { className: `${styles.input} ${styles.marginTop12}`, rows: 4, placeholder: "Definition of Done items, one per line", value: cloneChecklistDodText, onChange: (e) => setCloneChecklistDodText(e.target.value) }), _jsx("textarea", { className: `${styles.input} ${styles.marginTop12}`, rows: 4, placeholder: "Rollback Plan items, one per line", value: cloneChecklistRollbackText, onChange: (e) => setCloneChecklistRollbackText(e.target.value) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, disabled: isCloningChecklists || !cloneChecklistParentTaskId.trim() || !onCloneChecklistBlocksToChildren, onClick: async () => {
|
|
466
|
-
if (!onCloneChecklistBlocksToChildren)
|
|
467
|
-
return;
|
|
468
|
-
setIsCloningChecklists(true);
|
|
469
|
-
const result = await onCloneChecklistBlocksToChildren({
|
|
470
|
-
parentTaskId: cloneChecklistParentTaskId.trim(),
|
|
471
|
-
checklistBlocks: {
|
|
472
|
-
definitionOfDone: cloneChecklistDodText.split('\n').map(s => s.trim()).filter(Boolean),
|
|
473
|
-
rollbackPlan: cloneChecklistRollbackText.split('\n').map(s => s.trim()).filter(Boolean)
|
|
859
|
+
}, disabled: !onShowTaskCardStatusLabelChange }), _jsx("span", { children: "Show status label" })] })] })), activeTab === 'appearanceTaskForms' && renderTaskFormsControls(), activeTab === 'commands' && (_jsx(_Fragment, { children: _jsxs("div", { className: styles.settingGroup, children: [_jsx("div", { className: styles.settingTitleRow, children: _jsx("h3", { className: styles.settingTitle, children: "Command Workflows" }) }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Export standard workflows to your project to verify and commit them." }), _jsxs("div", { className: `${styles.exportRow} ${styles.exportRowGrid}`, children: [_jsxs("div", { className: styles.settingGroup, children: [_jsx("h4", { className: `${styles.settingSubtitle} ${styles.settingSubtitleCustom}`, children: "Target Environment" }), _jsx("div", { className: styles.buttonGrid, children: availableEnvironments.map(env => (_jsxs("button", { onClick: () => onExportEnvironmentChange(env.id), className: `${styles.themeBtn} ${exportEnvironment === env.id ? styles.activeTheme : ''} ${styles.capitalize}`, children: [getIconComponent(env.icon), env.name] }, env.id))) })] }), _jsxs("div", { className: styles.exportItem, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.label, children: "Workflows" }), _jsxs("span", { className: styles.settingDescription, children: ["Destination: ", _jsx("code", { className: styles.code, children: exportWorkflowsPath })] })] }), _jsxs("div", { className: styles.workflowList, children: [_jsxs("div", { className: styles.workflowActions, children: [_jsx("button", { onClick: handleSelectAllWorkflows, className: styles.textBtn, children: "All" }), _jsx("button", { onClick: handleDeselectAllWorkflows, className: styles.textBtn, children: "None" })] }), _jsx("div", { className: styles.workflowGrid, children: availableWorkflows.length === 0 ? (_jsxs("div", { className: styles.emptyState, children: ["No workflow templates found.", _jsx("button", { onClick: () => onRefreshWorkflows?.(true), className: styles.secondaryBtn, style: { marginTop: '8px' }, children: "Retry Fetch" })] })) : availableWorkflows.map(wf => (_jsxs("label", { className: styles.checkboxLabel, children: [_jsx("input", { type: "checkbox", checked: selectedWorkflows.includes(wf), onChange: () => handleToggleWorkflow(wf) }), wf] }, wf))) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, onClick: () => onExportWorkflows?.(exportEnvironment, selectedWorkflows), disabled: exportingResource === 'workflows' || selectedWorkflows.length === 0, children: [exportingResource === 'workflows' ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(FileText, { size: 14 }), "Export Selected (", selectedWorkflows.length, ")"] })] })] }), exportResult && (_jsxs("div", { className: `${exportResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [exportResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), exportResult.message] }))] }) })), activeTab === 'initiatives' && (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: styles.settingTitle, children: "Initiative Templates" }), _jsx("button", { className: styles.copyBtn, onClick: () => { void onRefreshInitiativeTemplates?.(); }, children: "Refresh" })] }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Create launch, migration, or incident initiatives from reusable templates." }), _jsxs("div", { className: styles.exportItem, children: [_jsx("label", { className: styles.label, children: "Template" }), _jsx("select", { className: styles.input, value: selectedInitiativeTemplateId, onChange: (e) => {
|
|
860
|
+
const nextId = e.target.value;
|
|
861
|
+
setSelectedInitiativeTemplateId(nextId);
|
|
862
|
+
}, children: initiativeTemplates.map(template => (_jsx("option", { value: template.id, children: template.name }, template.id))) })] }), _jsxs("div", { className: `${styles.exportItem} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, children: "Initiative Title" }), _jsx("input", { className: styles.input, placeholder: "e.g. Taskforce Private Beta Launch", value: initiativeTitle, onChange: (e) => setInitiativeTitle(e.target.value) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, disabled: isCreatingInitiative || !selectedInitiativeTemplateId || !initiativeTitle.trim() || !onCreateInitiativeFromTemplate, onClick: async () => {
|
|
863
|
+
if (!onCreateInitiativeFromTemplate)
|
|
864
|
+
return;
|
|
865
|
+
setIsCreatingInitiative(true);
|
|
866
|
+
const result = await onCreateInitiativeFromTemplate({
|
|
867
|
+
templateId: selectedInitiativeTemplateId,
|
|
868
|
+
title: initiativeTitle.trim(),
|
|
869
|
+
});
|
|
870
|
+
setIsCreatingInitiative(false);
|
|
871
|
+
setSettingsFeedback({
|
|
872
|
+
type: result.success ? 'success' : 'error',
|
|
873
|
+
message: result.success
|
|
874
|
+
? 'Initiative created from template.'
|
|
875
|
+
: (result.error || 'Failed to create initiative.')
|
|
876
|
+
});
|
|
877
|
+
}, children: [isCreatingInitiative ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(Zap, { size: 14 }), "Create Initiative"] })] })), activeTab === 'agents' && (_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { children: [_jsx("h4", { className: styles.settingSubTitle, children: "Registered AI Profiles" }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost." }), aiProfilesLoading && (_jsxs("div", { className: styles.settingsHint, children: [_jsx(Loader2, { size: 13, className: styles.spinner }), " Loading profiles\u2026"] })), !aiProfilesLoading && aiProfiles.length === 0 && (_jsx("div", { className: styles.settingsHint, children: "No AI profiles registered yet." })), !aiProfilesLoading && aiProfiles.length > 0 && (() => {
|
|
878
|
+
const byName = new Map();
|
|
879
|
+
for (const p of aiProfiles) {
|
|
880
|
+
const key = p.name.toLowerCase();
|
|
881
|
+
if (!byName.has(key))
|
|
882
|
+
byName.set(key, []);
|
|
883
|
+
byName.get(key).push(p);
|
|
474
884
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
885
|
+
return (_jsx("div", { className: styles.aiProfilesList, children: Array.from(byName.entries()).map(([, group]) => (_jsxs("div", { className: `${styles.aiProfileGroup} ${group.length > 1 ? styles.aiProfileGroupDuplicate : ''}`, children: [_jsxs("div", { className: styles.aiProfileGroupHeader, children: [_jsx(Bot, { size: 13, style: { color: group[0].color } }), _jsx("span", { className: styles.aiProfileName, children: group[0].name }), group.length > 1 && (_jsxs("span", { className: styles.aiProfileDuplicateBadge, children: [_jsx(AlertTriangle, { size: 11 }), " ", group.length, " duplicates"] }))] }), _jsxs("div", { className: styles.settingsHint, style: { marginTop: 6 }, children: ["@", group[0].username, group[0].role ? ` · ${group[0].role}` : ''] }), group[0].description && (_jsx("div", { className: styles.settingsHint, style: { marginTop: 4 }, children: group[0].description })), (group[0].provider || group[0].model) && (_jsx("div", { className: styles.settingsHint, style: { marginTop: 4 }, children: [group[0].provider, group[0].model].filter(Boolean).join(' · ') })), group.length > 1 && (_jsxs("div", { className: styles.aiProfileMergeSection, children: [group.map((p) => (_jsxs("div", { className: styles.aiProfileMergeRow, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [_jsx("span", { className: styles.aiProfileIdChip, children: p.id }), _jsxs("span", { className: styles.settingsHint, children: ["@", p.username] })] }), aiProfileMergeState?.keepId !== p.id && (_jsx("button", { className: styles.secondaryHeaderBtn, title: "Keep this profile, merge others into it", onClick: () => {
|
|
886
|
+
const otherId = group.find((x) => x.id !== p.id)?.id;
|
|
887
|
+
if (otherId)
|
|
888
|
+
setAiProfileMergeState({ keepId: p.id, mergeId: otherId });
|
|
889
|
+
}, children: "Keep this" })), aiProfileMergeState?.keepId === p.id && (_jsx("span", { className: styles.aiProfileKeepBadge, children: "\u2713 keeping" }))] }, p.id))), aiProfileMergeState && group.some((p) => p.id === aiProfileMergeState.keepId) && (_jsxs("div", { className: styles.aiProfileMergeActions, children: [_jsxs("button", { className: styles.dangerBtn, onClick: () => doMergeAiProfiles(aiProfileMergeState.keepId, aiProfileMergeState.mergeId), children: ["Merge (keep ", aiProfileMergeState.keepId.slice(-6), ", delete ", aiProfileMergeState.mergeId.slice(-6), ")"] }), _jsx("button", { className: styles.secondaryHeaderBtn, onClick: () => setAiProfileMergeState(null), children: "Cancel" })] }))] }))] }, group[0].id))) }));
|
|
890
|
+
})(), aiProfileMergeStatus && (_jsxs("div", { className: `${aiProfileMergeStatus.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [aiProfileMergeStatus.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), aiProfileMergeStatus.message] }))] }) })), activeTab === 'taxonomy' && (_jsxs("div", { className: `${styles.settingGroup} ${styles.flex1} ${styles.flexCol}`, children: [_jsx("h3", { className: styles.settingTitle, children: "Taxonomy & Classification" }), _jsx("p", { className: styles.settingsHint, children: "Configure categories, task types, and custom classification systems." }), _jsx(TaxonomyManager, { taxonomies: taxonomies, onUpdateTaxonomies: onUpdateTaxonomies, onApplySystemTaxonomyPack: onApplySystemTaxonomyPack, taxonomyDisplayLabels: taxonomyDisplayLabels, onUpdateTaxonomyDisplayLabels: onUpdateTaxonomyDisplayLabels,
|
|
891
|
+
// Inject Category and Type managers as system taxonomies
|
|
892
|
+
categories: categories, pathValidation: pathValidation, onUpdateCategory: onUpdateCategory, onRemoveCategory: onRemoveCategory, onSaveCategory: onSaveCategory, onAddPath: onAddPath, onRemovePath: onRemovePath, onUpdateCategoryIcon: onUpdateCategoryIcon, onUpdateCategoryColor: onUpdateCategoryColor, onBrowseFolders: handleBrowseFolders, types: types, onSaveType: onSaveType, onRemoveType: onRemoveType, onUpdateType: onUpdateType, priorities: priorities, onUpdatePriorities: onUpdatePriorities, onAnalyzeSystemTaxonomyPack: onAnalyzeSystemTaxonomyPack, manualComplexityEnabled: manualComplexityEnabled, onManualComplexityEnabledChange: async (enabled) => {
|
|
893
|
+
const success = await onManualComplexityEnabledChange(enabled);
|
|
894
|
+
setSettingsFeedback({
|
|
895
|
+
type: success ? 'success' : 'error',
|
|
896
|
+
message: success ? 'Project complexity setting saved.' : 'Failed to save project complexity setting.'
|
|
897
|
+
});
|
|
898
|
+
}, initialTab: (initialSection === 'categories' || initialSection === 'types' || initialSection === 'priorities')
|
|
899
|
+
? initialSection
|
|
900
|
+
: undefined })] })), activeTab === 'mcp' && (_jsxs("div", { className: styles.settingsGroup, children: [showMcpModeToggle && (_jsxs("div", { className: styles.settingsTabs, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'cloud' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('cloud'), children: "Cloud MCP" }), _jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'local' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('local'), children: "Local MCP" })] })), showCloudMcp && (_jsx(_Fragment, { children: selectedMcpClientUsesOAuth ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "OAuth Connector Setup" }), _jsx("span", { className: styles.settingDescription, children: selectedMcpClient === 'chatgpt-desktop'
|
|
901
|
+
? 'ChatGPT Desktop uses the Taskforce OAuth connector flow instead of a personal MCP token.'
|
|
902
|
+
: 'Claude Desktop uses the Taskforce OAuth connector flow instead of a personal MCP token.' })] }), _jsx("div", { className: `${selectedConnectorGrant ? styles.successMessage : styles.settingHelper} ${styles.marginTop12}`, children: selectedConnectorGrant ? (_jsxs(_Fragment, { children: [_jsx(Check, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: "Connector already authorized for this workspace." }), _jsxs("div", { className: styles.settingHelper, children: ["Last used ", selectedConnectorGrant.lastUsedAt
|
|
903
|
+
? new Date(selectedConnectorGrant.lastUsedAt).toLocaleString()
|
|
904
|
+
: 'not yet'] })] })] })) : ('No active connector authorization for this workspace yet.') }), _jsx("div", { className: styles.settingDescription, style: { marginTop: '12px' }, children: "Use the server URL above in your client, then finish the OAuth authorization flow from the Integrations tab." }), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end', width: '100%', marginTop: '12px' }, children: _jsx("button", { className: styles.copyBtn, onClick: () => setActiveTab('integrations'), children: "Open Integrations" }) })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
|
|
905
|
+
? renderMcpConfigBlock(cloudMcpServerId, cloudMcpServerConfig, cloudClientIntegration.rootKey || 'mcpServers', cloudClientIntegration.wrapperKeys || [])
|
|
906
|
+
: renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }), _jsx("div", { style: { padding: '16px 20px' }, children: _jsx("div", { className: styles.settingDescription, children: cloudClientIntegration.instructionText }) })] })] })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Generate Token" }), _jsx("span", { className: styles.settingDescription, children: "Tokens are shown once. Default scopes allow task read/write. Add workspace read if you want config and skills metadata in the client." })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(0, 2fr) minmax(220px, 1fr)', gap: '12px', alignItems: 'end' }, children: [_jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token Name" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "Cursor on MacBook", value: newTokenName, onChange: (e) => setNewTokenName(e.target.value) })] }), _jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Expiry (Optional)" }) }), _jsx("input", { type: "date", className: `${styles.settingInput} ${styles.taskFormDateInput}`, value: newTokenExpiresAt, onChange: (e) => setNewTokenExpiresAt(e.target.value) })] })] }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Scopes" }) }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '96px repeat(3, minmax(110px, 1fr))', gap: '10px 16px', alignItems: 'center' }, children: [_jsx("span", {}), _jsx("span", { className: styles.settingDescription, children: "Tasks" }), _jsx("span", { className: styles.settingDescription, children: "Workspace" }), _jsx("span", { className: styles.settingDescription, style: { opacity: 0.55 }, children: "Attachments" }), _jsx("span", { className: styles.settingDescription, children: "Read" }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: newTokenScopes.includes('tasks:read'), onChange: () => toggleTokenScope('tasks:read') }) }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: newTokenScopes.includes('workspace:read'), onChange: () => toggleTokenScope('workspace:read') }) }), _jsx("label", { className: styles.checkboxLabel, style: { opacity: 0.55 }, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: false, disabled: true }) }), _jsx("span", { className: styles.settingDescription, children: "Write" }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: newTokenScopes.includes('tasks:write'), onChange: () => toggleTokenScope('tasks:write') }) }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: false, disabled: true }) }), _jsx("label", { className: styles.checkboxLabel, style: { opacity: 0.55 }, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: false, disabled: true }) })] })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Automation Identity (Optional)" }), _jsx("span", { className: styles.settingDescription, children: "For recurring or background AI workers, set an AI name here so the generated MCP config includes Taskforce automation headers. After the first run, paste the returned profile token too so the same AI profile is reused across runs without extra bootstrap steps." })] }), aiProfiles.length > 0 && (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Use Existing AI Profile" }) }), _jsxs("select", { className: styles.settingInput, "aria-label": "Use existing AI profile", value: selectedAutomationProfileId, onChange: (e) => {
|
|
907
|
+
const nextId = e.target.value;
|
|
908
|
+
if (!nextId) {
|
|
909
|
+
setAutomationAiName('');
|
|
910
|
+
setAutomationAiProfileToken('');
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
const profile = aiProfiles.find((entry) => entry.id === nextId);
|
|
914
|
+
if (!profile)
|
|
915
|
+
return;
|
|
916
|
+
setAutomationAiName(profile.name);
|
|
917
|
+
setAutomationAiProfileToken(String(profile.profileToken || ''));
|
|
918
|
+
}, children: [_jsx("option", { value: "", children: "Custom\u2026" }), aiProfiles.map((profile) => (_jsxs("option", { value: profile.id, children: [profile.name, " (@", profile.username, ")"] }, profile.id)))] })] })), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: '12px', alignItems: 'end' }, children: [_jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "AI Name Header" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "Automation Codex", value: automationAiName, onChange: (e) => setAutomationAiName(e.target.value) })] }), _jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "AI Profile Token Header" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "tfp_...", value: automationAiProfileToken, onChange: (e) => setAutomationAiProfileToken(e.target.value) })] })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsx("div", { className: styles.settingHelper, children: "Generated tokens are only shown once. Copy the token before leaving this page." }), (() => {
|
|
919
|
+
const displayedGeneratedToken = copiedConfig === 'token'
|
|
920
|
+
? 'Copied to clipboard'
|
|
921
|
+
: (generatedTokenValue || '');
|
|
922
|
+
return (_jsx("div", { style: { display: 'flex', gap: '8px', alignItems: 'stretch' }, children: _jsx("div", { className: styles.codeBlockWrapper, style: { flex: 1, cursor: generatedTokenValue ? 'pointer' : 'default' }, onClick: () => generatedTokenValue && copyToClipboard(generatedTokenValue, 'token'), role: generatedTokenValue ? 'button' : undefined, tabIndex: generatedTokenValue ? 0 : -1, onKeyDown: (e) => {
|
|
923
|
+
if (!generatedTokenValue)
|
|
924
|
+
return;
|
|
925
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
926
|
+
e.preventDefault();
|
|
927
|
+
copyToClipboard(generatedTokenValue, 'token');
|
|
928
|
+
}
|
|
929
|
+
}, title: generatedTokenValue ? (copiedConfig === 'token' ? 'Token copied' : 'Click to copy token') : undefined, children: _jsx("pre", { className: styles.codeBlock, style: { textAlign: 'center' }, children: _jsx("code", { children: displayedGeneratedToken }) }) }) }));
|
|
930
|
+
})()] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [mcpTokenNotice?.type === 'error' && (_jsxs("div", { className: `${styles.errorMessage} ${styles.marginTop12}`, children: [_jsx(AlertTriangle, { size: 14 }), mcpTokenNotice.message] })), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsxs("button", { className: styles.copyBtn, onClick: () => void handleCreateMcpToken(), disabled: mcpActionBusyId === 'create', title: "Generate Token", "aria-label": "Generate Token", children: [mcpActionBusyId === 'create' ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), _jsx("span", { children: "GENERATE TOKEN" })] }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
|
|
931
|
+
? renderMcpConfigBlock(cloudMcpServerId, cloudMcpServerConfig, cloudClientIntegration.rootKey || 'mcpServers', cloudClientIntegration.wrapperKeys || [])
|
|
932
|
+
: renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }), _jsx("div", { style: { padding: '16px 20px' }, children: _jsx("div", { className: styles.settingDescription, children: cloudClientIntegration.instructionText }) })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowMcpConnectionTest((prev) => !prev), onKeyDown: (e) => {
|
|
933
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
934
|
+
e.preventDefault();
|
|
935
|
+
setShowMcpConnectionTest((prev) => !prev);
|
|
936
|
+
}
|
|
937
|
+
}, role: "button", tabIndex: 0, title: showMcpConnectionTest ? 'Hide connection test' : 'Show connection test', children: [_jsx("label", { className: styles.label, children: "Test Connection" }), showMcpConnectionTest ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpConnectionTest && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Validate that a token works for this workspace before you paste it into your MCP client." }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token to Test" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "tfmcp_xxxxx_replace-me", value: mcpConnectionToken, onChange: (e) => {
|
|
938
|
+
setMcpConnectionToken(e.target.value);
|
|
939
|
+
setMcpConnectionResult(null);
|
|
940
|
+
} })] }), _jsxs("div", { className: styles.marginTop12, style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [generatedTokenValue && (_jsx("button", { className: styles.copyBtn, onClick: () => {
|
|
941
|
+
setMcpConnectionToken(generatedTokenValue);
|
|
942
|
+
setMcpConnectionResult(null);
|
|
943
|
+
}, children: "Use Generated Token" })), _jsxs("button", { className: styles.copyBtn, onClick: () => void handleTestMcpConnection(), disabled: mcpConnectionBusy, children: [mcpConnectionBusy ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), "Test Connection"] })] }), mcpConnectionResult && (_jsxs("div", { className: `${mcpConnectionResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpConnectionResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: mcpConnectionResult.message }), mcpConnectionResult.type === 'success' && (mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId) && (_jsxs("div", { className: styles.settingHelper, children: ["Workspace: ", mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId, mcpConnectionResult.workspaceId ? ` (${mcpConnectionResult.workspaceId})` : ''] })), mcpConnectionResult.type === 'success' && Array.isArray(mcpConnectionResult.scopes) && mcpConnectionResult.scopes.length > 0 && (_jsxs("div", { className: styles.settingHelper, children: ["Granted scopes: ", mcpConnectionResult.scopes.join(', ')] }))] })] }))] }))] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowMcpTokensList((prev) => !prev), onKeyDown: (e) => {
|
|
944
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
945
|
+
e.preventDefault();
|
|
946
|
+
setShowMcpTokensList((prev) => !prev);
|
|
947
|
+
}
|
|
948
|
+
}, role: "button", tabIndex: 0, title: showMcpTokensList ? 'Hide workspace tokens' : 'Show workspace tokens', children: [_jsx("label", { className: styles.label, children: "Your Tokens" }), showMcpTokensList ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpTokensList && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Manage tokens created for this workspace." }), mcpTokensLoading ? (_jsx("p", { className: styles.settingHelper, children: "Loading tokens\u2026" })) : mcpTokensError ? (_jsxs("div", { className: styles.errorMessage, children: [_jsx(AlertTriangle, { size: 14 }), mcpTokensError] })) : mcpTokens.length === 0 ? (_jsx("p", { className: styles.settingHelper, children: "No MCP tokens yet." })) : (_jsx("div", { className: styles.settingGroup, children: sortedMcpTokens.map((token) => (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, style: {
|
|
949
|
+
padding: '14px 16px',
|
|
950
|
+
borderRadius: '12px',
|
|
951
|
+
border: '1px solid var(--border-primary, rgba(255, 255, 255, 0.1))',
|
|
952
|
+
background: 'rgba(255, 255, 255, 0.03)'
|
|
953
|
+
}, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: token.name }), _jsx("span", { className: `${styles.configBadge} ${token.status === 'revoked' ? styles.configBadgeRevoked : token.status === 'expired' ? styles.configBadgeExpired : styles.configBadgeActive}`, children: token.status })] }), _jsx("span", { className: styles.settingDescription, style: { fontFamily: '"JetBrains Mono", "Fira Code", monospace' }, children: token.tokenPrefix }), _jsxs("span", { className: styles.settingDescription, children: ["Scopes: ", token.scopes.join(', ')] }), _jsxs("span", { className: styles.settingDescription, children: ["Created ", new Date(token.createdAt).toLocaleDateString(), token.lastUsedAt ? ` · Last used ${new Date(token.lastUsedAt).toLocaleString()}` : ' · Never used'] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [token.status !== 'revoked' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'regenerate'), disabled: mcpActionBusyId === `regenerate:${token.id}`, children: "Regenerate" })), token.status === 'active' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'revoke'), disabled: mcpActionBusyId === `revoke:${token.id}`, children: "Revoke" }))] })] }, token.id))) }))] }))] })] })) })), showLocalMcp && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Local MCP" }), _jsx("span", { className: styles.settingDescription, children: "Local MCP runs over stdio and does not require a cloud token. Use this for Codex, Claude Code CLI, Gemini CLI, and similar local MCP clients." })] }) }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom}`, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Local MCP Configuration" }), _jsx("div", { className: styles.codeHeaderActions, children: _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: () => handleCopyConfig('full'), title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) }) })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: (() => {
|
|
954
|
+
const { serverId, serverConfig } = buildMcpServerConfig();
|
|
955
|
+
return renderMcpConfigBlock(serverId, serverConfig);
|
|
956
|
+
})() }) })] }), _jsx("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: _jsxs("div", { className: styles.toggleHeading, onClick: () => setShowAdvancedMcp((prev) => !prev), onKeyDown: (e) => {
|
|
957
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
958
|
+
e.preventDefault();
|
|
959
|
+
setShowAdvancedMcp((prev) => !prev);
|
|
960
|
+
}
|
|
961
|
+
}, role: "button", tabIndex: 0, title: "Show advanced MCP install options", children: [_jsx("label", { className: styles.label, children: "Advanced" }), showAdvancedMcp ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }) }), showAdvancedMcp && (_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Advanced Installation Mode" }), _jsx("span", { className: styles.settingDescription, children: "Global mode is recommended. Local / npx is intended for Taskforce development workflows." })] }), _jsxs("div", { className: styles.buttonGrid, children: [_jsx("button", { className: `${styles.themeBtn} ${useGlobalMcp ? styles.activeTheme : ''}`, onClick: () => setUseGlobalMcp(true), children: "Global" }), _jsx("button", { className: `${styles.themeBtn} ${!useGlobalMcp ? styles.activeTheme : ''}`, onClick: () => setUseGlobalMcp(false), children: "Local / npx (Dev)" })] }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: "MCP Path Mapping (Host Root)" }), serverHostRoot && !mcpHostRoot && (_jsx("span", { className: styles.configBadge, children: "Server Configured" }))] }), _jsx("span", { className: styles.settingDescription, children: "If running in Docker, WSL, or Remote Dev, provide the absolute path to this project as seen by your host OS." })] }), _jsx("div", { className: styles.pathInputWrapper, children: _jsx("input", { type: "text", className: styles.settingInput, placeholder: serverHostRoot || "/Users/username/Projects/my-project or C:\\Projects\\my-project", value: mcpHostRoot || '', onChange: (e) => onMcpHostRootChange?.(e.target.value) }) })] })] }))] }))] })), activeTab === 'integrations' && (_jsxs("div", { className: styles.settingsGroup, children: [_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Integrations" }), _jsx("span", { className: styles.settingDescription, children: "Manage OAuth-based app connectors separately from MCP tokens and local client setup." })] }) }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [[
|
|
962
|
+
{
|
|
963
|
+
key: 'chatgpt',
|
|
964
|
+
label: 'ChatGPT Connector',
|
|
965
|
+
description: 'Use the dedicated MCP host in ChatGPT Apps & Connectors. Taskforce handles OAuth and binds each connector authorization to one workspace.',
|
|
966
|
+
emptyMessage: 'No active ChatGPT connector grant for this workspace yet.',
|
|
967
|
+
connector: activeChatGptConnector
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
key: 'claude',
|
|
971
|
+
label: 'Claude Desktop Connector',
|
|
972
|
+
description: 'Use the dedicated MCP host in Claude Desktop Settings > Connectors. Taskforce handles OAuth and binds each connector authorization to one workspace.',
|
|
973
|
+
emptyMessage: 'No active Claude Desktop connector grant for this workspace yet.',
|
|
974
|
+
connector: activeClaudeConnector
|
|
975
|
+
}
|
|
976
|
+
].map((item) => {
|
|
977
|
+
const connector = item.connector;
|
|
978
|
+
return (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, style: {
|
|
979
|
+
padding: '16px',
|
|
980
|
+
borderRadius: '14px',
|
|
981
|
+
border: '1px solid var(--border-primary, rgba(255, 255, 255, 0.1))',
|
|
982
|
+
background: 'rgba(255, 255, 255, 0.03)'
|
|
983
|
+
}, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: item.label }), _jsx("span", { className: `${styles.configBadge} ${connector ? styles.configBadgeActive : styles.configBadgeRevoked}`, children: connector ? 'connected' : 'not connected' })] }), _jsx("span", { className: styles.settingDescription, children: item.description }), _jsx("span", { className: styles.settingDescription, style: { fontFamily: '"JetBrains Mono", "Fira Code", monospace' }, children: cloudMcpEndpoint }), connector ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: styles.settingDescription, children: ["Authorized workspace: ", currentWorkspaceName || connector.workspaceId] }), _jsxs("span", { className: styles.settingDescription, children: ["Granted scopes: ", connector.scopes.join(', ')] }), _jsxs("span", { className: styles.settingDescription, children: ["Connected ", new Date(connector.createdAt).toLocaleString(), connector.lastUsedAt ? ` · Last used ${new Date(connector.lastUsedAt).toLocaleString()}` : ' · Never used'] })] })) : (_jsx("span", { className: styles.settingDescription, children: item.emptyMessage }))] }), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end', gap: '8px', flexWrap: 'wrap' }, children: connector && (_jsxs("button", { className: styles.copyBtn, onClick: () => void handleDisconnectConnector(connector.id), disabled: mcpConnectorBusyId === connector.id, children: [mcpConnectorBusyId === connector.id ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Trash2, { size: 14 }), "Disconnect"] })) })] }, item.key));
|
|
984
|
+
}), mcpConnectorsLoading && (_jsx("p", { className: `${styles.settingHelper} ${styles.marginTop12}`, children: "Loading connector grants\u2026" })), mcpConnectorsError && (_jsxs("div", { className: `${styles.errorMessage} ${styles.marginTop12}`, children: [_jsx(AlertTriangle, { size: 14 }), mcpConnectorsError] }))] })] }))] })] }) }));
|
|
500
985
|
}
|