@taskforcehq/taskforce 0.3.328 → 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 +233 -34
- 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/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/PlanningModule.js +2 -5
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +65 -10
- package/dist/components/task/TaskImageReviews.js +14 -5
- 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/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- 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 +7 -31
- package/dist/components/views/WidgetView.js +3 -3
- package/dist/components/views/panels/PlanningDrawer.js +5 -12
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +12 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.js +46 -8
- package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
- package/dist/core/DeletedTaskLifecycleService.js +37 -6
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
- package/dist/core/Taskforce.d.ts +62 -2
- package/dist/core/Taskforce.js +635 -32
- package/dist/core/types.d.ts +6 -0
- 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 +6 -0
- package/dist/hooks/tasks/useTaskFormActions.js +65 -12
- 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 +37 -9
- package/dist/hooks/useTaskforce.js +349 -39
- 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/documentAssetRegistrar.js +44 -35
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/runtime.js +172 -42
- package/dist/mcp/taskPlanningRegistrar.js +41 -38
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/migrations/taskSchemaMigrations.js +12 -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/cloudCollectionRead.d.ts +1 -1
- package/dist/server/cloudCollectionRead.js +2 -2
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +15 -3
- package/dist/server/localServiceLease.d.ts +3 -0
- package/dist/server/localServiceLease.js +9 -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/durableTaskHttpRouters.d.ts +9 -2
- package/dist/server/routes/localService.js +2 -0
- package/dist/server/routes/primitives.d.ts +2 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +18 -16
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +10 -0
- package/dist/server/routes/tasks.js +103 -11
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +16 -0
- package/dist/service/localServiceClientLifecycle.js +36 -10
- 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/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 +106 -14
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -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 +1 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +7 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -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 +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +25 -8
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +4 -1
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +11 -1
- 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 +30 -8
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
- 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/syncDurabilityStore.d.ts +7 -0
- package/dist/sync/v3/syncDurabilityStore.js +31 -11
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
- 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/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 +13 -3
- 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 +9 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +30 -18
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +98 -47
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +58 -21
- 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 +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- 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/workspacePullFeed.js +2 -1
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/types.d.ts +47 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-MZs7lVED.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-Kf1pelSy.js → AssetTraySortControl-C8Rztyal.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Cj3c7X9y.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-B5uvzems.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-BVFvCB5R.js} +1 -1
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-BazdUwxZ.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DEr5di_r.js} +1 -1
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- 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 +16 -4
- package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
- package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
- package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
- package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
- package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
- package/dist/ui/assets/index-BUplSsv_.js +0 -7
- package/dist/ui/assets/index-gz2EXuoK.css +0 -1
|
@@ -41,6 +41,8 @@ import { resolveRuntimeModeContract } from '../shared/runtimeContract';
|
|
|
41
41
|
import { DEFAULT_TYPE_VALUE } from '../shared/taxonomyDefaults.js';
|
|
42
42
|
import { resolveClientDeploymentConfig } from '../config/clientDeployment';
|
|
43
43
|
import { resolveTaskforceMcpBaseUrlFromBaseUrl } from '../config/cloudEnvironment';
|
|
44
|
+
import { applyEditorDraftToTask, formatTaskEditorConflictFields, preserveUnresolvedTaskEditorConflicts, reconcileTaskEditorDraft, resolveTaskEditorConflicts, taskToEditorDraft, } from '../utils/taskEditorReconciliation';
|
|
45
|
+
import { isResolvedFeatureAccessMap, } from '../runtime/appGates';
|
|
44
46
|
import { buildBootstrapTraceId, withBootstrapTraceHeader } from '../utils/bootstrapTrace';
|
|
45
47
|
import { buildTaskforceCredentialLoginPayload } from '../utils/authLogin';
|
|
46
48
|
import { createDefaultAssigneeOptions } from '../utils/assignees';
|
|
@@ -59,6 +61,7 @@ import { useCurrentTaskRelations } from './tasks/useCurrentTaskRelations';
|
|
|
59
61
|
import { useTaskEditorNavigation } from './tasks/useTaskEditorNavigation';
|
|
60
62
|
import { useTaskFilters } from './tasks/useTaskFilters';
|
|
61
63
|
import { useTaskFormActions } from './tasks/useTaskFormActions';
|
|
64
|
+
import { useTaskDescriptionImageDraftRecovery } from './tasks/useTaskDescriptionImageDraftRecovery';
|
|
62
65
|
import { useTaskRelationships } from './tasks/useTaskRelationships';
|
|
63
66
|
import { useTaskActions } from './tasks/useTaskActions';
|
|
64
67
|
import { clearPersistedWorkspaceId, logBootstrapDebug, readPersistedWorkspaceId, writePersistedWorkspaceId } from './workspace/workspaceLocalState';
|
|
@@ -80,6 +83,19 @@ import { createTaskInvalidationScope, mergeTaskInvalidationScopes, resolveTaskIn
|
|
|
80
83
|
import { createCloudWorkstreamHttpMutationClient, fetchWorkstreamHttpMutation, isConclusiveWorkstreamHttpResponse, selectCreatedWorkstreamAfterRefresh, } from './workstreams/workstreamHttpMutation';
|
|
81
84
|
import { dispatchTaskforceWorkspaceResourcesInvalidated } from '../utils/workspaceResourceEvents';
|
|
82
85
|
import { dispatchTaskforceAuthSessionChanged } from '../utils/authSessionEvents';
|
|
86
|
+
export function buildRelationshipTasks(tasks, archivedTasks, taskDetails, editingTaskId) {
|
|
87
|
+
const byId = new Map();
|
|
88
|
+
for (const task of archivedTasks)
|
|
89
|
+
byId.set(task.id, task);
|
|
90
|
+
for (const task of tasks)
|
|
91
|
+
byId.set(task.id, task);
|
|
92
|
+
if (editingTaskId && byId.has(editingTaskId)) {
|
|
93
|
+
const currentDetail = taskDetails.find((task) => task.id === editingTaskId);
|
|
94
|
+
if (currentDetail)
|
|
95
|
+
byId.set(editingTaskId, currentDetail);
|
|
96
|
+
}
|
|
97
|
+
return Array.from(byId.values());
|
|
98
|
+
}
|
|
83
99
|
function upsertEntityById(items, nextItem) {
|
|
84
100
|
const existingIndex = items.findIndex((item) => item.id === nextItem.id);
|
|
85
101
|
if (existingIndex === -1) {
|
|
@@ -208,6 +224,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
208
224
|
authSource: '',
|
|
209
225
|
workspaceMode: '',
|
|
210
226
|
workspaceSwitchingEnabled: null,
|
|
227
|
+
appGates: undefined,
|
|
211
228
|
syncV3TaskMetadataActivation: false,
|
|
212
229
|
syncV3TaskCreateActivation: false,
|
|
213
230
|
syncV3TaskStatusActivation: false,
|
|
@@ -267,6 +284,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
267
284
|
workspaceSwitchingEnabled: typeof cfg.workspaceSwitchingEnabled === 'boolean'
|
|
268
285
|
? Boolean(cfg.workspaceSwitchingEnabled)
|
|
269
286
|
: (workspaceMode === 'multi-cloud'),
|
|
287
|
+
appGates: isResolvedFeatureAccessMap(cfg.appGates)
|
|
288
|
+
? cfg.appGates
|
|
289
|
+
: undefined,
|
|
270
290
|
syncV3TaskMetadataActivation: cfg.syncV3?.taskMetadataActivation === true,
|
|
271
291
|
syncV3TaskCreateActivation: cfg.syncV3?.taskCreateActivation === true,
|
|
272
292
|
syncV3TaskStatusActivation: cfg.syncV3?.taskStatusActivation === true,
|
|
@@ -619,6 +639,11 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
619
639
|
const [manualComplexityEnabled, setManualComplexityEnabled] = useState(false);
|
|
620
640
|
const [checklistDropdownEnabled, setChecklistDropdownEnabled] = useState(true);
|
|
621
641
|
const [showTaskCardStatusLabel, setShowTaskCardStatusLabel] = useState(false);
|
|
642
|
+
const [showTaskCardDescription, setShowTaskCardDescription] = useState(true);
|
|
643
|
+
const [showTaskCardAttachments, setShowTaskCardAttachments] = useState(true);
|
|
644
|
+
const [showTaskCardChecklistProgress, setShowTaskCardChecklistProgress] = useState(true);
|
|
645
|
+
const [showTaskCardLatestActivity, setShowTaskCardLatestActivity] = useState(true);
|
|
646
|
+
const [tintTaskCardActivityBackground, setTintTaskCardActivityBackground] = useState(false);
|
|
622
647
|
const [serverHostRoot, setServerHostRoot] = useState('');
|
|
623
648
|
const [returnTab, setReturnTab] = useState(null);
|
|
624
649
|
useTaskforceApiRouting({
|
|
@@ -666,6 +691,12 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
666
691
|
const deletedHydrationRequestRef = useRef(null);
|
|
667
692
|
const [loadingTasks, setLoadingTasks] = useState(false);
|
|
668
693
|
const [editingTaskId, setEditingTaskId] = useState(null);
|
|
694
|
+
const editorBaselineRef = useRef(null);
|
|
695
|
+
const [editorBaseline, setEditorBaseline] = useState(null);
|
|
696
|
+
const [editingTaskRevisionConflict, setEditingTaskRevisionConflict] = useState(null);
|
|
697
|
+
const editingTaskRevisionConflictRef = useRef(null);
|
|
698
|
+
const reconcileOpenTaskWithRemoteRef = useRef(() => null);
|
|
699
|
+
const refreshingTaskRevisionRef = useRef(null);
|
|
669
700
|
const [pendingOpenTaskId, setPendingOpenTaskId] = useState(null);
|
|
670
701
|
const setPendingOpenTaskIdFromPersistedState = useCallback((taskId) => {
|
|
671
702
|
if (String(initialTaskId || '').trim())
|
|
@@ -852,7 +883,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
852
883
|
}, [AUTH_REQUIRED_ERROR, runtimeMode]);
|
|
853
884
|
// === SECTION: Task Data ===
|
|
854
885
|
// Delegated to useTaskData — see src/hooks/useTaskData.ts
|
|
855
|
-
const { tasksRef, archivedTasksRef, recentlyChangedTaskIds, markRecentlyChangedTasks, fetchTasks: fetchTasksBase, fetchArchive: fetchArchiveBase, refreshTaskCollections: refreshTaskCollectionsBase, refreshTaskCollectionsFromInvalidation: refreshTaskCollectionsFromInvalidationBase, mergeTaskFromServer, getTaskRevisionKey } = useTaskData({
|
|
886
|
+
const { tasksRef, archivedTasksRef, taskDetails, staleTaskDetailRevisions, recentlyChangedTaskIds, markRecentlyChangedTasks, fetchTasks: fetchTasksBase, fetchArchive: fetchArchiveBase, loadTaskDetail, cancelTaskDetailLoad, refreshTaskCollections: refreshTaskCollectionsBase, refreshTaskCollectionsFromInvalidation: refreshTaskCollectionsFromInvalidationBase, mergeTaskFromServer, getTaskRevisionKey } = useTaskData({
|
|
856
887
|
tasks,
|
|
857
888
|
archivedTasks,
|
|
858
889
|
setTasks,
|
|
@@ -863,7 +894,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
863
894
|
shouldDeferProtectedApiCalls,
|
|
864
895
|
shouldBlockProtectedApiCalls,
|
|
865
896
|
handleUnauthorized,
|
|
866
|
-
authRequiredForApi
|
|
897
|
+
authRequiredForApi,
|
|
898
|
+
setError,
|
|
899
|
+
setLoading
|
|
867
900
|
});
|
|
868
901
|
useEffect(() => {
|
|
869
902
|
if (workspaceTransitionEpoch === 0)
|
|
@@ -1445,7 +1478,15 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
1445
1478
|
configLoaded,
|
|
1446
1479
|
referenceDataLoaded,
|
|
1447
1480
|
assigneeOptionsLoaded,
|
|
1448
|
-
assigneeOptions
|
|
1481
|
+
assigneeOptions,
|
|
1482
|
+
runtimeMode,
|
|
1483
|
+
workspaceId: currentWorkspaceId,
|
|
1484
|
+
cloudTaskSearchEnabled: runtimeMode === 'cloud'
|
|
1485
|
+
&& isAuthenticated
|
|
1486
|
+
&& taskScope !== 'deleted'
|
|
1487
|
+
&& !shouldDeferProtectedApiCalls
|
|
1488
|
+
&& !shouldBlockProtectedApiCalls,
|
|
1489
|
+
cloudTaskSearchScope: taskScope === 'archived' ? 'archive' : 'active',
|
|
1449
1490
|
});
|
|
1450
1491
|
setUserGlobalSyncStatusRef.current = setUserGlobalSyncStatus;
|
|
1451
1492
|
setUserGlobalSyncErrorRef.current = setUserGlobalSyncError;
|
|
@@ -1549,7 +1590,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
1549
1590
|
const referenceDataRequestRef = useRef(null);
|
|
1550
1591
|
const workspaceListHydratedRef = useRef(false);
|
|
1551
1592
|
const hasBootstrappedDataRef = useRef(false);
|
|
1552
|
-
const { handleSaveSettings, handleSaveTheme, handleSaveGlobalTheme, handleJsonBackupEnabledChange, handleSaveGlobalJsonBackupEnabled, handleSaveGlobalWeekStartsOn, handleSaveLocale, handleManualComplexityEnabledChange, handleChecklistDropdownEnabledChange, handleShowTaskCardStatusLabelChange,
|
|
1593
|
+
const { handleSaveSettings, handleSaveTheme, handleSaveGlobalTheme, handleUseGlobalThemeDefault, handleJsonBackupEnabledChange, handleSaveGlobalJsonBackupEnabled, handleUseGlobalJsonBackupDefault, handleSaveGlobalWeekStartsOn, handleSaveLocale, handleManualComplexityEnabledChange, handleChecklistDropdownEnabledChange, handleShowTaskCardStatusLabelChange, handleShowTaskCardDescriptionChange, handleShowTaskCardAttachmentsChange, handleShowTaskCardChecklistProgressChange, handleShowTaskCardLatestActivityChange, handleTintTaskCardActivityBackgroundChange } = useSettingsPersistence({
|
|
1553
1594
|
keyShortcut,
|
|
1554
1595
|
themeUseGlobalDefault,
|
|
1555
1596
|
runtimeMode,
|
|
@@ -1566,7 +1607,12 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
1566
1607
|
setLocale,
|
|
1567
1608
|
setManualComplexityEnabled,
|
|
1568
1609
|
setChecklistDropdownEnabled,
|
|
1569
|
-
setShowTaskCardStatusLabel
|
|
1610
|
+
setShowTaskCardStatusLabel,
|
|
1611
|
+
setShowTaskCardDescription,
|
|
1612
|
+
setShowTaskCardAttachments,
|
|
1613
|
+
setShowTaskCardChecklistProgress,
|
|
1614
|
+
setShowTaskCardLatestActivity,
|
|
1615
|
+
setTintTaskCardActivityBackground
|
|
1570
1616
|
});
|
|
1571
1617
|
useEffect(() => {
|
|
1572
1618
|
if (runtimeMode !== 'cloud')
|
|
@@ -1767,6 +1813,36 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
1767
1813
|
else {
|
|
1768
1814
|
setShowTaskCardStatusLabel(false);
|
|
1769
1815
|
}
|
|
1816
|
+
if (typeof data.showTaskCardDescription === 'boolean') {
|
|
1817
|
+
setShowTaskCardDescription(data.showTaskCardDescription);
|
|
1818
|
+
}
|
|
1819
|
+
else {
|
|
1820
|
+
setShowTaskCardDescription(true);
|
|
1821
|
+
}
|
|
1822
|
+
if (typeof data.showTaskCardAttachments === 'boolean') {
|
|
1823
|
+
setShowTaskCardAttachments(data.showTaskCardAttachments);
|
|
1824
|
+
}
|
|
1825
|
+
else {
|
|
1826
|
+
setShowTaskCardAttachments(true);
|
|
1827
|
+
}
|
|
1828
|
+
if (typeof data.showTaskCardChecklistProgress === 'boolean') {
|
|
1829
|
+
setShowTaskCardChecklistProgress(data.showTaskCardChecklistProgress);
|
|
1830
|
+
}
|
|
1831
|
+
else {
|
|
1832
|
+
setShowTaskCardChecklistProgress(true);
|
|
1833
|
+
}
|
|
1834
|
+
if (typeof data.showTaskCardLatestActivity === 'boolean') {
|
|
1835
|
+
setShowTaskCardLatestActivity(data.showTaskCardLatestActivity);
|
|
1836
|
+
}
|
|
1837
|
+
else {
|
|
1838
|
+
setShowTaskCardLatestActivity(true);
|
|
1839
|
+
}
|
|
1840
|
+
if (typeof data.tintTaskCardActivityBackground === 'boolean') {
|
|
1841
|
+
setTintTaskCardActivityBackground(data.tintTaskCardActivityBackground);
|
|
1842
|
+
}
|
|
1843
|
+
else {
|
|
1844
|
+
setTintTaskCardActivityBackground(false);
|
|
1845
|
+
}
|
|
1770
1846
|
}, [applyResolvedWorkspaceId, commitCurrentWorkspaceId, configLoaded, currentWorkspaceIdRef]);
|
|
1771
1847
|
const fetchBuildInfo = useCallback(async () => {
|
|
1772
1848
|
const startedAt = typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
@@ -3301,13 +3377,8 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3301
3377
|
coordinatorDataVersion: localCoordinatorDataVersion,
|
|
3302
3378
|
});
|
|
3303
3379
|
const relationshipTasks = useMemo(() => {
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
byId.set(task.id, task);
|
|
3307
|
-
for (const task of tasks)
|
|
3308
|
-
byId.set(task.id, task);
|
|
3309
|
-
return Array.from(byId.values());
|
|
3310
|
-
}, [tasks, archivedTasks]);
|
|
3380
|
+
return buildRelationshipTasks(tasks, archivedTasks, taskDetails, editingTaskId);
|
|
3381
|
+
}, [tasks, archivedTasks, taskDetails, editingTaskId]);
|
|
3311
3382
|
const deletedRelationshipTasks = useMemo(() => deletedTasks.map((entry) => ({
|
|
3312
3383
|
...entry.taskSnapshot,
|
|
3313
3384
|
isDeleted: true,
|
|
@@ -3463,13 +3534,25 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3463
3534
|
setActiveTab__internal(tab);
|
|
3464
3535
|
}, [activeTab]);
|
|
3465
3536
|
const flushAutoSaveRef = useRef(async () => true);
|
|
3466
|
-
const
|
|
3537
|
+
const adoptTaskEditorBaseline = useCallback((task) => {
|
|
3538
|
+
const baseline = {
|
|
3539
|
+
taskId: task.id,
|
|
3540
|
+
task,
|
|
3541
|
+
draft: taskToEditorDraft(task),
|
|
3542
|
+
};
|
|
3543
|
+
editorBaselineRef.current = baseline;
|
|
3544
|
+
setEditorBaseline(baseline);
|
|
3545
|
+
editingTaskRevisionConflictRef.current = null;
|
|
3546
|
+
setEditingTaskRevisionConflict(null);
|
|
3547
|
+
}, []);
|
|
3548
|
+
const { handleNavigation, handleClose, resetForm, resolveTaskIdInput, resolveWorkstreamIdInput, handleEdit, applyTaskToEditor, handleOpenTaskById, returnToPreviousTask, clearReturnToParentTask } = useTaskEditorNavigation({
|
|
3467
3549
|
activeCategories,
|
|
3468
3550
|
activeTypes,
|
|
3469
3551
|
activeTab,
|
|
3470
3552
|
attachments,
|
|
3471
3553
|
checklistItems,
|
|
3472
3554
|
comments,
|
|
3555
|
+
cancelTaskDetailLoad,
|
|
3473
3556
|
description,
|
|
3474
3557
|
editingTaskId,
|
|
3475
3558
|
flushPendingAutoSave: () => flushAutoSaveRef.current(),
|
|
@@ -3477,7 +3560,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3477
3560
|
getPreferredCategoryValue,
|
|
3478
3561
|
getTitleDraft,
|
|
3479
3562
|
lastUsedCategory,
|
|
3563
|
+
loadTaskDetail,
|
|
3480
3564
|
newCommentText,
|
|
3565
|
+
onTaskApplied: adoptTaskEditorBaseline,
|
|
3481
3566
|
relationshipTasks,
|
|
3482
3567
|
workstreams,
|
|
3483
3568
|
showArchive,
|
|
@@ -3510,6 +3595,43 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3510
3595
|
taskReturnTrail,
|
|
3511
3596
|
title,
|
|
3512
3597
|
});
|
|
3598
|
+
const readCurrentTaskEditorDraft = useCallback(() => {
|
|
3599
|
+
const resolvedWorkstream = workstreamInput.trim()
|
|
3600
|
+
? resolveWorkstreamIdInput(workstreamInput)
|
|
3601
|
+
: null;
|
|
3602
|
+
return {
|
|
3603
|
+
title: getTitleDraft(),
|
|
3604
|
+
description: getDescriptionDraft(),
|
|
3605
|
+
category: typeof category === 'string' ? category : String(category.label || ''),
|
|
3606
|
+
type: typeof type === 'string' ? type : String(type.label || ''),
|
|
3607
|
+
priority,
|
|
3608
|
+
complexity: Number(complexity) || 3,
|
|
3609
|
+
status,
|
|
3610
|
+
assignee,
|
|
3611
|
+
scheduledDate,
|
|
3612
|
+
dueDate,
|
|
3613
|
+
workstreamId: resolvedWorkstream?.id || workstreamInput.trim(),
|
|
3614
|
+
taxonomies: { ...formTaxonomies },
|
|
3615
|
+
checklistItems: [...checklistItems],
|
|
3616
|
+
attachments: getAttachmentsDraft(),
|
|
3617
|
+
};
|
|
3618
|
+
}, [
|
|
3619
|
+
assignee,
|
|
3620
|
+
category,
|
|
3621
|
+
checklistItems,
|
|
3622
|
+
complexity,
|
|
3623
|
+
dueDate,
|
|
3624
|
+
formTaxonomies,
|
|
3625
|
+
getAttachmentsDraft,
|
|
3626
|
+
getDescriptionDraft,
|
|
3627
|
+
getTitleDraft,
|
|
3628
|
+
priority,
|
|
3629
|
+
resolveWorkstreamIdInput,
|
|
3630
|
+
scheduledDate,
|
|
3631
|
+
status,
|
|
3632
|
+
type,
|
|
3633
|
+
workstreamInput,
|
|
3634
|
+
]);
|
|
3513
3635
|
useEffect(() => {
|
|
3514
3636
|
const normalizedTaskId = String(pendingOpenTaskId || '').trim();
|
|
3515
3637
|
if (!uiStateReady || !normalizedTaskId)
|
|
@@ -3805,10 +3927,45 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3805
3927
|
isAuthenticated,
|
|
3806
3928
|
dispatchEnabled: workspaceCloudSyncEnabled,
|
|
3807
3929
|
});
|
|
3930
|
+
const handleTaskRevisionConflict = useCallback(async (taskId, _currentDetailRevision) => {
|
|
3931
|
+
if (taskId !== editingTaskId)
|
|
3932
|
+
return { handled: false };
|
|
3933
|
+
const task = [...tasks, ...archivedTasks].find((candidate) => candidate.id === taskId);
|
|
3934
|
+
if (!task)
|
|
3935
|
+
return { handled: false };
|
|
3936
|
+
const detail = await loadTaskDetail(task, {
|
|
3937
|
+
force: true,
|
|
3938
|
+
shouldCommit: () => editorBaselineRef.current?.taskId === taskId,
|
|
3939
|
+
});
|
|
3940
|
+
if (!detail || editorBaselineRef.current?.taskId !== taskId)
|
|
3941
|
+
return { handled: false };
|
|
3942
|
+
const reconciliation = reconcileOpenTaskWithRemoteRef.current(detail, 'save');
|
|
3943
|
+
return {
|
|
3944
|
+
handled: true,
|
|
3945
|
+
retryDetailRevision: reconciliation?.conflicts.length === 0
|
|
3946
|
+
? detail.detailRevision
|
|
3947
|
+
: undefined,
|
|
3948
|
+
retryPatch: reconciliation?.conflicts.length === 0
|
|
3949
|
+
? applyEditorDraftToTask(detail, reconciliation.merged)
|
|
3950
|
+
: undefined,
|
|
3951
|
+
};
|
|
3952
|
+
}, [archivedTasks, editingTaskId, loadTaskDetail, tasks]);
|
|
3953
|
+
const handleTaskMutationAccepted = useCallback((task) => {
|
|
3954
|
+
if (task.id !== editingTaskId)
|
|
3955
|
+
return;
|
|
3956
|
+
if (editingTaskRevisionConflictRef.current?.taskId === task.id) {
|
|
3957
|
+
reconcileOpenTaskWithRemoteRef.current(task, 'refresh');
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3960
|
+
adoptTaskEditorBaseline(task);
|
|
3961
|
+
}, [adoptTaskEditorBaseline, editingTaskId]);
|
|
3808
3962
|
const { copiedId, handleDelete, handleUpdateTask, handleSetStatus, handleToggleComplete, handleToggleCancel, handleToggleInProgress, handleToggleReview, handleArchiveTask, handleBulkArchive, handleUnarchive, handleRestoreDeletedTask, handleRestoreSelectedDeletedTasks, handlePermanentlyDeleteDeletedTask, handleEmptyDeletedTasks, handleCopyId, queueWorkspaceSyncFromAuthoritativeTaskState, } = useTaskActions({
|
|
3809
3963
|
tasks,
|
|
3810
3964
|
archivedTasks,
|
|
3811
3965
|
editingTaskId,
|
|
3966
|
+
editingTaskDetailRevision: editorBaseline?.taskId === editingTaskId
|
|
3967
|
+
? editorBaseline.task.detailRevision || null
|
|
3968
|
+
: null,
|
|
3812
3969
|
setTasks,
|
|
3813
3970
|
setArchivedTasks,
|
|
3814
3971
|
setDeletedTasks,
|
|
@@ -3840,24 +3997,19 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3840
3997
|
durableTaskDeleteActivationEnabled: taskDeleteActivationEnabled,
|
|
3841
3998
|
durableTaskHttpRootActivationEnabled: runtimeConfigOverride.syncV3TaskCloudHttpRootActivation,
|
|
3842
3999
|
workspaceId: currentWorkspaceId,
|
|
4000
|
+
onTaskRevisionConflict: handleTaskRevisionConflict,
|
|
4001
|
+
onTaskMutationAccepted: handleTaskMutationAccepted,
|
|
3843
4002
|
});
|
|
4003
|
+
const { resolveDraft: resolveDescriptionImageDraft } = useTaskDescriptionImageDraftRecovery(currentWorkspaceId, authUserId);
|
|
3844
4004
|
const promoteDescriptionImageDraft = useCallback(async () => {
|
|
3845
4005
|
const draftId = descriptionImageDraftIdRef.current;
|
|
3846
|
-
const response = await fetch('/api/taskforce/context-upload/draft/promote', {
|
|
3847
|
-
method: 'POST',
|
|
3848
|
-
headers: { 'Content-Type': 'application/json' },
|
|
3849
|
-
body: JSON.stringify({
|
|
3850
|
-
workspaceId: currentWorkspaceId,
|
|
3851
|
-
draftUploadId: draftId,
|
|
3852
|
-
uploadPurpose: 'task-description-draft',
|
|
3853
|
-
}),
|
|
3854
|
-
});
|
|
3855
|
-
if (!response.ok) {
|
|
3856
|
-
throw new Error('Task was created, but its draft upload records could not be finalized.');
|
|
3857
|
-
}
|
|
3858
4006
|
rotateDescriptionImageDraftId();
|
|
3859
|
-
|
|
3860
|
-
|
|
4007
|
+
await resolveDescriptionImageDraft({
|
|
4008
|
+
draftUploadId: draftId,
|
|
4009
|
+
resolution: 'promote',
|
|
4010
|
+
});
|
|
4011
|
+
}, [resolveDescriptionImageDraft, rotateDescriptionImageDraftId]);
|
|
4012
|
+
const { autoSaveState, hasUnsavedChanges, flushAutoSave, scheduleWarningPrompt, handleSubmit, confirmScheduleWarning, cancelScheduleWarning, handleAddComment } = useTaskFormActions({
|
|
3861
4013
|
activeCategories,
|
|
3862
4014
|
activeTab,
|
|
3863
4015
|
apiEndpoint,
|
|
@@ -3875,6 +4027,8 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3875
4027
|
workspaceId: currentWorkspaceId,
|
|
3876
4028
|
updateTask: handleUpdateTask,
|
|
3877
4029
|
editingTaskId,
|
|
4030
|
+
editorBaselineDraft: editorBaseline?.taskId === editingTaskId ? editorBaseline.draft : null,
|
|
4031
|
+
revisionConflict: editingTaskRevisionConflict?.taskId === editingTaskId,
|
|
3878
4032
|
fetchTasks,
|
|
3879
4033
|
formTaxonomies,
|
|
3880
4034
|
getAttachmentsDraft,
|
|
@@ -3907,27 +4061,166 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3907
4061
|
textDraftOccupied,
|
|
3908
4062
|
type
|
|
3909
4063
|
});
|
|
4064
|
+
const reconcileOpenTaskWithRemote = useCallback((remoteTask, source) => {
|
|
4065
|
+
if (!editingTaskId || remoteTask.id !== editingTaskId)
|
|
4066
|
+
return null;
|
|
4067
|
+
const previousBaseline = editorBaselineRef.current?.taskId === editingTaskId
|
|
4068
|
+
? editorBaselineRef.current
|
|
4069
|
+
: { taskId: editingTaskId, task: remoteTask, draft: taskToEditorDraft(remoteTask) };
|
|
4070
|
+
const localDraft = readCurrentTaskEditorDraft();
|
|
4071
|
+
const remoteDraft = taskToEditorDraft(remoteTask);
|
|
4072
|
+
const nextReconciliation = reconcileTaskEditorDraft(previousBaseline.draft, localDraft, remoteDraft);
|
|
4073
|
+
const unresolvedConflicts = editingTaskRevisionConflictRef.current?.taskId === editingTaskId
|
|
4074
|
+
? editingTaskRevisionConflictRef.current.reconciliation.conflicts
|
|
4075
|
+
: [];
|
|
4076
|
+
const reconciliation = {
|
|
4077
|
+
...nextReconciliation,
|
|
4078
|
+
conflicts: preserveUnresolvedTaskEditorConflicts(unresolvedConflicts, nextReconciliation.conflicts, localDraft, remoteDraft),
|
|
4079
|
+
};
|
|
4080
|
+
const mergedTask = applyEditorDraftToTask(remoteTask, reconciliation.merged);
|
|
4081
|
+
const nextBaseline = { taskId: editingTaskId, task: remoteTask, draft: remoteDraft };
|
|
4082
|
+
editorBaselineRef.current = nextBaseline;
|
|
4083
|
+
setEditorBaseline(nextBaseline);
|
|
4084
|
+
applyTaskToEditor(mergedTask, { preserveReturnTrail: true, adoptAsBaseline: false });
|
|
4085
|
+
setAttachmentsDirty(JSON.stringify(reconciliation.merged.attachments) !== JSON.stringify(remoteDraft.attachments));
|
|
4086
|
+
setError('');
|
|
4087
|
+
if (reconciliation.conflicts.length > 0) {
|
|
4088
|
+
const nextConflict = {
|
|
4089
|
+
taskId: editingTaskId,
|
|
4090
|
+
detailRevision: remoteTask.detailRevision || 'unknown',
|
|
4091
|
+
source,
|
|
4092
|
+
reconciliation,
|
|
4093
|
+
remoteTask,
|
|
4094
|
+
remoteDraft,
|
|
4095
|
+
};
|
|
4096
|
+
editingTaskRevisionConflictRef.current = nextConflict;
|
|
4097
|
+
setEditingTaskRevisionConflict(nextConflict);
|
|
4098
|
+
}
|
|
4099
|
+
else {
|
|
4100
|
+
editingTaskRevisionConflictRef.current = null;
|
|
4101
|
+
setEditingTaskRevisionConflict(null);
|
|
4102
|
+
if (reconciliation.remoteChangedFields.length > 0) {
|
|
4103
|
+
pushNotice('Task updated', 'info', 2200);
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
return reconciliation;
|
|
4107
|
+
}, [
|
|
4108
|
+
applyTaskToEditor,
|
|
4109
|
+
editingTaskId,
|
|
4110
|
+
pushNotice,
|
|
4111
|
+
readCurrentTaskEditorDraft,
|
|
4112
|
+
setAttachmentsDirty,
|
|
4113
|
+
setError,
|
|
4114
|
+
]);
|
|
4115
|
+
reconcileOpenTaskWithRemoteRef.current = reconcileOpenTaskWithRemote;
|
|
4116
|
+
const resolveEditingTaskConflict = useCallback((resolution) => {
|
|
4117
|
+
const conflict = editingTaskRevisionConflict;
|
|
4118
|
+
if (!conflict || conflict.taskId !== editingTaskId)
|
|
4119
|
+
return;
|
|
4120
|
+
const resolvedDraft = resolveTaskEditorConflicts(conflict.reconciliation, conflict.remoteDraft, resolution, readCurrentTaskEditorDraft());
|
|
4121
|
+
const resolvedTask = applyEditorDraftToTask(conflict.remoteTask, resolvedDraft);
|
|
4122
|
+
applyTaskToEditor(resolvedTask, { preserveReturnTrail: true, adoptAsBaseline: false });
|
|
4123
|
+
setAttachmentsDirty(JSON.stringify(resolvedDraft.attachments) !== JSON.stringify(conflict.remoteDraft.attachments));
|
|
4124
|
+
editingTaskRevisionConflictRef.current = null;
|
|
4125
|
+
setEditingTaskRevisionConflict(null);
|
|
4126
|
+
setError('');
|
|
4127
|
+
clearNotice();
|
|
4128
|
+
const statusWasConflicted = conflict.reconciliation.conflicts.some((item) => item.field === 'status');
|
|
4129
|
+
if (resolution === 'local'
|
|
4130
|
+
&& statusWasConflicted
|
|
4131
|
+
&& resolvedDraft.status !== conflict.remoteDraft.status) {
|
|
4132
|
+
void handleSetStatus(conflict.remoteTask, resolvedDraft.status);
|
|
4133
|
+
}
|
|
4134
|
+
}, [
|
|
4135
|
+
applyTaskToEditor,
|
|
4136
|
+
clearNotice,
|
|
4137
|
+
editingTaskId,
|
|
4138
|
+
editingTaskRevisionConflict,
|
|
4139
|
+
handleSetStatus,
|
|
4140
|
+
readCurrentTaskEditorDraft,
|
|
4141
|
+
setAttachmentsDirty,
|
|
4142
|
+
setError,
|
|
4143
|
+
]);
|
|
4144
|
+
useEffect(() => {
|
|
4145
|
+
const conflict = editingTaskRevisionConflict;
|
|
4146
|
+
if (!conflict || conflict.taskId !== editingTaskId)
|
|
4147
|
+
return;
|
|
4148
|
+
const fields = formatTaskEditorConflictFields(conflict.reconciliation.conflicts);
|
|
4149
|
+
const fieldSummary = fields.length > 0 ? fields.join(', ') : 'task fields';
|
|
4150
|
+
pushNotice(`${fieldSummary.charAt(0).toUpperCase()}${fieldSummary.slice(1)} also changed elsewhere.`, 'info', undefined, {
|
|
4151
|
+
label: 'Use latest',
|
|
4152
|
+
primary: true,
|
|
4153
|
+
onAction: () => resolveEditingTaskConflict('latest'),
|
|
4154
|
+
secondaryLabel: 'Keep mine',
|
|
4155
|
+
onSecondaryAction: () => resolveEditingTaskConflict('local'),
|
|
4156
|
+
dismissible: false,
|
|
4157
|
+
ownerKey: `task-editor-conflict:${conflict.taskId}:${conflict.detailRevision}`,
|
|
4158
|
+
});
|
|
4159
|
+
}, [editingTaskId, editingTaskRevisionConflict, pushNotice, resolveEditingTaskConflict]);
|
|
4160
|
+
useEffect(() => {
|
|
4161
|
+
if (!editingTaskId) {
|
|
4162
|
+
refreshingTaskRevisionRef.current = null;
|
|
4163
|
+
setEditingTaskRevisionConflict(null);
|
|
4164
|
+
editingTaskRevisionConflictRef.current = null;
|
|
4165
|
+
editorBaselineRef.current = null;
|
|
4166
|
+
setEditorBaseline(null);
|
|
4167
|
+
return;
|
|
4168
|
+
}
|
|
4169
|
+
const staleRevision = staleTaskDetailRevisions[editingTaskId];
|
|
4170
|
+
if (!staleRevision) {
|
|
4171
|
+
refreshingTaskRevisionRef.current = null;
|
|
4172
|
+
return;
|
|
4173
|
+
}
|
|
4174
|
+
const summary = [...tasks, ...archivedTasks].find((task) => task.id === editingTaskId);
|
|
4175
|
+
if (!summary)
|
|
4176
|
+
return;
|
|
4177
|
+
const refreshKey = `${editingTaskId}:${staleRevision}`;
|
|
4178
|
+
if (refreshingTaskRevisionRef.current === refreshKey)
|
|
4179
|
+
return;
|
|
4180
|
+
refreshingTaskRevisionRef.current = refreshKey;
|
|
4181
|
+
void loadTaskDetail(summary, {
|
|
4182
|
+
shouldCommit: () => editorBaselineRef.current?.taskId === editingTaskId,
|
|
4183
|
+
}).then((detail) => {
|
|
4184
|
+
if (editorBaselineRef.current?.taskId !== editingTaskId)
|
|
4185
|
+
return;
|
|
4186
|
+
if (!detail) {
|
|
4187
|
+
setError('The latest task update could not be loaded. Your local draft has been preserved.');
|
|
4188
|
+
return;
|
|
4189
|
+
}
|
|
4190
|
+
reconcileOpenTaskWithRemote(detail, 'refresh');
|
|
4191
|
+
}).finally(() => {
|
|
4192
|
+
if (refreshingTaskRevisionRef.current === refreshKey) {
|
|
4193
|
+
refreshingTaskRevisionRef.current = null;
|
|
4194
|
+
}
|
|
4195
|
+
});
|
|
4196
|
+
}, [
|
|
4197
|
+
archivedTasks,
|
|
4198
|
+
editingTaskId,
|
|
4199
|
+
loadTaskDetail,
|
|
4200
|
+
reconcileOpenTaskWithRemote,
|
|
4201
|
+
setError,
|
|
4202
|
+
staleTaskDetailRevisions,
|
|
4203
|
+
tasks,
|
|
4204
|
+
]);
|
|
3910
4205
|
const discardDescriptionImageDraft = useCallback(async () => {
|
|
3911
4206
|
const draftId = descriptionImageDraftIdRef.current;
|
|
3912
4207
|
rotateDescriptionImageDraftId();
|
|
3913
4208
|
try {
|
|
3914
4209
|
await awaitPendingDescriptionImageUpload();
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
4210
|
+
}
|
|
4211
|
+
catch (error) {
|
|
4212
|
+
console.warn('[Taskforce] Description image upload failed while the draft was being discarded.', error);
|
|
4213
|
+
}
|
|
4214
|
+
try {
|
|
4215
|
+
await resolveDescriptionImageDraft({
|
|
4216
|
+
draftUploadId: draftId,
|
|
4217
|
+
resolution: 'discard',
|
|
3923
4218
|
});
|
|
3924
|
-
if (!response.ok)
|
|
3925
|
-
throw new Error('Draft upload cleanup was rejected.');
|
|
3926
4219
|
}
|
|
3927
4220
|
catch (error) {
|
|
3928
4221
|
console.warn('[Taskforce] Failed to clean discarded Description image uploads.', error);
|
|
3929
4222
|
}
|
|
3930
|
-
}, [awaitPendingDescriptionImageUpload,
|
|
4223
|
+
}, [awaitPendingDescriptionImageUpload, resolveDescriptionImageDraft, rotateDescriptionImageDraftId]);
|
|
3931
4224
|
useEffect(() => {
|
|
3932
4225
|
flushAutoSaveRef.current = flushAutoSave;
|
|
3933
4226
|
}, [flushAutoSave]);
|
|
@@ -3974,6 +4267,11 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3974
4267
|
manualComplexityEnabled,
|
|
3975
4268
|
checklistDropdownEnabled,
|
|
3976
4269
|
showTaskCardStatusLabel,
|
|
4270
|
+
showTaskCardDescription,
|
|
4271
|
+
showTaskCardAttachments,
|
|
4272
|
+
showTaskCardChecklistProgress,
|
|
4273
|
+
showTaskCardLatestActivity,
|
|
4274
|
+
tintTaskCardActivityBackground,
|
|
3977
4275
|
pathSaved,
|
|
3978
4276
|
settingsSection,
|
|
3979
4277
|
setupState,
|
|
@@ -3983,15 +4281,21 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3983
4281
|
setCurrentTheme,
|
|
3984
4282
|
handleSaveTheme,
|
|
3985
4283
|
handleSaveGlobalTheme,
|
|
4284
|
+
handleUseGlobalThemeDefault,
|
|
3986
4285
|
setKeyShortcut,
|
|
3987
4286
|
handleJsonBackupEnabledChange,
|
|
3988
4287
|
handleSaveGlobalJsonBackupEnabled,
|
|
4288
|
+
handleUseGlobalJsonBackupDefault,
|
|
3989
4289
|
handleSaveGlobalWeekStartsOn,
|
|
3990
4290
|
handleSaveLocale,
|
|
3991
4291
|
handleManualComplexityEnabledChange,
|
|
3992
4292
|
handleChecklistDropdownEnabledChange,
|
|
3993
4293
|
handleShowTaskCardStatusLabelChange,
|
|
3994
|
-
|
|
4294
|
+
handleShowTaskCardDescriptionChange,
|
|
4295
|
+
handleShowTaskCardAttachmentsChange,
|
|
4296
|
+
handleShowTaskCardChecklistProgressChange,
|
|
4297
|
+
handleShowTaskCardLatestActivityChange,
|
|
4298
|
+
handleTintTaskCardActivityBackgroundChange,
|
|
3995
4299
|
handleSaveSettings,
|
|
3996
4300
|
initiativeTemplates,
|
|
3997
4301
|
fetchInitiativeTemplates,
|
|
@@ -4091,6 +4395,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
4091
4395
|
const effectiveConfig = {
|
|
4092
4396
|
...mergedConfig,
|
|
4093
4397
|
cloudEnvironment: runtimeConfigOverride.cloudEnvironment || mergedConfig.cloudEnvironment || '',
|
|
4398
|
+
appGates: runtimeConfigOverride.appGates || mergedConfig.appGates,
|
|
4094
4399
|
apiBaseUrl: normalizedApiBaseUrl || mergedConfig.apiBaseUrl,
|
|
4095
4400
|
cloudAuthBaseUrl: normalizedCloudAuthBaseUrl || mergedConfig.cloudAuthBaseUrl,
|
|
4096
4401
|
wsBaseUrl: effectiveWsBaseUrl || mergedConfig.wsBaseUrl
|
|
@@ -4121,6 +4426,11 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
4121
4426
|
manualComplexityEnabled,
|
|
4122
4427
|
checklistDropdownEnabled,
|
|
4123
4428
|
showTaskCardStatusLabel,
|
|
4429
|
+
showTaskCardDescription,
|
|
4430
|
+
showTaskCardAttachments,
|
|
4431
|
+
showTaskCardChecklistProgress,
|
|
4432
|
+
showTaskCardLatestActivity,
|
|
4433
|
+
tintTaskCardActivityBackground,
|
|
4124
4434
|
setManualComplexityEnabled,
|
|
4125
4435
|
mcpHostRoot,
|
|
4126
4436
|
setMcpHostRoot,
|
|
@@ -14,6 +14,10 @@ export declare function useUiNotice(): {
|
|
|
14
14
|
pushNotice: (message: string, tone?: UiNotice["tone"], ttlMs?: number, action?: {
|
|
15
15
|
label: string;
|
|
16
16
|
onAction: () => void;
|
|
17
|
+
primary?: boolean;
|
|
18
|
+
secondaryLabel?: string;
|
|
19
|
+
onSecondaryAction?: () => void;
|
|
20
|
+
dismissible?: boolean;
|
|
17
21
|
ownerKey?: string;
|
|
18
22
|
}) => void;
|
|
19
23
|
clearNotice: () => void;
|
|
@@ -35,6 +35,10 @@ export function useUiNotice() {
|
|
|
35
35
|
ttlMs,
|
|
36
36
|
actionLabel: action?.label,
|
|
37
37
|
onAction: action?.onAction,
|
|
38
|
+
actionPrimary: action?.primary,
|
|
39
|
+
secondaryActionLabel: action?.secondaryLabel,
|
|
40
|
+
onSecondaryAction: action?.onSecondaryAction,
|
|
41
|
+
dismissible: action?.dismissible,
|
|
38
42
|
ownerKey: action?.ownerKey
|
|
39
43
|
});
|
|
40
44
|
// Actionable notices stay available until the action or explicit
|
|
@@ -78,11 +78,11 @@ export function registerAdminWorkspaceTools(registerTool, executeTool) {
|
|
|
78
78
|
description: { type: 'string' },
|
|
79
79
|
category: { type: 'string' },
|
|
80
80
|
type: { type: 'string' },
|
|
81
|
-
priority: { type: '
|
|
81
|
+
priority: { type: 'integer', description: context.priorityDesc, enum: context.priorityEnum },
|
|
82
82
|
assignee: { type: 'string', description: `${context.assigneeHint} Call list_assignees to inspect the current eligible IDs.` },
|
|
83
83
|
owner: { type: 'string', description: `${context.assigneeHint} Alias for assignee.` },
|
|
84
84
|
status: { type: 'string', enum: ['task', 'on-hold', 'in-progress', 'review', 'done', 'cancelled'] },
|
|
85
|
-
complexity: { type: '
|
|
85
|
+
complexity: { type: 'integer', minimum: 1, maximum: 5, description: context.complexityDesc },
|
|
86
86
|
},
|
|
87
87
|
required: ['id'],
|
|
88
88
|
}),
|
|
@@ -101,7 +101,7 @@ export function registerAdminWorkspaceTools(registerTool, executeTool) {
|
|
|
101
101
|
priorities: arrayProperty('Ordered priority definitions to save.', {
|
|
102
102
|
type: 'object',
|
|
103
103
|
properties: {
|
|
104
|
-
value: { type: '
|
|
104
|
+
value: { type: 'integer', minimum: 1 },
|
|
105
105
|
label: { type: 'string' },
|
|
106
106
|
},
|
|
107
107
|
}),
|