@taskforcehq/taskforce 0.3.306 → 0.3.307
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/dist/Taskforce.module.css +317 -27
- package/dist/TaskforceCore.js +1 -0
- package/dist/TaskforceCore.test.js +178 -0
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.js +15 -3
- package/dist/components/features/AgentsModule.d.ts +5 -1
- package/dist/components/features/AgentsModule.js +142 -39
- package/dist/components/features/AgentsModule.test.js +260 -11
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +3 -1
- package/dist/components/features/DocumentViewer.js +6 -5
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +20 -3
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +6 -2
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +14 -64
- package/dist/components/task/TaskKanban.js +0 -8
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.js +9 -1
- package/dist/components/views/PlanComparisonPage.test.js +19 -0
- package/dist/components/views/PlansPage.js +1 -1
- package/dist/components/views/StandaloneLayout.js +256 -69
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
- package/dist/components/views/panels/PlanningDrawer.js +259 -51
- package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +7 -0
- package/dist/core/AiProfileService.js +460 -35
- package/dist/core/AiProfiles.test.js +648 -2
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +58 -13
- package/dist/core/GlobalSettingsService.js +12 -0
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanningEntities.test.js +366 -4
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +190 -26
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +775 -71
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
- package/dist/hooks/sync/orchestratorShared.js +61 -1
- package/dist/hooks/sync/recovery.js +8 -0
- package/dist/hooks/sync/recovery.test.js +5 -5
- package/dist/hooks/sync/transfers.d.ts +2 -1
- package/dist/hooks/sync/transfers.js +36 -9
- package/dist/hooks/sync/transfers.test.js +534 -2
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.js +50 -5
- package/dist/hooks/useTaskforce.d.ts +85 -50
- package/dist/hooks/useTaskforce.js +44 -14
- package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
- package/dist/hooks/useWorkspaceSyncController.js +7 -1
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +113 -7
- package/dist/mcp/runtime.d.ts +1 -0
- package/dist/mcp/runtime.js +969 -122
- package/dist/mcp/runtime.test.js +1083 -11
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.js +21 -0
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
- package/dist/server/index.js +4 -0
- package/dist/server/index.test.js +6 -1
- package/dist/server/routes/admin.js +187 -9
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +11 -0
- package/dist/server/routes/auth.js +189 -27
- package/dist/server/routes/authSupport.d.ts +4 -0
- package/dist/server/routes/authSupport.js +12 -1
- package/dist/server/routes/billing.js +11 -0
- package/dist/server/routes/billing.test.js +3 -0
- package/dist/server/routes/documents.js +10 -0
- package/dist/server/routes/shared.js +0 -10
- package/dist/server/routes/sync.integration.test.js +221 -0
- package/dist/server/routes/sync.js +13 -3
- package/dist/server/routes/syncSnapshotRoutes.js +2 -0
- package/dist/server/routes/tasks.js +12 -9
- package/dist/server/routes.js +87 -8
- package/dist/server/routes.test.js +890 -22
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/sync/collaborationSyncPayload.js +2 -0
- package/dist/sync/collaborationSyncPayload.test.js +1 -0
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +5 -1
- package/dist/sync/contentSyncState.js +231 -37
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +4 -4
- package/dist/sync/syncApplyHandlers.js +89 -31
- package/dist/sync/syncApplyHandlers.test.js +184 -4
- package/dist/sync/syncResourceAdapters.d.ts +2 -0
- package/dist/sync/syncResourceAdapters.js +2 -0
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/syncService.test.js +39 -0
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +129 -70
- package/dist/sync/workspacePullFeed.test.js +49 -0
- package/dist/sync/workspaceSyncModel.d.ts +28 -6
- package/dist/sync/workspaceSyncModel.js +159 -45
- package/dist/sync/workspaceSyncModel.test.js +269 -3
- package/dist/types.d.ts +33 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +6 -0
- package/dist/utils/assignees.js +8 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/taskActivity.d.ts +7 -1
- package/dist/utils/taskActivity.js +63 -1
- package/dist/utils/taskActivity.test.js +23 -1
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/package.json +1 -1
- package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
- package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
- package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
- package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
- package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
- package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
- package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
- package/dist/ui/assets/index-C6k75jr8.js +0 -6
|
@@ -26,7 +26,8 @@ function makeTask(overrides) {
|
|
|
26
26
|
comments: overrides.comments || [],
|
|
27
27
|
attachments: overrides.attachments || [],
|
|
28
28
|
activity: overrides.activity || [],
|
|
29
|
-
taskEvents: overrides.taskEvents || []
|
|
29
|
+
taskEvents: overrides.taskEvents || [],
|
|
30
|
+
referenceLabel: overrides.referenceLabel
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
describe('useFilterSort', () => {
|
|
@@ -107,6 +108,91 @@ describe('useFilterSort', () => {
|
|
|
107
108
|
expect(result.current.searchAgnosticTasks.map((task) => task.id)).toEqual(['known-task', 'unknown-task']);
|
|
108
109
|
expect(result.current.filteredArchive.map((task) => task.id)).toEqual(['unknown-archived-task']);
|
|
109
110
|
});
|
|
111
|
+
it('matches task reference labels when the search query has surrounding spaces or pasted formatting', async () => {
|
|
112
|
+
const matchingTask = makeTask({
|
|
113
|
+
id: 'matching-task',
|
|
114
|
+
title: 'Reference match',
|
|
115
|
+
referenceLabel: 'T-123'
|
|
116
|
+
});
|
|
117
|
+
const otherTask = makeTask({
|
|
118
|
+
id: 'other-task',
|
|
119
|
+
title: 'Other task',
|
|
120
|
+
referenceLabel: 'T-456'
|
|
121
|
+
});
|
|
122
|
+
const archivedMatch = makeTask({
|
|
123
|
+
id: 'archived-match',
|
|
124
|
+
title: 'Archived reference match',
|
|
125
|
+
referenceLabel: 'T-123',
|
|
126
|
+
isArchived: true
|
|
127
|
+
});
|
|
128
|
+
const { result } = renderHook(() => useFilterSort({
|
|
129
|
+
tasks: [matchingTask, otherTask],
|
|
130
|
+
archivedTasks: [archivedMatch],
|
|
131
|
+
activeCategories,
|
|
132
|
+
activeTypes,
|
|
133
|
+
priorities,
|
|
134
|
+
taxonomies: [],
|
|
135
|
+
configLoaded: true,
|
|
136
|
+
referenceDataLoaded: true,
|
|
137
|
+
assigneeOptionsLoaded: true,
|
|
138
|
+
assigneeOptions
|
|
139
|
+
}));
|
|
140
|
+
await waitFor(() => {
|
|
141
|
+
expect(result.current.hasInitedFilters).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
act(() => {
|
|
144
|
+
result.current.setSearchQuery(' T - 123 ');
|
|
145
|
+
});
|
|
146
|
+
expect(result.current.filteredTasks.map((task) => task.id)).toEqual(['matching-task']);
|
|
147
|
+
expect(result.current.filteredArchive.map((task) => task.id)).toEqual(['archived-match']);
|
|
148
|
+
act(() => {
|
|
149
|
+
result.current.setSearchQuery('t–123');
|
|
150
|
+
});
|
|
151
|
+
expect(result.current.filteredTasks.map((task) => task.id)).toEqual(['matching-task']);
|
|
152
|
+
act(() => {
|
|
153
|
+
result.current.setSearchQuery(' ');
|
|
154
|
+
});
|
|
155
|
+
expect(result.current.filteredTasks.map((task) => task.id)).toEqual(['matching-task', 'other-task']);
|
|
156
|
+
});
|
|
157
|
+
it('matches tokenized search text and task metadata labels', async () => {
|
|
158
|
+
const matchingTask = makeTask({
|
|
159
|
+
id: 'matching-task',
|
|
160
|
+
title: 'Billing API cleanup',
|
|
161
|
+
category: 'ops',
|
|
162
|
+
priority: 3,
|
|
163
|
+
assignee: 'member-1'
|
|
164
|
+
});
|
|
165
|
+
const otherTask = makeTask({
|
|
166
|
+
id: 'other-task',
|
|
167
|
+
title: 'Marketing copy cleanup',
|
|
168
|
+
category: 'default',
|
|
169
|
+
priority: 1,
|
|
170
|
+
assignee: 'unassigned'
|
|
171
|
+
});
|
|
172
|
+
const { result } = renderHook(() => useFilterSort({
|
|
173
|
+
tasks: [matchingTask, otherTask],
|
|
174
|
+
archivedTasks: [],
|
|
175
|
+
activeCategories,
|
|
176
|
+
activeTypes,
|
|
177
|
+
priorities,
|
|
178
|
+
taxonomies: [],
|
|
179
|
+
configLoaded: true,
|
|
180
|
+
referenceDataLoaded: true,
|
|
181
|
+
assigneeOptionsLoaded: true,
|
|
182
|
+
assigneeOptions
|
|
183
|
+
}));
|
|
184
|
+
await waitFor(() => {
|
|
185
|
+
expect(result.current.hasInitedFilters).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
act(() => {
|
|
188
|
+
result.current.setSearchQuery('api billing');
|
|
189
|
+
});
|
|
190
|
+
expect(result.current.filteredTasks.map((task) => task.id)).toEqual(['matching-task']);
|
|
191
|
+
act(() => {
|
|
192
|
+
result.current.setSearchQuery('Member One');
|
|
193
|
+
});
|
|
194
|
+
expect(result.current.filteredTasks.map((task) => task.id)).toEqual(['matching-task']);
|
|
195
|
+
});
|
|
110
196
|
it('still excludes unknown values when the user selects a subset filter', async () => {
|
|
111
197
|
const knownTask = makeTask({
|
|
112
198
|
id: 'known-task',
|
|
@@ -26,6 +26,7 @@ import { useWorkspaceSyncController } from './useWorkspaceSyncController';
|
|
|
26
26
|
import { normalizeTaskforceTheme } from '../utils/theme';
|
|
27
27
|
import { useRealtimeSync } from './useRealtimeSync';
|
|
28
28
|
import { TASKFORCE_CONTEXT_ASSETS_MUTATED_EVENT } from '../utils/contextAssetEvents';
|
|
29
|
+
import { TASKFORCE_AI_PROFILES_MUTATED_EVENT } from '../utils/aiProfileEvents';
|
|
29
30
|
import { setLocale as setAppLocale } from '../localization';
|
|
30
31
|
import { normalizeTaskFromApi } from '../utils/taskNormalization.js';
|
|
31
32
|
import { normalizeSyncEventDetails } from '../utils/syncEventDetails';
|
|
@@ -642,7 +643,7 @@ export function useSyncOrchestrator(input) {
|
|
|
642
643
|
return buildWorkspaceSyncPayloadModel({
|
|
643
644
|
tasks: workspaceTasksRef.current,
|
|
644
645
|
archivedTasks: workspaceArchivedTasksRef.current,
|
|
645
|
-
taskEvents: flattenTaskEvents(workspaceTasksRef.current, workspaceArchivedTasksRef.current),
|
|
646
|
+
taskEvents: flattenTaskEvents(workspaceTasksRef.current, workspaceArchivedTasksRef.current, workspaceInitiativesRef.current, workspaceWorkstreamsRef.current),
|
|
646
647
|
lastPushedTaskIds: workspaceLastPushedTaskIdsRef.current,
|
|
647
648
|
pendingDeletedTaskIds: workspaceDeletedTaskIdsRef.current,
|
|
648
649
|
pendingDeletedTaskWatermarks: workspaceDeletedTaskWatermarksRef.current,
|
|
@@ -720,7 +721,7 @@ export function useSyncOrchestrator(input) {
|
|
|
720
721
|
workspaceId: currentWorkspaceId,
|
|
721
722
|
tasks: workspaceTasksRef.current,
|
|
722
723
|
archivedTasks: workspaceArchivedTasksRef.current,
|
|
723
|
-
taskEvents: flattenTaskEvents(workspaceTasksRef.current, workspaceArchivedTasksRef.current),
|
|
724
|
+
taskEvents: flattenTaskEvents(workspaceTasksRef.current, workspaceArchivedTasksRef.current, workspaceInitiativesRef.current, workspaceWorkstreamsRef.current),
|
|
724
725
|
pendingDeletedTaskIds: workspaceDeletedTaskIdsRef.current,
|
|
725
726
|
initiatives: workspaceInitiativesRef.current,
|
|
726
727
|
workstreams: workspaceWorkstreamsRef.current,
|
|
@@ -767,10 +768,11 @@ export function useSyncOrchestrator(input) {
|
|
|
767
768
|
isArchived: Boolean(workstream.isArchived)
|
|
768
769
|
}))
|
|
769
770
|
.sort((left, right) => left.id.localeCompare(right.id)),
|
|
770
|
-
taskEvents: flattenTaskEvents(tasks || [], archivedTasks || [])
|
|
771
|
+
taskEvents: flattenTaskEvents(tasks || [], archivedTasks || [], initiatives || [], workstreams || [])
|
|
771
772
|
.map((event) => ({
|
|
772
773
|
id: String(event.id || '').trim(),
|
|
773
|
-
|
|
774
|
+
entityType: String(event.entityType || 'task').trim(),
|
|
775
|
+
entityId: String(event.entityId || event.taskId || '').trim(),
|
|
774
776
|
createdAt: String(event.createdAt || '').trim(),
|
|
775
777
|
action: String(event.action || '').trim(),
|
|
776
778
|
}))
|
|
@@ -1005,6 +1007,37 @@ export function useSyncOrchestrator(input) {
|
|
|
1005
1007
|
markWorkspaceSyncReferenceSnapshotReady('assets');
|
|
1006
1008
|
}
|
|
1007
1009
|
}, [runtimeMode, currentWorkspaceId, cloudAuthConfigured, authSessionResolved, isAuthenticated, markWorkspaceSyncReferenceSnapshotReady]);
|
|
1010
|
+
const refreshWorkspaceSyncPlanningEntitiesSnapshot = useCallback(async () => {
|
|
1011
|
+
if (runtimeMode !== 'local')
|
|
1012
|
+
return;
|
|
1013
|
+
if (!isValidWorkspaceKey(currentWorkspaceId))
|
|
1014
|
+
return;
|
|
1015
|
+
if (cloudAuthConfigured && (!authSessionResolved || !isAuthenticated))
|
|
1016
|
+
return;
|
|
1017
|
+
try {
|
|
1018
|
+
const res = await fetch(`/api/taskforce/planning/bootstrap?workspaceId=${encodeURIComponent(currentWorkspaceId)}`, {
|
|
1019
|
+
method: 'GET',
|
|
1020
|
+
credentials: 'include'
|
|
1021
|
+
});
|
|
1022
|
+
if (!res.ok)
|
|
1023
|
+
return;
|
|
1024
|
+
const data = await res.json().catch(() => ({}));
|
|
1025
|
+
const nextInitiatives = Array.isArray(data?.initiatives)
|
|
1026
|
+
? data.initiatives.filter((entry) => (Boolean(entry && typeof entry === 'object' && typeof entry.id === 'string')))
|
|
1027
|
+
: [];
|
|
1028
|
+
const nextWorkstreams = Array.isArray(data?.workstreams)
|
|
1029
|
+
? data.workstreams.filter((entry) => (Boolean(entry && typeof entry === 'object' && typeof entry.id === 'string')))
|
|
1030
|
+
: [];
|
|
1031
|
+
workspaceInitiativesRef.current = nextInitiatives;
|
|
1032
|
+
workspaceWorkstreamsRef.current = nextWorkstreams;
|
|
1033
|
+
}
|
|
1034
|
+
catch (error) {
|
|
1035
|
+
logSyncDebug('planning_snapshot_refresh_failed', {
|
|
1036
|
+
workspaceId: currentWorkspaceId,
|
|
1037
|
+
error: String(error?.message || error || '')
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
}, [runtimeMode, currentWorkspaceId, cloudAuthConfigured, authSessionResolved, isAuthenticated]);
|
|
1008
1041
|
const refreshWorkspaceSyncDocumentReviewSessionsSnapshot = useCallback(async () => {
|
|
1009
1042
|
if (runtimeMode !== 'local')
|
|
1010
1043
|
return;
|
|
@@ -1196,7 +1229,7 @@ export function useSyncOrchestrator(input) {
|
|
|
1196
1229
|
workspaceLastPushedAnnotatedAttachmentSessionWatermarksRef.current = new Map(workspaceSyncAnnotatedAttachmentSessionsRef.current
|
|
1197
1230
|
.map((entry) => [String(entry?.id || '').trim(), String(entry?.updatedAt || entry?.createdAt || '').trim()])
|
|
1198
1231
|
.filter(([id]) => id.length > 0));
|
|
1199
|
-
workspaceLastPushedTaskEventWatermarksRef.current = new Map(flattenTaskEvents(workspaceTasksRef.current, workspaceArchivedTasksRef.current)
|
|
1232
|
+
workspaceLastPushedTaskEventWatermarksRef.current = new Map(flattenTaskEvents(workspaceTasksRef.current, workspaceArchivedTasksRef.current, workspaceInitiativesRef.current, workspaceWorkstreamsRef.current)
|
|
1200
1233
|
.map((entry) => [String(entry?.id || '').trim(), String(entry?.createdAt || '').trim()])
|
|
1201
1234
|
.filter(([id]) => id.length > 0));
|
|
1202
1235
|
const persisted = persistWorkspaceSyncWatermarksSnapshotBestEffort();
|
|
@@ -1292,6 +1325,7 @@ export function useSyncOrchestrator(input) {
|
|
|
1292
1325
|
refreshWorkspaceSyncMarkdownDocumentsSnapshot,
|
|
1293
1326
|
refreshWorkspaceSyncAiProfilesSnapshot,
|
|
1294
1327
|
refreshWorkspaceSyncAssetsSnapshot,
|
|
1328
|
+
refreshWorkspaceSyncPlanningEntitiesSnapshot,
|
|
1295
1329
|
refreshWorkspaceSyncDocumentReviewSessionsSnapshot,
|
|
1296
1330
|
refreshWorkspaceSyncAnnotatedAttachmentSessionsSnapshot,
|
|
1297
1331
|
refreshLocalWorkspaceTaskCollections,
|
|
@@ -1373,6 +1407,7 @@ export function useSyncOrchestrator(input) {
|
|
|
1373
1407
|
refreshWorkspaceSyncMarkdownDocumentsSnapshot,
|
|
1374
1408
|
refreshWorkspaceSyncAiProfilesSnapshot,
|
|
1375
1409
|
refreshWorkspaceSyncAssetsSnapshot,
|
|
1410
|
+
refreshWorkspaceSyncPlanningEntitiesSnapshot,
|
|
1376
1411
|
refreshWorkspaceSyncDocumentReviewSessionsSnapshot,
|
|
1377
1412
|
refreshWorkspaceSyncAnnotatedAttachmentSessionsSnapshot,
|
|
1378
1413
|
refreshLocalWorkspaceTaskCollections,
|
|
@@ -1656,7 +1691,16 @@ export function useSyncOrchestrator(input) {
|
|
|
1656
1691
|
return;
|
|
1657
1692
|
refreshWorkspaceSyncContextAssetSnapshots();
|
|
1658
1693
|
};
|
|
1694
|
+
const handleAiProfilesMutated = (event) => {
|
|
1695
|
+
const detail = event.detail;
|
|
1696
|
+
const eventWorkspaceId = String(detail?.workspaceId || '').trim() || 'default';
|
|
1697
|
+
if (eventWorkspaceId !== currentWorkspaceId)
|
|
1698
|
+
return;
|
|
1699
|
+
void refreshWorkspaceSyncAiProfilesSnapshot();
|
|
1700
|
+
void refreshWorkspaceSyncAssetsSnapshot();
|
|
1701
|
+
};
|
|
1659
1702
|
window.addEventListener(TASKFORCE_CONTEXT_ASSETS_MUTATED_EVENT, handleContextAssetsMutated);
|
|
1703
|
+
window.addEventListener(TASKFORCE_AI_PROFILES_MUTATED_EVENT, handleAiProfilesMutated);
|
|
1660
1704
|
const docsIntervalId = window.setInterval(() => {
|
|
1661
1705
|
void refreshWorkspaceSyncMarkdownDocumentsSnapshot();
|
|
1662
1706
|
}, workspaceDocumentsRefreshIntervalMs);
|
|
@@ -1674,6 +1718,7 @@ export function useSyncOrchestrator(input) {
|
|
|
1674
1718
|
}, workspaceDocumentsRefreshIntervalMs);
|
|
1675
1719
|
return () => {
|
|
1676
1720
|
window.removeEventListener(TASKFORCE_CONTEXT_ASSETS_MUTATED_EVENT, handleContextAssetsMutated);
|
|
1721
|
+
window.removeEventListener(TASKFORCE_AI_PROFILES_MUTATED_EVENT, handleAiProfilesMutated);
|
|
1677
1722
|
window.clearInterval(docsIntervalId);
|
|
1678
1723
|
window.clearInterval(aiProfilesIntervalId);
|
|
1679
1724
|
window.clearInterval(assetsIntervalId);
|
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTaskforce
|
|
3
|
+
*
|
|
4
|
+
* Central React hook for the Taskforce task-management system.
|
|
5
|
+
* Orchestrates all application state: runtime config, auth, workspace,
|
|
6
|
+
* bootstrap, task data, filtering/sorting, form editing, settings,
|
|
7
|
+
* sync, and UI notices.
|
|
8
|
+
*
|
|
9
|
+
* SECTION MAP (use Ctrl+F on the === markers to jump):
|
|
10
|
+
* === SECTION: Runtime Config === Line ~189 — URL resolution, cloud/local mode detection
|
|
11
|
+
* === SECTION: Settings State === Line ~388 — Theme, shortcut, locale, feature flags
|
|
12
|
+
* === SECTION: Workspace Storage === Line ~415 — workspaceStorageScope, project root/name
|
|
13
|
+
* === SECTION: Auth State === Line ~426 — isAuthenticated, authBlocked, userId, beta access
|
|
14
|
+
* === SECTION: Bootstrap State === Line ~442 — bootstrapPhase, setupState, runtimeCapabilities
|
|
15
|
+
* === SECTION: Fetch Intercept === Line ~490 — window.fetch patch for cloud API routing
|
|
16
|
+
* === SECTION: Workflow Templates === Line ~577 — fetchWorkflows, fetchInitiativeTemplates
|
|
17
|
+
* === SECTION: Export State === Line ~678 — exportEnvironment, exportWorkflowsPath
|
|
18
|
+
* === SECTION: Task State === Line ~1065 — tasks, archivedTasks, editingTaskId
|
|
19
|
+
* === SECTION: Filter & Sort State === Line ~1394 — searchQuery, filterCategories, sortBy, sortOrder
|
|
20
|
+
* === SECTION: UI State === Line ~1469 — uiStateReady, persisted UI preferences
|
|
21
|
+
* === SECTION: Config Fetch === Line ~1578 — fetchConfig (the main bootstrap loader)
|
|
22
|
+
* === SECTION: Workspace Actions === Line ~1855 — fetchWorkspaces, switchWorkspace, createWorkspace
|
|
23
|
+
* === SECTION: Auth Actions === Line ~2210 — loginWithCredentials, logout, invite flows
|
|
24
|
+
* === SECTION: Task Fetch === Line ~2158 — fetchTasks, fetchArchive, refreshTaskCollections
|
|
25
|
+
* === SECTION: Bootstrap Effects === Line ~2641 — initialization useEffects
|
|
26
|
+
* === SECTION: Filtering Logic === Line ~3068 — filteredTasks, searchAgnosticTasks, filteredArchive
|
|
27
|
+
* === SECTION: Navigation === Line ~3410 — setActiveTab, handleNavigation
|
|
28
|
+
* === SECTION: Form === Line ~3489 — resetForm, handleEdit, handleSubmit, saveTask
|
|
29
|
+
* === SECTION: Task CRUD === Line ~3691 — handleDelete, handleUpdateTask, handleToggle*
|
|
30
|
+
* === SECTION: Planning Links === Line ~4129 — workstream and initiative link handlers
|
|
31
|
+
* === SECTION: Category/Type Mgmt === Line ~4462 — handleSaveCategory, handleRemoveCategory
|
|
32
|
+
* === SECTION: Settings Model === Line ~4625 — settingsModel object
|
|
33
|
+
* === SECTION: Return Value === Line ~4817 — final return object (public API shape)
|
|
34
|
+
*/
|
|
35
|
+
import { type Dispatch, type SetStateAction } from 'react';
|
|
1
36
|
import type { TaskforceConfig, TaskforceTheme, Comment, AttachmentItem, CategoryConfig, TaskItem, TaxonomyDefinition, Environment, TaskAssignee, TaskStatus, DeletedTaskRecord, InitiativeItem, WorkstreamItem, ChecklistItem, PlanningBootstrapWorkstreamTaskSummary } from '../types';
|
|
2
37
|
import { type FirstClassTaxonomyDisplayLabels } from '../shared/taxonomyState.js';
|
|
3
38
|
import type { UiNotice } from '../utils/uiNotice';
|
|
@@ -106,31 +141,31 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
106
141
|
showTaskCardStatusLabel: boolean;
|
|
107
142
|
};
|
|
108
143
|
isOpen: boolean;
|
|
109
|
-
setIsOpen:
|
|
144
|
+
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
|
110
145
|
activeTab: "tasks" | "settings" | "add";
|
|
111
146
|
setActiveTab: (tab: "add" | "tasks" | "settings") => void;
|
|
112
147
|
currentTheme: "light" | "dawn" | "dark" | "midnight";
|
|
113
|
-
setCurrentTheme:
|
|
148
|
+
setCurrentTheme: Dispatch<SetStateAction<"light" | "dawn" | "dark" | "midnight">>;
|
|
114
149
|
configLoaded: boolean;
|
|
115
150
|
storagePath: string;
|
|
116
151
|
saveSettings: () => Promise<boolean>;
|
|
117
152
|
pathSaved: boolean;
|
|
118
153
|
keyShortcut: string;
|
|
119
|
-
setKeyShortcut:
|
|
154
|
+
setKeyShortcut: Dispatch<SetStateAction<string>>;
|
|
120
155
|
globalWeekStartsOn: WeekStartsOn;
|
|
121
156
|
locale: "en-US" | "es-419" | "pt-BR";
|
|
122
157
|
supportedLocales: ("en-US" | "es-419" | "pt-BR")[];
|
|
123
158
|
saveLocale: (nextLocale: string) => Promise<boolean>;
|
|
124
159
|
jsonBackupEnabled: boolean;
|
|
125
|
-
setJsonBackupEnabled:
|
|
160
|
+
setJsonBackupEnabled: Dispatch<SetStateAction<boolean>>;
|
|
126
161
|
manualComplexityEnabled: boolean;
|
|
127
162
|
checklistDropdownEnabled: boolean;
|
|
128
163
|
showTaskCardStatusLabel: boolean;
|
|
129
|
-
setManualComplexityEnabled:
|
|
164
|
+
setManualComplexityEnabled: Dispatch<SetStateAction<boolean>>;
|
|
130
165
|
mcpHostRoot: string;
|
|
131
|
-
setMcpHostRoot:
|
|
166
|
+
setMcpHostRoot: Dispatch<SetStateAction<string>>;
|
|
132
167
|
settingsSection: "mcp" | "categories" | "types" | "general" | "agents" | "taxonomy" | "documents" | "appearance-application" | "appearance-task-cards" | "appearance-task-forms" | "commands" | "workflow-editor" | "integrations" | "resources" | null;
|
|
133
|
-
setSettingsSection:
|
|
168
|
+
setSettingsSection: Dispatch<SetStateAction<"mcp" | "categories" | "types" | "general" | "agents" | "taxonomy" | "documents" | "appearance-application" | "appearance-task-cards" | "appearance-task-forms" | "commands" | "workflow-editor" | "integrations" | "resources" | null>>;
|
|
134
169
|
runtimeMode: "local" | "cloud";
|
|
135
170
|
workspaceMode: "single-local" | "multi-cloud";
|
|
136
171
|
workspaceSwitchingEnabled: boolean;
|
|
@@ -383,7 +418,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
383
418
|
}>;
|
|
384
419
|
logout: () => Promise<void>;
|
|
385
420
|
showFolderBrowser: boolean;
|
|
386
|
-
setShowFolderBrowser:
|
|
421
|
+
setShowFolderBrowser: Dispatch<SetStateAction<boolean>>;
|
|
387
422
|
folders: string[];
|
|
388
423
|
files: string[];
|
|
389
424
|
currentBrowsePath: string;
|
|
@@ -392,16 +427,16 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
392
427
|
type: "category";
|
|
393
428
|
value: string;
|
|
394
429
|
} | null;
|
|
395
|
-
setBrowserTarget:
|
|
430
|
+
setBrowserTarget: Dispatch<SetStateAction<"storage" | {
|
|
396
431
|
type: "category";
|
|
397
432
|
value: string;
|
|
398
433
|
} | null>>;
|
|
399
434
|
groupBy: "category" | "type" | "priority" | "status" | "complexity" | "approach" | "assignee" | "schedule";
|
|
400
|
-
setGroupBy:
|
|
435
|
+
setGroupBy: Dispatch<SetStateAction<"category" | "type" | "priority" | "status" | "complexity" | "approach" | "assignee" | "schedule">>;
|
|
401
436
|
activeWorkspaceModule: WorkspaceModuleId;
|
|
402
|
-
setActiveWorkspaceModule:
|
|
437
|
+
setActiveWorkspaceModule: Dispatch<SetStateAction<WorkspaceModuleId>>;
|
|
403
438
|
emptyColumnMode: "show" | "collapse" | "hide";
|
|
404
|
-
setEmptyColumnMode:
|
|
439
|
+
setEmptyColumnMode: Dispatch<SetStateAction<"show" | "collapse" | "hide">>;
|
|
405
440
|
zenMode: boolean;
|
|
406
441
|
setZenMode: () => Promise<void>;
|
|
407
442
|
handleSelectPath: (path: string) => void;
|
|
@@ -438,36 +473,36 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
438
473
|
}[];
|
|
439
474
|
taxonomies: TaxonomyDefinition[];
|
|
440
475
|
searchQuery: string;
|
|
441
|
-
setSearchQuery:
|
|
476
|
+
setSearchQuery: Dispatch<SetStateAction<string>>;
|
|
442
477
|
filterCategories: string[];
|
|
443
|
-
setFilterCategories:
|
|
478
|
+
setFilterCategories: Dispatch<SetStateAction<string[]>>;
|
|
444
479
|
filterTypes: string[];
|
|
445
|
-
setFilterTypes:
|
|
480
|
+
setFilterTypes: Dispatch<SetStateAction<string[]>>;
|
|
446
481
|
filterPriorities: (string | number)[];
|
|
447
|
-
setFilterPriorities:
|
|
482
|
+
setFilterPriorities: Dispatch<SetStateAction<(string | number)[]>>;
|
|
448
483
|
filterStatus: (string | number)[];
|
|
449
|
-
setFilterStatus:
|
|
484
|
+
setFilterStatus: Dispatch<SetStateAction<(string | number)[]>>;
|
|
450
485
|
filterAssignees: string[];
|
|
451
486
|
setFilterAssignees: (nextValues: TaskAssignee[] | ((prev: TaskAssignee[]) => TaskAssignee[])) => void;
|
|
452
487
|
filterTaxonomies: Record<string, (string | number)[]>;
|
|
453
|
-
setFilterTaxonomies:
|
|
488
|
+
setFilterTaxonomies: Dispatch<SetStateAction<Record<string, (string | number)[]>>>;
|
|
454
489
|
hasInitedFilters: boolean;
|
|
455
490
|
sortBy: import("../utils/taxonomySorting").TaskSortKey;
|
|
456
|
-
setSortBy:
|
|
491
|
+
setSortBy: Dispatch<SetStateAction<import("../utils/taxonomySorting").TaskSortKey>>;
|
|
457
492
|
sortOrder: "asc" | "desc";
|
|
458
|
-
setSortOrder:
|
|
493
|
+
setSortOrder: Dispatch<SetStateAction<"asc" | "desc">>;
|
|
459
494
|
toggleSortOrder: () => void;
|
|
460
495
|
showArchive: boolean;
|
|
461
|
-
setShowArchive:
|
|
496
|
+
setShowArchive: Dispatch<SetStateAction<boolean>>;
|
|
462
497
|
taskScope: TaskScope;
|
|
463
|
-
setTaskScope:
|
|
498
|
+
setTaskScope: Dispatch<SetStateAction<TaskScope>>;
|
|
464
499
|
clearFilters: () => void;
|
|
465
500
|
filteredTasks: TaskItem[];
|
|
466
501
|
searchAgnosticTasks: TaskItem[];
|
|
467
502
|
filteredArchive: TaskItem[];
|
|
468
503
|
groupedTasks: Record<string, TaskItem[]>;
|
|
469
504
|
collapsedCategories: Record<string, boolean>;
|
|
470
|
-
setCollapsedCategories:
|
|
505
|
+
setCollapsedCategories: Dispatch<SetStateAction<Record<string, boolean>>>;
|
|
471
506
|
fetchTasks: (isSilent?: boolean, options?: {
|
|
472
507
|
ignoreAuthGuard?: boolean;
|
|
473
508
|
}) => Promise<void>;
|
|
@@ -514,50 +549,50 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
514
549
|
loading: boolean;
|
|
515
550
|
error: string;
|
|
516
551
|
title: string;
|
|
517
|
-
setTitle:
|
|
552
|
+
setTitle: Dispatch<SetStateAction<string>>;
|
|
518
553
|
description: string;
|
|
519
|
-
setDescription:
|
|
554
|
+
setDescription: Dispatch<SetStateAction<string>>;
|
|
520
555
|
checklistItems: ChecklistItem[];
|
|
521
|
-
setChecklistItems:
|
|
556
|
+
setChecklistItems: Dispatch<SetStateAction<ChecklistItem[]>>;
|
|
522
557
|
category: string;
|
|
523
|
-
setCategory:
|
|
558
|
+
setCategory: Dispatch<SetStateAction<string>>;
|
|
524
559
|
type: string;
|
|
525
|
-
setType:
|
|
560
|
+
setType: Dispatch<SetStateAction<string>>;
|
|
526
561
|
priority: string | number;
|
|
527
|
-
setPriority:
|
|
562
|
+
setPriority: Dispatch<SetStateAction<string | number>>;
|
|
528
563
|
complexity: string | number;
|
|
529
|
-
setComplexity:
|
|
564
|
+
setComplexity: Dispatch<SetStateAction<string | number>>;
|
|
530
565
|
status: TaskStatus;
|
|
531
|
-
setStatus:
|
|
566
|
+
setStatus: Dispatch<SetStateAction<TaskStatus>>;
|
|
532
567
|
approach: string;
|
|
533
|
-
setApproach:
|
|
568
|
+
setApproach: Dispatch<SetStateAction<string>>;
|
|
534
569
|
assignee: string;
|
|
535
|
-
setAssignee:
|
|
570
|
+
setAssignee: Dispatch<SetStateAction<string>>;
|
|
536
571
|
scheduledDate: string;
|
|
537
|
-
setScheduledDate:
|
|
572
|
+
setScheduledDate: Dispatch<SetStateAction<string>>;
|
|
538
573
|
dueDate: string;
|
|
539
|
-
setDueDate:
|
|
574
|
+
setDueDate: Dispatch<SetStateAction<string>>;
|
|
540
575
|
workstreamInput: string;
|
|
541
|
-
setWorkstreamInput:
|
|
576
|
+
setWorkstreamInput: Dispatch<SetStateAction<string>>;
|
|
542
577
|
formTaxonomies: Record<string, string | number | string[] | number[]>;
|
|
543
|
-
setFormTaxonomies:
|
|
578
|
+
setFormTaxonomies: Dispatch<SetStateAction<Record<string, string | number | string[] | number[]>>>;
|
|
544
579
|
comments: Comment[];
|
|
545
580
|
newCommentText: string;
|
|
546
|
-
setNewCommentText:
|
|
581
|
+
setNewCommentText: Dispatch<SetStateAction<string>>;
|
|
547
582
|
attachments: (string | AttachmentItem)[];
|
|
548
|
-
setAttachments:
|
|
583
|
+
setAttachments: Dispatch<SetStateAction<(string | AttachmentItem)[]>>;
|
|
549
584
|
attachmentsDirty: boolean;
|
|
550
|
-
setAttachmentsDirty:
|
|
585
|
+
setAttachmentsDirty: Dispatch<SetStateAction<boolean>>;
|
|
551
586
|
descriptionFocused: boolean;
|
|
552
|
-
setDescriptionFocused:
|
|
587
|
+
setDescriptionFocused: Dispatch<SetStateAction<boolean>>;
|
|
553
588
|
showMarkdownHelp: boolean;
|
|
554
|
-
setShowMarkdownHelp:
|
|
589
|
+
setShowMarkdownHelp: Dispatch<SetStateAction<boolean>>;
|
|
555
590
|
showChecklist: boolean;
|
|
556
|
-
setShowChecklist:
|
|
591
|
+
setShowChecklist: Dispatch<SetStateAction<boolean>>;
|
|
557
592
|
showComments: boolean;
|
|
558
|
-
setShowComments:
|
|
593
|
+
setShowComments: Dispatch<SetStateAction<boolean>>;
|
|
559
594
|
isCapturingScreenshot: boolean;
|
|
560
|
-
setIsCapturingScreenshot:
|
|
595
|
+
setIsCapturingScreenshot: Dispatch<SetStateAction<boolean>>;
|
|
561
596
|
handleSubmit: (event: React.FormEvent) => Promise<void>;
|
|
562
597
|
resetForm: () => void;
|
|
563
598
|
handleAddComment: (text: string) => Promise<void>;
|
|
@@ -566,7 +601,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
566
601
|
returnToPreviousTask: () => boolean;
|
|
567
602
|
autoSaveState: import("./tasks/useTaskFormActions").TaskAutoSaveState;
|
|
568
603
|
unsavedModalOpen: boolean;
|
|
569
|
-
setUnsavedModalOpen:
|
|
604
|
+
setUnsavedModalOpen: Dispatch<SetStateAction<boolean>>;
|
|
570
605
|
pendingNavigation: (() => void) | null;
|
|
571
606
|
handleNavigation: (action: () => void) => void;
|
|
572
607
|
handleClose: () => void;
|
|
@@ -588,11 +623,11 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
588
623
|
confirmScheduleWarning: () => Promise<void>;
|
|
589
624
|
cancelScheduleWarning: () => void;
|
|
590
625
|
tasksScrollRef: import("react").RefObject<HTMLDivElement | null>;
|
|
591
|
-
setTasksScrollPos:
|
|
626
|
+
setTasksScrollPos: Dispatch<SetStateAction<number>>;
|
|
592
627
|
exportEnvironment: string;
|
|
593
|
-
setExportEnvironment:
|
|
628
|
+
setExportEnvironment: Dispatch<SetStateAction<string>>;
|
|
594
629
|
exportWorkflowsPath: string;
|
|
595
|
-
setExportWorkflowsPath:
|
|
630
|
+
setExportWorkflowsPath: Dispatch<SetStateAction<string>>;
|
|
596
631
|
exportResult: {
|
|
597
632
|
type: "success" | "error";
|
|
598
633
|
message: string;
|
|
@@ -627,7 +662,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
|
|
|
627
662
|
validatePaths: (paths: string[]) => Promise<void>;
|
|
628
663
|
getCategoryPaths: (cat: CategoryConfig) => string[];
|
|
629
664
|
customCategories: CategoryConfig[];
|
|
630
|
-
setCustomCategories:
|
|
665
|
+
setCustomCategories: Dispatch<SetStateAction<CategoryConfig[]>>;
|
|
631
666
|
projectRoot: string;
|
|
632
667
|
projectName: string;
|
|
633
668
|
mcpScriptPath: string;
|
|
@@ -68,6 +68,7 @@ import { useTaskforceAuthBootstrap } from './auth/useTaskforceAuthBootstrap';
|
|
|
68
68
|
import { deriveAuthGuardPolicy } from './auth/useAuthGuardPolicy';
|
|
69
69
|
import { useTaskforceWorkspaceBootstrap } from './workspace/useTaskforceWorkspaceBootstrap';
|
|
70
70
|
import { useDataVersionRefresh } from './sync/useDataVersionRefresh';
|
|
71
|
+
import { BOOTSTRAP_REQUEST_TIMEOUT_MS } from './bootstrapTimeouts';
|
|
71
72
|
function upsertEntityById(items, nextItem) {
|
|
72
73
|
const existingIndex = items.findIndex((item) => item.id === nextItem.id);
|
|
73
74
|
if (existingIndex === -1) {
|
|
@@ -89,7 +90,6 @@ const DEFAULT_CLOUD_APP_ORIGIN = (() => {
|
|
|
89
90
|
// Safety default for local runtime cloud auth/sync fallback.
|
|
90
91
|
return 'https://app.taskforcehq.ai';
|
|
91
92
|
})();
|
|
92
|
-
const BOOTSTRAP_REQUEST_TIMEOUT_MS = 12_000;
|
|
93
93
|
const PLANNING_BOOTSTRAP_REQUEST_TIMEOUT_MS = 20_000;
|
|
94
94
|
const EXPECTED_WORKSPACE_ABORT_REASONS = new Set([
|
|
95
95
|
'external-abort',
|
|
@@ -944,7 +944,10 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
944
944
|
setPlanningBootstrapTaskSummaries([]);
|
|
945
945
|
return;
|
|
946
946
|
}
|
|
947
|
-
if (bootstrapRes
|
|
947
|
+
if (bootstrapRes === null) {
|
|
948
|
+
throw createBootstrapTimeoutError(PLANNING_BOOTSTRAP_REQUEST_TIMEOUT_MS);
|
|
949
|
+
}
|
|
950
|
+
if (bootstrapRes.ok) {
|
|
948
951
|
bootstrapPayload = sanitizePlanningBootstrapPayload(await bootstrapRes.json().catch(() => ({})));
|
|
949
952
|
}
|
|
950
953
|
else {
|
|
@@ -982,7 +985,18 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
982
985
|
catch (err) {
|
|
983
986
|
if (isExpectedWorkspaceAbortFailure(err, abortController.signal) || isAbortError(err))
|
|
984
987
|
return;
|
|
985
|
-
|
|
988
|
+
const startupTimeout = isBootstrapTimeoutError(err);
|
|
989
|
+
if (startupTimeout) {
|
|
990
|
+
logBootstrapDebug('planning_bootstrap_timeout', {
|
|
991
|
+
workspaceId: requestState.workspaceId,
|
|
992
|
+
epoch: requestState.epoch,
|
|
993
|
+
timeoutMs: PLANNING_BOOTSTRAP_REQUEST_TIMEOUT_MS,
|
|
994
|
+
});
|
|
995
|
+
console.warn('[Taskforce] Planning bootstrap timed out during startup; retrying in background.');
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
console.error('[Taskforce] Failed to fetch planning entities:', err);
|
|
999
|
+
}
|
|
986
1000
|
if (typeof window !== 'undefined'
|
|
987
1001
|
&& !isWorkspaceRequestStale(requestState)
|
|
988
1002
|
&& initiatives.length === 0
|
|
@@ -1160,7 +1174,7 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
1160
1174
|
}
|
|
1161
1175
|
});
|
|
1162
1176
|
checkAuthSessionImplRef.current = checkAuthSessionImpl;
|
|
1163
|
-
const [activeWorkspaceModule,
|
|
1177
|
+
const [activeWorkspaceModule, setActiveWorkspaceModuleState] = useState('tasks');
|
|
1164
1178
|
const [showComments, setShowComments] = useState(false);
|
|
1165
1179
|
const [descriptionFocused, setDescriptionFocused] = useState(false);
|
|
1166
1180
|
const [isCapturingScreenshot, setIsCapturingScreenshot] = useState(false);
|
|
@@ -1181,10 +1195,17 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
1181
1195
|
const lastTaskSurfaceLoadKeyRef = useRef('');
|
|
1182
1196
|
const lastSettingsSurfaceLoadKeyRef = useRef('');
|
|
1183
1197
|
const skipNextUiStatePersistRef = useRef(false);
|
|
1198
|
+
const activeWorkspaceModuleOverridePendingRef = useRef(false);
|
|
1184
1199
|
const referenceDataRequestRef = useRef(null);
|
|
1185
1200
|
const workspaceListHydratedRef = useRef(false);
|
|
1186
1201
|
const hasBootstrappedDataRef = useRef(false);
|
|
1187
1202
|
const [uiStateReady, setUiStateReady] = useState(false);
|
|
1203
|
+
const setActiveWorkspaceModule = useCallback((nextModule) => {
|
|
1204
|
+
if (!uiStateReady) {
|
|
1205
|
+
activeWorkspaceModuleOverridePendingRef.current = true;
|
|
1206
|
+
}
|
|
1207
|
+
setActiveWorkspaceModuleState(nextModule);
|
|
1208
|
+
}, [uiStateReady]);
|
|
1188
1209
|
const { handleSaveSettings, handleSaveTheme, handleSaveGlobalTheme, handleJsonBackupEnabledChange, handleSaveGlobalJsonBackupEnabled, handleSaveGlobalWeekStartsOn, handleSaveLocale, handleManualComplexityEnabledChange, handleChecklistDropdownEnabledChange, handleShowTaskCardStatusLabelChange, handleResetProjectToGlobal } = useSettingsPersistence({
|
|
1189
1210
|
keyShortcut,
|
|
1190
1211
|
themeUseGlobalDefault,
|
|
@@ -1217,7 +1238,7 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
1217
1238
|
authRequiredForApiRef.current = authRequiredForApi;
|
|
1218
1239
|
isAuthenticatedRef.current = isAuthenticated;
|
|
1219
1240
|
}, [authSessionResolved, authRequiredForApi, isAuthenticated]);
|
|
1220
|
-
const applyPersistedUiState = useCallback((state) => {
|
|
1241
|
+
const applyPersistedUiState = useCallback((state, options) => {
|
|
1221
1242
|
if (!state)
|
|
1222
1243
|
return;
|
|
1223
1244
|
const hasPersistedFilterState = Array.isArray(state.filterCategories)
|
|
@@ -1227,11 +1248,13 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
1227
1248
|
|| Array.isArray(state.filterAssignees)
|
|
1228
1249
|
|| typeof state.filterAssigneesAllSelected === 'boolean'
|
|
1229
1250
|
|| (state.filterTaxonomies && typeof state.filterTaxonomies === 'object');
|
|
1230
|
-
if (
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1251
|
+
if (!options?.skipActiveWorkspaceModule) {
|
|
1252
|
+
if (typeof state.activeWorkspaceModule === 'string') {
|
|
1253
|
+
setActiveWorkspaceModuleState(state.activeWorkspaceModule);
|
|
1254
|
+
}
|
|
1255
|
+
else if (state.groupBy === 'docs') {
|
|
1256
|
+
setActiveWorkspaceModuleState('docs');
|
|
1257
|
+
}
|
|
1235
1258
|
}
|
|
1236
1259
|
if (state.groupBy && state.groupBy !== 'docs')
|
|
1237
1260
|
setGroupBy(state.groupBy);
|
|
@@ -1295,19 +1318,24 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
1295
1318
|
if (currentWorkspaceIdRef.current !== targetWorkspaceId) {
|
|
1296
1319
|
return;
|
|
1297
1320
|
}
|
|
1298
|
-
applyPersistedUiState(state
|
|
1321
|
+
applyPersistedUiState(state, {
|
|
1322
|
+
skipActiveWorkspaceModule: activeWorkspaceModuleOverridePendingRef.current
|
|
1323
|
+
});
|
|
1299
1324
|
lastLoadedUiStateKeyRef.current = uiStateLoadKey;
|
|
1300
1325
|
}
|
|
1301
1326
|
catch {
|
|
1302
1327
|
const localState = readPersistedAppUiState(workspaceUiStateScope);
|
|
1303
1328
|
if (currentWorkspaceIdRef.current === targetWorkspaceId) {
|
|
1304
|
-
applyPersistedUiState(localState
|
|
1329
|
+
applyPersistedUiState(localState, {
|
|
1330
|
+
skipActiveWorkspaceModule: activeWorkspaceModuleOverridePendingRef.current
|
|
1331
|
+
});
|
|
1305
1332
|
lastLoadedUiStateKeyRef.current = uiStateLoadKey;
|
|
1306
1333
|
}
|
|
1307
1334
|
}
|
|
1308
1335
|
finally {
|
|
1309
1336
|
if (currentWorkspaceIdRef.current !== targetWorkspaceId)
|
|
1310
1337
|
return;
|
|
1338
|
+
activeWorkspaceModuleOverridePendingRef.current = false;
|
|
1311
1339
|
skipNextUiStatePersistRef.current = true;
|
|
1312
1340
|
setUiStateReady(true);
|
|
1313
1341
|
}
|
|
@@ -1533,10 +1561,12 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
|
|
|
1533
1561
|
}
|
|
1534
1562
|
catch (versionError) {
|
|
1535
1563
|
if (isBootstrapTimeoutError(versionError)) {
|
|
1536
|
-
|
|
1564
|
+
logBootstrapDebug('build_info_timeout', {
|
|
1565
|
+
durationMs: Math.round((typeof performance !== 'undefined' ? performance.now() : Date.now()) - startedAt)
|
|
1566
|
+
});
|
|
1537
1567
|
}
|
|
1538
1568
|
}
|
|
1539
|
-
}, [fetchWithTimeout, isBootstrapTimeoutError
|
|
1569
|
+
}, [fetchWithTimeout, isBootstrapTimeoutError]);
|
|
1540
1570
|
const { fetchReferenceData, fetchBootstrapConfig, fetchConfig, fetchWorkspaces, fetchAssigneeOptions, switchWorkspace, resolveWorkspaceAfterAuth, retryBootstrapChecks, runCloudBootstrap } = useTaskforceWorkspaceBootstrap({
|
|
1541
1571
|
shouldDeferProtectedApiCalls,
|
|
1542
1572
|
shouldBlockProtectedApiCalls,
|