@taskforcehq/taskforce 0.3.305 → 0.3.307
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 +0 -2
- package/dist/Taskforce.module.css +603 -107
- package/dist/TaskforceCore.js +216 -43
- package/dist/TaskforceCore.test.js +611 -28
- package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/assets/fonts/Noir_medium.woff2 +0 -0
- package/dist/assets/fonts/Noir_regular.woff2 +0 -0
- package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/compat/workspaceSyncCompat.js +46 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +561 -0
- package/dist/components/features/AgentsModule.d.ts +14 -1
- package/dist/components/features/AgentsModule.js +366 -18
- package/dist/components/features/AgentsModule.test.js +507 -8
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +7 -1
- package/dist/components/features/DocumentViewer.js +62 -4
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +51 -1
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +24 -29
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +61 -116
- package/dist/components/task/TaskForm.test.js +110 -8
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +94 -21
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.d.ts +9 -1
- package/dist/components/views/PlanComparisonPage.js +78 -14
- package/dist/components/views/PlanComparisonPage.test.js +257 -0
- package/dist/components/views/PlansPage.js +127 -36
- package/dist/components/views/PlansPage.test.js +294 -12
- package/dist/components/views/StandaloneLayout.js +529 -592
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
- package/dist/components/views/panels/PlanningDrawer.js +270 -55
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
- package/dist/components/views/planningScope.d.ts +20 -0
- package/dist/components/views/planningScope.js +25 -0
- package/dist/components/views/planningScope.test.d.ts +1 -0
- package/dist/components/views/planningScope.test.js +60 -0
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
- package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +46 -2
- package/dist/core/AiProfileService.js +1073 -82
- package/dist/core/AiProfileService.test.js +19 -1
- package/dist/core/AiProfiles.test.js +1249 -44
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +110 -23
- package/dist/core/AuthIdentityService.d.ts +107 -0
- package/dist/core/AuthIdentityService.js +284 -0
- package/dist/core/AuthTokenService.d.ts +4 -0
- package/dist/core/AuthTokenService.js +34 -6
- package/dist/core/AuthTokenService.test.js +3 -3
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +127 -6
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +23 -2
- package/dist/core/PlanEntitlementService.js +343 -57
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +35 -2
- package/dist/core/PlanningEntities.test.js +418 -4
- package/dist/core/SignupMonetizationSettings.test.js +199 -27
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +42 -42
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +415 -40
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +1543 -266
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
- package/dist/core/WorkspaceLifecycleService.js +0 -5
- package/dist/core/WorkspacePermissions.test.js +25 -1
- package/dist/core/WorkspacePlanMode.test.js +117 -16
- package/dist/core/shared.d.ts +1 -1
- package/dist/core/shared.js +5 -1
- package/dist/core/types.d.ts +75 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/bootstrap.js +2 -0
- package/dist/hooks/sync/controlPlane.d.ts +37 -0
- package/dist/hooks/sync/controlPlane.js +78 -0
- package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
- package/dist/hooks/sync/controlPlane.test.js +121 -0
- package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
- package/dist/hooks/sync/lifecyclePolicy.js +93 -0
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
- package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
- package/dist/hooks/sync/orchestratorShared.js +129 -48
- package/dist/hooks/sync/orchestratorShared.test.js +50 -1
- package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
- package/dist/hooks/sync/pullLifecycle.js +24 -0
- package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
- package/dist/hooks/sync/pullLifecycle.test.js +80 -0
- package/dist/hooks/sync/recovery.d.ts +16 -2
- package/dist/hooks/sync/recovery.js +179 -53
- package/dist/hooks/sync/recovery.test.d.ts +1 -0
- package/dist/hooks/sync/recovery.test.js +292 -0
- package/dist/hooks/sync/transfers.d.ts +16 -3
- package/dist/hooks/sync/transfers.js +210 -66
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +928 -0
- package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
- package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
- package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
- package/dist/hooks/sync/useSyncStatusActions.js +88 -0
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
- package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
- package/dist/hooks/sync/useSyncStatusControls.js +60 -0
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
- package/dist/hooks/useSyncOrchestrator.js +409 -183
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskforce.d.ts +145 -52
- package/dist/hooks/useTaskforce.js +592 -253
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +13 -2
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
- package/dist/localization/locales/en-US.d.ts +0 -1
- package/dist/localization/locales/en-US.js +0 -1
- package/dist/localization/locales/es-419.js +0 -1
- package/dist/localization/locales/pt-BR.js +0 -1
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +116 -10
- package/dist/mcp/runtime.d.ts +3 -0
- package/dist/mcp/runtime.js +1099 -185
- package/dist/mcp/runtime.test.js +1491 -140
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +192 -61
- package/dist/migrations/taskSchemaMigrations.test.js +15 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/dist/resources/templates/workflows/collaborate.yaml +1 -1
- package/dist/resources/templates/workflows/evaluate.yaml +2 -2
- package/dist/resources/templates/workflows/plan.yaml +1 -1
- package/dist/resources/templates/workflows/review.yaml +2 -2
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
- package/dist/server/auth/providers/apple.d.ts +33 -0
- package/dist/server/auth/providers/apple.js +82 -0
- package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
- package/dist/server/auth/providers/appleClientSecret.js +65 -0
- package/dist/server/auth/providers/github.d.ts +26 -0
- package/dist/server/auth/providers/github.js +86 -0
- package/dist/server/auth/providers/google.d.ts +21 -0
- package/dist/server/auth/providers/google.js +56 -0
- package/dist/server/auth/providers/types.d.ts +21 -0
- package/dist/server/auth/providers/types.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +6 -3
- package/dist/server/documentReviewRoutes.test.js +36 -3
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +124 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +111 -3
- package/dist/server/routes/admin.d.ts +3 -0
- package/dist/server/routes/admin.js +459 -28
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +26 -2
- package/dist/server/routes/auth.js +1170 -71
- package/dist/server/routes/authSupport.d.ts +5 -1
- package/dist/server/routes/authSupport.js +13 -2
- package/dist/server/routes/billing.js +372 -35
- package/dist/server/routes/billing.test.js +595 -12
- package/dist/server/routes/documents.d.ts +1 -0
- package/dist/server/routes/documents.js +182 -70
- package/dist/server/routes/shared.d.ts +28 -2
- package/dist/server/routes/shared.js +69 -14
- package/dist/server/routes/sync.integration.test.js +658 -39
- package/dist/server/routes/sync.js +74 -608
- package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
- package/dist/server/routes/syncAuxRoutes.js +91 -0
- package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
- package/dist/server/routes/syncAuxRoutes.test.js +158 -0
- package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
- package/dist/server/routes/syncPullApplyRoutes.js +204 -0
- package/dist/server/routes/syncPushRoutes.d.ts +24 -0
- package/dist/server/routes/syncPushRoutes.js +212 -0
- package/dist/server/routes/syncRouteGuards.d.ts +36 -0
- package/dist/server/routes/syncRouteGuards.js +67 -0
- package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
- package/dist/server/routes/syncRouteGuards.test.js +94 -0
- package/dist/server/routes/syncRouteTypes.d.ts +13 -0
- package/dist/server/routes/syncRouteTypes.js +1 -0
- package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
- package/dist/server/routes/syncSnapshotRoutes.js +182 -0
- package/dist/server/routes/tasks.js +55 -10
- package/dist/server/routes/workspaces.js +36 -5
- package/dist/server/routes.js +147 -11
- package/dist/server/routes.test.js +2704 -183
- package/dist/services/workflowExportSnapshots.test.js +2 -0
- package/dist/shared/aiProfileSeatScope.d.ts +5 -0
- package/dist/shared/aiProfileSeatScope.js +21 -0
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/shared/passwordPolicy.d.ts +13 -0
- package/dist/shared/passwordPolicy.js +84 -0
- package/dist/shared/passwordPolicy.test.d.ts +1 -0
- package/dist/shared/passwordPolicy.test.js +34 -0
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/storage/workspaceAssetStore.d.ts +15 -3
- package/dist/storage/workspaceAssetStore.js +132 -44
- package/dist/storage/workspaceAssetStore.test.js +93 -6
- package/dist/styles/fonts.css +70 -0
- package/dist/sync/collaborationSyncPayload.d.ts +6 -1
- package/dist/sync/collaborationSyncPayload.js +19 -11
- package/dist/sync/collaborationSyncPayload.test.js +14 -1
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +9 -9
- package/dist/sync/contentSyncState.js +248 -107
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +11 -4
- package/dist/sync/syncApplyHandlers.js +115 -42
- package/dist/sync/syncApplyHandlers.test.js +251 -4
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +46 -0
- package/dist/sync/syncResourceAdapters.js +79 -0
- package/dist/sync/syncService.d.ts +6 -0
- package/dist/sync/syncService.js +65 -1
- package/dist/sync/syncService.test.js +96 -3
- package/dist/sync/taskSyncChangeKey.d.ts +2 -0
- package/dist/sync/taskSyncChangeKey.js +143 -0
- package/dist/sync/taskSyncPayload.js +3 -8
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +132 -72
- package/dist/sync/workspacePullFeed.test.js +92 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +73 -6
- package/dist/sync/workspaceSyncModel.js +342 -73
- package/dist/sync/workspaceSyncModel.test.js +559 -14
- package/dist/sync/workspaceSyncState.d.ts +17 -0
- package/dist/sync/workspaceSyncState.js +2 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +50 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
- package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
- package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/ui/fonts/Noir_medium.otf +0 -0
- package/dist/ui/fonts/Noir_medium.woff2 +0 -0
- package/dist/ui/fonts/Noir_regular.otf +0 -0
- package/dist/ui/fonts/Noir_regular.woff2 +0 -0
- package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +8 -0
- package/dist/utils/assignees.js +10 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/avatarUpload.d.ts +27 -0
- package/dist/utils/avatarUpload.js +132 -0
- package/dist/utils/avatarUpload.test.d.ts +1 -0
- package/dist/utils/avatarUpload.test.js +40 -0
- package/dist/utils/bootstrapTrace.d.ts +7 -0
- package/dist/utils/bootstrapTrace.js +29 -0
- package/dist/utils/commercialLifecyclePresentation.js +3 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/syncEventDetails.d.ts +3 -0
- package/dist/utils/syncEventDetails.js +64 -0
- package/dist/utils/syncEventDetails.test.d.ts +1 -0
- package/dist/utils/syncEventDetails.test.js +23 -0
- package/dist/utils/syncEventPresentation.d.ts +15 -0
- package/dist/utils/syncEventPresentation.js +129 -0
- package/dist/utils/syncEventPresentation.test.d.ts +1 -0
- package/dist/utils/syncEventPresentation.test.js +64 -0
- package/dist/utils/syncStatusPresentation.d.ts +72 -0
- package/dist/utils/syncStatusPresentation.js +217 -0
- package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
- package/dist/utils/syncStatusPresentation.test.js +164 -0
- package/dist/utils/taskActivity.d.ts +9 -1
- package/dist/utils/taskActivity.js +290 -22
- package/dist/utils/taskActivity.test.js +141 -8
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.js +68 -2
- package/dist/utils/workspaceSyncPresentation.test.js +36 -1
- package/package.json +3 -2
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/run-e2e-realtime.sh +17 -3
- package/scripts/run-smoke.sh +17 -5
- package/scripts/run-soak.sh +17 -5
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/src/resources/templates/workflows/collaborate.yaml +1 -1
- package/src/resources/templates/workflows/evaluate.yaml +2 -2
- package/src/resources/templates/workflows/plan.yaml +1 -1
- package/src/resources/templates/workflows/review.yaml +2 -2
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
- package/dist/ui/assets/index-C2-OXZV7.css +0 -1
- package/dist/ui/assets/index-DcSI5F86.js +0 -6
- package/scripts/migrate-planning-model.ts +0 -233
|
@@ -7,6 +7,28 @@ import { TaskforceCore } from './TaskforceCore';
|
|
|
7
7
|
import fs from 'fs';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import modalStyles from './components/ui/Modal.module.css';
|
|
10
|
+
vi.mock('react-avatar-editor', async () => {
|
|
11
|
+
const React = await import('react');
|
|
12
|
+
return {
|
|
13
|
+
default: React.forwardRef((_props, ref) => {
|
|
14
|
+
React.useImperativeHandle(ref, () => ({
|
|
15
|
+
getImageScaledToCanvas: () => ({
|
|
16
|
+
width: 1024,
|
|
17
|
+
height: 1024,
|
|
18
|
+
getContext: () => ({
|
|
19
|
+
drawImage: () => undefined
|
|
20
|
+
}),
|
|
21
|
+
toBlob: (callback, type) => {
|
|
22
|
+
callback(new Blob([new Uint8Array([1, 2, 3, 4])], { type: type || 'image/webp' }));
|
|
23
|
+
}
|
|
24
|
+
}),
|
|
25
|
+
getImage: () => document.createElement('canvas'),
|
|
26
|
+
getCroppingRect: () => ({ x: 0, y: 0, width: 1, height: 1 })
|
|
27
|
+
}));
|
|
28
|
+
return _jsx("div", { "data-testid": "avatar-editor" });
|
|
29
|
+
})
|
|
30
|
+
};
|
|
31
|
+
});
|
|
10
32
|
const mockTasks = [
|
|
11
33
|
{
|
|
12
34
|
id: 'task-20260130-abc123',
|
|
@@ -888,6 +910,48 @@ describe('TaskforceCore Integration', () => {
|
|
|
888
910
|
});
|
|
889
911
|
expect(container.querySelector('[aria-pressed]')).not.toBeInTheDocument();
|
|
890
912
|
});
|
|
913
|
+
it('renders the cloud login route even while protected startup config is pending', async () => {
|
|
914
|
+
const hangingConfig = new Promise(() => { });
|
|
915
|
+
const fetchMock = vi.fn((url) => {
|
|
916
|
+
if (url.includes('/api/taskforce/auth/runtime-config')) {
|
|
917
|
+
return Promise.resolve({
|
|
918
|
+
ok: true,
|
|
919
|
+
json: () => Promise.resolve({
|
|
920
|
+
config: {
|
|
921
|
+
runtimeMode: 'cloud',
|
|
922
|
+
workspaceMode: 'multi-cloud',
|
|
923
|
+
authSource: 'cloud',
|
|
924
|
+
workspaceSwitchingEnabled: true
|
|
925
|
+
}
|
|
926
|
+
})
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
if (url.includes('/api/taskforce/auth/session')) {
|
|
930
|
+
return Promise.resolve({
|
|
931
|
+
ok: true,
|
|
932
|
+
json: () => Promise.resolve({
|
|
933
|
+
authenticated: false,
|
|
934
|
+
runtimeMode: 'cloud'
|
|
935
|
+
})
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
if (url.includes('/api/taskforce/config')) {
|
|
939
|
+
return hangingConfig;
|
|
940
|
+
}
|
|
941
|
+
if (url.includes('/api/taskforce/auth/providers')) {
|
|
942
|
+
return Promise.resolve({ ok: true, json: () => Promise.resolve({ providers: [] }) });
|
|
943
|
+
}
|
|
944
|
+
return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
|
|
945
|
+
});
|
|
946
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
947
|
+
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=login&next=%2Ftaskforce%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
948
|
+
await waitFor(() => {
|
|
949
|
+
expect(screen.getByPlaceholderText('Email')).toBeInTheDocument();
|
|
950
|
+
expect(screen.getByPlaceholderText('Password')).toBeInTheDocument();
|
|
951
|
+
expect(screen.getByRole('button', { name: 'Sign In' })).toBeInTheDocument();
|
|
952
|
+
});
|
|
953
|
+
expect(screen.queryByText('Loading Taskforce')).not.toBeInTheDocument();
|
|
954
|
+
});
|
|
891
955
|
it('allows public access to /pricing in cloud mode without login redirect', async () => {
|
|
892
956
|
const fetchMock = vi.fn((url) => {
|
|
893
957
|
if (url.includes('/api/taskforce/auth/session')) {
|
|
@@ -1085,7 +1149,6 @@ describe('TaskforceCore Integration', () => {
|
|
|
1085
1149
|
render(_jsx(MemoryRouter, { initialEntries: ['/'], children: _jsx(TaskforceCore, {}) }));
|
|
1086
1150
|
await waitFor(() => {
|
|
1087
1151
|
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
1088
|
-
expect(screen.getByText('Choose a plan to continue.')).toBeInTheDocument();
|
|
1089
1152
|
});
|
|
1090
1153
|
});
|
|
1091
1154
|
it('redirects authenticated users with a blocking account access gate to the plans page', async () => {
|
|
@@ -1789,11 +1852,12 @@ describe('TaskforceCore Integration', () => {
|
|
|
1789
1852
|
if (url.includes('/api/taskforce/workspace/assignee-options')) {
|
|
1790
1853
|
return jsonResponse({ assignees: [] });
|
|
1791
1854
|
}
|
|
1792
|
-
if (url.includes('/api/taskforce/
|
|
1793
|
-
return jsonResponse(
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1855
|
+
if (url.includes('/api/taskforce/planning/bootstrap')) {
|
|
1856
|
+
return jsonResponse({
|
|
1857
|
+
initiatives: [],
|
|
1858
|
+
workstreams: [],
|
|
1859
|
+
workstreamTaskSummaries: [],
|
|
1860
|
+
});
|
|
1797
1861
|
}
|
|
1798
1862
|
return jsonResponse({});
|
|
1799
1863
|
});
|
|
@@ -1820,7 +1884,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
1820
1884
|
await user.click(screen.getByRole('button', { name: 'Register' }));
|
|
1821
1885
|
await user.type(await screen.findByPlaceholderText('Email'), accounts.newcomer.email);
|
|
1822
1886
|
await user.type(screen.getByPlaceholderText('Display name'), accounts.newcomer.displayName);
|
|
1823
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
1887
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
1888
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
1824
1889
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
1825
1890
|
await waitFor(() => {
|
|
1826
1891
|
expect(screen.getByTitle(/Account/i)).toBeInTheDocument();
|
|
@@ -1902,6 +1967,7 @@ describe('TaskforceCore Integration', () => {
|
|
|
1902
1967
|
expect(screen.getByText('Create your Taskforce account.')).toBeInTheDocument();
|
|
1903
1968
|
expect(screen.getByLabelText('Email')).toBeInTheDocument();
|
|
1904
1969
|
expect(screen.getByLabelText('Display name')).toBeInTheDocument();
|
|
1970
|
+
expect(screen.getByLabelText('Confirm password')).toBeInTheDocument();
|
|
1905
1971
|
expect(screen.getByPlaceholderText('Email')).toBeInTheDocument();
|
|
1906
1972
|
expect(screen.getByPlaceholderText('Display name')).toBeInTheDocument();
|
|
1907
1973
|
expect(screen.getByRole('button', { name: 'Create Account' })).toBeInTheDocument();
|
|
@@ -1913,6 +1979,56 @@ describe('TaskforceCore Integration', () => {
|
|
|
1913
1979
|
});
|
|
1914
1980
|
expect(container.querySelector('[aria-pressed]')).not.toBeInTheDocument();
|
|
1915
1981
|
});
|
|
1982
|
+
it('blocks registration when the confirmation does not match', async () => {
|
|
1983
|
+
const user = userEvent.setup();
|
|
1984
|
+
const fetchMock = vi.fn((url) => {
|
|
1985
|
+
if (url.includes('/api/taskforce/auth/session')) {
|
|
1986
|
+
return Promise.resolve({
|
|
1987
|
+
ok: true,
|
|
1988
|
+
json: () => Promise.resolve({
|
|
1989
|
+
authenticated: false,
|
|
1990
|
+
runtimeMode: 'cloud',
|
|
1991
|
+
authRequiredForApi: false
|
|
1992
|
+
})
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
if (url.includes('/api/taskforce/config')) {
|
|
1996
|
+
return Promise.resolve({
|
|
1997
|
+
ok: true,
|
|
1998
|
+
json: () => Promise.resolve({
|
|
1999
|
+
...mockConfig,
|
|
2000
|
+
runtimeMode: 'cloud',
|
|
2001
|
+
authRequiredForApi: false,
|
|
2002
|
+
setupState: {
|
|
2003
|
+
globalSetupState: 'present',
|
|
2004
|
+
workspaceSetupState: 'present',
|
|
2005
|
+
runtimeMode: 'cloud',
|
|
2006
|
+
workspaceId: 'workspace-local-active',
|
|
2007
|
+
mode: 'core',
|
|
2008
|
+
forceSetup: false,
|
|
2009
|
+
forceGlobalSetup: false,
|
|
2010
|
+
forceWorkspaceSetup: false
|
|
2011
|
+
}
|
|
2012
|
+
})
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
if (url.includes('/api/taskforce/workflow-templates')) {
|
|
2016
|
+
return Promise.resolve({ ok: true, json: () => Promise.resolve({ templates: [] }) });
|
|
2017
|
+
}
|
|
2018
|
+
return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
|
|
2019
|
+
});
|
|
2020
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
2021
|
+
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2022
|
+
await user.type(await screen.findByPlaceholderText('Email'), 'mismatch@example.com');
|
|
2023
|
+
await user.type(screen.getByPlaceholderText('Display name'), 'Mismatch User');
|
|
2024
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
2025
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'DifferentPassphrase123!');
|
|
2026
|
+
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2027
|
+
await waitFor(() => {
|
|
2028
|
+
expect(screen.getByText('Passwords do not match.')).toBeInTheDocument();
|
|
2029
|
+
});
|
|
2030
|
+
expect(fetchMock.mock.calls.some((call) => String(call[0]).includes('/api/taskforce/auth/register'))).toBe(false);
|
|
2031
|
+
});
|
|
1916
2032
|
it('keeps the verification screen focused on verification and lets the user request a fresh email token', async () => {
|
|
1917
2033
|
const fetchMock = vi.fn((url) => {
|
|
1918
2034
|
if (url.includes('/api/taskforce/auth/session')) {
|
|
@@ -2204,7 +2320,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
2204
2320
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2Fplans'], children: _jsx(TaskforceCore, {}) }));
|
|
2205
2321
|
await user.type(await screen.findByPlaceholderText('Email'), 'local@example.com');
|
|
2206
2322
|
await user.type(screen.getByPlaceholderText('Display name'), 'Local User');
|
|
2207
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
2323
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
2324
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2208
2325
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2209
2326
|
await waitFor(() => {
|
|
2210
2327
|
expect(screen.getByText('Configure your new workspace.')).toBeInTheDocument();
|
|
@@ -2362,11 +2479,11 @@ describe('TaskforceCore Integration', () => {
|
|
|
2362
2479
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2363
2480
|
await user.type(await screen.findByPlaceholderText('Email'), 'pending@example.com');
|
|
2364
2481
|
await user.type(screen.getByPlaceholderText('Display name'), 'Pending User');
|
|
2365
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
2482
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
2483
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2366
2484
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2367
2485
|
await waitFor(() => {
|
|
2368
2486
|
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
2369
|
-
expect(screen.getByText('Choose a plan to continue.')).toBeInTheDocument();
|
|
2370
2487
|
});
|
|
2371
2488
|
expect(fetchMock.mock.calls.some(([url]) => String(url).includes('/api/taskforce/billing/checkout-session'))).toBe(false);
|
|
2372
2489
|
});
|
|
@@ -2478,11 +2595,148 @@ describe('TaskforceCore Integration', () => {
|
|
|
2478
2595
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2479
2596
|
await user.type(await screen.findByPlaceholderText('Email'), 'brandnew@example.com');
|
|
2480
2597
|
await user.type(screen.getByPlaceholderText('Display name'), 'Brand New');
|
|
2481
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
2598
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
2599
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2482
2600
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2483
2601
|
await waitFor(() => {
|
|
2484
2602
|
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
2485
|
-
|
|
2603
|
+
});
|
|
2604
|
+
expect(screen.queryByText('Configure your new workspace.')).not.toBeInTheDocument();
|
|
2605
|
+
});
|
|
2606
|
+
it('keeps registration on plan selection while the post-auth cloud session is still resolving for a commercially gated user with no workspace', async () => {
|
|
2607
|
+
const user = userEvent.setup();
|
|
2608
|
+
let authenticated = false;
|
|
2609
|
+
let authSessionCallCount = 0;
|
|
2610
|
+
let releaseInitialSession = null;
|
|
2611
|
+
const initialSessionGate = new Promise((resolve) => {
|
|
2612
|
+
releaseInitialSession = resolve;
|
|
2613
|
+
});
|
|
2614
|
+
const fetchMock = vi.fn((input) => {
|
|
2615
|
+
const url = String(input);
|
|
2616
|
+
if (url.includes('/api/taskforce/auth/runtime-config')) {
|
|
2617
|
+
return jsonResponse({
|
|
2618
|
+
config: {
|
|
2619
|
+
baseUrl: 'https://app.taskforce.example',
|
|
2620
|
+
apiBaseUrl: 'https://app.taskforce.example/api',
|
|
2621
|
+
cloudAuthBaseUrl: 'https://app.taskforce.example',
|
|
2622
|
+
runtimeMode: 'cloud',
|
|
2623
|
+
authSource: 'cloud',
|
|
2624
|
+
workspaceMode: 'multi-cloud',
|
|
2625
|
+
workspaceSwitchingEnabled: true,
|
|
2626
|
+
authRequiredForApi: true
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
if (url.includes('/api/taskforce/auth/session')) {
|
|
2631
|
+
authSessionCallCount += 1;
|
|
2632
|
+
const payload = () => ({
|
|
2633
|
+
authenticated,
|
|
2634
|
+
runtimeMode: 'cloud',
|
|
2635
|
+
authRequiredForApi: true,
|
|
2636
|
+
userId: authenticated ? 'user-gated-pending' : null,
|
|
2637
|
+
workspaceId: null,
|
|
2638
|
+
betaAccess: true
|
|
2639
|
+
});
|
|
2640
|
+
if (authSessionCallCount === 1) {
|
|
2641
|
+
return initialSessionGate.then(() => jsonResponse(payload()));
|
|
2642
|
+
}
|
|
2643
|
+
return jsonResponse(payload());
|
|
2644
|
+
}
|
|
2645
|
+
if (url.includes('/api/taskforce/config')) {
|
|
2646
|
+
return jsonResponse({
|
|
2647
|
+
...mockConfig,
|
|
2648
|
+
runtimeMode: 'cloud',
|
|
2649
|
+
authRequiredForApi: true,
|
|
2650
|
+
workspaceSwitchingEnabled: true,
|
|
2651
|
+
setupState: {
|
|
2652
|
+
globalSetupState: 'present',
|
|
2653
|
+
workspaceSetupState: 'missing',
|
|
2654
|
+
runtimeMode: 'cloud',
|
|
2655
|
+
workspaceId: 'default',
|
|
2656
|
+
mode: 'core',
|
|
2657
|
+
forceSetup: true,
|
|
2658
|
+
forceGlobalSetup: false,
|
|
2659
|
+
forceWorkspaceSetup: true
|
|
2660
|
+
}
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
if (url.includes('/api/taskforce/workspaces')) {
|
|
2664
|
+
return jsonResponse({
|
|
2665
|
+
success: true,
|
|
2666
|
+
workspaces: [],
|
|
2667
|
+
currentWorkspaceId: 'default'
|
|
2668
|
+
});
|
|
2669
|
+
}
|
|
2670
|
+
if (url.includes('/api/taskforce/account/access-status')) {
|
|
2671
|
+
return jsonResponse({
|
|
2672
|
+
gate: 'plan_selection_required',
|
|
2673
|
+
hasEntitlement: true,
|
|
2674
|
+
canAccessApp: false,
|
|
2675
|
+
canAccessPlans: true,
|
|
2676
|
+
message: 'Choose a plan to continue.'
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
if (url.includes('/api/taskforce/account/profile-summary')) {
|
|
2680
|
+
return jsonResponse({
|
|
2681
|
+
entitlementState: 'pending_plan_selection',
|
|
2682
|
+
gate: 'plan_selection_required',
|
|
2683
|
+
message: 'Choose a plan to continue.',
|
|
2684
|
+
workspaceId: null
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
if (url.includes('/api/taskforce/public/pricing')) {
|
|
2688
|
+
return jsonResponse({ plans: [] });
|
|
2689
|
+
}
|
|
2690
|
+
if (url.includes('/api/taskforce/auth/register')) {
|
|
2691
|
+
authenticated = true;
|
|
2692
|
+
return jsonResponse({
|
|
2693
|
+
success: true,
|
|
2694
|
+
workspaceSetupRequired: true,
|
|
2695
|
+
verificationRequired: false,
|
|
2696
|
+
planSelectionRequired: true,
|
|
2697
|
+
commercialState: 'pending_plan_selection'
|
|
2698
|
+
});
|
|
2699
|
+
}
|
|
2700
|
+
if (url.includes('/api/taskforce/categories'))
|
|
2701
|
+
return jsonResponse(mockCategories);
|
|
2702
|
+
if (url.includes('/api/taskforce/tasks'))
|
|
2703
|
+
return jsonResponse({ tasks: mockTasks });
|
|
2704
|
+
if (url.includes('/api/taskforce/archive'))
|
|
2705
|
+
return jsonResponse({ archived: [] });
|
|
2706
|
+
if (url.includes('/api/taskforce/data-version'))
|
|
2707
|
+
return jsonResponse({ dataVersion: 1 });
|
|
2708
|
+
if (url.includes('/api/taskforce/types'))
|
|
2709
|
+
return jsonResponse({ types: [] });
|
|
2710
|
+
if (url.includes('/api/taskforce/priorities'))
|
|
2711
|
+
return jsonResponse({ priorities: [] });
|
|
2712
|
+
if (url.includes('/api/taskforce/approaches'))
|
|
2713
|
+
return jsonResponse({ approaches: [] });
|
|
2714
|
+
if (url.includes('/api/taskforce/specialists'))
|
|
2715
|
+
return jsonResponse({ specialists: [] });
|
|
2716
|
+
if (url.includes('/api/taskforce/workflow-templates'))
|
|
2717
|
+
return jsonResponse({ templates: [] });
|
|
2718
|
+
return jsonResponse({});
|
|
2719
|
+
});
|
|
2720
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
2721
|
+
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2722
|
+
await user.type(await screen.findByPlaceholderText('Email'), 'gated-pending@example.com');
|
|
2723
|
+
await user.type(screen.getByPlaceholderText('Display name'), 'Gated Pending');
|
|
2724
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
2725
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2726
|
+
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2727
|
+
await act(async () => {
|
|
2728
|
+
await Promise.resolve();
|
|
2729
|
+
});
|
|
2730
|
+
await waitFor(() => {
|
|
2731
|
+
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
2732
|
+
});
|
|
2733
|
+
expect(screen.queryByText('Configure your new workspace.')).not.toBeInTheDocument();
|
|
2734
|
+
await act(async () => {
|
|
2735
|
+
releaseInitialSession?.();
|
|
2736
|
+
await Promise.resolve();
|
|
2737
|
+
});
|
|
2738
|
+
await waitFor(() => {
|
|
2739
|
+
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
2486
2740
|
});
|
|
2487
2741
|
expect(screen.queryByText('Configure your new workspace.')).not.toBeInTheDocument();
|
|
2488
2742
|
});
|
|
@@ -2653,7 +2907,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
2653
2907
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&planId=basic&planVersionId=basic-v1&interval=year&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2654
2908
|
await user.type(await screen.findByPlaceholderText('Email'), 'checkout@example.com');
|
|
2655
2909
|
await user.type(screen.getByPlaceholderText('Display name'), 'Checkout User');
|
|
2656
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
2910
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
2911
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2657
2912
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2658
2913
|
await waitFor(() => {
|
|
2659
2914
|
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
@@ -2786,7 +3041,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
2786
3041
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2787
3042
|
await user.type(await screen.findByPlaceholderText('Email'), 'free-user@example.com');
|
|
2788
3043
|
await user.type(screen.getByPlaceholderText('Display name'), 'Free User');
|
|
2789
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
3044
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
3045
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2790
3046
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2791
3047
|
await act(async () => {
|
|
2792
3048
|
await Promise.resolve();
|
|
@@ -2912,7 +3168,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
2912
3168
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
2913
3169
|
await user.type(await screen.findByPlaceholderText('Email'), 'existing-workspace@example.com');
|
|
2914
3170
|
await user.type(screen.getByPlaceholderText('Display name'), 'Existing Workspace User');
|
|
2915
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
3171
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
3172
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2916
3173
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2917
3174
|
await act(async () => {
|
|
2918
3175
|
await Promise.resolve();
|
|
@@ -2982,7 +3239,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
2982
3239
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2Fplans'], children: _jsx(TaskforceCore, {}) }));
|
|
2983
3240
|
await user.type(await screen.findByPlaceholderText('Email'), 'local@example.com');
|
|
2984
3241
|
await user.type(screen.getByPlaceholderText('Display name'), 'Local User');
|
|
2985
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
3242
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
3243
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
2986
3244
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
2987
3245
|
await waitFor(() => {
|
|
2988
3246
|
expect(screen.getByPlaceholderText('Verification token')).toBeInTheDocument();
|
|
@@ -2990,6 +3248,156 @@ describe('TaskforceCore Integration', () => {
|
|
|
2990
3248
|
expect(screen.queryByRole('button', { name: 'Create Account' })).not.toBeInTheDocument();
|
|
2991
3249
|
expect(screen.queryByText('Subscription Plans')).not.toBeInTheDocument();
|
|
2992
3250
|
});
|
|
3251
|
+
it('keeps verified registration on plan selection when commercial onboarding is still blocked', async () => {
|
|
3252
|
+
const user = userEvent.setup();
|
|
3253
|
+
let authenticated = false;
|
|
3254
|
+
const fetchMock = vi.fn((input) => {
|
|
3255
|
+
const url = String(input);
|
|
3256
|
+
if (url.includes('/api/taskforce/auth/runtime-config')) {
|
|
3257
|
+
return jsonResponse({
|
|
3258
|
+
config: {
|
|
3259
|
+
baseUrl: 'https://app.taskforce.example',
|
|
3260
|
+
apiBaseUrl: 'https://app.taskforce.example/api',
|
|
3261
|
+
cloudAuthBaseUrl: 'https://app.taskforce.example',
|
|
3262
|
+
runtimeMode: 'cloud',
|
|
3263
|
+
authSource: 'cloud',
|
|
3264
|
+
workspaceMode: 'multi-cloud',
|
|
3265
|
+
workspaceSwitchingEnabled: true,
|
|
3266
|
+
authRequiredForApi: true
|
|
3267
|
+
}
|
|
3268
|
+
});
|
|
3269
|
+
}
|
|
3270
|
+
if (url.includes('/api/taskforce/auth/session')) {
|
|
3271
|
+
return jsonResponse({
|
|
3272
|
+
authenticated,
|
|
3273
|
+
runtimeMode: 'cloud',
|
|
3274
|
+
authRequiredForApi: true,
|
|
3275
|
+
userId: authenticated ? 'user-verify' : null,
|
|
3276
|
+
workspaceId: authenticated ? 'default' : null,
|
|
3277
|
+
betaAccess: true
|
|
3278
|
+
});
|
|
3279
|
+
}
|
|
3280
|
+
if (url.includes('/api/taskforce/config')) {
|
|
3281
|
+
return jsonResponse({
|
|
3282
|
+
...mockConfig,
|
|
3283
|
+
runtimeMode: 'cloud',
|
|
3284
|
+
authRequiredForApi: true,
|
|
3285
|
+
workspaceSwitchingEnabled: true,
|
|
3286
|
+
setupState: {
|
|
3287
|
+
globalSetupState: 'present',
|
|
3288
|
+
workspaceSetupState: authenticated ? 'missing' : 'present',
|
|
3289
|
+
runtimeMode: 'cloud',
|
|
3290
|
+
workspaceId: 'default',
|
|
3291
|
+
mode: 'core',
|
|
3292
|
+
forceSetup: false,
|
|
3293
|
+
forceGlobalSetup: false,
|
|
3294
|
+
forceWorkspaceSetup: false
|
|
3295
|
+
}
|
|
3296
|
+
});
|
|
3297
|
+
}
|
|
3298
|
+
if (url.includes('/api/taskforce/workspaces')) {
|
|
3299
|
+
return jsonResponse({
|
|
3300
|
+
success: true,
|
|
3301
|
+
workspaces: [],
|
|
3302
|
+
currentWorkspaceId: null
|
|
3303
|
+
});
|
|
3304
|
+
}
|
|
3305
|
+
if (url.includes('/api/taskforce/account/access-status')) {
|
|
3306
|
+
return jsonResponse({
|
|
3307
|
+
gate: 'plan_selection_required',
|
|
3308
|
+
hasEntitlement: true,
|
|
3309
|
+
canAccessApp: false,
|
|
3310
|
+
canAccessPlans: true,
|
|
3311
|
+
message: 'Choose a plan to continue.'
|
|
3312
|
+
});
|
|
3313
|
+
}
|
|
3314
|
+
if (url.includes('/api/taskforce/account/profile-summary')) {
|
|
3315
|
+
return jsonResponse({
|
|
3316
|
+
entitlementState: 'pending_plan_selection',
|
|
3317
|
+
gate: 'plan_selection_required',
|
|
3318
|
+
message: 'Choose a plan to continue.',
|
|
3319
|
+
workspaceId: null
|
|
3320
|
+
});
|
|
3321
|
+
}
|
|
3322
|
+
if (url.includes('/api/taskforce/public/pricing')) {
|
|
3323
|
+
return jsonResponse({
|
|
3324
|
+
plans: [{
|
|
3325
|
+
planId: 'free',
|
|
3326
|
+
displayName: 'Free',
|
|
3327
|
+
status: 'active',
|
|
3328
|
+
defaultVersion: {
|
|
3329
|
+
planVersionId: 'free-v1',
|
|
3330
|
+
versionNumber: 1,
|
|
3331
|
+
seatLimit: null,
|
|
3332
|
+
metadata: {}
|
|
3333
|
+
},
|
|
3334
|
+
features: [],
|
|
3335
|
+
pricing: {
|
|
3336
|
+
month: {
|
|
3337
|
+
planVersionId: 'free-v1',
|
|
3338
|
+
interval: 'month',
|
|
3339
|
+
pricingType: 'free',
|
|
3340
|
+
stripePriceId: 'free:free-v1:month',
|
|
3341
|
+
displayAmount: '$0.00',
|
|
3342
|
+
unitAmount: 0,
|
|
3343
|
+
currency: 'usd'
|
|
3344
|
+
},
|
|
3345
|
+
year: null
|
|
3346
|
+
}
|
|
3347
|
+
}]
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
if (url.includes('/api/taskforce/auth/register')) {
|
|
3351
|
+
return jsonResponse({
|
|
3352
|
+
success: true,
|
|
3353
|
+
workspaceSetupRequired: true,
|
|
3354
|
+
verificationRequired: true,
|
|
3355
|
+
verificationToken: 'verify-token',
|
|
3356
|
+
emailSent: true,
|
|
3357
|
+
planSelectionRequired: true,
|
|
3358
|
+
commercialState: 'pending_plan_selection'
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
if (url.includes('/api/taskforce/auth/verify-email/confirm')) {
|
|
3362
|
+
authenticated = true;
|
|
3363
|
+
return jsonResponse({ success: true });
|
|
3364
|
+
}
|
|
3365
|
+
if (url.includes('/api/taskforce/categories'))
|
|
3366
|
+
return jsonResponse(mockCategories);
|
|
3367
|
+
if (url.includes('/api/taskforce/tasks'))
|
|
3368
|
+
return jsonResponse({ tasks: mockTasks });
|
|
3369
|
+
if (url.includes('/api/taskforce/archive'))
|
|
3370
|
+
return jsonResponse({ archived: [] });
|
|
3371
|
+
if (url.includes('/api/taskforce/data-version'))
|
|
3372
|
+
return jsonResponse({ dataVersion: 1 });
|
|
3373
|
+
if (url.includes('/api/taskforce/types'))
|
|
3374
|
+
return jsonResponse({ types: [] });
|
|
3375
|
+
if (url.includes('/api/taskforce/priorities'))
|
|
3376
|
+
return jsonResponse({ priorities: [] });
|
|
3377
|
+
if (url.includes('/api/taskforce/approaches'))
|
|
3378
|
+
return jsonResponse({ approaches: [] });
|
|
3379
|
+
if (url.includes('/api/taskforce/specialists'))
|
|
3380
|
+
return jsonResponse({ specialists: [] });
|
|
3381
|
+
if (url.includes('/api/taskforce/workflow-templates'))
|
|
3382
|
+
return jsonResponse({ templates: [] });
|
|
3383
|
+
return jsonResponse({});
|
|
3384
|
+
});
|
|
3385
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
3386
|
+
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
3387
|
+
await user.type(await screen.findByPlaceholderText('Email'), 'verify-gated@example.com');
|
|
3388
|
+
await user.type(screen.getByPlaceholderText('Display name'), 'Verify Gated User');
|
|
3389
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
3390
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
3391
|
+
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
3392
|
+
await waitFor(() => {
|
|
3393
|
+
expect(screen.getByPlaceholderText('Verification token')).toHaveValue('verify-token');
|
|
3394
|
+
});
|
|
3395
|
+
await user.click(screen.getByRole('button', { name: 'Verify Email' }));
|
|
3396
|
+
await waitFor(() => {
|
|
3397
|
+
expect(screen.getByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
3398
|
+
});
|
|
3399
|
+
expect(screen.queryByText('Configure your new workspace.')).not.toBeInTheDocument();
|
|
3400
|
+
});
|
|
2993
3401
|
it('allows returning to sign-in/register from forgot mode in local runtime', async () => {
|
|
2994
3402
|
const user = userEvent.setup();
|
|
2995
3403
|
const fetchMock = vi.fn((url) => {
|
|
@@ -3291,7 +3699,8 @@ describe('TaskforceCore Integration', () => {
|
|
|
3291
3699
|
render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=register&next=%2F'], children: _jsx(TaskforceCore, {}) }));
|
|
3292
3700
|
await user.type(await screen.findByPlaceholderText('Email'), 'local@example.com');
|
|
3293
3701
|
await user.type(screen.getByPlaceholderText('Display name'), 'Local User');
|
|
3294
|
-
await user.type(screen.getByPlaceholderText('Password'), '
|
|
3702
|
+
await user.type(screen.getByPlaceholderText('Password'), 'GoodPassphrase123!');
|
|
3703
|
+
await user.type(screen.getByPlaceholderText('Confirm password'), 'GoodPassphrase123!');
|
|
3295
3704
|
await user.click(screen.getByRole('button', { name: 'Create Account' }));
|
|
3296
3705
|
await waitFor(() => {
|
|
3297
3706
|
expect(screen.getByText('Choose a plan to continue.')).toBeInTheDocument();
|
|
@@ -3677,6 +4086,7 @@ describe('TaskforceCore Integration', () => {
|
|
|
3677
4086
|
await waitFor(() => {
|
|
3678
4087
|
expect(screen.getByText('Create your account to join this workspace.')).toBeInTheDocument();
|
|
3679
4088
|
expect(screen.getByPlaceholderText('Create password')).toBeInTheDocument();
|
|
4089
|
+
expect(screen.getByPlaceholderText('Confirm password')).toBeInTheDocument();
|
|
3680
4090
|
expect(screen.getByRole('button', { name: 'Create Account and Join' })).toBeInTheDocument();
|
|
3681
4091
|
});
|
|
3682
4092
|
});
|
|
@@ -5417,6 +5827,15 @@ describe('TaskforceCore Integration', () => {
|
|
|
5417
5827
|
expect(useTaskforceSource).toContain("|| path.startsWith('/api/taskforce/account/')");
|
|
5418
5828
|
expect(useTaskforceSource).toContain("|| path.startsWith('/api/taskforce/billing/')");
|
|
5419
5829
|
});
|
|
5830
|
+
it('keeps plans on a dedicated surface while preserving the faster exit flow', () => {
|
|
5831
|
+
const standaloneLayoutPath = path.join(process.cwd(), 'src/components/views/StandaloneLayout.tsx');
|
|
5832
|
+
const standaloneLayoutSource = fs.readFileSync(standaloneLayoutPath, 'utf8');
|
|
5833
|
+
expect(standaloneLayoutSource).toContain('{!isPlansScreen && <WorkspaceHeaderActions actions={universalFilterActions} />}');
|
|
5834
|
+
expect(standaloneLayoutSource).toContain('{!isPlansScreen && showFilters && workspaceFilterBar}');
|
|
5835
|
+
expect(standaloneLayoutSource).not.toMatch(/\{isPlansScreen \? \([\s\S]*\{workspaceToolRail\}[\s\S]*<PlansPage/);
|
|
5836
|
+
expect(standaloneLayoutSource).toContain('closePlansScreen();');
|
|
5837
|
+
expect(standaloneLayoutSource).toContain('void (async () => {');
|
|
5838
|
+
});
|
|
5420
5839
|
it('uses shared /login flow for local sign in instead of a duplicate modal', async () => {
|
|
5421
5840
|
const standaloneLayoutPath = path.join(process.cwd(), 'src/components/views/StandaloneLayout.tsx');
|
|
5422
5841
|
const standaloneLayoutSource = fs.readFileSync(standaloneLayoutPath, 'utf8');
|
|
@@ -5601,11 +6020,12 @@ describe('TaskforceCore Integration', () => {
|
|
|
5601
6020
|
if (url.includes('/api/taskforce/workflow-templates')) {
|
|
5602
6021
|
return jsonResponse({ templates: [] });
|
|
5603
6022
|
}
|
|
5604
|
-
if (url.includes('/api/taskforce/
|
|
5605
|
-
return jsonResponse(
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
6023
|
+
if (url.includes('/api/taskforce/planning/bootstrap')) {
|
|
6024
|
+
return jsonResponse({
|
|
6025
|
+
initiatives: [],
|
|
6026
|
+
workstreams: [],
|
|
6027
|
+
workstreamTaskSummaries: [],
|
|
6028
|
+
});
|
|
5609
6029
|
}
|
|
5610
6030
|
return jsonResponse({});
|
|
5611
6031
|
});
|
|
@@ -5624,6 +6044,142 @@ describe('TaskforceCore Integration', () => {
|
|
|
5624
6044
|
await user.click(screen.getByTitle(/Account/i));
|
|
5625
6045
|
expect(await screen.findByText('Sign In / Register')).toBeInTheDocument();
|
|
5626
6046
|
});
|
|
6047
|
+
it('returns to the login screen after signing out from the cloud plans screen', async () => {
|
|
6048
|
+
const user = userEvent.setup();
|
|
6049
|
+
let signedIn = true;
|
|
6050
|
+
const fetchMock = vi.fn((url) => {
|
|
6051
|
+
if (url.includes('/api/taskforce/auth/runtime-config')) {
|
|
6052
|
+
return jsonResponse({ config: { runtimeMode: 'cloud', workspaceMode: 'team', authSource: 'cloud' } });
|
|
6053
|
+
}
|
|
6054
|
+
if (url.includes('/api/taskforce/auth/session')) {
|
|
6055
|
+
return jsonResponse({
|
|
6056
|
+
authenticated: signedIn,
|
|
6057
|
+
runtimeMode: 'cloud',
|
|
6058
|
+
authRequiredForApi: true,
|
|
6059
|
+
email: signedIn ? 'member@example.com' : '',
|
|
6060
|
+
userId: signedIn ? 'user-member' : 'anonymous',
|
|
6061
|
+
workspaceId: signedIn ? 'workspace-cloud-active' : '',
|
|
6062
|
+
betaAccess: true
|
|
6063
|
+
});
|
|
6064
|
+
}
|
|
6065
|
+
if (url.includes('/api/taskforce/auth/logout')) {
|
|
6066
|
+
signedIn = false;
|
|
6067
|
+
return jsonResponse({ success: true });
|
|
6068
|
+
}
|
|
6069
|
+
if (url.includes('/api/taskforce/config')) {
|
|
6070
|
+
return jsonResponse({
|
|
6071
|
+
...mockConfig,
|
|
6072
|
+
runtimeMode: 'cloud',
|
|
6073
|
+
authRequiredForApi: true,
|
|
6074
|
+
workspaceId: 'workspace-cloud-active',
|
|
6075
|
+
workspaceSwitchingEnabled: true,
|
|
6076
|
+
setupState: {
|
|
6077
|
+
globalSetupState: 'present',
|
|
6078
|
+
workspaceSetupState: 'present',
|
|
6079
|
+
runtimeMode: 'cloud',
|
|
6080
|
+
workspaceId: 'workspace-cloud-active',
|
|
6081
|
+
mode: 'core',
|
|
6082
|
+
forceSetup: false,
|
|
6083
|
+
forceGlobalSetup: false,
|
|
6084
|
+
forceWorkspaceSetup: false
|
|
6085
|
+
}
|
|
6086
|
+
});
|
|
6087
|
+
}
|
|
6088
|
+
if (url.includes('/api/taskforce/account/access-status')) {
|
|
6089
|
+
return jsonResponse({
|
|
6090
|
+
gate: 'plan_selection_required',
|
|
6091
|
+
hasEntitlement: false,
|
|
6092
|
+
canAccessApp: false,
|
|
6093
|
+
canAccessPlans: true
|
|
6094
|
+
});
|
|
6095
|
+
}
|
|
6096
|
+
if (url.includes('/api/taskforce/public/pricing')) {
|
|
6097
|
+
return jsonResponse({
|
|
6098
|
+
plans: [
|
|
6099
|
+
{
|
|
6100
|
+
planId: 'free',
|
|
6101
|
+
displayName: 'Free',
|
|
6102
|
+
status: 'active',
|
|
6103
|
+
features: [],
|
|
6104
|
+
pricing: {
|
|
6105
|
+
month: { pricingType: 'free', stripePriceId: null, unitAmount: 0, currency: null, interval: 'month' },
|
|
6106
|
+
year: null
|
|
6107
|
+
},
|
|
6108
|
+
defaultVersion: {
|
|
6109
|
+
planVersionId: 'free-v1',
|
|
6110
|
+
versionNumber: 1,
|
|
6111
|
+
seatLimit: null,
|
|
6112
|
+
metadata: {}
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
]
|
|
6116
|
+
});
|
|
6117
|
+
}
|
|
6118
|
+
if (url.includes('/api/taskforce/account/profile-summary')) {
|
|
6119
|
+
return jsonResponse({
|
|
6120
|
+
planId: 'free',
|
|
6121
|
+
planName: 'Free',
|
|
6122
|
+
planVersionId: 'free-v1',
|
|
6123
|
+
entitlementState: 'pending_plan_selection',
|
|
6124
|
+
gate: 'plan_selection_required',
|
|
6125
|
+
planSelectionRequired: true
|
|
6126
|
+
});
|
|
6127
|
+
}
|
|
6128
|
+
if (url.includes('/api/taskforce/workspaces')) {
|
|
6129
|
+
return jsonResponse({ workspaces: [] });
|
|
6130
|
+
}
|
|
6131
|
+
if (url.includes('/api/taskforce/ui-state?key=app')) {
|
|
6132
|
+
return jsonResponse({ success: true, state: {} });
|
|
6133
|
+
}
|
|
6134
|
+
if (url.includes('/api/taskforce/ui-state?key=workspace-sync')) {
|
|
6135
|
+
return jsonResponse({ success: true, state: {} });
|
|
6136
|
+
}
|
|
6137
|
+
if (url.includes('/api/taskforce/categories')) {
|
|
6138
|
+
return jsonResponse(mockCategories);
|
|
6139
|
+
}
|
|
6140
|
+
if (url.includes('/api/taskforce/tasks')) {
|
|
6141
|
+
return jsonResponse({ tasks: mockTasks });
|
|
6142
|
+
}
|
|
6143
|
+
if (url.includes('/api/taskforce/archive')) {
|
|
6144
|
+
return jsonResponse({ archived: [] });
|
|
6145
|
+
}
|
|
6146
|
+
if (url.includes('/api/taskforce/types')) {
|
|
6147
|
+
return jsonResponse({ types: [] });
|
|
6148
|
+
}
|
|
6149
|
+
if (url.includes('/api/taskforce/priorities')) {
|
|
6150
|
+
return jsonResponse({ priorities: [] });
|
|
6151
|
+
}
|
|
6152
|
+
if (url.includes('/api/taskforce/approaches')) {
|
|
6153
|
+
return jsonResponse({ approaches: [] });
|
|
6154
|
+
}
|
|
6155
|
+
if (url.includes('/api/taskforce/specialists')) {
|
|
6156
|
+
return jsonResponse({ specialists: [] });
|
|
6157
|
+
}
|
|
6158
|
+
if (url.includes('/api/taskforce/workflow-templates')) {
|
|
6159
|
+
return jsonResponse({ templates: [] });
|
|
6160
|
+
}
|
|
6161
|
+
if (url.includes('/api/taskforce/workspace/assignee-options')) {
|
|
6162
|
+
return jsonResponse({ assignees: [] });
|
|
6163
|
+
}
|
|
6164
|
+
if (url.includes('/api/taskforce/planning/bootstrap')) {
|
|
6165
|
+
return jsonResponse({
|
|
6166
|
+
initiatives: [],
|
|
6167
|
+
workstreams: [],
|
|
6168
|
+
workstreamTaskSummaries: [],
|
|
6169
|
+
});
|
|
6170
|
+
}
|
|
6171
|
+
return jsonResponse({});
|
|
6172
|
+
});
|
|
6173
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
6174
|
+
render(_jsx(MemoryRouter, { initialEntries: ['/?screen=plans&gate=plan_selection_required'], children: _jsx(TaskforceCore, { config: { cloudAuthBaseUrl: 'https://cloud.example.com' } }) }));
|
|
6175
|
+
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
6176
|
+
await user.click(screen.getByTitle(/Account/i));
|
|
6177
|
+
await user.click(await screen.findByRole('menuitem', { name: 'Sign Out' }));
|
|
6178
|
+
await waitFor(() => {
|
|
6179
|
+
expect(fetchMock.mock.calls.some((call) => String(call[0]).includes('/api/taskforce/auth/logout'))).toBe(true);
|
|
6180
|
+
expect(screen.getByText('Sign in with your account credentials.')).toBeInTheDocument();
|
|
6181
|
+
});
|
|
6182
|
+
});
|
|
5627
6183
|
it('uses an explicit cloud sign-out redirect and broader cloud logout reset path', () => {
|
|
5628
6184
|
const standaloneLayoutSource = fs.readFileSync(path.join(__dirname, 'components/views/StandaloneLayout.tsx'), 'utf8');
|
|
5629
6185
|
const useTaskforceSource = fs.readFileSync(path.join(__dirname, 'hooks/useTaskforce.ts'), 'utf8');
|
|
@@ -5947,9 +6503,9 @@ describe('TaskforceCore Integration', () => {
|
|
|
5947
6503
|
occurredAt: '2026-03-15T14:28:17.000Z',
|
|
5948
6504
|
eventType: 'apply',
|
|
5949
6505
|
status: 'error',
|
|
5950
|
-
errorMessage: 'Detected
|
|
6506
|
+
errorMessage: 'Detected task reference number mismatch during normal sync.',
|
|
5951
6507
|
details: {
|
|
5952
|
-
|
|
6508
|
+
taskId: 'task-1',
|
|
5953
6509
|
existingReferenceNumber: 12,
|
|
5954
6510
|
incomingReferenceNumber: 18
|
|
5955
6511
|
}
|
|
@@ -7183,6 +7739,7 @@ describe('TaskforceCore Integration', () => {
|
|
|
7183
7739
|
const user = userEvent.setup();
|
|
7184
7740
|
let savedDisplayName = 'Original Name';
|
|
7185
7741
|
let savedAvatarUrl = '';
|
|
7742
|
+
const cloudAuthBaseUrl = 'https://performance-app.taskforcehq.ai';
|
|
7186
7743
|
const fetchMock = vi.fn((input, init) => {
|
|
7187
7744
|
const url = String(input);
|
|
7188
7745
|
if (url.includes('/api/taskforce/auth/runtime-config')) {
|
|
@@ -7222,6 +7779,9 @@ describe('TaskforceCore Integration', () => {
|
|
|
7222
7779
|
...mockConfig,
|
|
7223
7780
|
runtimeMode: 'local',
|
|
7224
7781
|
authRequiredForApi: false,
|
|
7782
|
+
apiBaseUrl: cloudAuthBaseUrl,
|
|
7783
|
+
cloudAuthBaseUrl,
|
|
7784
|
+
cloudAuthViaLocalProxy: true,
|
|
7225
7785
|
workspaceId: 'workspace-local-active',
|
|
7226
7786
|
setupState: {
|
|
7227
7787
|
globalSetupState: 'present',
|
|
@@ -7257,13 +7817,12 @@ describe('TaskforceCore Integration', () => {
|
|
|
7257
7817
|
return jsonResponse({
|
|
7258
7818
|
success: true,
|
|
7259
7819
|
draftId: 'avatar-draft-1',
|
|
7260
|
-
uploadUrl: 'https://upload.example.com/avatar-draft-1',
|
|
7261
7820
|
relativePath: 'users/user-1/profile/avatar/avatar-draft-1-avatar.png',
|
|
7262
7821
|
path: '/api/taskforce/context/users%2Fuser-1%2Fprofile%2Favatar%2Favatar-draft-1-avatar.png'
|
|
7263
7822
|
});
|
|
7264
7823
|
}
|
|
7265
|
-
if (url.includes('
|
|
7266
|
-
return
|
|
7824
|
+
if (url.includes('/api/taskforce/auth/profile/avatar/upload')) {
|
|
7825
|
+
return jsonResponse({ success: true, draftId: 'avatar-draft-1' });
|
|
7267
7826
|
}
|
|
7268
7827
|
if (url.includes('/api/taskforce/auth/profile/avatar/finalize')) {
|
|
7269
7828
|
return jsonResponse({
|
|
@@ -7304,8 +7863,21 @@ describe('TaskforceCore Integration', () => {
|
|
|
7304
7863
|
const displayNameInput = within(modal).getByPlaceholderText('Display name');
|
|
7305
7864
|
await user.clear(displayNameInput);
|
|
7306
7865
|
await user.type(displayNameInput, 'Updated Name');
|
|
7307
|
-
const
|
|
7866
|
+
const getContextSpy = vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue({
|
|
7867
|
+
drawImage: () => undefined
|
|
7868
|
+
});
|
|
7869
|
+
const toBlobSpy = vi.spyOn(HTMLCanvasElement.prototype, 'toBlob').mockImplementation(function toBlob(callback, type) {
|
|
7870
|
+
callback(new Blob([new Uint8Array([1, 2, 3, 4])], { type: type || 'image/webp' }));
|
|
7871
|
+
});
|
|
7872
|
+
await user.click(within(modal).getByLabelText('Edit profile photo'));
|
|
7873
|
+
const avatarManager = await screen.findByText('Edit Profile Photo');
|
|
7874
|
+
const avatarManagerModal = avatarManager.closest(`.${modalStyles.modal}`);
|
|
7875
|
+
const avatarInput = within(avatarManagerModal).getByLabelText('Choose profile photo');
|
|
7308
7876
|
await user.upload(avatarInput, new File(['avatar'], 'avatar.png', { type: 'image/png' }));
|
|
7877
|
+
await user.click(within(avatarManagerModal).getByRole('button', { name: 'Apply Photo' }));
|
|
7878
|
+
await waitFor(() => {
|
|
7879
|
+
expect(screen.queryByText('Edit Profile Photo')).not.toBeInTheDocument();
|
|
7880
|
+
});
|
|
7309
7881
|
await user.click(within(modal).getByRole('button', { name: 'Save Profile' }));
|
|
7310
7882
|
await waitFor(() => {
|
|
7311
7883
|
const profileCall = fetchMock.mock.calls.find((call) => {
|
|
@@ -7317,6 +7889,17 @@ describe('TaskforceCore Integration', () => {
|
|
|
7317
7889
|
expect(payload.displayName).toBe('Updated Name');
|
|
7318
7890
|
expect(payload.avatarDraftId).toBe('avatar-draft-1');
|
|
7319
7891
|
});
|
|
7892
|
+
expect(fetchMock).toHaveBeenCalledWith('/api/taskforce/auth/profile/avatar/init', expect.objectContaining({ method: 'POST' }));
|
|
7893
|
+
const avatarUploadCall = fetchMock.mock.calls.find((call) => String(call[0]) === '/api/taskforce/auth/profile/avatar/upload');
|
|
7894
|
+
expect(avatarUploadCall).toBeTruthy();
|
|
7895
|
+
expect(avatarUploadCall?.[1]).toEqual(expect.objectContaining({ method: 'POST' }));
|
|
7896
|
+
const avatarUploadHeaders = new Headers(avatarUploadCall?.[1]?.headers);
|
|
7897
|
+
expect(avatarUploadHeaders.get('Content-Type')).toBe('image/webp');
|
|
7898
|
+
expect(avatarUploadHeaders.get('x-taskforce-avatar-draft-id')).toBe('avatar-draft-1');
|
|
7899
|
+
expect(fetchMock).toHaveBeenCalledWith('/api/taskforce/auth/profile/avatar/finalize', expect.objectContaining({ method: 'POST' }));
|
|
7900
|
+
expect(fetchMock.mock.calls.some((call) => String(call[0]).startsWith(`${cloudAuthBaseUrl}/api/taskforce/auth/profile/avatar/`))).toBe(false);
|
|
7901
|
+
getContextSpy.mockRestore();
|
|
7902
|
+
toBlobSpy.mockRestore();
|
|
7320
7903
|
await waitFor(() => {
|
|
7321
7904
|
expect(screen.queryByText('Edit Profile')).not.toBeInTheDocument();
|
|
7322
7905
|
});
|