@taskforcehq/taskforce 0.3.327 → 0.3.329
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Taskforce.module.css +257 -87
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/activity/EntityActivityTimeline.js +15 -5
- package/dist/components/context/AttachmentPreviewHost.js +1 -1
- package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
- package/dist/components/context/ContextAttachmentManager.js +116 -20
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +147 -40
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
- package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
- package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
- package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
- package/dist/components/features/planning/PlanningModule.js +28 -14
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
- package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +2 -2
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +101 -13
- package/dist/components/task/TaskContextUpload.d.ts +3 -0
- package/dist/components/task/TaskContextUpload.js +2 -2
- package/dist/components/task/TaskForm.d.ts +4 -0
- package/dist/components/task/TaskForm.js +32 -7
- package/dist/components/task/TaskImageReviews.js +28 -19
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/task/TaskStatusActions.js +11 -2
- package/dist/components/task/TaskWorkstreamPicker.js +2 -1
- package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
- package/dist/components/ui/DocumentTypeIcon.js +8 -0
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
- package/dist/components/ui/TaxonomyDropdown.js +30 -3
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +68 -39
- package/dist/components/views/WidgetView.js +10 -7
- package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
- package/dist/components/views/panels/PlanningDrawer.js +51 -54
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +13 -0
- package/dist/config/localServiceCloudTarget.d.ts +10 -0
- package/dist/config/localServiceCloudTarget.js +76 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.d.ts +1 -0
- package/dist/core/AiProfileService.js +48 -9
- package/dist/core/AttachmentLinkService.js +7 -4
- package/dist/core/DeletedTaskLifecycleService.d.ts +5 -0
- package/dist/core/DeletedTaskLifecycleService.js +55 -3
- package/dist/core/McpTokenService.d.ts +4 -0
- package/dist/core/McpTokenService.js +52 -0
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +8 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +51 -18
- package/dist/core/Taskforce.d.ts +124 -2
- package/dist/core/Taskforce.js +1175 -87
- package/dist/core/types.d.ts +8 -1
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
- package/dist/documentReviews/service.d.ts +4 -0
- package/dist/documentReviews/service.js +141 -46
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +9 -0
- package/dist/hooks/tasks/useTaskFormActions.js +96 -17
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useTaskData.d.ts +10 -1
- package/dist/hooks/useTaskData.js +216 -7
- package/dist/hooks/useTaskMutations.d.ts +10 -2
- package/dist/hooks/useTaskMutations.js +223 -43
- package/dist/hooks/useTaskforce.d.ts +94 -57
- package/dist/hooks/useTaskforce.js +428 -16
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/canonicalAssetHelpers.d.ts +13 -0
- package/dist/mcp/canonicalAssetHelpers.js +39 -5
- package/dist/mcp/collaborationRegistrar.js +15 -13
- package/dist/mcp/documentAssetRegistrar.js +60 -44
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/localServiceProxy.js +4 -1
- package/dist/mcp/runtime.d.ts +16 -0
- package/dist/mcp/runtime.js +735 -210
- package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
- package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
- package/dist/mcp/taskPlanningRegistrar.js +78 -67
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +2 -2
- package/dist/migrations/taskSchemaMigrations.js +47 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +12 -13
- package/dist/runtime/appGates.js +29 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/appAccess.d.ts +12 -0
- package/dist/server/appAccess.js +21 -0
- package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
- package/dist/server/authorizedWorkspaceAccess.js +40 -0
- package/dist/server/cloudCollectionRead.d.ts +25 -0
- package/dist/server/cloudCollectionRead.js +120 -0
- package/dist/server/cloudCollectionReadPool.d.ts +52 -0
- package/dist/server/cloudCollectionReadPool.js +140 -0
- package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
- package/dist/server/cloudCollectionReadWorker.js +36 -0
- package/dist/server/index.d.ts +6 -11
- package/dist/server/index.js +67 -42
- package/dist/server/localServiceLease.d.ts +6 -0
- package/dist/server/localServiceLease.js +17 -1
- package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.js +1 -0
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.js +118 -16
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/documents.d.ts +5 -2
- package/dist/server/routes/documents.js +160 -13
- package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
- package/dist/server/routes/durableTaskHttpRouters.js +2 -2
- package/dist/server/routes/localService.js +4 -0
- package/dist/server/routes/primitives.d.ts +4 -0
- package/dist/server/routes/shared.d.ts +24 -0
- package/dist/server/routes/shared.js +114 -18
- package/dist/server/routes/sync.js +22 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +22 -18
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +48 -4
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +27 -2
- package/dist/server/routes/tasks.js +299 -97
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/routes.js +35 -7
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +52 -25
- package/dist/service/localServiceClientLifecycle.js +93 -6
- package/dist/services/codexAppServerModelGateway.d.ts +112 -0
- package/dist/services/codexAppServerModelGateway.js +438 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
- package/dist/services/taskforceAgentMcpBridge.js +23 -3
- package/dist/shared/planningIdentity.d.ts +20 -0
- package/dist/shared/planningIdentity.js +79 -0
- package/dist/shared/taskforceAgentDefinition.js +7 -1
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +30 -1
- package/dist/storage/postgresAdapter.d.ts +20 -3
- package/dist/storage/postgresAdapter.js +110 -14
- package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
- package/dist/storage/postgresRequestDiagnostics.js +24 -0
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/storage/workspaceAssetStore.d.ts +32 -0
- package/dist/storage/workspaceAssetStore.js +70 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +17 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +77 -23
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +16 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +46 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +51 -11
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
- package/dist/sync/syncApplyHandlers.d.ts +3 -1
- package/dist/sync/syncApplyHandlers.js +29 -0
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/taskSyncPayload.d.ts +1 -0
- package/dist/sync/taskSyncPayload.js +6 -0
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +3 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +31 -3
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +47 -12
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
- package/dist/sync/v3/localOutboxDispatcher.js +5 -1
- package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +3 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +62 -10
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
- package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
- package/dist/sync/v3/syncDurabilityStore.d.ts +15 -0
- package/dist/sync/v3/syncDurabilityStore.js +201 -43
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +7 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +37 -12
- package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
- package/dist/sync/v3/taskChecklistMutationService.js +4 -0
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
- package/dist/sync/v3/taskStatusMutationService.js +4 -0
- package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
- package/dist/sync/v3/workflowAssignmentSync.js +3 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +14 -12
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +10 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +15 -4
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +66 -13
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +57 -22
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +10 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -51
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +120 -28
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -0
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
- package/dist/sync/workspacePullFeed.d.ts +6 -1
- package/dist/sync/workspacePullFeed.js +174 -162
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/sync/workspaceSyncModel.d.ts +11 -0
- package/dist/sync/workspaceSyncModel.js +27 -2
- package/dist/types.d.ts +55 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/AssetTraySortControl-C8Rztyal.js +1 -0
- package/dist/ui/assets/ContextAttachmentManager-Cj3c7X9y.js +3 -0
- package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-B5uvzems.js} +4 -4
- package/dist/ui/assets/EntityActivityTimeline-BVFvCB5R.js +1 -0
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/WorkflowManagerModule-DEr5di_r.js +1 -0
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.js +1 -1
- package/dist/utils/contextAttachmentUpload.d.ts +2 -0
- package/dist/utils/contextAttachmentUpload.js +7 -0
- package/dist/utils/contextFiles.d.ts +1 -1
- package/dist/utils/contextFiles.js +4 -4
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/package.json +21 -4
- package/dist/ui/assets/AiProfilesModule-DPxQeF9N.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DHNYaNg6.js +0 -3
- package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
- package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
- package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
- package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
- package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
- package/dist/ui/assets/PlansPage-BVH_NfgT.js +0 -1
- package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
- package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
- package/dist/ui/assets/TaskSettings-xVsxSa0g.js +0 -12
- package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
- package/dist/ui/assets/index-BzJlVnNS.css +0 -1
- package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
|
@@ -29,8 +29,9 @@ import { normalizeTaskSearchQuery, taskMatchesSearch } from '../utils/taskSearch
|
|
|
29
29
|
import { compareTasksBySortKey } from '../utils/taxonomySorting.js';
|
|
30
30
|
import { getFilterVisibleTaxonomyOptions } from '../utils/taxonomyFilterOptions.js';
|
|
31
31
|
import { getVisibleTaxonomiesForTasks } from '../utils/taxonomyLifecycle.js';
|
|
32
|
+
import { useCloudTaskSearch } from './tasks/useCloudTaskSearch';
|
|
32
33
|
// === SECTION: Filter State ===
|
|
33
|
-
export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTypes, priorities, taxonomies, configLoaded, referenceDataLoaded, assigneeOptionsLoaded, assigneeOptions }) {
|
|
34
|
+
export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTypes, priorities, taxonomies, configLoaded, referenceDataLoaded, assigneeOptionsLoaded, assigneeOptions, runtimeMode = 'local', workspaceId = '', cloudTaskSearchEnabled = false, cloudTaskSearchScope = 'active', }) {
|
|
34
35
|
const relationshipTasks = useMemo(() => [...tasks, ...archivedTasks], [archivedTasks, tasks]);
|
|
35
36
|
const resolvedAssigneeOptions = useMemo(() => normalizeAssigneeOptions(assigneeOptions), [assigneeOptions]);
|
|
36
37
|
const filterableTaxonomies = useMemo(() => getVisibleTaxonomiesForTasks(taxonomies, relationshipTasks)
|
|
@@ -42,6 +43,13 @@ export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTy
|
|
|
42
43
|
const filterableTaxonomyById = useMemo(() => new Map(filterableTaxonomies.map((taxonomy) => [taxonomy.id, taxonomy])), [filterableTaxonomies]);
|
|
43
44
|
const assigneeFilterValues = useMemo(() => resolvedAssigneeOptions.map((opt) => opt.value), [resolvedAssigneeOptions]);
|
|
44
45
|
const [searchQuery, setSearchQuery] = useState('');
|
|
46
|
+
const cloudSearchMatchIds = useCloudTaskSearch({
|
|
47
|
+
query: searchQuery,
|
|
48
|
+
runtimeMode,
|
|
49
|
+
workspaceId,
|
|
50
|
+
enabled: cloudTaskSearchEnabled,
|
|
51
|
+
scope: cloudTaskSearchScope,
|
|
52
|
+
});
|
|
45
53
|
const [filterCategories, setFilterCategories] = useState([]);
|
|
46
54
|
const [filterPriorities, setFilterPriorities] = useState([]);
|
|
47
55
|
const [filterTypes, setFilterTypes] = useState([]);
|
|
@@ -229,7 +237,8 @@ export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTy
|
|
|
229
237
|
const isAllPrioritiesSelected = isAllFilterValuesSelected(Array.from(new Set(filterPriorities.map((value) => Number(value)).filter((value) => Number.isFinite(value)))), priorities.map((priority) => Number(priority.value)).filter((value) => Number.isFinite(value)));
|
|
230
238
|
const isAllStatusesSelected = isAllFilterValuesSelected(filterStatus, STATUS_OPTIONS.map((status) => status.value));
|
|
231
239
|
return tasks.filter(t => {
|
|
232
|
-
const matchSearch = taskMatchesSearch(t, normalizedSearchQuery, taskSearchContext)
|
|
240
|
+
const matchSearch = taskMatchesSearch(t, normalizedSearchQuery, taskSearchContext)
|
|
241
|
+
|| (Boolean(normalizedSearchQuery.raw) && cloudSearchMatchIds.has(t.id));
|
|
233
242
|
const matchCategory = !hasInitedFilters || isAllCategoriesSelected || filterCategories.includes(t.category);
|
|
234
243
|
const matchPriority = !hasInitedFilters || isAllPrioritiesSelected || matchesPriorityFilter(t.priority, filterPriorities);
|
|
235
244
|
const matchType = !hasInitedFilters || isAllTypesSelected || filterTypes.includes(t.type || DEFAULT_TYPE_VALUE);
|
|
@@ -253,7 +262,7 @@ export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTy
|
|
|
253
262
|
});
|
|
254
263
|
return matchSearch && matchCategory && matchPriority && matchType && matchStatus && matchAssignee && matchTaxonomies;
|
|
255
264
|
}).sort((a, b) => compareTasksBySortKey(a, b, sortBy, sortOrder, taxonomies));
|
|
256
|
-
}, [tasks, normalizedSearchQuery, taskSearchContext, filterCategories, filterPriorities, filterTypes, filterStatus, filterAssignees, filterAssigneesAllSelected, filterTaxonomies, sortBy, sortOrder, hasInitedFilters, filterableTaxonomies, filterableTaxonomyById, activeCategories, activeTypes, priorities, isAllFilterValuesSelected, taxonomies]);
|
|
265
|
+
}, [tasks, normalizedSearchQuery, taskSearchContext, cloudSearchMatchIds, filterCategories, filterPriorities, filterTypes, filterStatus, filterAssignees, filterAssigneesAllSelected, filterTaxonomies, sortBy, sortOrder, hasInitedFilters, filterableTaxonomies, filterableTaxonomyById, activeCategories, activeTypes, priorities, isAllFilterValuesSelected, taxonomies]);
|
|
257
266
|
const searchAgnosticTasks = useMemo(() => {
|
|
258
267
|
const isAllCategoriesSelected = isAllFilterValuesSelected(filterCategories, activeCategories.map((category) => category.value));
|
|
259
268
|
const isAllTypesSelected = isAllFilterValuesSelected(filterTypes, activeTypes.map((type) => type.value));
|
|
@@ -288,7 +297,8 @@ export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTy
|
|
|
288
297
|
const isAllTypesSelected = isAllFilterValuesSelected(filterTypes, activeTypes.map((type) => type.value));
|
|
289
298
|
const isAllPrioritiesSelected = isAllFilterValuesSelected(Array.from(new Set(filterPriorities.map((value) => Number(value)).filter((value) => Number.isFinite(value)))), priorities.map((priority) => Number(priority.value)).filter((value) => Number.isFinite(value)));
|
|
290
299
|
return archivedTasks.filter(t => {
|
|
291
|
-
const matchSearch = taskMatchesSearch(t, normalizedSearchQuery, taskSearchContext)
|
|
300
|
+
const matchSearch = taskMatchesSearch(t, normalizedSearchQuery, taskSearchContext)
|
|
301
|
+
|| (Boolean(normalizedSearchQuery.raw) && cloudSearchMatchIds.has(t.id));
|
|
292
302
|
const matchCategory = !hasInitedFilters || isAllCategoriesSelected || filterCategories.includes(t.category);
|
|
293
303
|
const matchPriority = !hasInitedFilters || isAllPrioritiesSelected || matchesPriorityFilter(t.priority, filterPriorities);
|
|
294
304
|
const matchType = !hasInitedFilters || isAllTypesSelected || filterTypes.includes(t.type || DEFAULT_TYPE_VALUE);
|
|
@@ -310,7 +320,7 @@ export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTy
|
|
|
310
320
|
});
|
|
311
321
|
return matchSearch && matchCategory && matchPriority && matchType && matchAssignee && matchTaxonomies;
|
|
312
322
|
}).sort((a, b) => compareTasksBySortKey(a, b, sortBy, sortOrder, taxonomies));
|
|
313
|
-
}, [archivedTasks, normalizedSearchQuery, taskSearchContext, filterCategories, filterPriorities, filterTypes, filterAssignees, filterAssigneesAllSelected, filterTaxonomies, sortBy, sortOrder, hasInitedFilters, activeCategories, activeTypes, priorities, filterableTaxonomies, filterableTaxonomyById, isAllFilterValuesSelected, taxonomies]);
|
|
323
|
+
}, [archivedTasks, normalizedSearchQuery, taskSearchContext, cloudSearchMatchIds, filterCategories, filterPriorities, filterTypes, filterAssignees, filterAssigneesAllSelected, filterTaxonomies, sortBy, sortOrder, hasInitedFilters, activeCategories, activeTypes, priorities, filterableTaxonomies, filterableTaxonomyById, isAllFilterValuesSelected, taxonomies]);
|
|
314
324
|
const groupedTasks = useMemo(() => {
|
|
315
325
|
const groups = {};
|
|
316
326
|
filteredTasks.forEach(task => {
|
|
@@ -12,10 +12,14 @@ interface UseTaskDataProps {
|
|
|
12
12
|
handleUnauthorized: () => void;
|
|
13
13
|
/** Only used to detect auth changes in the fetch dependency array */
|
|
14
14
|
authRequiredForApi: boolean;
|
|
15
|
+
setError?: (value: string) => void;
|
|
16
|
+
setLoading?: (value: boolean) => void;
|
|
15
17
|
}
|
|
16
|
-
export declare function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks, setLoadingTasks, getCurrentWorkspaceId, workspaceResetKey, shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, handleUnauthorized, authRequiredForApi }: UseTaskDataProps): {
|
|
18
|
+
export declare function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks, setLoadingTasks, getCurrentWorkspaceId, workspaceResetKey, shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, handleUnauthorized, authRequiredForApi, setError, setLoading }: UseTaskDataProps): {
|
|
17
19
|
tasksRef: import("react").RefObject<TaskItem[]>;
|
|
18
20
|
archivedTasksRef: import("react").RefObject<TaskItem[]>;
|
|
21
|
+
taskDetails: TaskItem[];
|
|
22
|
+
staleTaskDetailRevisions: Record<string, string>;
|
|
19
23
|
recentlyChangedTaskIds: string[];
|
|
20
24
|
markRecentlyChangedTasks: (taskIds: string[]) => void;
|
|
21
25
|
fetchTasks: (isSilent?: boolean, options?: {
|
|
@@ -26,6 +30,11 @@ export declare function useTaskData({ tasks, archivedTasks, setTasks, setArchive
|
|
|
26
30
|
fetchArchive: (isSilent?: boolean, options?: {
|
|
27
31
|
ignoreAuthGuard?: boolean;
|
|
28
32
|
}) => Promise<boolean>;
|
|
33
|
+
loadTaskDetail: (task: TaskItem, options?: {
|
|
34
|
+
shouldCommit?: () => boolean;
|
|
35
|
+
force?: boolean;
|
|
36
|
+
}) => Promise<TaskItem | null>;
|
|
37
|
+
cancelTaskDetailLoad: () => void;
|
|
29
38
|
refreshTaskCollections: (options?: {
|
|
30
39
|
isSilent?: boolean;
|
|
31
40
|
ignoreAuthGuard?: boolean;
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
* - getTaskRevisionKey(task) — stable revision string for change detection
|
|
24
24
|
*/
|
|
25
25
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
26
|
-
import { getTaskContentRevision, mergeNormalizedTaskIntoCollections, normalizeTaskFromApi, reconcileTaskCollection } from '../utils/taskNormalization.js';
|
|
26
|
+
import { getTaskContentRevision, mergeNormalizedTaskIntoCollections, normalizeTaskFromApi, reconcileTaskCollection, toTaskCollectionSummary } from '../utils/taskNormalization.js';
|
|
27
27
|
import { resolveTaskReferenceId } from '../utils/taskReferences.js';
|
|
28
|
-
export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks, setLoadingTasks, getCurrentWorkspaceId, workspaceResetKey, shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, handleUnauthorized, authRequiredForApi }) {
|
|
28
|
+
export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks, setLoadingTasks, getCurrentWorkspaceId, workspaceResetKey, shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, handleUnauthorized, authRequiredForApi, setError, setLoading }) {
|
|
29
29
|
// === SECTION: Revision Tracking ===
|
|
30
30
|
const taskRevisionMapRef = useRef(new Map());
|
|
31
31
|
const hasFetchedTasksRef = useRef(false);
|
|
@@ -34,6 +34,21 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
34
34
|
const archivedTasksRef = useRef(archivedTasks);
|
|
35
35
|
const tasksAbortRef = useRef(null);
|
|
36
36
|
const archiveAbortRef = useRef(null);
|
|
37
|
+
const taskDetailAbortRef = useRef(null);
|
|
38
|
+
const taskDetailCacheRef = useRef(new Map());
|
|
39
|
+
const [taskDetails, setTaskDetails] = useState([]);
|
|
40
|
+
const [staleTaskDetailRevisions, setStaleTaskDetailRevisions] = useState({});
|
|
41
|
+
const getTaskSummaryRevision = useCallback((task) => (String(task.detailRevision || JSON.stringify([
|
|
42
|
+
task.updatedAt || task.createdAt || '',
|
|
43
|
+
task.commentCount || 0,
|
|
44
|
+
task.checklistCount || 0,
|
|
45
|
+
task.completedChecklistCount || 0,
|
|
46
|
+
task.attachmentCount || 0,
|
|
47
|
+
task.relationshipCount || 0,
|
|
48
|
+
]))), []);
|
|
49
|
+
const publishTaskDetailCache = useCallback(() => {
|
|
50
|
+
setTaskDetails(Array.from(taskDetailCacheRef.current.values(), (entry) => entry.detail));
|
|
51
|
+
}, []);
|
|
37
52
|
useEffect(() => {
|
|
38
53
|
tasksRef.current = tasks;
|
|
39
54
|
}, [tasks]);
|
|
@@ -87,12 +102,68 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
87
102
|
tasksAbortRef.current = null;
|
|
88
103
|
archiveAbortRef.current?.abort('workspace-reset');
|
|
89
104
|
archiveAbortRef.current = null;
|
|
105
|
+
const hadPendingTaskDetail = taskDetailAbortRef.current !== null;
|
|
106
|
+
taskDetailAbortRef.current?.abort('workspace-reset');
|
|
107
|
+
taskDetailAbortRef.current = null;
|
|
108
|
+
if (hadPendingTaskDetail)
|
|
109
|
+
setLoading?.(false);
|
|
110
|
+
taskDetailCacheRef.current = new Map();
|
|
111
|
+
setTaskDetails([]);
|
|
112
|
+
setStaleTaskDetailRevisions({});
|
|
90
113
|
if (typeof window !== 'undefined') {
|
|
91
114
|
highlightTimersRef.current.forEach((timerId) => window.clearTimeout(timerId));
|
|
92
115
|
highlightTimersRef.current.clear();
|
|
93
116
|
}
|
|
94
117
|
setRecentlyChangedTaskIds([]);
|
|
95
|
-
}, [workspaceResetKey]);
|
|
118
|
+
}, [setLoading, workspaceResetKey]);
|
|
119
|
+
useEffect(() => () => {
|
|
120
|
+
taskDetailAbortRef.current?.abort('unmount');
|
|
121
|
+
}, []);
|
|
122
|
+
const reconcileTaskDetailCache = useCallback((summaries, archived) => {
|
|
123
|
+
const summaryById = new Map(summaries.map((task) => [task.id, task]));
|
|
124
|
+
let changed = false;
|
|
125
|
+
const next = new Map(taskDetailCacheRef.current);
|
|
126
|
+
const nextStaleRevisions = {};
|
|
127
|
+
const reconciledTaskIds = new Set();
|
|
128
|
+
for (const [taskId, cached] of next) {
|
|
129
|
+
const summary = summaryById.get(taskId);
|
|
130
|
+
const belongsToCollection = Boolean(cached.detail.isArchived) === archived;
|
|
131
|
+
if (belongsToCollection)
|
|
132
|
+
reconciledTaskIds.add(taskId);
|
|
133
|
+
if (!summary && belongsToCollection) {
|
|
134
|
+
next.delete(taskId);
|
|
135
|
+
changed = true;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (summary) {
|
|
139
|
+
const summaryRevision = getTaskSummaryRevision(summary);
|
|
140
|
+
if (summaryRevision !== cached.summaryRevision) {
|
|
141
|
+
nextStaleRevisions[taskId] = summaryRevision;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
setStaleTaskDetailRevisions((current) => {
|
|
146
|
+
const retained = Object.fromEntries(Object.entries(current).filter(([taskId]) => (!reconciledTaskIds.has(taskId))));
|
|
147
|
+
const combined = { ...retained, ...nextStaleRevisions };
|
|
148
|
+
const currentEntries = Object.entries(current);
|
|
149
|
+
const combinedEntries = Object.entries(combined);
|
|
150
|
+
return currentEntries.length === combinedEntries.length
|
|
151
|
+
&& currentEntries.every(([taskId, revision]) => combined[taskId] === revision)
|
|
152
|
+
? current
|
|
153
|
+
: combined;
|
|
154
|
+
});
|
|
155
|
+
if (changed) {
|
|
156
|
+
taskDetailCacheRef.current = next;
|
|
157
|
+
publishTaskDetailCache();
|
|
158
|
+
}
|
|
159
|
+
}, [getTaskSummaryRevision, publishTaskDetailCache]);
|
|
160
|
+
const cancelTaskDetailLoad = useCallback(() => {
|
|
161
|
+
const hadPendingTaskDetail = taskDetailAbortRef.current !== null;
|
|
162
|
+
taskDetailAbortRef.current?.abort('navigation');
|
|
163
|
+
taskDetailAbortRef.current = null;
|
|
164
|
+
if (hadPendingTaskDetail)
|
|
165
|
+
setLoading?.(false);
|
|
166
|
+
}, [setLoading]);
|
|
96
167
|
// === SECTION: Fetch Functions ===
|
|
97
168
|
const fetchTasks = useCallback(async (isSilent = false, options) => {
|
|
98
169
|
const ignoreAuthGuard = options?.ignoreAuthGuard === true;
|
|
@@ -126,6 +197,7 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
126
197
|
if (liveWorkspaceId !== requestWorkspaceId) {
|
|
127
198
|
return;
|
|
128
199
|
}
|
|
200
|
+
reconcileTaskDetailCache(sanitized, false);
|
|
129
201
|
const nextRevisionMap = new Map();
|
|
130
202
|
const changedTaskIds = [];
|
|
131
203
|
const highlightChangedTaskIds = options?.highlightChangedTaskIds === undefined
|
|
@@ -178,7 +250,8 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
178
250
|
setLoadingTasks,
|
|
179
251
|
authRequiredForApi,
|
|
180
252
|
shouldDeferProtectedApiCalls,
|
|
181
|
-
shouldBlockProtectedApiCalls
|
|
253
|
+
shouldBlockProtectedApiCalls,
|
|
254
|
+
reconcileTaskDetailCache
|
|
182
255
|
]);
|
|
183
256
|
const fetchArchive = useCallback(async (isSilent = false, options) => {
|
|
184
257
|
const ignoreAuthGuard = options?.ignoreAuthGuard === true;
|
|
@@ -202,6 +275,7 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
202
275
|
...normalizeTaskFromApi(t),
|
|
203
276
|
isArchived: true
|
|
204
277
|
}));
|
|
278
|
+
reconcileTaskDetailCache(sanitized, true);
|
|
205
279
|
const previousArchivedTasks = archivedTasksRef.current;
|
|
206
280
|
const reconciledArchivedTasks = reconcileTaskCollection(previousArchivedTasks, sanitized);
|
|
207
281
|
archivedTasksRef.current = reconciledArchivedTasks;
|
|
@@ -225,7 +299,109 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
225
299
|
setLoadingTasks(false);
|
|
226
300
|
}
|
|
227
301
|
}
|
|
228
|
-
}, [getCurrentWorkspaceId, isExpectedAbortFailure, setArchivedTasks, setLoadingTasks, shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls]);
|
|
302
|
+
}, [getCurrentWorkspaceId, isExpectedAbortFailure, reconcileTaskDetailCache, setArchivedTasks, setLoadingTasks, shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls]);
|
|
303
|
+
const loadTaskDetail = useCallback(async (task, options) => {
|
|
304
|
+
const force = options?.force === true;
|
|
305
|
+
if (!force && !task.isSummary) {
|
|
306
|
+
const summary = toTaskCollectionSummary(task);
|
|
307
|
+
taskDetailCacheRef.current.set(task.id, { detail: task, summaryRevision: getTaskSummaryRevision(summary) });
|
|
308
|
+
setStaleTaskDetailRevisions((current) => {
|
|
309
|
+
if (!Object.prototype.hasOwnProperty.call(current, task.id))
|
|
310
|
+
return current;
|
|
311
|
+
const next = { ...current };
|
|
312
|
+
delete next[task.id];
|
|
313
|
+
return next;
|
|
314
|
+
});
|
|
315
|
+
publishTaskDetailCache();
|
|
316
|
+
return task;
|
|
317
|
+
}
|
|
318
|
+
const cached = taskDetailCacheRef.current.get(task.id);
|
|
319
|
+
let requestedSummary = task;
|
|
320
|
+
let summaryRevision = getTaskSummaryRevision(requestedSummary);
|
|
321
|
+
if (!force && cached && cached.summaryRevision === summaryRevision)
|
|
322
|
+
return cached.detail;
|
|
323
|
+
const requestWorkspaceId = String(getCurrentWorkspaceId() || '').trim();
|
|
324
|
+
taskDetailAbortRef.current?.abort('superseded');
|
|
325
|
+
const abortController = new AbortController();
|
|
326
|
+
taskDetailAbortRef.current = abortController;
|
|
327
|
+
setLoading?.(true);
|
|
328
|
+
setError?.('');
|
|
329
|
+
try {
|
|
330
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
331
|
+
const response = await fetch(`/api/taskforce/task/${encodeURIComponent(requestedSummary.id)}`, {
|
|
332
|
+
signal: abortController.signal,
|
|
333
|
+
});
|
|
334
|
+
if (response.status === 401) {
|
|
335
|
+
handleUnauthorized();
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
if (response.status === 404) {
|
|
339
|
+
setError?.('Task not found. It may have moved or been deleted.');
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
setError?.('Unable to load task details.');
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const normalizedDetail = normalizeTaskFromApi(await response.json());
|
|
347
|
+
const liveWorkspaceId = String(getCurrentWorkspaceId() || '').trim();
|
|
348
|
+
if (abortController.signal.aborted || liveWorkspaceId !== requestWorkspaceId)
|
|
349
|
+
return null;
|
|
350
|
+
const currentSummary = [...tasksRef.current, ...archivedTasksRef.current]
|
|
351
|
+
.find((candidate) => candidate.id === requestedSummary.id);
|
|
352
|
+
if (!currentSummary) {
|
|
353
|
+
setError?.('Task not found. It may have moved or been deleted.');
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
const currentRevision = getTaskSummaryRevision(currentSummary);
|
|
357
|
+
if (currentRevision !== summaryRevision) {
|
|
358
|
+
if (attempt === 0 && currentSummary) {
|
|
359
|
+
requestedSummary = currentSummary;
|
|
360
|
+
summaryRevision = currentRevision;
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
setError?.('Task details changed while loading. Please open the task again.');
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
if (requestedSummary.updatedAt
|
|
367
|
+
&& normalizedDetail.updatedAt
|
|
368
|
+
&& Date.parse(normalizedDetail.updatedAt) < Date.parse(requestedSummary.updatedAt)) {
|
|
369
|
+
setError?.('Task details changed while loading. Please open the task again.');
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
const detail = {
|
|
373
|
+
...normalizedDetail,
|
|
374
|
+
detailRevision: normalizedDetail.detailRevision || summaryRevision,
|
|
375
|
+
};
|
|
376
|
+
if (options?.shouldCommit && !options.shouldCommit())
|
|
377
|
+
return null;
|
|
378
|
+
taskDetailCacheRef.current.set(detail.id, { detail, summaryRevision });
|
|
379
|
+
setStaleTaskDetailRevisions((current) => {
|
|
380
|
+
if (!Object.prototype.hasOwnProperty.call(current, detail.id))
|
|
381
|
+
return current;
|
|
382
|
+
const next = { ...current };
|
|
383
|
+
delete next[detail.id];
|
|
384
|
+
return next;
|
|
385
|
+
});
|
|
386
|
+
publishTaskDetailCache();
|
|
387
|
+
return detail;
|
|
388
|
+
}
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
if (isExpectedAbortFailure(error, abortController.signal))
|
|
393
|
+
return null;
|
|
394
|
+
console.error('[Taskforce] Failed to fetch task detail:', error);
|
|
395
|
+
setError?.('Unable to load task details.');
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
if (taskDetailAbortRef.current === abortController) {
|
|
400
|
+
taskDetailAbortRef.current = null;
|
|
401
|
+
setLoading?.(false);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}, [getCurrentWorkspaceId, getTaskSummaryRevision, handleUnauthorized, isExpectedAbortFailure, publishTaskDetailCache, setError, setLoading]);
|
|
229
405
|
const refreshTaskCollections = useCallback(async (options) => {
|
|
230
406
|
const isSilent = options?.isSilent !== false;
|
|
231
407
|
const ignoreAuthGuard = options?.ignoreAuthGuard === true;
|
|
@@ -253,7 +429,36 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
253
429
|
}, [refreshTaskCollections]);
|
|
254
430
|
// === SECTION: Merge Helper ===
|
|
255
431
|
const mergeTaskFromServer = useCallback((task) => {
|
|
256
|
-
const
|
|
432
|
+
const normalized = normalizeTaskFromApi(task);
|
|
433
|
+
const existingSummary = [...tasksRef.current, ...archivedTasksRef.current]
|
|
434
|
+
.find((candidate) => candidate.id === normalized.id);
|
|
435
|
+
const collectionSummary = normalized.isSummary
|
|
436
|
+
? normalized
|
|
437
|
+
: toTaskCollectionSummary({
|
|
438
|
+
...normalized,
|
|
439
|
+
detailRevision: undefined,
|
|
440
|
+
commentCount: normalized.commentCount ?? (normalized.comments ? undefined : existingSummary?.commentCount),
|
|
441
|
+
checklistCount: normalized.checklistCount ?? (normalized.checklistItems ? undefined : existingSummary?.checklistCount),
|
|
442
|
+
completedChecklistCount: normalized.completedChecklistCount
|
|
443
|
+
?? (normalized.checklistItems ? undefined : existingSummary?.completedChecklistCount),
|
|
444
|
+
attachmentCount: normalized.attachmentCount ?? (normalized.attachments ? undefined : existingSummary?.attachmentCount),
|
|
445
|
+
relationshipCount: normalized.relationshipCount ?? existingSummary?.relationshipCount ?? 0,
|
|
446
|
+
});
|
|
447
|
+
if (!normalized.isSummary) {
|
|
448
|
+
taskDetailCacheRef.current.set(normalized.id, {
|
|
449
|
+
detail: normalized,
|
|
450
|
+
summaryRevision: getTaskSummaryRevision(collectionSummary),
|
|
451
|
+
});
|
|
452
|
+
publishTaskDetailCache();
|
|
453
|
+
setStaleTaskDetailRevisions((current) => {
|
|
454
|
+
if (!Object.prototype.hasOwnProperty.call(current, normalized.id))
|
|
455
|
+
return current;
|
|
456
|
+
const next = { ...current };
|
|
457
|
+
delete next[normalized.id];
|
|
458
|
+
return next;
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
const merged = mergeNormalizedTaskIntoCollections(collectionSummary, tasksRef.current, archivedTasksRef.current);
|
|
257
462
|
const tasksChanged = merged.tasks !== tasksRef.current;
|
|
258
463
|
const archivedTasksChanged = merged.archivedTasks !== archivedTasksRef.current;
|
|
259
464
|
tasksRef.current = merged.tasks;
|
|
@@ -262,17 +467,21 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
|
|
|
262
467
|
setTasks(merged.tasks);
|
|
263
468
|
if (archivedTasksChanged)
|
|
264
469
|
setArchivedTasks(merged.archivedTasks);
|
|
265
|
-
}, [setTasks, setArchivedTasks]);
|
|
470
|
+
}, [getTaskSummaryRevision, publishTaskDetailCache, setTasks, setArchivedTasks]);
|
|
266
471
|
return {
|
|
267
472
|
// Stable refs (for use inside closures)
|
|
268
473
|
tasksRef,
|
|
269
474
|
archivedTasksRef,
|
|
475
|
+
taskDetails,
|
|
476
|
+
staleTaskDetailRevisions,
|
|
270
477
|
// Recently changed
|
|
271
478
|
recentlyChangedTaskIds,
|
|
272
479
|
markRecentlyChangedTasks,
|
|
273
480
|
// Fetch functions
|
|
274
481
|
fetchTasks,
|
|
275
482
|
fetchArchive,
|
|
483
|
+
loadTaskDetail,
|
|
484
|
+
cancelTaskDetailLoad,
|
|
276
485
|
refreshTaskCollections,
|
|
277
486
|
refreshTaskCollectionsFromInvalidation,
|
|
278
487
|
// Helpers
|
|
@@ -13,6 +13,7 @@ export interface UseTaskMutationsProps {
|
|
|
13
13
|
tasks: TaskItem[];
|
|
14
14
|
archivedTasks: TaskItem[];
|
|
15
15
|
editingTaskId: string | null;
|
|
16
|
+
editingTaskDetailRevision?: string | null;
|
|
16
17
|
setTasks: React.Dispatch<React.SetStateAction<TaskItem[]>>;
|
|
17
18
|
setArchivedTasks: React.Dispatch<React.SetStateAction<TaskItem[]>>;
|
|
18
19
|
setDeletedTasks: React.Dispatch<React.SetStateAction<DeletedTaskRecord[]>>;
|
|
@@ -44,6 +45,13 @@ export interface UseTaskMutationsProps {
|
|
|
44
45
|
durableTaskHttpRootActivationEnabled?: boolean;
|
|
45
46
|
workspaceId?: string;
|
|
46
47
|
taskHttpMutationClient?: ReturnType<typeof createCloudTaskHttpMutationClient>;
|
|
48
|
+
onTaskRevisionConflict?: (taskId: string, currentDetailRevision: string | null) => TaskRevisionConflictResolution | void | Promise<TaskRevisionConflictResolution | void>;
|
|
49
|
+
onTaskMutationAccepted?: (task: TaskItem) => void;
|
|
50
|
+
}
|
|
51
|
+
export interface TaskRevisionConflictResolution {
|
|
52
|
+
handled: boolean;
|
|
53
|
+
retryDetailRevision?: string;
|
|
54
|
+
retryPatch?: Partial<TaskItem>;
|
|
47
55
|
}
|
|
48
56
|
export interface DeletedTaskRestoreFailure {
|
|
49
57
|
deletedRecordId: string;
|
|
@@ -58,13 +66,13 @@ export interface DeletedTaskRestoreBatchResult {
|
|
|
58
66
|
succeeded: DeletedTaskRecord[];
|
|
59
67
|
failed: DeletedTaskRestoreFailure[];
|
|
60
68
|
}
|
|
61
|
-
export declare function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks, setArchivedTasks, setDeletedTasks, setError, resetForm, setActiveTab, fetchTasks, fetchArchive, fetchDeletedTasks, mergeTaskFromServer, pushNotice, cloudAuthConfigured, runtimeMode, isAuthenticated, workspaceCloudSyncEnabled, buildWorkspaceSyncSignature, pushWorkspaceChangesToCloud, workspacePendingSignatureRef, workspaceDeletedTaskIdsRef, workspaceDeletedTaskWatermarksRef, mutateTaskMetadata, mutateTaskStatus, mutateTaskLifecycle, mutateTaskDelete, mutateTaskRestore, durableTaskMetadataActivationEnabled, durableTaskStatusActivationEnabled, durableTaskDeleteActivationEnabled, durableTaskHttpRootActivationEnabled, workspaceId, taskHttpMutationClient, }: UseTaskMutationsProps): {
|
|
69
|
+
export declare function useTaskMutations({ tasks, archivedTasks, editingTaskId, editingTaskDetailRevision, setTasks, setArchivedTasks, setDeletedTasks, setError, resetForm, setActiveTab, fetchTasks, fetchArchive, fetchDeletedTasks, mergeTaskFromServer, pushNotice, cloudAuthConfigured, runtimeMode, isAuthenticated, workspaceCloudSyncEnabled, buildWorkspaceSyncSignature, pushWorkspaceChangesToCloud, workspacePendingSignatureRef, workspaceDeletedTaskIdsRef, workspaceDeletedTaskWatermarksRef, mutateTaskMetadata, mutateTaskStatus, mutateTaskLifecycle, mutateTaskDelete, mutateTaskRestore, durableTaskMetadataActivationEnabled, durableTaskStatusActivationEnabled, durableTaskDeleteActivationEnabled, durableTaskHttpRootActivationEnabled, workspaceId, taskHttpMutationClient, onTaskRevisionConflict, onTaskMutationAccepted, }: UseTaskMutationsProps): {
|
|
62
70
|
copiedId: string | null;
|
|
63
71
|
handleDelete: (id: string, archive?: boolean, options?: {
|
|
64
72
|
skipConfirm?: boolean;
|
|
65
73
|
}) => Promise<boolean>;
|
|
66
74
|
handleUpdateTask: (id: string, updates: Partial<TaskItem>) => Promise<boolean | undefined>;
|
|
67
|
-
handleSetStatus: (task: TaskItem, status: DurableTaskTargetStatus, updates?: Partial<TaskItem
|
|
75
|
+
handleSetStatus: (task: TaskItem, status: DurableTaskTargetStatus, updates?: Partial<TaskItem>, expectedDetailRevisionOverride?: string | null) => Promise<void>;
|
|
68
76
|
handleToggleComplete: (task: TaskItem) => Promise<void>;
|
|
69
77
|
handleToggleCancel: (task: TaskItem) => Promise<void>;
|
|
70
78
|
handleToggleInProgress: (task: TaskItem) => Promise<void>;
|