@taskforcehq/taskforce 0.3.170 → 0.3.301

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.
Files changed (698) hide show
  1. package/README.md +71 -21
  2. package/dist/Taskforce.module.css +3394 -5981
  3. package/dist/TaskforceCore.CategoryFallback.test.js +5 -2
  4. package/dist/TaskforceCore.filter-persistence.test.js +402 -0
  5. package/dist/TaskforceCore.js +388 -71
  6. package/dist/TaskforceCore.routing.test.js +311 -0
  7. package/dist/TaskforceCore.test.js +3344 -615
  8. package/dist/TaskforceWidget.js +3 -2
  9. package/dist/__tests__/localizationCatalogs.test.js +48 -31
  10. package/dist/__tests__/workflowSimulation.test.js +2 -2
  11. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.d.ts +60 -0
  12. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +324 -0
  13. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.js +278 -0
  14. package/dist/annotatedAttachments/payload.d.ts +2 -0
  15. package/dist/annotatedAttachments/payload.js +54 -0
  16. package/dist/annotatedAttachments/payload.test.js +67 -0
  17. package/dist/annotatedAttachments/service.d.ts +49 -0
  18. package/dist/annotatedAttachments/service.js +121 -0
  19. package/dist/annotatedAttachments/types.d.ts +86 -0
  20. package/dist/cli.js +74 -25
  21. package/dist/compat/deploymentCompat.d.ts +12 -0
  22. package/dist/compat/deploymentCompat.js +43 -0
  23. package/dist/compat/workspaceSyncCompat.d.ts +6 -0
  24. package/dist/compat/workspaceSyncCompat.js +79 -0
  25. package/dist/compat/workspaceSyncCompat.test.js +87 -0
  26. package/dist/components/features/AgentsModule.d.ts +5 -0
  27. package/dist/components/features/AgentsModule.js +131 -0
  28. package/dist/components/features/AgentsModule.test.js +102 -0
  29. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +24 -0
  30. package/dist/components/features/AnnotatedAttachmentWorkspace.js +1942 -0
  31. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +2831 -0
  32. package/dist/components/features/DocumentGenerateModal.js +8 -16
  33. package/dist/components/features/DocumentIndex.d.ts +3 -4
  34. package/dist/components/features/DocumentIndex.js +22 -10
  35. package/dist/components/features/DocumentViewer.d.ts +6 -2
  36. package/dist/components/features/DocumentViewer.js +1000 -18
  37. package/dist/components/features/DocumentWorkspace.d.ts +40 -2
  38. package/dist/components/features/DocumentWorkspace.js +96 -16
  39. package/dist/components/features/DocumentWorkspace.test.js +1202 -0
  40. package/dist/components/features/InitiativesModule.d.ts +22 -0
  41. package/dist/components/features/InitiativesModule.js +33 -0
  42. package/dist/components/features/TaskSettings.d.ts +41 -32
  43. package/dist/components/features/TaskSettings.js +798 -313
  44. package/dist/components/features/TaskSettings.test.js +1221 -47
  45. package/dist/components/features/WorkflowsModule.d.ts +27 -0
  46. package/dist/components/features/WorkflowsModule.js +21 -0
  47. package/dist/components/features/documentWorkspaceFilters.d.ts +10 -0
  48. package/dist/components/features/documentWorkspaceFilters.js +11 -0
  49. package/dist/components/features/settings/CategoryManager.d.ts +2 -0
  50. package/dist/components/features/settings/CategoryManager.js +15 -8
  51. package/dist/components/features/settings/PriorityManager.d.ts +18 -0
  52. package/dist/components/features/settings/PriorityManager.js +51 -0
  53. package/dist/components/features/settings/TaxonomyEditor.d.ts +2 -1
  54. package/dist/components/features/settings/TaxonomyEditor.js +41 -18
  55. package/dist/components/features/settings/TaxonomyLibraryManager.d.ts +26 -0
  56. package/dist/components/features/settings/TaxonomyLibraryManager.js +301 -0
  57. package/dist/components/features/settings/TaxonomyLibraryManager.test.js +141 -0
  58. package/dist/components/features/settings/TaxonomyManager.d.ts +35 -12
  59. package/dist/components/features/settings/TaxonomyManager.js +59 -27
  60. package/dist/components/features/settings/TypeManager.d.ts +11 -0
  61. package/dist/components/features/settings/TypeManager.js +48 -11
  62. package/dist/components/features/settings/{WorkflowEditorPrototype.d.ts → WorkflowEditor.d.ts} +2 -2
  63. package/dist/components/features/settings/{WorkflowEditorPrototype.js → WorkflowEditor.js} +3 -3
  64. package/dist/components/task/TaskActionHeader.d.ts +12 -2
  65. package/dist/components/task/TaskActionHeader.js +64 -8
  66. package/dist/components/task/TaskActionHeader.test.js +73 -0
  67. package/dist/components/task/TaskCard.d.ts +14 -16
  68. package/dist/components/task/TaskCard.js +144 -174
  69. package/dist/components/task/TaskCard.test.js +416 -64
  70. package/dist/components/task/TaskContextUpload.d.ts +6 -5
  71. package/dist/components/task/TaskContextUpload.js +199 -64
  72. package/dist/components/task/TaskContextUpload.test.js +331 -14
  73. package/dist/components/task/TaskForm.d.ts +23 -29
  74. package/dist/components/task/TaskForm.js +348 -169
  75. package/dist/components/task/TaskForm.test.js +419 -23
  76. package/dist/components/task/TaskKanban.d.ts +20 -21
  77. package/dist/components/task/TaskKanban.js +176 -316
  78. package/dist/components/task/TaskKanban.planning-drop.test.js +93 -0
  79. package/dist/components/task/TaskList.d.ts +22 -11
  80. package/dist/components/task/TaskList.js +98 -12
  81. package/dist/components/task/TaskList.test.js +206 -7
  82. package/dist/components/task/TaskReferenceBadge.d.ts +12 -0
  83. package/dist/components/task/TaskReferenceBadge.js +5 -0
  84. package/dist/components/task/TaskStatusActions.d.ts +12 -0
  85. package/dist/components/task/TaskStatusActions.js +18 -0
  86. package/dist/components/task/TaskStatusActions.test.js +45 -0
  87. package/dist/components/ui/ImageReferenceBadge.d.ts +12 -0
  88. package/dist/components/ui/ImageReferenceBadge.js +5 -0
  89. package/dist/components/ui/LevelSelector.d.ts +2 -1
  90. package/dist/components/ui/LevelSelector.js +2 -2
  91. package/dist/components/ui/Markdown.d.ts +1 -2
  92. package/dist/components/ui/Markdown.js +2 -13
  93. package/dist/components/ui/Modal.d.ts +3 -2
  94. package/dist/components/ui/Modal.js +4 -3
  95. package/dist/components/ui/MultiSelectFilter.d.ts +3 -1
  96. package/dist/components/ui/MultiSelectFilter.js +2 -2
  97. package/dist/components/ui/ReferenceBadgeButton.d.ts +13 -0
  98. package/dist/components/ui/ReferenceBadgeButton.js +6 -0
  99. package/dist/components/ui/TaxonomyDropdown.d.ts +7 -1
  100. package/dist/components/ui/TaxonomyDropdown.js +58 -23
  101. package/dist/components/ui/TopNoticeLayer.d.ts +7 -0
  102. package/dist/components/ui/TopNoticeLayer.js +14 -0
  103. package/dist/components/ui/TopNoticeLayer.test.js +25 -0
  104. package/dist/components/views/AppShellHeader.d.ts +13 -0
  105. package/dist/components/views/AppShellHeader.js +19 -0
  106. package/dist/components/views/AppShellHeader.test.js +21 -0
  107. package/dist/components/views/PlanComparisonPage.d.ts +73 -0
  108. package/dist/components/views/PlanComparisonPage.js +196 -0
  109. package/dist/components/views/PlanComparisonPage.test.js +251 -0
  110. package/dist/components/views/PlansPage.d.ts +14 -0
  111. package/dist/components/views/PlansPage.js +355 -0
  112. package/dist/components/views/StandaloneLayout.d.ts +2 -2
  113. package/dist/components/views/StandaloneLayout.js +2227 -1188
  114. package/dist/components/views/WidgetView.d.ts +2 -2
  115. package/dist/components/views/WidgetView.js +149 -43
  116. package/dist/components/views/chrome/WorkspaceChromeSections.d.ts +57 -0
  117. package/dist/components/views/chrome/WorkspaceChromeSections.js +38 -0
  118. package/dist/components/views/chrome/WorkspaceChromeSections.test.js +54 -0
  119. package/dist/components/views/chrome/workspaceChrome.d.ts +31 -0
  120. package/dist/components/views/chrome/workspaceChrome.js +108 -0
  121. package/dist/components/views/chrome/workspaceChrome.test.js +52 -0
  122. package/dist/components/views/panels/DocumentFilterToolbar.d.ts +10 -0
  123. package/dist/components/views/panels/DocumentFilterToolbar.js +7 -0
  124. package/dist/components/views/panels/DocumentFilterToolbar.test.js +19 -0
  125. package/dist/components/views/panels/FilterToolbar.d.ts +68 -0
  126. package/dist/components/views/panels/FilterToolbar.js +21 -0
  127. package/dist/components/views/panels/FilterToolbar.test.d.ts +1 -0
  128. package/dist/components/views/panels/FilterToolbar.test.js +45 -0
  129. package/dist/components/views/panels/FilterToolbarControls.d.ts +47 -0
  130. package/dist/components/views/panels/FilterToolbarControls.js +61 -0
  131. package/dist/components/views/panels/PlanningDrawer.d.ts +115 -0
  132. package/dist/components/views/panels/PlanningDrawer.js +220 -0
  133. package/dist/components/views/panels/ScheduleSidebar.d.ts +52 -0
  134. package/dist/components/views/panels/ScheduleSidebar.js +127 -0
  135. package/dist/components/views/panels/scheduleUtils.d.ts +14 -0
  136. package/dist/components/views/panels/scheduleUtils.js +79 -0
  137. package/dist/components/views/teamManagementAccess.d.ts +6 -0
  138. package/dist/components/views/teamManagementAccess.js +18 -0
  139. package/dist/components/views/teamManagementAccess.test.d.ts +1 -0
  140. package/dist/components/views/teamManagementAccess.test.js +44 -0
  141. package/dist/config/clientDeployment.d.ts +2 -0
  142. package/dist/config/clientDeployment.js +13 -0
  143. package/dist/config/cloudEnvironment.d.ts +15 -0
  144. package/dist/config/cloudEnvironment.js +60 -0
  145. package/dist/config/deployment.d.ts +20 -0
  146. package/dist/config/deployment.js +67 -0
  147. package/dist/config/deployment.test.d.ts +1 -0
  148. package/dist/config/deployment.test.js +88 -0
  149. package/dist/config/envSchema.js +36 -8
  150. package/dist/config/envSchema.test.js +28 -0
  151. package/dist/core/AiProfileService.d.ts +66 -0
  152. package/dist/core/AiProfileService.js +320 -0
  153. package/dist/core/AiProfileService.test.d.ts +1 -0
  154. package/dist/core/AiProfileService.test.js +164 -0
  155. package/dist/core/AiProfiles.test.d.ts +1 -0
  156. package/dist/core/AiProfiles.test.js +449 -0
  157. package/dist/core/AttachmentLinkService.d.ts +15 -0
  158. package/dist/core/AttachmentLinkService.js +157 -0
  159. package/dist/core/AuthTokenService.d.ts +44 -0
  160. package/dist/core/AuthTokenService.js +207 -0
  161. package/dist/core/CreatedBy.test.js +134 -6
  162. package/dist/core/DeletedTaskLifecycleService.d.ts +33 -0
  163. package/dist/core/DeletedTaskLifecycleService.js +158 -0
  164. package/dist/core/DeletedTaskTrash.test.d.ts +1 -0
  165. package/dist/core/DeletedTaskTrash.test.js +104 -0
  166. package/dist/core/EntitlementsPolicy.test.js +78 -5
  167. package/dist/core/GlobalSettingsService.d.ts +16 -0
  168. package/dist/core/GlobalSettingsService.js +370 -0
  169. package/dist/core/JsonBackupRuntime.test.d.ts +1 -0
  170. package/dist/core/JsonBackupRuntime.test.js +155 -0
  171. package/dist/core/McpTokenService.d.ts +118 -0
  172. package/dist/core/McpTokenService.js +921 -0
  173. package/dist/core/PlanEntitlementService.d.ts +201 -0
  174. package/dist/core/PlanEntitlementService.js +1442 -0
  175. package/dist/core/PlanVersionPolicy.test.d.ts +1 -0
  176. package/dist/core/PlanVersionPolicy.test.js +178 -0
  177. package/dist/core/PlanningEntities.test.d.ts +1 -0
  178. package/dist/core/PlanningEntities.test.js +95 -0
  179. package/dist/core/ScheduleFields.test.js +15 -19
  180. package/dist/core/SignupMonetizationSettings.test.d.ts +1 -0
  181. package/dist/core/SignupMonetizationSettings.test.js +159 -0
  182. package/dist/core/Stats.test.d.ts +1 -0
  183. package/dist/core/Stats.test.js +36 -0
  184. package/dist/core/SyncReconciliationService.d.ts +93 -0
  185. package/dist/core/SyncReconciliationService.js +406 -0
  186. package/dist/core/SystemAdmin.test.js +578 -13
  187. package/dist/core/TaskActivityService.d.ts +21 -0
  188. package/dist/core/TaskActivityService.js +130 -0
  189. package/dist/core/TaskAttachmentsCanonical.test.d.ts +1 -0
  190. package/dist/core/TaskAttachmentsCanonical.test.js +306 -0
  191. package/dist/core/TaskAuditTimeline.test.d.ts +1 -0
  192. package/dist/core/TaskAuditTimeline.test.js +132 -0
  193. package/dist/core/TaskTaxonomyValidation.test.js +338 -15
  194. package/dist/core/Taskforce.d.ts +930 -183
  195. package/dist/core/Taskforce.ids.test.js +252 -0
  196. package/dist/core/Taskforce.js +3848 -2532
  197. package/dist/core/Taskforce.mcpAuth.test.d.ts +1 -0
  198. package/dist/core/Taskforce.mcpAuth.test.js +343 -0
  199. package/dist/core/Taskforce.realtimeMutation.test.js +57 -2
  200. package/dist/core/TaxonomySettingsService.d.ts +18 -0
  201. package/dist/core/TaxonomySettingsService.js +162 -0
  202. package/dist/core/WorkspaceDelete.test.js +32 -13
  203. package/dist/core/WorkspaceLifecycleService.d.ts +11 -0
  204. package/dist/core/WorkspaceLifecycleService.js +88 -0
  205. package/dist/core/WorkspacePermissions.test.js +95 -0
  206. package/dist/core/WorkspacePlanMode.test.js +114 -1
  207. package/dist/core/WorkspacePreferenceService.d.ts +41 -0
  208. package/dist/core/WorkspacePreferenceService.js +246 -0
  209. package/dist/core/WorkspaceSyncSettings.test.d.ts +1 -0
  210. package/dist/core/WorkspaceSyncSettings.test.js +65 -0
  211. package/dist/core/__tests__/TaskAttachmentsCanonical.test.d.ts +1 -0
  212. package/dist/core/__tests__/TaskAttachmentsCanonical.test.js +212 -0
  213. package/dist/core/shared.d.ts +36 -0
  214. package/dist/core/shared.js +128 -0
  215. package/dist/core/types.d.ts +614 -0
  216. package/dist/core/types.js +27 -0
  217. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +56 -0
  218. package/dist/documentReviews/DocumentReviewCommentStore.js +230 -0
  219. package/dist/documentReviews/DocumentReviewSessionStore.d.ts +52 -0
  220. package/dist/documentReviews/DocumentReviewSessionStore.js +193 -0
  221. package/dist/documentReviews/DocumentReviewSessionStore.test.d.ts +1 -0
  222. package/dist/documentReviews/DocumentReviewSessionStore.test.js +127 -0
  223. package/dist/documentReviews/service.d.ts +68 -0
  224. package/dist/documentReviews/service.js +210 -0
  225. package/dist/documentReviews/types.d.ts +58 -0
  226. package/dist/documentReviews/types.js +1 -0
  227. package/dist/hooks/auth/useAuthGuardPolicy.d.ts +2 -0
  228. package/dist/hooks/auth/useAuthGuardPolicy.js +1 -0
  229. package/dist/hooks/tasks/useCurrentTaskRelations.d.ts +15 -0
  230. package/dist/hooks/tasks/useCurrentTaskRelations.js +37 -0
  231. package/dist/hooks/tasks/useTaskActions.d.ts +3 -0
  232. package/dist/hooks/tasks/useTaskActions.js +2 -0
  233. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +65 -0
  234. package/dist/hooks/tasks/useTaskEditorNavigation.js +235 -0
  235. package/dist/hooks/tasks/useTaskFilters.d.ts +2 -0
  236. package/dist/hooks/tasks/useTaskFilters.js +2 -0
  237. package/dist/hooks/tasks/useTaskFormActions.d.ts +58 -0
  238. package/dist/hooks/tasks/useTaskFormActions.js +365 -0
  239. package/dist/hooks/tasks/useTaskRelationships.d.ts +16 -0
  240. package/dist/hooks/tasks/useTaskRelationships.js +64 -0
  241. package/dist/hooks/ui/useResourceExport.d.ts +19 -0
  242. package/dist/hooks/ui/useResourceExport.js +84 -0
  243. package/dist/hooks/ui/useSettingsModel.d.ts +203 -0
  244. package/dist/hooks/ui/useSettingsModel.js +125 -0
  245. package/dist/hooks/ui/useSettingsPersistence.d.ts +36 -0
  246. package/dist/hooks/ui/useSettingsPersistence.js +254 -0
  247. package/dist/hooks/ui/useSettingsTaxonomyManagement.d.ts +119 -0
  248. package/dist/hooks/ui/useSettingsTaxonomyManagement.js +536 -0
  249. package/dist/hooks/ui/useUiNotice.d.ts +1 -0
  250. package/dist/hooks/ui/useUiNotice.js +1 -0
  251. package/dist/hooks/ui/useWorkflowTemplates.d.ts +37 -0
  252. package/dist/hooks/ui/useWorkflowTemplates.js +111 -0
  253. package/dist/hooks/ui/useZenMode.d.ts +5 -0
  254. package/dist/hooks/ui/useZenMode.js +32 -0
  255. package/dist/hooks/useFilterSort.d.ts +60 -0
  256. package/dist/hooks/useFilterSort.js +362 -0
  257. package/dist/hooks/useFilterSort.test.d.ts +1 -0
  258. package/dist/hooks/useFilterSort.test.js +333 -0
  259. package/dist/hooks/useRealtimeSync.d.ts +1 -0
  260. package/dist/hooks/useRealtimeSync.js +24 -9
  261. package/dist/hooks/useRealtimeSync.test.js +28 -1
  262. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.d.ts +1 -0
  263. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +34 -0
  264. package/dist/hooks/useSyncOrchestrator.d.ts +65 -103
  265. package/dist/hooks/useSyncOrchestrator.js +1538 -670
  266. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +700 -174
  267. package/dist/hooks/useTaskData.d.ts +35 -0
  268. package/dist/hooks/useTaskData.js +243 -0
  269. package/dist/hooks/useTaskData.test.d.ts +1 -0
  270. package/dist/hooks/useTaskData.test.js +180 -0
  271. package/dist/hooks/useTaskMutations.d.ts +46 -0
  272. package/dist/hooks/useTaskMutations.js +472 -0
  273. package/dist/hooks/useTaskMutations.test.d.ts +1 -0
  274. package/dist/hooks/useTaskMutations.test.js +80 -0
  275. package/dist/hooks/useTaskforce.contract.test.d.ts +1 -0
  276. package/dist/hooks/useTaskforce.contract.test.js +7 -0
  277. package/dist/hooks/useTaskforce.d.ts +260 -295
  278. package/dist/hooks/useTaskforce.js +1954 -2623
  279. package/dist/hooks/useTaskforce.priority-filters.test.js +6 -11
  280. package/dist/hooks/useTaskforce.sync-behavior.test.d.ts +1 -0
  281. package/dist/hooks/useTaskforce.sync-behavior.test.js +1120 -0
  282. package/dist/hooks/useUiNotice.d.ts +16 -0
  283. package/dist/hooks/useUiNotice.js +49 -0
  284. package/dist/hooks/useWorkspaceSyncController.d.ts +23 -46
  285. package/dist/hooks/useWorkspaceSyncController.js +280 -461
  286. package/dist/hooks/useWorkspaceSyncController.test.js +106 -199
  287. package/dist/hooks/workspace/useTaskforceApiRouting.d.ts +8 -0
  288. package/dist/hooks/workspace/useTaskforceApiRouting.js +91 -0
  289. package/dist/hooks/workspace/useTaskforceApiRouting.test.d.ts +1 -0
  290. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +60 -0
  291. package/dist/hooks/workspace/useWorkspaceSyncController.d.ts +1 -0
  292. package/dist/hooks/workspace/useWorkspaceSyncController.js +1 -0
  293. package/dist/hooks/workspace/workspaceLocalState.d.ts +30 -0
  294. package/dist/hooks/workspace/workspaceLocalState.js +101 -0
  295. package/dist/localization/locales/en-US.d.ts +1 -8
  296. package/dist/localization/locales/en-US.js +4 -11
  297. package/dist/localization/locales/es-419.js +2 -9
  298. package/dist/localization/locales/pt-BR.js +2 -9
  299. package/dist/localization/localizationCatalogs.test.d.ts +1 -0
  300. package/dist/localization/localizationCatalogs.test.js +37 -0
  301. package/dist/main.d.ts +1 -0
  302. package/dist/main.js +9 -15
  303. package/dist/mcp/clientIntegrations.d.ts +33 -0
  304. package/dist/mcp/clientIntegrations.js +199 -0
  305. package/dist/mcp/clientIntegrations.test.d.ts +1 -0
  306. package/dist/mcp/clientIntegrations.test.js +110 -0
  307. package/dist/mcp/index.d.ts +2 -0
  308. package/dist/mcp/index.js +2 -0
  309. package/dist/mcp/optionResolution.test.js +6 -2
  310. package/dist/mcp/runtime.d.ts +120 -0
  311. package/dist/mcp/runtime.js +5668 -0
  312. package/dist/mcp/runtime.test.d.ts +1 -0
  313. package/dist/mcp/runtime.test.js +3299 -0
  314. package/dist/mcp/server.js +2 -1793
  315. package/dist/mcp/structuredCommentValidation.test.d.ts +1 -0
  316. package/dist/{__tests__ → mcp}/structuredCommentValidation.test.js +1 -1
  317. package/dist/mcp/structuredDocValidation.js +1 -2
  318. package/dist/mcp/structuredDocValidation.test.d.ts +1 -0
  319. package/dist/{__tests__ → mcp}/structuredDocValidation.test.js +9 -4
  320. package/dist/mcp/toolRegistry.d.ts +570 -0
  321. package/dist/mcp/toolRegistry.js +90 -0
  322. package/dist/mcp/toolRegistry.test.d.ts +1 -0
  323. package/dist/mcp/toolRegistry.test.js +30 -0
  324. package/dist/migrations/billingSchemaParity.test.js +111 -0
  325. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  326. package/dist/migrations/taskSchemaMigrations.js +681 -39
  327. package/dist/migrations/taskSchemaMigrations.test.d.ts +1 -0
  328. package/dist/migrations/taskSchemaMigrations.test.js +210 -0
  329. package/dist/plugins/vite.js +13 -7
  330. package/dist/public/apple-touch-icon.png +0 -0
  331. package/dist/public/archive/phoenix/apple-touch-icon.png +0 -0
  332. package/dist/public/archive/phoenix/favicon.ico +0 -0
  333. package/dist/public/archive/phoenix/site.webmanifest +1 -0
  334. package/dist/public/favicon-96x96.png +0 -0
  335. package/dist/public/favicon.ico +0 -0
  336. package/dist/public/favicon.svg +17 -0
  337. package/dist/public/site.webmanifest +21 -1
  338. package/dist/public/web-app-manifest-192x192.png +0 -0
  339. package/dist/public/web-app-manifest-512x512.png +0 -0
  340. package/dist/releaseVersion.test.d.ts +1 -0
  341. package/dist/{__tests__/releaseVersion.test.js → releaseVersion.test.js} +1 -1
  342. package/dist/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
  343. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
  344. package/dist/resources/templates/workflows/collaborate.yaml +11 -5
  345. package/dist/resources/templates/workflows/do.yaml +8 -2
  346. package/dist/resources/templates/workflows/evaluate.yaml +13 -7
  347. package/dist/resources/templates/workflows/execute.yaml +40 -23
  348. package/dist/resources/templates/workflows/plan.yaml +15 -8
  349. package/dist/resources/templates/workflows/review.yaml +14 -8
  350. package/dist/runtime/appGateDefinitions.d.ts +32 -0
  351. package/dist/runtime/appGateDefinitions.js +32 -0
  352. package/dist/runtime/appGates.d.ts +29 -0
  353. package/dist/runtime/appGates.js +53 -0
  354. package/dist/runtime/appGates.test.d.ts +1 -0
  355. package/dist/runtime/appGates.test.js +42 -0
  356. package/dist/runtime/migrationFlags.d.ts +1 -0
  357. package/dist/runtime/migrationFlags.js +1 -0
  358. package/dist/server/annotatedAttachmentsRoutes.test.d.ts +1 -0
  359. package/dist/server/annotatedAttachmentsRoutes.test.js +473 -0
  360. package/dist/server/auth.js +14 -2
  361. package/dist/server/auth.test.js +21 -1
  362. package/dist/server/cors.js +11 -5
  363. package/dist/server/cors.test.js +6 -0
  364. package/dist/server/documentReviewRoutes.test.d.ts +1 -0
  365. package/dist/server/documentReviewRoutes.test.js +157 -0
  366. package/dist/server/index.cookieProxy.test.js +46 -1
  367. package/dist/server/index.d.ts +20 -0
  368. package/dist/server/index.js +168 -41
  369. package/dist/server/index.rateLimit.test.js +6 -0
  370. package/dist/server/index.test.js +133 -2
  371. package/dist/server/mockStripe.d.ts +72 -0
  372. package/dist/server/mockStripe.js +357 -0
  373. package/dist/server/realtimeSyncWs.js +4 -0
  374. package/dist/server/routes/admin.d.ts +114 -0
  375. package/dist/server/routes/admin.js +2226 -0
  376. package/dist/server/routes/annotatedAttachments.d.ts +24 -0
  377. package/dist/server/routes/annotatedAttachments.js +235 -0
  378. package/dist/server/routes/auth.d.ts +61 -0
  379. package/dist/server/routes/auth.js +1296 -0
  380. package/dist/server/{routes.billing.d.ts → routes/billing.d.ts} +3 -2
  381. package/dist/server/routes/billing.js +2001 -0
  382. package/dist/server/routes/billing.test.d.ts +1 -0
  383. package/dist/server/routes/billing.test.js +1631 -0
  384. package/dist/server/routes/documentReviews.d.ts +11 -0
  385. package/dist/server/routes/documentReviews.js +191 -0
  386. package/dist/server/routes/documents.d.ts +118 -0
  387. package/dist/server/routes/documents.js +1113 -0
  388. package/dist/server/routes/resources.d.ts +25 -0
  389. package/dist/server/routes/resources.js +225 -0
  390. package/dist/server/routes/shared.d.ts +35 -0
  391. package/dist/server/routes/shared.js +305 -0
  392. package/dist/server/routes/shared.test.d.ts +1 -0
  393. package/dist/server/routes/shared.test.js +32 -0
  394. package/dist/server/{routes.sync.d.ts → routes/sync.d.ts} +5 -5
  395. package/dist/server/routes/sync.integration.test.d.ts +1 -0
  396. package/dist/server/routes/sync.integration.test.js +2003 -0
  397. package/dist/server/routes/sync.js +3143 -0
  398. package/dist/server/routes/tasks.d.ts +72 -0
  399. package/dist/server/routes/tasks.js +1252 -0
  400. package/dist/server/routes/workspaces.d.ts +32 -0
  401. package/dist/server/routes/workspaces.js +307 -0
  402. package/dist/server/routes.d.ts +8 -9
  403. package/dist/server/routes.js +968 -4092
  404. package/dist/server/routes.test.js +9043 -2415
  405. package/dist/server/runtimeMode.d.ts +1 -1
  406. package/dist/server/runtimeMode.js +3 -18
  407. package/dist/server/runtimeMode.test.js +3 -3
  408. package/dist/server/securityHeaders.d.ts +1 -1
  409. package/dist/server/securityHeaders.js +65 -6
  410. package/dist/server/securityHeaders.test.js +40 -2
  411. package/dist/services/templateEngine.test.d.ts +1 -0
  412. package/dist/{__tests__ → services}/templateEngine.test.js +1 -1
  413. package/dist/services/templates.test.d.ts +1 -0
  414. package/dist/{__tests__ → services}/templates.test.js +1 -1
  415. package/dist/services/workflowDocumentFixtures.test.d.ts +1 -0
  416. package/dist/{__tests__ → services}/workflowDocumentFixtures.test.js +4 -4
  417. package/dist/services/workflowExportMatrix.test.d.ts +1 -0
  418. package/dist/{__tests__ → services}/workflowExportMatrix.test.js +1 -1
  419. package/dist/services/workflowExportSnapshots.test.d.ts +1 -0
  420. package/dist/services/workflowGeneration.test.d.ts +1 -0
  421. package/dist/services/workflowSimulation.test.d.ts +1 -0
  422. package/dist/services/workflowSimulation.test.js +113 -0
  423. package/dist/services/workflowV2Policy.test.d.ts +1 -0
  424. package/dist/{__tests__ → services}/workflowV2Policy.test.js +2 -2
  425. package/dist/shared/aiProfileSurfaceType.d.ts +9 -0
  426. package/dist/shared/aiProfileSurfaceType.js +49 -0
  427. package/dist/shared/customTaxonomyLibrary.d.ts +11 -0
  428. package/dist/shared/customTaxonomyLibrary.js +276 -0
  429. package/dist/shared/customTaxonomyLibrary.test.d.ts +1 -0
  430. package/dist/shared/customTaxonomyLibrary.test.js +20 -0
  431. package/dist/shared/taxonomyCatalog.d.ts +19 -0
  432. package/dist/shared/taxonomyCatalog.js +36 -0
  433. package/dist/shared/taxonomyDefaults.d.ts +29 -0
  434. package/dist/shared/taxonomyDefaults.js +26 -0
  435. package/dist/shared/taxonomyLibrary.d.ts +15 -0
  436. package/dist/shared/taxonomyLibrary.js +98 -0
  437. package/dist/shared/taxonomyLibrary.test.d.ts +1 -0
  438. package/dist/shared/taxonomyLibrary.test.js +26 -0
  439. package/dist/shared/taxonomyState.d.ts +36 -0
  440. package/dist/shared/taxonomyState.js +73 -0
  441. package/dist/shared/taxonomyState.test.d.ts +1 -0
  442. package/dist/shared/taxonomyState.test.js +71 -0
  443. package/dist/shared/workflowDefaults.d.ts +9 -0
  444. package/dist/shared/workflowDefaults.js +11 -0
  445. package/dist/storage/documentIntegrity.d.ts +2 -0
  446. package/dist/storage/documentIntegrity.js +34 -17
  447. package/dist/storage/documentPurge.d.ts +2 -1
  448. package/dist/storage/documentPurge.js +35 -8
  449. package/dist/storage/index.d.ts +4 -0
  450. package/dist/storage/index.js +2 -0
  451. package/dist/storage/objectStorage.d.ts +1 -1
  452. package/dist/storage/objectStorageClient.d.ts +6 -4
  453. package/dist/storage/objectStorageClient.js +77 -29
  454. package/dist/storage/objectStorageClient.test.d.ts +1 -0
  455. package/dist/storage/objectStorageClient.test.js +57 -0
  456. package/dist/storage/objectStorageConfig.js +3 -1
  457. package/dist/storage/objectStorageConfig.test.d.ts +1 -0
  458. package/dist/storage/objectStorageConfig.test.js +38 -0
  459. package/dist/storage/postgresAdapter.d.ts +5 -0
  460. package/dist/storage/postgresAdapter.js +2 -2
  461. package/dist/storage/postgresAdapter.test.d.ts +1 -0
  462. package/dist/storage/postgresAdapter.test.js +29 -0
  463. package/dist/storage/taskAssetStore.d.ts +7 -4
  464. package/dist/storage/taskAssetStore.js +65 -60
  465. package/dist/storage/workspaceAssetStore.d.ts +122 -0
  466. package/dist/storage/workspaceAssetStore.js +496 -0
  467. package/dist/storage/workspaceAssetStore.test.d.ts +1 -0
  468. package/dist/storage/workspaceAssetStore.test.js +501 -0
  469. package/dist/sync/cloudSyncApi.d.ts +33 -2
  470. package/dist/sync/cloudSyncApi.js +37 -15
  471. package/dist/sync/cloudSyncApi.test.js +60 -3
  472. package/dist/sync/index.d.ts +2 -0
  473. package/dist/sync/index.js +3 -0
  474. package/dist/sync/syncService.d.ts +25 -0
  475. package/dist/sync/syncService.js +184 -16
  476. package/dist/sync/syncService.test.js +289 -25
  477. package/dist/sync/workspaceRepair.d.ts +114 -0
  478. package/dist/sync/workspaceRepair.js +566 -0
  479. package/dist/sync/workspaceSyncModel.d.ts +230 -2
  480. package/dist/sync/workspaceSyncModel.js +456 -17
  481. package/dist/sync/workspaceSyncModel.test.js +642 -0
  482. package/dist/sync/workspaceSyncState.d.ts +12 -0
  483. package/dist/sync/workspaceSyncState.js +12 -0
  484. package/dist/sync/workspaceSyncSurface.d.ts +33 -0
  485. package/dist/sync/workspaceSyncSurface.js +74 -0
  486. package/dist/types.d.ts +143 -18
  487. package/dist/types.js +9 -24
  488. package/dist/ui/assets/AgentsModule-Bdq3T1Ts.js +1 -0
  489. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +1 -0
  490. package/dist/ui/assets/AnnotatedAttachmentWorkspace-jKUVo-PJ.js +3 -0
  491. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +1 -0
  492. package/dist/ui/assets/DocumentWorkspace-DuQa-uIC.js +250 -0
  493. package/dist/ui/assets/InitiativesModule-C8Pi2VTk.js +1 -0
  494. package/dist/ui/assets/PlansPage-B6BDECSi.js +1 -0
  495. package/dist/ui/assets/PlansPage-BlVC_lRq.css +1 -0
  496. package/dist/ui/assets/TaskSettings-BwB9NtmJ.css +1 -0
  497. package/dist/ui/assets/TaskSettings-DUJgRTPU.js +8 -0
  498. package/dist/ui/assets/WorkflowsModule-b6TLuHwJ.js +5 -0
  499. package/dist/ui/assets/index-BiiF1cLQ.css +1 -0
  500. package/dist/ui/assets/index-xBWLPOEb.js +6 -0
  501. package/dist/ui/assets/vendor-dnd-DRzYolkg.js +5 -0
  502. package/dist/ui/assets/{vendor-icons-ZFG3SGwo.js → vendor-icons-QZyhEwgT.js} +1 -1
  503. package/dist/ui/assets/{vendor-markdown-CKYkQHfj.js → vendor-markdown-BUxTU7dS.js} +1 -1
  504. package/dist/ui/assets/vendor-react-CKJs5o3c.js +61 -0
  505. package/dist/ui/assets/vendor-router-BbWMxlnO.js +3 -0
  506. package/dist/ui/branding/logos/logo.png +0 -0
  507. package/dist/ui/branding/logos/logo_dark.svg +27 -0
  508. package/dist/ui/branding/logos/logo_favicon.svg +35 -0
  509. package/dist/ui/branding/logos/logo_light.svg +27 -0
  510. package/dist/ui/favicon/apple-touch-icon.png +0 -0
  511. package/dist/ui/favicon/archive/phoenix/apple-touch-icon.png +0 -0
  512. package/dist/ui/favicon/archive/phoenix/favicon.ico +0 -0
  513. package/dist/ui/favicon/archive/phoenix/site.webmanifest +1 -0
  514. package/dist/ui/favicon/favicon-96x96.png +0 -0
  515. package/dist/ui/favicon/favicon.ico +0 -0
  516. package/dist/ui/favicon/favicon.svg +17 -0
  517. package/dist/ui/favicon/site.webmanifest +21 -1
  518. package/dist/ui/favicon/web-app-manifest-192x192.png +0 -0
  519. package/dist/ui/favicon/web-app-manifest-512x512.png +0 -0
  520. package/dist/ui/index.html +10 -7
  521. package/dist/ui/product/screen_01.png +0 -0
  522. package/dist/ui/product/screen_02.png +0 -0
  523. package/dist/ui/product/screen_03.png +0 -0
  524. package/dist/utils/annotatedAttachments.d.ts +20 -0
  525. package/dist/utils/annotatedAttachments.js +74 -0
  526. package/dist/utils/annotatedAttachments.test.d.ts +1 -0
  527. package/dist/utils/annotatedAttachments.test.js +108 -0
  528. package/dist/utils/assignees.d.ts +26 -0
  529. package/dist/utils/assignees.js +132 -0
  530. package/dist/utils/canonicalAssetKind.d.ts +16 -0
  531. package/dist/utils/canonicalAssetKind.js +39 -0
  532. package/dist/utils/canonicalAssetKind.test.d.ts +1 -0
  533. package/dist/utils/canonicalAssetKind.test.js +24 -0
  534. package/dist/utils/coalescedRefresh.d.ts +5 -0
  535. package/dist/utils/coalescedRefresh.js +16 -0
  536. package/dist/utils/coalescedRefresh.test.d.ts +1 -0
  537. package/dist/utils/coalescedRefresh.test.js +30 -0
  538. package/dist/utils/constants.d.ts +16 -3
  539. package/dist/utils/constants.icons.test.js +2 -1
  540. package/dist/utils/constants.js +70 -13
  541. package/dist/utils/contextAssetEvents.d.ts +7 -0
  542. package/dist/utils/contextAssetEvents.js +6 -0
  543. package/dist/utils/contextFiles.d.ts +14 -3
  544. package/dist/utils/contextFiles.js +40 -8
  545. package/dist/utils/documentManagerApi.d.ts +6 -0
  546. package/dist/utils/documentManagerApi.js +19 -0
  547. package/dist/utils/documentNames.d.ts +24 -0
  548. package/dist/utils/documentNames.js +91 -0
  549. package/dist/utils/documentReferences.d.ts +9 -0
  550. package/dist/utils/documentReferences.js +11 -0
  551. package/dist/utils/entityReferences.d.ts +9 -0
  552. package/dist/utils/entityReferences.js +32 -0
  553. package/dist/utils/imageReferences.d.ts +9 -0
  554. package/dist/utils/imageReferences.js +11 -0
  555. package/dist/utils/planParser.d.ts +2 -2
  556. package/dist/utils/planParser.js +11 -11
  557. package/dist/utils/planParser.test.d.ts +1 -0
  558. package/dist/{__tests__ → utils}/planParser.test.js +22 -22
  559. package/dist/utils/planningReferences.d.ts +17 -0
  560. package/dist/utils/planningReferences.js +30 -0
  561. package/dist/utils/planningReferences.test.d.ts +1 -0
  562. package/dist/utils/planningReferences.test.js +17 -0
  563. package/dist/utils/taskActivity.d.ts +9 -0
  564. package/dist/utils/taskActivity.js +147 -0
  565. package/dist/utils/taskActivity.test.d.ts +1 -0
  566. package/dist/utils/taskActivity.test.js +34 -0
  567. package/dist/utils/taskDraftDefaults.d.ts +21 -0
  568. package/dist/utils/taskDraftDefaults.js +40 -0
  569. package/dist/utils/taskDraftDefaults.test.d.ts +1 -0
  570. package/dist/utils/taskDraftDefaults.test.js +34 -0
  571. package/dist/utils/taskNormalization.d.ts +25 -0
  572. package/dist/utils/taskNormalization.js +161 -0
  573. package/dist/utils/taskNormalization.test.d.ts +1 -0
  574. package/dist/utils/taskNormalization.test.js +158 -0
  575. package/dist/utils/taskReferences.d.ts +5 -0
  576. package/dist/utils/taskReferences.js +11 -0
  577. package/dist/utils/taskforceApiClient.d.ts +2 -0
  578. package/dist/utils/taskforceApiClient.js +101 -3
  579. package/dist/utils/taskforceApiClient.test.d.ts +1 -0
  580. package/dist/utils/taskforceApiClient.test.js +44 -0
  581. package/dist/utils/taxonomyFilterOptions.d.ts +2 -0
  582. package/dist/utils/taxonomyFilterOptions.js +17 -0
  583. package/dist/utils/taxonomyFormDefaults.d.ts +3 -0
  584. package/dist/utils/taxonomyFormDefaults.js +28 -0
  585. package/dist/utils/taxonomyFormDefaults.test.d.ts +1 -0
  586. package/dist/utils/taxonomyFormDefaults.test.js +63 -0
  587. package/dist/utils/taxonomyLifecycle.d.ts +3 -0
  588. package/dist/utils/taxonomyLifecycle.js +17 -0
  589. package/dist/utils/taxonomySorting.d.ts +7 -0
  590. package/dist/utils/taxonomySorting.js +74 -0
  591. package/dist/utils/theme.d.ts +15 -0
  592. package/dist/utils/theme.js +23 -0
  593. package/dist/utils/uiNotice.d.ts +7 -0
  594. package/dist/utils/uiNotice.js +6 -0
  595. package/dist/utils/uiNotice.test.d.ts +1 -0
  596. package/dist/utils/uiNotice.test.js +18 -0
  597. package/dist/utils/workspaceIdentity.d.ts +14 -0
  598. package/dist/utils/workspaceIdentity.js +21 -0
  599. package/dist/utils/workspaceIdentity.test.js +30 -1
  600. package/dist/utils/workspaceSyncPresentation.d.ts +20 -0
  601. package/dist/utils/workspaceSyncPresentation.js +21 -0
  602. package/dist/utils/workspaceSyncPresentation.test.d.ts +1 -0
  603. package/dist/utils/workspaceSyncPresentation.test.js +36 -0
  604. package/package.json +30 -23
  605. package/scripts/bootstrap-playwright-auth.mjs +155 -0
  606. package/scripts/check-compat-boundaries.mjs +41 -0
  607. package/scripts/check-env.ts +9 -2
  608. package/scripts/debug-login.mjs +32 -0
  609. package/scripts/deploy-prod.sh +41 -0
  610. package/scripts/deploy-staging.sh +23 -0
  611. package/scripts/migrate-planning-model.ts +233 -0
  612. package/scripts/migrate-task-data-assets.mjs +408 -0
  613. package/scripts/playwright-auth.sh +11 -0
  614. package/scripts/run-dev-proxy.sh +2 -0
  615. package/scripts/update-homebrew-formula.sh +2 -2
  616. package/scripts/with-esbuild.sh +11 -0
  617. package/src/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
  618. package/src/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
  619. package/src/resources/templates/workflows/collaborate.yaml +11 -5
  620. package/src/resources/templates/workflows/do.yaml +8 -2
  621. package/src/resources/templates/workflows/evaluate.yaml +13 -7
  622. package/src/resources/templates/workflows/execute.yaml +40 -23
  623. package/src/resources/templates/workflows/plan.yaml +15 -8
  624. package/src/resources/templates/workflows/review.yaml +14 -8
  625. package/dist/TaskforceScreenshot.d.ts +0 -11
  626. package/dist/TaskforceScreenshot.js +0 -113
  627. package/dist/compat/priorityCompat.d.ts +0 -2
  628. package/dist/compat/priorityCompat.js +0 -24
  629. package/dist/components/features/settings/TaxonomyManager 2.d.ts +0 -52
  630. package/dist/components/features/settings/TaxonomyManager 2.js +0 -75
  631. package/dist/components/task/TaskKanban 2.d.ts +0 -76
  632. package/dist/components/task/TaskKanban 2.js +0 -1004
  633. package/dist/components/task/TaskScreenshotSection.d.ts +0 -15
  634. package/dist/components/task/TaskScreenshotSection.js +0 -22
  635. package/dist/components/views/StandaloneLayout 2.d.ts +0 -8
  636. package/dist/components/views/StandaloneLayout 2.js +0 -1660
  637. package/dist/core/InitiativeTemplates.test.js +0 -50
  638. package/dist/core/ParentLifecycle.test.js +0 -98
  639. package/dist/migrations/clientMigrations.d.ts +0 -9
  640. package/dist/migrations/clientMigrations.js +0 -74
  641. package/dist/migrations/flags.d.ts +0 -6
  642. package/dist/migrations/flags.js +0 -8
  643. package/dist/migrations/taskMigrations.d.ts +0 -71
  644. package/dist/migrations/taskMigrations.js +0 -236
  645. package/dist/migrations/taskMigrations.test.js +0 -34
  646. package/dist/server/routes.billing.js +0 -991
  647. package/dist/server/routes.billing.test.js +0 -387
  648. package/dist/server/routes.sync.integration.test.js +0 -470
  649. package/dist/server/routes.sync.js +0 -1141
  650. package/dist/soak/syncSoakHarness.d.ts +0 -6
  651. package/dist/soak/syncSoakHarness.js +0 -10
  652. package/dist/ui/assets/index-0W5vyCpn.css +0 -1
  653. package/dist/ui/assets/index-MCZuNNfn.js +0 -23
  654. package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
  655. package/dist/ui/assets/vendor-dnd-BI1K77C1.js +0 -5
  656. package/dist/ui/assets/vendor-react-DdIDsh7f.js +0 -9
  657. package/dist/ui/assets/vendor-router-BtiNU7Dl.js +0 -3
  658. package/dist/utils/taskHierarchy.d.ts +0 -4
  659. package/dist/utils/taskHierarchy.js +0 -69
  660. package/dist/utils/taskHierarchy.test.js +0 -38
  661. package/dist/utils/taskParenting.d.ts +0 -3
  662. package/dist/utils/taskParenting.js +0 -24
  663. package/dist/utils/taskParenting.test.js +0 -21
  664. package/dist/utils/taskRelations.d.ts +0 -6
  665. package/dist/utils/taskRelations.js +0 -24
  666. package/dist/utils/taskRelations.test.js +0 -34
  667. package/scripts/check-compat-boundaries.js +0 -48
  668. /package/dist/{__tests__/planParser.test.d.ts → TaskforceCore.filter-persistence.test.d.ts} +0 -0
  669. /package/dist/{__tests__/releaseVersion.test.d.ts → TaskforceCore.routing.test.d.ts} +0 -0
  670. /package/dist/{__tests__/structuredCommentValidation.test.d.ts → annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts} +0 -0
  671. /package/dist/{__tests__/structuredDocValidation.test.d.ts → annotatedAttachments/payload.test.d.ts} +0 -0
  672. /package/dist/{__tests__/templateEngine.test.d.ts → annotatedAttachments/types.js} +0 -0
  673. /package/dist/{__tests__/templates.test.d.ts → compat/workspaceSyncCompat.test.d.ts} +0 -0
  674. /package/dist/{__tests__/workflowDocumentFixtures.test.d.ts → components/features/AgentsModule.test.d.ts} +0 -0
  675. /package/dist/{__tests__/workflowExportMatrix.test.d.ts → components/features/AnnotatedAttachmentWorkspace.test.d.ts} +0 -0
  676. /package/dist/{__tests__/workflowExportSnapshots.test.d.ts → components/features/DocumentWorkspace.test.d.ts} +0 -0
  677. /package/dist/{__tests__/workflowGeneration.test.d.ts → components/features/settings/TaxonomyLibraryManager.test.d.ts} +0 -0
  678. /package/dist/{__tests__/workflowV2Policy.test.d.ts → components/task/TaskActionHeader.test.d.ts} +0 -0
  679. /package/dist/{core/InitiativeTemplates.test.d.ts → components/task/TaskKanban.planning-drop.test.d.ts} +0 -0
  680. /package/dist/{core/ParentLifecycle.test.d.ts → components/task/TaskStatusActions.test.d.ts} +0 -0
  681. /package/dist/{migrations/taskMigrations.test.d.ts → components/ui/TopNoticeLayer.test.d.ts} +0 -0
  682. /package/dist/{server/routes.billing.test.d.ts → components/views/AppShellHeader.test.d.ts} +0 -0
  683. /package/dist/{server/routes.sync.integration.test.d.ts → components/views/PlanComparisonPage.test.d.ts} +0 -0
  684. /package/dist/{utils/taskHierarchy.test.d.ts → components/views/chrome/WorkspaceChromeSections.test.d.ts} +0 -0
  685. /package/dist/{utils/taskParenting.test.d.ts → components/views/chrome/workspaceChrome.test.d.ts} +0 -0
  686. /package/dist/{utils/taskRelations.test.d.ts → components/views/panels/DocumentFilterToolbar.test.d.ts} +0 -0
  687. /package/dist/public/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
  688. /package/dist/public/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
  689. /package/dist/public/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
  690. /package/dist/public/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
  691. /package/dist/public/{favicon.png → archive/phoenix/favicon.png} +0 -0
  692. /package/dist/{__tests__ → services}/workflowExportSnapshots.test.js +0 -0
  693. /package/dist/{__tests__ → services}/workflowGeneration.test.js +0 -0
  694. /package/dist/ui/favicon/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
  695. /package/dist/ui/favicon/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
  696. /package/dist/ui/favicon/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
  697. /package/dist/ui/favicon/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
  698. /package/dist/ui/favicon/{favicon.png → archive/phoenix/favicon.png} +0 -0
@@ -1,1660 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useMemo, useCallback, useState, useEffect, useRef } from 'react';
3
- import { createPortal } from 'react-dom';
4
- import { useNavigate } from 'react-router-dom';
5
- import { Settings, Plus, Search, Filter, Layers, User, Maximize2, Minimize2, Check, X, Ban, ChevronLeft, ChevronRight, ArrowUp, ArrowDown, ArrowUpDown, AlertTriangle, Save, Loader2, Folder, FileText, Trash2, LogOut, Cloud, CloudOff, RefreshCw, ChevronsUp, ChevronsDown, EyeOff, Zap, HelpCircle, CalendarDays, PanelRightClose, PanelRightOpen } from 'lucide-react';
6
- import { STATUS_OPTIONS } from '../../utils/constants';
7
- import { MultiSelectFilter } from '../ui/MultiSelectFilter';
8
- import styles from '../../Taskforce.module.css';
9
- import modalStyles from '../ui/Modal.module.css';
10
- import { Modal } from '../ui/Modal';
11
- import { TaskForm } from '../task/TaskForm';
12
- import { TaskSettings } from '../features/TaskSettings';
13
- import { DocumentWorkspace } from '../features/DocumentWorkspace';
14
- import { TaskKanban } from '../task/TaskKanban';
15
- import { TaskActionHeader } from '../task/TaskActionHeader';
16
- import { TypeMeta } from '../../utils/constants';
17
- import { buildHierarchyDepthMap, collectSubtreeTaskIds } from '../../utils/taskHierarchy';
18
- import { formatDate } from '../../utils/formatting';
19
- import { getLocale, t } from '../../localization';
20
- import logo from '../../assets/branding/logos/logo_white_01.png';
21
- import favicon from '../../assets/favicon/favicon.png';
22
- import taskforceBg from '../../assets/images/taskforce.png';
23
- const SCHEDULE_DAY_KEYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
24
- const SCHEDULE_DAY_LABELS = {
25
- mon: 'Mon',
26
- tue: 'Tue',
27
- wed: 'Wed',
28
- thu: 'Thu',
29
- fri: 'Fri',
30
- sat: 'Sat',
31
- sun: 'Sun'
32
- };
33
- const SYNCING_DISPLAY_DELAY_MS = 220;
34
- const SYNCING_MIN_VISIBLE_MS = 1200;
35
- const ERROR_MIN_VISIBLE_MS = 1800;
36
- function toDateOnlyLocal(date) {
37
- const y = date.getFullYear();
38
- const m = String(date.getMonth() + 1).padStart(2, '0');
39
- const d = String(date.getDate()).padStart(2, '0');
40
- return `${y}-${m}-${d}`;
41
- }
42
- function parseDateOnlyLocal(dateOnly) {
43
- const match = dateOnly.match(/^(\d{4})-(\d{2})-(\d{2})$/);
44
- if (!match)
45
- return null;
46
- const parsed = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
47
- if (Number.isNaN(parsed.getTime()))
48
- return null;
49
- return parsed;
50
- }
51
- function startOfWeek(date, weekStartsOn) {
52
- const day = date.getDay();
53
- const delta = weekStartsOn === 'sunday'
54
- ? -day
55
- : (day === 0 ? -6 : 1 - day);
56
- const result = new Date(date);
57
- result.setHours(0, 0, 0, 0);
58
- result.setDate(result.getDate() + delta);
59
- return result;
60
- }
61
- function getDayOffsetFromWeekStart(dayKey, weekStartsOn) {
62
- if (weekStartsOn === 'sunday') {
63
- const sundayFirst = {
64
- sun: 0,
65
- mon: 1,
66
- tue: 2,
67
- wed: 3,
68
- thu: 4,
69
- fri: 5,
70
- sat: 6
71
- };
72
- return sundayFirst[dayKey];
73
- }
74
- const mondayFirst = {
75
- mon: 0,
76
- tue: 1,
77
- wed: 2,
78
- thu: 3,
79
- fri: 4,
80
- sat: 5,
81
- sun: 6
82
- };
83
- return mondayFirst[dayKey];
84
- }
85
- function addDays(base, days) {
86
- const next = new Date(base);
87
- next.setDate(base.getDate() + days);
88
- return next;
89
- }
90
- function dateOnlyToIsoWeekKey(dateOnly) {
91
- const match = dateOnly.match(/^(\d{4})-(\d{2})-(\d{2})$/);
92
- if (!match)
93
- return null;
94
- const dt = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
95
- const day = dt.getUTCDay() || 7;
96
- dt.setUTCDate(dt.getUTCDate() + 4 - day);
97
- const yearStart = new Date(Date.UTC(dt.getUTCFullYear(), 0, 1));
98
- const week = Math.ceil((((dt.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
99
- return `${dt.getUTCFullYear()}-W${String(week).padStart(2, '0')}`;
100
- }
101
- export function StandaloneLayout(props) {
102
- const navigate = useNavigate();
103
- const {
104
- // State
105
- activeTab, setActiveTab, activeCategories, groupBy, setGroupBy, emptyColumnMode, setEmptyColumnMode, zenMode, setZenMode, filterStatus, setFilterStatus, parentTaskFilterMode, setParentTaskFilterMode,
106
- // Data & Actions
107
- tasks, handleEdit, handleSubmit, resetForm, handleUpdateTask,
108
- // Form State (destructure all needed for TaskForm)
109
- editingTaskId, loading, error, title, setTitle, description, setDescription, category, setCategory, type, setType, priority, setPriority, complexity, setComplexity, approach, setApproach, assignee, setAssignee, scheduledDate, setScheduledDate, dueDate, setDueDate, parentTaskIdInput, setParentTaskIdInput, addChildTaskIdInput, setAddChildTaskIdInput, manualComplexityEnabled, checklistDropdownEnabled, formTaxonomies, setFormTaxonomies, selectedSpecialists, setSelectedSpecialists, comments, newCommentText, setNewCommentText, screenshots, setScreenshots, descriptionFocused, setDescriptionFocused, showMarkdownHelp, setShowMarkdownHelp, showSpecialists, setShowSpecialists, showChecklist, setShowChecklist, showTaskRelationships, setShowTaskRelationships, showChildTasks, setShowChildTasks, showComments, setShowComments,
110
- // Form Actions
111
- handleAddComment, handleSetParentForCurrentTask, handleAddChildToCurrentTask, handleCreateChildForCurrentTask, handleUnlinkChildTask, handleReorderChildTasks, handleClearParentTask, handleOpenTaskById,
112
- // Other Props for Form
113
- taxonomies, activeTypes, priorities, approaches, availableSpecialists, copiedId, handleCopyId, handleToggleInProgress, handleToggleComplete, handleToggleReview, handleToggleCancel, handleArchiveTask, handleDelete, handleUnarchive, fetchTasks, searchQuery, setSearchQuery, filterCategories, setFilterCategories, filterTypes, setFilterTypes, filterPriorities, setFilterPriorities, filterAssignees, setFilterAssignees,
114
- // filterStatus, setFilterStatus, // This was duplicated, removed one instance
115
- sortBy, setSortBy, clearFilters, // setSearchQuery, // This was duplicated, removed one instance
116
- // filterCategories, setFilterCategories, // This was duplicated, removed one instance
117
- // filterTypes, setFilterTypes, // This was duplicated, removed one instance
118
- // filterPriorities, setFilterPriorities, // This was duplicated, removed one instance
119
- // filterStatus, setFilterStatus, // This was duplicated, removed one instance
120
- // sortBy, setSortBy, // This was duplicated, removed one instance
121
- // clearFilters, // This was duplicated, removed one instance
122
- // activeTypes, // This was duplicated, removed one instance
123
- // Settings State & Props
124
- settingsModel, currentTheme, setCurrentTheme, pathSaved, saveSettings, keyShortcut, setKeyShortcut, globalWeekStartsOn, locale, jsonBackupEnabled, setJsonBackupEnabled, assigneeFilterEnabled, mcpHostRoot, setMcpHostRoot, settingsSection, setSettingsSection, runtimeMode, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, workspaceCloudSyncEnabled, workspaceSyncSourceOfTruth, workspaceSyncOnboardingCompleted, workspaceSyncReady, workspaceCloudHydrated, saveWorkspaceCloudSyncSettings, userGlobalSyncStatus, userGlobalLastSyncedAt, workspaceLastPullAt, workspaceLastPushAt, workspaceLastErrorAt, workspaceRetryAt, workspaceBootstrapSyncInProgress, workspaceBootstrapSyncPages, workspaceBootstrapSyncAppliedChanges, userGlobalSyncPendingChanges, userGlobalSyncError, workspaceLastErrorMessage, workspaceLastWarningMessage, workspaceSyncFailureCount, workspaceSyncRetryScheduledCount, workspaceSyncAuthFailureCount, workspaceSyncLastFailureSource, workspaceSyncLastFailureStatusCode, retryWorkspaceCloudSync, resetWorkspaceSyncCursorAndPull, loginWithCredentials, currentWorkspaceId, availableWorkspaces, fetchWorkspaces, createWorkspace, switchWorkspace, logout, projectRoot, projectName, mcpScriptPath, serverHostRoot,
125
- // Browser Props
126
- showFolderBrowser, setShowFolderBrowser, folders, files, currentBrowsePath, fetchFolders, browserTarget, setBrowserTarget, contextLinkBrowsePath, handleSelectPath, handleAddPath, handleRemovePath,
127
- // Settings Managers
128
- handleUpdateCategory, handleRemoveCategory, handleSaveCategory, handleUpdateCategoryIcon, handleUpdateCategoryColor, handleSaveType, handleRemoveType, handleUpdateTaxonomies, handleUpdatePriorities, handleUpdateApproaches, pathValidation,
129
- // Exports
130
- exportEnvironment, setExportEnvironment, exportWorkflowsPath, setExportWorkflowsPath, exportSpecialistsPath, setExportSpecialistsPath, exportResult, handleExportResources, exportingResource, availableWorkflows, onExportWorkflows, fetchWorkflows, availableEnvironments,
131
- // Misc
132
- successBanner, returnToParentTaskId, returnFromChildTaskId, clearReturnToParentTask, tasksScrollRef, setTasksScrollPos,
133
- // Refs
134
- commentsEndRef,
135
- // Modals - Unsaved Changes
136
- unsavedModalOpen, setUnsavedModalOpen, pendingNavigation, handleNavigation, currentTask, currentTaskParent, currentTaskChildren,
137
- // Modals - Cancellation
138
- cancellationPromptTask, confirmCancellation, cancelCancellationPrompt, scheduleWarningPrompt, confirmScheduleWarning, cancelScheduleWarning } = props;
139
- const resolvedLocale = locale || getLocale();
140
- useEffect(() => {
141
- const normalizedProject = String(projectName || '').trim();
142
- document.title = normalizedProject ? `Taskforce - ${normalizedProject}` : 'Taskforce';
143
- }, [projectName]);
144
- // Handlers
145
- const handleDiscard = () => {
146
- setUnsavedModalOpen(false);
147
- if (pendingNavigation) {
148
- if (activeTab === 'add')
149
- resetForm();
150
- pendingNavigation();
151
- }
152
- else {
153
- if (activeTab === 'add')
154
- resetForm();
155
- setActiveTab('tasks');
156
- }
157
- };
158
- const handleSaveAndNavigate = async () => {
159
- // Fake event for handleSubmit
160
- const fakeEvent = { preventDefault: () => { } };
161
- await handleSubmit(fakeEvent);
162
- setUnsavedModalOpen(false);
163
- if (pendingNavigation) {
164
- pendingNavigation();
165
- }
166
- };
167
- // State for Card Compression
168
- const [compressedCards, setCompressedCards] = useState(false);
169
- const [scheduleShowWeekends, setScheduleShowWeekends] = useState(false);
170
- const [scheduleShowBacklog, setScheduleShowBacklog] = useState(true);
171
- const [scheduleOnlyExpired, setScheduleOnlyExpired] = useState(false);
172
- const [scheduleSidebarOpen, setScheduleSidebarOpen] = useState(true);
173
- const [hierarchySidebarOpen, setHierarchySidebarOpen] = useState(true);
174
- const [hierarchyRootTaskId, setHierarchyRootTaskId] = useState('');
175
- const [hierarchyShowUnlinkedColumn, setHierarchyShowUnlinkedColumn] = useState(true);
176
- const [hierarchyChildOrderMode, setHierarchyChildOrderMode] = useState('manual');
177
- const [hierarchyRootSearch, setHierarchyRootSearch] = useState('');
178
- const [scheduleSelectedDate, setScheduleSelectedDate] = useState(toDateOnlyLocal(new Date()));
179
- const [scheduleCalendarMonth, setScheduleCalendarMonth] = useState(() => {
180
- const now = new Date();
181
- return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
182
- });
183
- const [scheduleScrollLeft, setScheduleScrollLeft] = useState(0);
184
- const [showFilters, setShowFilters] = useState(false);
185
- const [requestedDocPath, setRequestedDocPath] = useState(null);
186
- const [layoutStateReady, setLayoutStateReady] = useState(false);
187
- const loadedLayoutStateWorkspaceRef = useRef('');
188
- const workspaceUiStateHeaders = useMemo(() => {
189
- const headers = {};
190
- const workspaceIdHeader = String(currentWorkspaceId || '').trim();
191
- if (runtimeMode === 'cloud' && workspaceIdHeader && workspaceIdHeader !== 'default') {
192
- headers['x-taskforce-workspace-id'] = workspaceIdHeader;
193
- }
194
- return headers;
195
- }, [runtimeMode, currentWorkspaceId]);
196
- const layoutStateWorkspaceKey = useMemo(() => `${runtimeMode}:${String(currentWorkspaceId || 'default').trim() || 'default'}`, [runtimeMode, currentWorkspaceId]);
197
- useEffect(() => {
198
- const handleOpenMarkdownDocument = (event) => {
199
- const customEvent = event;
200
- const fsPath = customEvent.detail?.fsPath;
201
- if (!fsPath)
202
- return;
203
- customEvent.preventDefault();
204
- setRequestedDocPath(fsPath);
205
- if (groupBy !== 'docs') {
206
- setGroupBy('docs');
207
- }
208
- };
209
- window.addEventListener('taskforce:open-markdown-document', handleOpenMarkdownDocument);
210
- return () => {
211
- window.removeEventListener('taskforce:open-markdown-document', handleOpenMarkdownDocument);
212
- };
213
- }, [groupBy, setGroupBy]);
214
- useEffect(() => {
215
- if (loadedLayoutStateWorkspaceRef.current === layoutStateWorkspaceKey)
216
- return;
217
- loadedLayoutStateWorkspaceRef.current = layoutStateWorkspaceKey;
218
- setLayoutStateReady(false);
219
- let cancelled = false;
220
- const loadLayoutUiState = async () => {
221
- try {
222
- const res = await fetch('/api/taskforce/ui-state?key=layout', {
223
- method: 'GET',
224
- credentials: 'include',
225
- headers: workspaceUiStateHeaders
226
- });
227
- if (!res.ok)
228
- return;
229
- const data = await res.json().catch(() => ({}));
230
- const state = (data?.state && typeof data.state === 'object')
231
- ? data.state
232
- : null;
233
- if (!state || cancelled)
234
- return;
235
- if (typeof state.scheduleShowWeekends === 'boolean')
236
- setScheduleShowWeekends(state.scheduleShowWeekends);
237
- if (typeof state.scheduleShowBacklog === 'boolean')
238
- setScheduleShowBacklog(state.scheduleShowBacklog);
239
- if (typeof state.scheduleOnlyExpired === 'boolean')
240
- setScheduleOnlyExpired(state.scheduleOnlyExpired);
241
- if (typeof state.scheduleSidebarOpen === 'boolean')
242
- setScheduleSidebarOpen(state.scheduleSidebarOpen);
243
- if (typeof state.hierarchySidebarOpen === 'boolean')
244
- setHierarchySidebarOpen(state.hierarchySidebarOpen);
245
- if (typeof state.hierarchyRootTaskId === 'string')
246
- setHierarchyRootTaskId(state.hierarchyRootTaskId);
247
- if (typeof state.hierarchyShowUnlinkedColumn === 'boolean')
248
- setHierarchyShowUnlinkedColumn(state.hierarchyShowUnlinkedColumn);
249
- if (state.hierarchyChildOrderMode === 'manual' || state.hierarchyChildOrderMode === 'auto') {
250
- setHierarchyChildOrderMode(state.hierarchyChildOrderMode);
251
- }
252
- if (typeof state.scheduleSelectedDate === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(state.scheduleSelectedDate)) {
253
- setScheduleSelectedDate(state.scheduleSelectedDate);
254
- }
255
- if (typeof state.scheduleCalendarMonth === 'string' && /^\d{4}-\d{2}$/.test(state.scheduleCalendarMonth)) {
256
- setScheduleCalendarMonth(state.scheduleCalendarMonth);
257
- }
258
- if (typeof state.scheduleScrollLeft === 'number' && Number.isFinite(state.scheduleScrollLeft) && state.scheduleScrollLeft >= 0) {
259
- setScheduleScrollLeft(state.scheduleScrollLeft);
260
- }
261
- if (typeof state.showFilters === 'boolean')
262
- setShowFilters(state.showFilters);
263
- }
264
- catch {
265
- // ignore read failure
266
- }
267
- finally {
268
- if (!cancelled)
269
- setLayoutStateReady(true);
270
- }
271
- };
272
- loadLayoutUiState();
273
- return () => {
274
- cancelled = true;
275
- };
276
- }, [layoutStateWorkspaceKey, workspaceUiStateHeaders]);
277
- useEffect(() => {
278
- if (!layoutStateReady)
279
- return;
280
- const timeoutId = window.setTimeout(async () => {
281
- try {
282
- await fetch('/api/taskforce/ui-state', {
283
- method: 'POST',
284
- headers: { 'Content-Type': 'application/json', ...workspaceUiStateHeaders },
285
- credentials: 'include',
286
- body: JSON.stringify({
287
- stateKey: 'layout',
288
- patch: {
289
- scheduleShowWeekends,
290
- scheduleShowBacklog,
291
- scheduleOnlyExpired,
292
- scheduleSidebarOpen,
293
- hierarchySidebarOpen,
294
- hierarchyRootTaskId,
295
- hierarchyShowUnlinkedColumn,
296
- hierarchyChildOrderMode,
297
- scheduleSelectedDate,
298
- scheduleCalendarMonth,
299
- scheduleScrollLeft,
300
- showFilters
301
- }
302
- })
303
- });
304
- }
305
- catch {
306
- // ignore write failure
307
- }
308
- }, 250);
309
- return () => window.clearTimeout(timeoutId);
310
- }, [
311
- layoutStateReady,
312
- scheduleShowWeekends,
313
- scheduleShowBacklog,
314
- scheduleOnlyExpired,
315
- scheduleSidebarOpen,
316
- hierarchySidebarOpen,
317
- hierarchyRootTaskId,
318
- hierarchyShowUnlinkedColumn,
319
- hierarchyChildOrderMode,
320
- scheduleSelectedDate,
321
- scheduleCalendarMonth,
322
- scheduleScrollLeft,
323
- showFilters,
324
- workspaceUiStateHeaders
325
- ]);
326
- useEffect(() => {
327
- if (groupBy === 'schedule') {
328
- setScheduleSidebarOpen(true);
329
- }
330
- if (groupBy === 'hierarchy') {
331
- setHierarchySidebarOpen(true);
332
- }
333
- }, [groupBy]);
334
- const { showArchive, setShowArchive, fetchArchive, filteredArchive } = props;
335
- const kanbanTasks = useMemo(() => {
336
- if (!showArchive)
337
- return props.filteredTasks;
338
- const archivedWithFlag = filteredArchive.map(t => ({ ...t, isArchived: true }));
339
- return [...props.filteredTasks, ...archivedWithFlag];
340
- }, [props.filteredTasks, filteredArchive, showArchive]);
341
- const scheduleBaseTasks = useMemo(() => props.tasks.filter(task => !task.isArchived), [props.tasks]);
342
- const scheduleFilteredTaskIds = useMemo(() => new Set(props.filteredTasks.map(task => task.id)), [props.filteredTasks]);
343
- const kanbanAllTasks = useMemo(() => {
344
- if (!showArchive)
345
- return props.searchAgnosticTasks;
346
- return [...props.searchAgnosticTasks, ...filteredArchive];
347
- }, [props.searchAgnosticTasks, filteredArchive, showArchive]);
348
- const hierarchyTasks = useMemo(() => {
349
- const byId = new Map();
350
- for (const task of props.archivedTasks)
351
- byId.set(task.id, task);
352
- for (const task of props.tasks)
353
- byId.set(task.id, task);
354
- return Array.from(byId.values());
355
- }, [props.tasks, props.archivedTasks]);
356
- const hierarchyParentIdSet = useMemo(() => {
357
- const set = new Set();
358
- for (const task of hierarchyTasks) {
359
- if (task.parentTaskId)
360
- set.add(task.parentTaskId);
361
- }
362
- return set;
363
- }, [hierarchyTasks]);
364
- const hierarchyTaskById = useMemo(() => {
365
- const map = new Map();
366
- hierarchyTasks.forEach((task) => map.set(task.id, task));
367
- return map;
368
- }, [hierarchyTasks]);
369
- const hierarchyChildrenByParent = useMemo(() => {
370
- const map = new Map();
371
- hierarchyTasks.forEach((task) => {
372
- if (!task.parentTaskId)
373
- return;
374
- const list = map.get(task.parentTaskId) || [];
375
- list.push(task);
376
- map.set(task.parentTaskId, list);
377
- });
378
- return map;
379
- }, [hierarchyTasks]);
380
- const hierarchySearchMatches = useMemo(() => {
381
- const needle = hierarchyRootSearch.trim().toLowerCase();
382
- if (!needle)
383
- return [];
384
- const rankForTask = (task) => {
385
- const id = task.id.toLowerCase();
386
- const shortId = (task.id.split('-').slice(-1)[0] || task.id).toLowerCase();
387
- const title = task.title.toLowerCase();
388
- if (id === needle)
389
- return 0;
390
- if (shortId === needle)
391
- return 1;
392
- if (id.startsWith(needle) || shortId.startsWith(needle))
393
- return 2;
394
- if (title.startsWith(needle))
395
- return 3;
396
- if (title.includes(needle))
397
- return 4;
398
- if (id.includes(needle) || shortId.includes(needle))
399
- return 5;
400
- return null;
401
- };
402
- return hierarchyTasks
403
- .map((task) => ({ task, rank: rankForTask(task) }))
404
- .filter((entry) => entry.rank !== null)
405
- .sort((a, b) => {
406
- if (a.rank !== b.rank)
407
- return a.rank - b.rank;
408
- return a.task.title.localeCompare(b.task.title);
409
- })
410
- .map((entry) => entry.task);
411
- }, [hierarchyTasks, hierarchyRootSearch]);
412
- const hierarchyDescendantIdSet = useMemo(() => {
413
- if (!hierarchyRootTaskId)
414
- return null;
415
- return collectSubtreeTaskIds(hierarchyTasks, hierarchyRootTaskId);
416
- }, [hierarchyRootTaskId, hierarchyTasks]);
417
- const hierarchyVisibleTasks = useMemo(() => {
418
- if (groupBy === 'schedule')
419
- return scheduleBaseTasks;
420
- if (groupBy !== 'hierarchy')
421
- return kanbanTasks;
422
- const isUnlinkedTask = (task) => !task.parentTaskId && !hierarchyParentIdSet.has(task.id);
423
- let base = kanbanTasks;
424
- if (parentTaskFilterMode === 'parents') {
425
- base = kanbanTasks.filter(task => hierarchyParentIdSet.has(task.id));
426
- }
427
- else if (parentTaskFilterMode === 'linked') {
428
- base = kanbanTasks.filter(task => !!task.parentTaskId || hierarchyParentIdSet.has(task.id));
429
- }
430
- else if (parentTaskFilterMode === 'unlinked') {
431
- base = kanbanTasks.filter(task => isUnlinkedTask(task));
432
- }
433
- if (!hierarchyShowUnlinkedColumn && parentTaskFilterMode !== 'unlinked') {
434
- base = base.filter((task) => !isUnlinkedTask(task));
435
- }
436
- if (hierarchyDescendantIdSet) {
437
- base = base.filter(task => hierarchyDescendantIdSet.has(task.id)
438
- || (hierarchyShowUnlinkedColumn && (parentTaskFilterMode === 'all' || parentTaskFilterMode === 'unlinked') && isUnlinkedTask(task)));
439
- }
440
- return base;
441
- }, [groupBy, parentTaskFilterMode, kanbanTasks, hierarchyParentIdSet, scheduleBaseTasks, hierarchyDescendantIdSet, hierarchyShowUnlinkedColumn]);
442
- const todayDateOnly = useMemo(() => {
443
- const now = new Date();
444
- const y = now.getFullYear();
445
- const m = String(now.getMonth() + 1).padStart(2, '0');
446
- const d = String(now.getDate()).padStart(2, '0');
447
- return `${y}-${m}-${d}`;
448
- }, []);
449
- const boardVisibleTasks = useMemo(() => {
450
- if (groupBy !== 'schedule' || !scheduleOnlyExpired)
451
- return hierarchyVisibleTasks;
452
- return hierarchyVisibleTasks.filter((task) => {
453
- const isTerminal = task.status === 'done' || task.status === 'cancelled';
454
- if (isTerminal)
455
- return false;
456
- const expiredScheduled = !!task.scheduledDate && task.scheduledDate < todayDateOnly;
457
- const overdueDue = !!task.dueDate && task.dueDate < todayDateOnly;
458
- return expiredScheduled || overdueDue;
459
- });
460
- }, [groupBy, scheduleOnlyExpired, hierarchyVisibleTasks, todayDateOnly]);
461
- const expiredRecoveryCandidates = useMemo(() => {
462
- if (groupBy !== 'schedule')
463
- return [];
464
- return hierarchyVisibleTasks.filter((task) => {
465
- const isTerminal = task.status === 'done' || task.status === 'cancelled';
466
- if (isTerminal)
467
- return false;
468
- const expiredScheduled = !!task.scheduledDate && task.scheduledDate < todayDateOnly;
469
- const overdueDue = !!task.dueDate && task.dueDate < todayDateOnly;
470
- return expiredScheduled || overdueDue;
471
- });
472
- }, [groupBy, hierarchyVisibleTasks, todayDateOnly]);
473
- const expiredScheduledCount = useMemo(() => {
474
- if (groupBy !== 'schedule')
475
- return 0;
476
- return hierarchyVisibleTasks.filter((task) => {
477
- const isTerminal = task.status === 'done' || task.status === 'cancelled';
478
- if (isTerminal)
479
- return false;
480
- return !!task.scheduledDate && task.scheduledDate < todayDateOnly;
481
- }).length;
482
- }, [groupBy, hierarchyVisibleTasks, todayDateOnly]);
483
- const overdueDueCount = useMemo(() => {
484
- if (groupBy !== 'schedule')
485
- return 0;
486
- return hierarchyVisibleTasks.filter((task) => {
487
- const isTerminal = task.status === 'done' || task.status === 'cancelled';
488
- if (isTerminal)
489
- return false;
490
- return !!task.dueDate && task.dueDate < todayDateOnly;
491
- }).length;
492
- }, [groupBy, hierarchyVisibleTasks, todayDateOnly]);
493
- const expiredColumnCandidates = useMemo(() => {
494
- if (groupBy !== 'schedule')
495
- return [];
496
- return hierarchyVisibleTasks.filter((task) => {
497
- const isTerminal = task.status === 'done' || task.status === 'cancelled';
498
- if (isTerminal)
499
- return false;
500
- return !!task.scheduledDate && task.scheduledDate < todayDateOnly;
501
- });
502
- }, [groupBy, hierarchyVisibleTasks, todayDateOnly]);
503
- const filteredExpiredColumnCandidates = useMemo(() => {
504
- if (groupBy !== 'schedule')
505
- return [];
506
- return expiredColumnCandidates.filter((task) => scheduleFilteredTaskIds.has(task.id));
507
- }, [groupBy, expiredColumnCandidates, scheduleFilteredTaskIds]);
508
- const expiredLeafCandidates = useMemo(() => expiredRecoveryCandidates.filter(task => !hierarchyParentIdSet.has(task.id)), [expiredRecoveryCandidates, hierarchyParentIdSet]);
509
- const [scheduleBulkBusy, setScheduleBulkBusy] = useState(false);
510
- const [scheduleParentDropBusy, setScheduleParentDropBusy] = useState(false);
511
- const [scheduleParentDropPrompt, setScheduleParentDropPrompt] = useState(null);
512
- const hierarchyDepthTasks = useMemo(() => hierarchyVisibleTasks.filter(task => !!task.parentTaskId || hierarchyParentIdSet.has(task.id)), [hierarchyVisibleTasks, hierarchyParentIdSet]);
513
- const hierarchyGlobalDepthMap = useMemo(() => buildHierarchyDepthMap(hierarchyTasks), [hierarchyTasks]);
514
- const maxHierarchyDepth = useMemo(() => hierarchyDepthTasks.reduce((maxDepth, task) => {
515
- const depth = hierarchyGlobalDepthMap.get(task.id) ?? 0;
516
- return depth > maxDepth ? depth : maxDepth;
517
- }, 0), [hierarchyDepthTasks, hierarchyGlobalDepthMap]);
518
- const tryReturnToParent = () => {
519
- if (activeTab === 'add'
520
- && editingTaskId
521
- && returnToParentTaskId
522
- && returnFromChildTaskId === editingTaskId) {
523
- const parentTask = tasks.find(t => t.id === returnToParentTaskId);
524
- clearReturnToParentTask();
525
- if (parentTask) {
526
- handleEdit(parentTask);
527
- return true;
528
- }
529
- }
530
- return false;
531
- };
532
- const handleCloseModal = () => {
533
- handleNavigation(() => {
534
- if (tryReturnToParent())
535
- return;
536
- if (activeTab === 'add')
537
- resetForm();
538
- setActiveTab('tasks');
539
- });
540
- };
541
- const [localCancellationReason, setLocalCancellationReason] = useState('');
542
- const handleConfirmCancellation = () => {
543
- confirmCancellation(localCancellationReason);
544
- setLocalCancellationReason('');
545
- };
546
- const handleCancelCancellation = () => {
547
- cancelCancellationPrompt();
548
- setLocalCancellationReason('');
549
- };
550
- const handleDeleteFromCancellation = async () => {
551
- if (!cancellationPromptTask)
552
- return;
553
- const confirmed = window.confirm('Delete this task permanently? This cannot be undone.');
554
- if (!confirmed)
555
- return;
556
- const deleted = await handleDelete(cancellationPromptTask.id, false, { skipConfirm: true });
557
- if (deleted) {
558
- handleCancelCancellation();
559
- }
560
- };
561
- const handleAddTaskToColumn = useCallback((groupField, value) => {
562
- resetForm();
563
- // Handle different grouping fields
564
- if (groupField === 'category') {
565
- const cat = activeCategories.find(c => String(c.value) === String(value) || c.label === String(value));
566
- if (cat)
567
- setCategory(cat.label);
568
- }
569
- else if (groupField === 'type') {
570
- setType(String(value));
571
- }
572
- else if (groupField === 'priority') {
573
- setPriority(Number(value));
574
- }
575
- else if (groupField === 'approach') {
576
- const app = approaches.find(a => String(a.value) === String(value) || a.label === String(value));
577
- if (app) {
578
- setApproach(app.value);
579
- setFormTaxonomies(prev => ({ ...prev, approach: app.value }));
580
- }
581
- }
582
- else if (groupField === 'status') {
583
- // When adding to a status column, we just open the form.
584
- // But we can preset the status flags if we want, or just let users set them.
585
- // Currently, the TaskForm doesn't expose a simple 'status' dropdown to preset.
586
- // So for now, we'll just open the form.
587
- // Ideally, we would preset the flags (inProgress, readyForReview, etc.)
588
- // implementing basic presetting:
589
- if (value === 'inProgress') {
590
- handleToggleInProgress({}); // Hacky: assumes handleToggle works on new task? No.
591
- // Better: we can't easily preset status flags in the current form setup without modifying resetForm/TaskForm props deeply.
592
- // For now, simple open.
593
- // Actually, let's try to pass initial state if possible, but useTaskforce API is limited.
594
- // We'll leave it as default (Task) for now, or users can toggle after adding.
595
- }
596
- }
597
- else if (groupField === 'complexity') {
598
- const direct = Number(value);
599
- if (Number.isFinite(direct)) {
600
- setComplexity(direct);
601
- }
602
- }
603
- else if (groupField === 'hierarchy') {
604
- // Hierarchy columns are depth-based and do not map to form defaults.
605
- }
606
- setActiveTab('add');
607
- }, [resetForm, activeCategories, approaches, setCategory, setType, setPriority, setComplexity, setApproach, setFormTaxonomies, setActiveTab]);
608
- // Ensure 'done' status is shown by default as requested
609
- React.useEffect(() => {
610
- if (filterStatus && !filterStatus.includes('done')) {
611
- setFilterStatus(prev => [...prev, 'done']);
612
- }
613
- }, []);
614
- // Local state for filter toolbar
615
- const [showHelpModal, setShowHelpModal] = useState(false);
616
- const [showAccountMenu, setShowAccountMenu] = useState(false);
617
- const [showAccountHub, setShowAccountHub] = useState(false);
618
- const [showSyncStatusModal, setShowSyncStatusModal] = useState(false);
619
- const [workspaceSyncBusy, setWorkspaceSyncBusy] = useState(false);
620
- const [workspaceSyncError, setWorkspaceSyncError] = useState(null);
621
- const [showCloudSignInModal, setShowCloudSignInModal] = useState(false);
622
- const [cloudSignInEmail, setCloudSignInEmail] = useState('');
623
- const [cloudSignInPassword, setCloudSignInPassword] = useState('');
624
- const [cloudSignInBusy, setCloudSignInBusy] = useState(false);
625
- const [cloudSignInError, setCloudSignInError] = useState(null);
626
- const [workspacePanelOpen, setWorkspacePanelOpen] = useState(false);
627
- const [workspaceFormName, setWorkspaceFormName] = useState('');
628
- const [workspaceFormDescription, setWorkspaceFormDescription] = useState('');
629
- const [workspaceActionBusy, setWorkspaceActionBusy] = useState(false);
630
- const [workspaceActionError, setWorkspaceActionError] = useState('');
631
- const accountMenuRef = useRef(null);
632
- // showSearch state removed - search always visible in actions area
633
- useEffect(() => {
634
- if (!showAccountMenu)
635
- return;
636
- const handlePointerDown = (event) => {
637
- if (!accountMenuRef.current?.contains(event.target)) {
638
- setShowAccountMenu(false);
639
- }
640
- };
641
- document.addEventListener('mousedown', handlePointerDown);
642
- return () => document.removeEventListener('mousedown', handlePointerDown);
643
- }, [showAccountMenu]);
644
- const canManageCloudWorkspaces = runtimeMode === 'cloud' && isAuthenticated;
645
- const canManageWorkspaceSync = runtimeMode === 'local' && isAuthenticated;
646
- const openCloudSignIn = useCallback(() => {
647
- setCloudSignInError(null);
648
- setShowCloudSignInModal(true);
649
- }, []);
650
- const closeCloudSignInModal = useCallback(() => {
651
- if (cloudSignInBusy)
652
- return;
653
- setShowCloudSignInModal(false);
654
- setCloudSignInError(null);
655
- }, [cloudSignInBusy]);
656
- const openWorkspaceSetup = useCallback(() => {
657
- setShowAccountMenu(false);
658
- setWorkspacePanelOpen(false);
659
- navigate('/setup?step=workspace', { replace: true });
660
- }, [navigate]);
661
- const routeToWorkspaceSetupIfNeeded = useCallback(async (hintWorkspaceSetupRequired) => {
662
- const workspacesResult = await fetchWorkspaces();
663
- if (workspacesResult.success) {
664
- const workspaceCount = Array.isArray(workspacesResult.workspaces)
665
- ? workspacesResult.workspaces.length
666
- : 0;
667
- if (workspaceCount === 0) {
668
- openWorkspaceSetup();
669
- return true;
670
- }
671
- return false;
672
- }
673
- if (hintWorkspaceSetupRequired) {
674
- openWorkspaceSetup();
675
- return true;
676
- }
677
- return false;
678
- }, [fetchWorkspaces, openWorkspaceSetup]);
679
- const handleSwitchWorkspace = useCallback(async (workspaceId) => {
680
- if (!workspaceId || workspaceActionBusy)
681
- return;
682
- setWorkspaceActionError('');
683
- setWorkspaceActionBusy(true);
684
- try {
685
- const result = await switchWorkspace(workspaceId);
686
- if (!result.success) {
687
- if (result.code === 'WORKSPACE_NOT_FOUND' || result.code === 'WORKSPACE_ID_REQUIRED') {
688
- openWorkspaceSetup();
689
- return;
690
- }
691
- setWorkspaceActionError(result.error || 'Failed to switch workspace.');
692
- return;
693
- }
694
- await fetchTasks(true);
695
- setShowAccountMenu(false);
696
- setWorkspacePanelOpen(false);
697
- }
698
- finally {
699
- setWorkspaceActionBusy(false);
700
- }
701
- }, [switchWorkspace, workspaceActionBusy, fetchTasks, openWorkspaceSetup]);
702
- const handleCreateWorkspace = useCallback(async () => {
703
- if (workspaceActionBusy)
704
- return;
705
- const name = workspaceFormName.trim();
706
- if (!name) {
707
- setWorkspaceActionError('Workspace name is required.');
708
- return;
709
- }
710
- setWorkspaceActionError('');
711
- setWorkspaceActionBusy(true);
712
- try {
713
- const result = await createWorkspace(name, workspaceFormDescription.trim() || undefined);
714
- if (!result.success) {
715
- if (result.code === 'WORKSPACE_NOT_FOUND' || result.code === 'WORKSPACE_ID_REQUIRED') {
716
- openWorkspaceSetup();
717
- return;
718
- }
719
- setWorkspaceActionError(result.error || 'Failed to create workspace.');
720
- return;
721
- }
722
- await fetchTasks(true);
723
- setWorkspaceFormName('');
724
- setWorkspaceFormDescription('');
725
- setWorkspacePanelOpen(false);
726
- setShowAccountMenu(false);
727
- }
728
- finally {
729
- setWorkspaceActionBusy(false);
730
- }
731
- }, [workspaceActionBusy, workspaceFormName, workspaceFormDescription, createWorkspace, fetchTasks, openWorkspaceSetup]);
732
- // Check if any filters are set
733
- const isFiltered = useMemo(() => {
734
- const hasSearch = searchQuery.trim().length > 0;
735
- const hasCategoryFilter = filterCategories.length !== activeCategories.length;
736
- const hasTypeFilter = filterTypes.length !== activeTypes.length;
737
- const hasPriorityFilter = filterPriorities.length !== priorities.length;
738
- const hasStatusFilter = filterStatus.length !== STATUS_OPTIONS.length;
739
- const hasAssigneeFilter = assigneeFilterEnabled && filterAssignees.length !== 3;
740
- const hasParentsOnlyFilter = parentTaskFilterMode !== 'all';
741
- return hasSearch || hasCategoryFilter || hasTypeFilter || hasPriorityFilter || hasStatusFilter || hasAssigneeFilter || hasParentsOnlyFilter;
742
- }, [searchQuery, filterCategories, activeCategories, filterTypes, activeTypes, filterPriorities, priorities, filterStatus, assigneeFilterEnabled, filterAssignees, parentTaskFilterMode]);
743
- const totalActiveCount = tasks.length;
744
- const visibleActiveCount = props.filteredTasks.length;
745
- const activeCountLabel = isFiltered ? `${visibleActiveCount}/${totalActiveCount}` : `${totalActiveCount}`;
746
- const activeCountTitle = isFiltered
747
- ? t('standalone.visibleActiveTasksTitle')
748
- : t('standalone.totalActiveTasksTitle');
749
- const shouldShowSyncStatus = runtimeMode === 'local';
750
- const formattedLastSyncTime = useMemo(() => {
751
- if (!userGlobalLastSyncedAt)
752
- return 'Never';
753
- const parsed = new Date(userGlobalLastSyncedAt);
754
- if (Number.isNaN(parsed.getTime()))
755
- return 'Never';
756
- return parsed.toLocaleString();
757
- }, [userGlobalLastSyncedAt]);
758
- const formatSyncTimestamp = useCallback((value) => {
759
- if (!value)
760
- return 'Never';
761
- const parsed = new Date(value);
762
- if (Number.isNaN(parsed.getTime()))
763
- return 'Never';
764
- return parsed.toLocaleString();
765
- }, []);
766
- const formattedLastPullTime = useMemo(() => formatSyncTimestamp(workspaceLastPullAt), [workspaceLastPullAt, formatSyncTimestamp]);
767
- const formattedLastPushTime = useMemo(() => formatSyncTimestamp(workspaceLastPushAt), [workspaceLastPushAt, formatSyncTimestamp]);
768
- const formattedLastErrorTime = useMemo(() => formatSyncTimestamp(workspaceLastErrorAt), [workspaceLastErrorAt, formatSyncTimestamp]);
769
- const formattedRetryTime = useMemo(() => formatSyncTimestamp(workspaceRetryAt), [workspaceRetryAt, formatSyncTimestamp]);
770
- const [displaySyncState, setDisplaySyncState] = useState(() => (workspaceCloudSyncEnabled ? userGlobalSyncStatus : 'disconnected'));
771
- const syncStateSinceRef = useRef(Date.now());
772
- const syncStateTimerRef = useRef(null);
773
- const rawSyncState = workspaceCloudSyncEnabled
774
- ? userGlobalSyncStatus
775
- : 'disconnected';
776
- useEffect(() => {
777
- if (syncStateTimerRef.current !== null) {
778
- window.clearTimeout(syncStateTimerRef.current);
779
- syncStateTimerRef.current = null;
780
- }
781
- const applyState = (next) => {
782
- setDisplaySyncState(next);
783
- syncStateSinceRef.current = Date.now();
784
- };
785
- if (rawSyncState === displaySyncState)
786
- return;
787
- // Delay "syncing" to avoid flicker on very fast sync cycles.
788
- if (rawSyncState === 'syncing') {
789
- syncStateTimerRef.current = window.setTimeout(() => {
790
- applyState('syncing');
791
- }, SYNCING_DISPLAY_DELAY_MS);
792
- return;
793
- }
794
- // Hold syncing/error briefly so status doesn't flash rapidly.
795
- if (displaySyncState === 'syncing') {
796
- const elapsed = Date.now() - syncStateSinceRef.current;
797
- const remaining = Math.max(0, SYNCING_MIN_VISIBLE_MS - elapsed);
798
- syncStateTimerRef.current = window.setTimeout(() => {
799
- applyState(rawSyncState);
800
- }, remaining);
801
- return;
802
- }
803
- if (displaySyncState === 'error' && rawSyncState !== 'error') {
804
- const elapsed = Date.now() - syncStateSinceRef.current;
805
- const remaining = Math.max(0, ERROR_MIN_VISIBLE_MS - elapsed);
806
- syncStateTimerRef.current = window.setTimeout(() => {
807
- applyState(rawSyncState);
808
- }, remaining);
809
- return;
810
- }
811
- applyState(rawSyncState);
812
- }, [rawSyncState, displaySyncState]);
813
- useEffect(() => {
814
- return () => {
815
- if (syncStateTimerRef.current !== null) {
816
- window.clearTimeout(syncStateTimerRef.current);
817
- syncStateTimerRef.current = null;
818
- }
819
- };
820
- }, []);
821
- const modalSyncStatusMeta = useMemo(() => {
822
- if (!workspaceCloudSyncEnabled) {
823
- return {
824
- label: 'Sync Off',
825
- color: '#94a3b8',
826
- border: 'rgba(148, 163, 184, 0.45)',
827
- background: 'rgba(148, 163, 184, 0.12)'
828
- };
829
- }
830
- switch (displaySyncState) {
831
- case 'syncing':
832
- return {
833
- label: 'Syncing',
834
- color: '#f59e0b',
835
- border: 'rgba(245, 158, 11, 0.45)',
836
- background: 'rgba(245, 158, 11, 0.16)'
837
- };
838
- case 'error':
839
- return {
840
- label: 'Sync Error',
841
- color: '#f87171',
842
- border: 'rgba(248, 113, 113, 0.45)',
843
- background: 'rgba(248, 113, 113, 0.14)'
844
- };
845
- case 'disconnected':
846
- return {
847
- label: 'Disconnected',
848
- color: '#94a3b8',
849
- border: 'rgba(148, 163, 184, 0.45)',
850
- background: 'rgba(148, 163, 184, 0.12)'
851
- };
852
- case 'idle':
853
- default:
854
- return {
855
- label: 'Synced',
856
- color: '#34d399',
857
- border: 'rgba(52, 211, 153, 0.45)',
858
- background: 'rgba(52, 211, 153, 0.14)'
859
- };
860
- }
861
- }, [displaySyncState, workspaceCloudSyncEnabled]);
862
- const headerSyncStatusMeta = useMemo(() => {
863
- if (!workspaceCloudSyncEnabled) {
864
- return {
865
- label: 'Sync Off',
866
- color: '#94a3b8',
867
- border: 'rgba(148, 163, 184, 0.45)',
868
- background: 'rgba(148, 163, 184, 0.12)',
869
- icon: 'off'
870
- };
871
- }
872
- if (displaySyncState === 'error') {
873
- return {
874
- label: 'Sync Error',
875
- color: '#f87171',
876
- border: 'rgba(248, 113, 113, 0.45)',
877
- background: 'rgba(248, 113, 113, 0.14)',
878
- icon: 'off'
879
- };
880
- }
881
- if (displaySyncState === 'disconnected') {
882
- return {
883
- label: 'Disconnected',
884
- color: '#94a3b8',
885
- border: 'rgba(148, 163, 184, 0.45)',
886
- background: 'rgba(148, 163, 184, 0.12)',
887
- icon: 'off'
888
- };
889
- }
890
- return {
891
- label: 'Synced',
892
- color: '#34d399',
893
- border: 'rgba(52, 211, 153, 0.45)',
894
- background: 'rgba(52, 211, 153, 0.14)',
895
- icon: 'cloud'
896
- };
897
- }, [displaySyncState, workspaceCloudSyncEnabled]);
898
- const parentFilterLabel = hierarchyRootTaskId
899
- ? 'Subtree'
900
- : parentTaskFilterMode === 'parents'
901
- ? t('standalone.linksParents')
902
- : parentTaskFilterMode === 'linked'
903
- ? t('standalone.linksLinked')
904
- : parentTaskFilterMode === 'unlinked'
905
- ? t('standalone.linksUnlinked')
906
- : t('standalone.linksAll');
907
- const selectedHierarchyRootTask = hierarchyRootTaskId ? hierarchyTaskById.get(hierarchyRootTaskId) : undefined;
908
- const hierarchySubtreeStats = useMemo(() => {
909
- if (!hierarchyDescendantIdSet || !selectedHierarchyRootTask)
910
- return null;
911
- const selectedTasks = hierarchyTasks.filter((task) => hierarchyDescendantIdSet.has(task.id));
912
- let active = 0;
913
- let terminal = 0;
914
- let overdue = 0;
915
- selectedTasks.forEach((task) => {
916
- const isTerminal = task.status === 'done' || task.status === 'cancelled' || Boolean(task.isArchived);
917
- if (isTerminal) {
918
- terminal += 1;
919
- }
920
- else {
921
- active += 1;
922
- if (task.dueDate && task.dueDate < todayDateOnly)
923
- overdue += 1;
924
- }
925
- });
926
- let depth = 0;
927
- const visited = new Set();
928
- const stack = [{ id: selectedHierarchyRootTask.id, depth: 0 }];
929
- while (stack.length > 0) {
930
- const current = stack.pop();
931
- if (visited.has(current.id))
932
- continue;
933
- visited.add(current.id);
934
- if (current.depth > depth)
935
- depth = current.depth;
936
- const children = hierarchyChildrenByParent.get(current.id) || [];
937
- children.forEach((child) => {
938
- if (!visited.has(child.id) && hierarchyDescendantIdSet.has(child.id)) {
939
- stack.push({ id: child.id, depth: current.depth + 1 });
940
- }
941
- });
942
- }
943
- return { total: selectedTasks.length, active, terminal, overdue, depth };
944
- }, [hierarchyDescendantIdSet, selectedHierarchyRootTask, hierarchyTasks, todayDateOnly, hierarchyChildrenByParent]);
945
- const hierarchyVisibleLevelCounts = useMemo(() => {
946
- const byLevel = new Map();
947
- hierarchyDepthTasks.forEach((task) => {
948
- const level = (hierarchyGlobalDepthMap.get(task.id) ?? 0) + 1;
949
- byLevel.set(level, (byLevel.get(level) || 0) + 1);
950
- });
951
- return Array.from(byLevel.entries())
952
- .sort((a, b) => a[0] - b[0])
953
- .map(([level, count]) => ({ level, count }));
954
- }, [hierarchyDepthTasks, hierarchyGlobalDepthMap]);
955
- const hierarchyVisibleUnlinkedCount = useMemo(() => hierarchyVisibleTasks.filter((task) => !task.parentTaskId && !hierarchyParentIdSet.has(task.id)).length, [hierarchyVisibleTasks, hierarchyParentIdSet]);
956
- const hierarchyVisibleRootCount = useMemo(() => hierarchyVisibleTasks.filter((task) => !task.parentTaskId && hierarchyParentIdSet.has(task.id)).length, [hierarchyVisibleTasks, hierarchyParentIdSet]);
957
- const hierarchySubtreeTaskList = useMemo(() => {
958
- if (!hierarchyRootTaskId || !hierarchyDescendantIdSet)
959
- return [];
960
- return hierarchyTasks
961
- .filter((task) => hierarchyDescendantIdSet.has(task.id))
962
- .sort((a, b) => {
963
- const levelA = hierarchyGlobalDepthMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
964
- const levelB = hierarchyGlobalDepthMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
965
- if (levelA !== levelB)
966
- return levelA - levelB;
967
- return a.title.localeCompare(b.title);
968
- });
969
- }, [hierarchyRootTaskId, hierarchyDescendantIdSet, hierarchyTasks, hierarchyGlobalDepthMap]);
970
- const applyHierarchySearchSelection = useCallback(() => {
971
- const bestMatch = hierarchySearchMatches[0];
972
- if (!bestMatch)
973
- return;
974
- setHierarchyRootTaskId(bestMatch.id);
975
- setHierarchyRootSearch('');
976
- if (parentTaskFilterMode === 'unlinked')
977
- setParentTaskFilterMode('all');
978
- }, [hierarchySearchMatches, parentTaskFilterMode, setParentTaskFilterMode]);
979
- const selectedDateObj = useMemo(() => parseDateOnlyLocal(scheduleSelectedDate) || new Date(), [scheduleSelectedDate]);
980
- const scheduleWeekStart = useMemo(() => startOfWeek(selectedDateObj, globalWeekStartsOn), [selectedDateObj, globalWeekStartsOn]);
981
- const scheduleDates = useMemo(() => {
982
- const map = {
983
- mon: '',
984
- tue: '',
985
- wed: '',
986
- thu: '',
987
- fri: '',
988
- sat: '',
989
- sun: ''
990
- };
991
- SCHEDULE_DAY_KEYS.forEach((key) => {
992
- const offset = getDayOffsetFromWeekStart(key, globalWeekStartsOn);
993
- map[key] = toDateOnlyLocal(addDays(scheduleWeekStart, offset));
994
- });
995
- return map;
996
- }, [scheduleWeekStart, globalWeekStartsOn]);
997
- const mapToSelectedWeekDate = useCallback((sourceDateOnly) => {
998
- const parsed = parseDateOnlyLocal(sourceDateOnly);
999
- if (!parsed)
1000
- return scheduleDates.mon;
1001
- const day = parsed.getDay();
1002
- const key = day === 1 ? 'mon' :
1003
- day === 2 ? 'tue' :
1004
- day === 3 ? 'wed' :
1005
- day === 4 ? 'thu' :
1006
- day === 5 ? 'fri' :
1007
- day === 6 ? (scheduleShowWeekends ? 'sat' : 'fri') :
1008
- (scheduleShowWeekends ? 'sun' : 'fri');
1009
- return scheduleDates[key] || scheduleDates.mon;
1010
- }, [scheduleDates, scheduleShowWeekends]);
1011
- const handleMoveExpiredToSelectedWeek = useCallback(async () => {
1012
- if (scheduleBulkBusy || expiredLeafCandidates.length === 0)
1013
- return;
1014
- setScheduleBulkBusy(true);
1015
- try {
1016
- for (const task of expiredLeafCandidates) {
1017
- const sourceDate = task.scheduledDate || task.dueDate || todayDateOnly;
1018
- const nextDate = mapToSelectedWeekDate(sourceDate);
1019
- await handleUpdateTask(task.id, {
1020
- scheduledDate: nextDate,
1021
- scheduledWeekKey: dateOnlyToIsoWeekKey(nextDate),
1022
- orderInDay: null
1023
- });
1024
- }
1025
- await fetchTasks(true);
1026
- }
1027
- finally {
1028
- setScheduleBulkBusy(false);
1029
- }
1030
- }, [scheduleBulkBusy, expiredLeafCandidates, todayDateOnly, mapToSelectedWeekDate, handleUpdateTask, fetchTasks]);
1031
- const handleMoveExpiredToBacklog = useCallback(async () => {
1032
- if (scheduleBulkBusy || expiredRecoveryCandidates.length === 0)
1033
- return;
1034
- setScheduleBulkBusy(true);
1035
- try {
1036
- for (const task of expiredRecoveryCandidates) {
1037
- await handleUpdateTask(task.id, {
1038
- scheduledDate: null,
1039
- scheduledWeekKey: null,
1040
- orderInDay: null
1041
- });
1042
- }
1043
- await fetchTasks(true);
1044
- }
1045
- finally {
1046
- setScheduleBulkBusy(false);
1047
- }
1048
- }, [scheduleBulkBusy, expiredRecoveryCandidates, handleUpdateTask, fetchTasks]);
1049
- const handleScheduleParentDrop = useCallback((payload) => {
1050
- if (payload.targetDate < todayDateOnly) {
1051
- const byId = new Map(tasks.map((task) => [task.id, task]));
1052
- const hasNonTerminalLeaf = payload.toScheduleLeafTaskIds.some((taskId) => {
1053
- const task = byId.get(taskId);
1054
- if (!task)
1055
- return true;
1056
- return task.status !== 'done' && task.status !== 'cancelled';
1057
- });
1058
- if (hasNonTerminalLeaf) {
1059
- window.alert(t('schedule.completedOnlyPastSchedule'));
1060
- return;
1061
- }
1062
- }
1063
- if (payload.toScheduleLeafTaskIds.length === 0) {
1064
- window.alert(t('schedule.noUnscheduledLeafTasks', { parentTitle: payload.parentTitle }));
1065
- return;
1066
- }
1067
- setScheduleParentDropPrompt(payload);
1068
- }, [tasks, todayDateOnly]);
1069
- const confirmScheduleParentDrop = useCallback(async () => {
1070
- if (!scheduleParentDropPrompt || scheduleParentDropBusy)
1071
- return;
1072
- setScheduleParentDropBusy(true);
1073
- try {
1074
- const { targetDate, toScheduleLeafTaskIds } = scheduleParentDropPrompt;
1075
- const dayTasks = tasks
1076
- .filter((task) => task.scheduledDate === targetDate && !toScheduleLeafTaskIds.includes(task.id))
1077
- .sort((a, b) => {
1078
- const orderA = typeof a.orderInDay === 'number' ? a.orderInDay : Number.MAX_SAFE_INTEGER;
1079
- const orderB = typeof b.orderInDay === 'number' ? b.orderInDay : Number.MAX_SAFE_INTEGER;
1080
- if (orderA !== orderB)
1081
- return orderA - orderB;
1082
- return String(a.createdAt || '').localeCompare(String(b.createdAt || ''));
1083
- });
1084
- let nextOrder = dayTasks.length;
1085
- for (const taskId of toScheduleLeafTaskIds) {
1086
- await handleUpdateTask(taskId, {
1087
- scheduledDate: targetDate,
1088
- scheduledWeekKey: dateOnlyToIsoWeekKey(targetDate),
1089
- orderInDay: nextOrder++
1090
- });
1091
- }
1092
- setScheduleParentDropPrompt(null);
1093
- await fetchTasks(true);
1094
- }
1095
- finally {
1096
- setScheduleParentDropBusy(false);
1097
- }
1098
- }, [scheduleParentDropPrompt, scheduleParentDropBusy, tasks, handleUpdateTask, fetchTasks]);
1099
- const cancelScheduleParentDrop = useCallback(() => {
1100
- if (scheduleParentDropBusy)
1101
- return;
1102
- setScheduleParentDropPrompt(null);
1103
- }, [scheduleParentDropBusy]);
1104
- const scheduleMonthDate = useMemo(() => {
1105
- const [yearRaw, monthRaw] = scheduleCalendarMonth.split('-');
1106
- const year = Number(yearRaw);
1107
- const month = Number(monthRaw);
1108
- if (!Number.isInteger(year) || !Number.isInteger(month) || month < 1 || month > 12) {
1109
- return new Date(selectedDateObj.getFullYear(), selectedDateObj.getMonth(), 1);
1110
- }
1111
- return new Date(year, month - 1, 1);
1112
- }, [scheduleCalendarMonth, selectedDateObj]);
1113
- const scheduleCalendarMonthLabel = useMemo(() => formatDate(scheduleMonthDate, { month: 'long', year: 'numeric' }, resolvedLocale), [scheduleMonthDate, resolvedLocale]);
1114
- const scheduleWeekLabel = useMemo(() => formatDate(scheduleWeekStart, { month: 'short', day: 'numeric', year: 'numeric' }, resolvedLocale), [scheduleWeekStart, resolvedLocale]);
1115
- const calendarCells = useMemo(() => {
1116
- const start = startOfWeek(scheduleMonthDate, globalWeekStartsOn);
1117
- return Array.from({ length: 42 }, (_, i) => addDays(start, i));
1118
- }, [scheduleMonthDate, globalWeekStartsOn]);
1119
- const calendarTaskSignals = useMemo(() => {
1120
- const byDate = new Map();
1121
- for (const task of scheduleBaseTasks) {
1122
- const dateOnly = task.scheduledDate || '';
1123
- if (!dateOnly)
1124
- continue;
1125
- const isTerminal = task.status === 'done' || task.status === 'cancelled';
1126
- const isExpired = !isTerminal && dateOnly < todayDateOnly;
1127
- const existing = byDate.get(dateOnly);
1128
- if (existing) {
1129
- existing.count += 1;
1130
- if (isExpired)
1131
- existing.hasExpired = true;
1132
- }
1133
- else {
1134
- byDate.set(dateOnly, { count: 1, hasExpired: isExpired });
1135
- }
1136
- }
1137
- return byDate;
1138
- }, [scheduleBaseTasks, todayDateOnly]);
1139
- const calendarWeekdayLabels = useMemo(() => (globalWeekStartsOn === 'sunday'
1140
- ? ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
1141
- : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']), [globalWeekStartsOn]);
1142
- // Calculate columns based on grouping
1143
- const scheduleColumns = useMemo(() => {
1144
- const orderedKeys = globalWeekStartsOn === 'sunday'
1145
- ? ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
1146
- : SCHEDULE_DAY_KEYS;
1147
- const visibleKeys = scheduleShowWeekends
1148
- ? orderedKeys
1149
- : ['mon', 'tue', 'wed', 'thu', 'fri'];
1150
- const days = visibleKeys.map((key) => {
1151
- const date = parseDateOnlyLocal(scheduleDates[key]) || scheduleWeekStart;
1152
- const dateOnly = scheduleDates[key];
1153
- const isWeekend = key === 'sat' || key === 'sun';
1154
- return {
1155
- value: key,
1156
- label: `${SCHEDULE_DAY_LABELS[key]} ${formatDate(date, { month: 'short', day: 'numeric' }, resolvedLocale)}`,
1157
- color: isWeekend ? '#1e3a8a' : '#3b82f6',
1158
- icon: 'Calendar',
1159
- date: dateOnly,
1160
- isPast: dateOnly < todayDateOnly,
1161
- isSelected: dateOnly === scheduleSelectedDate,
1162
- isWeekend
1163
- };
1164
- });
1165
- const hasExpiredTasks = filteredExpiredColumnCandidates.length > 0;
1166
- return [
1167
- ...(scheduleShowBacklog ? [{ value: 'backlog', label: 'Backlog', color: '#64748b', icon: 'Inbox' }] : []),
1168
- ...(hasExpiredTasks ? [{ value: 'expired', label: 'Expired', color: '#ef4444', icon: 'AlertTriangle' }] : []),
1169
- ...days
1170
- ];
1171
- }, [scheduleShowWeekends, scheduleShowBacklog, scheduleDates, scheduleWeekStart, filteredExpiredColumnCandidates.length, todayDateOnly, scheduleSelectedDate, globalWeekStartsOn, resolvedLocale]);
1172
- const kanbanColumns = useMemo(() => {
1173
- switch (groupBy) {
1174
- case 'category':
1175
- return activeCategories;
1176
- case 'type':
1177
- return (activeTypes || []).map(t => ({
1178
- ...t,
1179
- icon: TypeMeta[t.value]?.icon,
1180
- color: TypeMeta[t.value]?.color
1181
- }));
1182
- case 'priority':
1183
- return priorities;
1184
- case 'complexity':
1185
- return [
1186
- { value: 1, label: 'Tiny', icon: 'Gauge', color: '#10b981' },
1187
- { value: 2, label: 'Low', icon: 'Gauge', color: '#14b8a6' },
1188
- { value: 3, label: 'Medium', icon: 'Gauge', color: '#3b82f6' },
1189
- { value: 4, label: 'High', icon: 'Gauge', color: '#8b5cf6' },
1190
- { value: 5, label: 'Epic', icon: 'Gauge', color: '#d946ef' }
1191
- ];
1192
- case 'approach':
1193
- return approaches;
1194
- case 'assignee':
1195
- return [
1196
- { value: 'agent', label: 'AI', icon: 'Bot', color: '#8b5cf6' },
1197
- { value: 'user', label: 'User', icon: 'User', color: '#22c55e' },
1198
- { value: 'unassigned', label: 'Unassigned', icon: 'Circle', color: '#64748b' }
1199
- ];
1200
- case 'status':
1201
- return STATUS_OPTIONS.map(opt => {
1202
- let icon = 'Circle';
1203
- let color = 'var(--text-secondary)';
1204
- switch (opt.value) {
1205
- case 'on-hold':
1206
- icon = 'Pause';
1207
- color = 'amber-500';
1208
- break;
1209
- case 'in-progress':
1210
- icon = 'Play';
1211
- color = 'blue-500';
1212
- break;
1213
- case 'review':
1214
- icon = 'Sparkles';
1215
- color = 'violet-500';
1216
- break;
1217
- case 'done':
1218
- icon = 'Check';
1219
- color = 'green-500';
1220
- break;
1221
- case 'cancelled':
1222
- icon = 'Ban';
1223
- color = 'red-500';
1224
- break;
1225
- case 'task':
1226
- default:
1227
- icon = 'Circle'; // Or List
1228
- color = 'blue-200'; // Default light shade
1229
- break;
1230
- }
1231
- return {
1232
- ...opt,
1233
- icon,
1234
- color
1235
- };
1236
- });
1237
- case 'hierarchy': {
1238
- if (parentTaskFilterMode === 'unlinked') {
1239
- return [{
1240
- value: 'standalone',
1241
- label: 'Unlinked',
1242
- icon: 'Circle',
1243
- color: '#64748b'
1244
- }];
1245
- }
1246
- const levels = Array.from({ length: hierarchyDepthTasks.length > 0 ? maxHierarchyDepth + 1 : 0 }, (_, index) => index + 1);
1247
- const hierarchyColumns = levels.map((level) => ({
1248
- value: level,
1249
- label: `Level ${level}`,
1250
- icon: 'Layers',
1251
- color: level === 1 ? '#3b82f6' : '#64748b'
1252
- }));
1253
- if (parentTaskFilterMode === 'all' && hierarchyShowUnlinkedColumn) {
1254
- hierarchyColumns.push({
1255
- value: 'standalone',
1256
- label: 'Unlinked',
1257
- icon: 'Circle',
1258
- color: '#64748b'
1259
- });
1260
- }
1261
- return hierarchyColumns;
1262
- }
1263
- case 'schedule':
1264
- return scheduleColumns;
1265
- default:
1266
- return activeCategories;
1267
- }
1268
- }, [groupBy, activeCategories, activeTypes, priorities, approaches, maxHierarchyDepth, parentTaskFilterMode, scheduleColumns, hierarchyDepthTasks.length, hierarchyShowUnlinkedColumn]);
1269
- return (_jsxs("div", { className: `${styles.standaloneWrapper} ${zenMode ? styles.zenModeEnabled : ''}`, "data-theme": currentTheme, children: [_jsxs("div", { className: `${styles.header} ${styles.standaloneHeader} `, children: [_jsxs("div", { className: `${styles.headerTitle} ${styles.standaloneTitle}`, children: [_jsx("img", { src: logo, alt: "Taskforce Logo", className: styles.brandIcon, onError: (e) => {
1270
- const target = e.currentTarget;
1271
- if (target.src !== favicon) {
1272
- target.src = favicon;
1273
- }
1274
- else {
1275
- target.style.display = 'none';
1276
- }
1277
- } }), _jsx("span", { children: "TaskForce" }), projectName && (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.projectSlash, children: "/" }), _jsx("span", { className: styles.projectName, title: `Workspace ID: ${currentWorkspaceId}`, children: projectName })] })), _jsx("span", { className: styles.taskCountBadge, title: activeCountTitle, children: activeCountLabel }), shouldShowSyncStatus && (_jsx("button", { className: styles.headerActionBtn, onClick: () => setShowSyncStatusModal(true), title: `Cloud sync status: ${headerSyncStatusMeta.label} | Pull: ${formattedLastPullTime} | Push: ${formattedLastPushTime}`, style: {
1278
- marginLeft: '6px',
1279
- height: '24px',
1280
- width: '24px',
1281
- padding: 0,
1282
- borderRadius: '999px',
1283
- border: `1px solid ${headerSyncStatusMeta.border}`,
1284
- background: headerSyncStatusMeta.background,
1285
- color: headerSyncStatusMeta.color,
1286
- display: 'inline-flex',
1287
- alignItems: 'center',
1288
- justifyContent: 'center'
1289
- }, children: headerSyncStatusMeta.icon === 'off' ? (_jsx(CloudOff, { size: 12 })) : (_jsx(Cloud, { size: 12 })) })), props.loadingTasks && (_jsx("div", { style: { marginLeft: '8px', display: 'flex', alignItems: 'center' }, children: _jsx(Loader2, { size: 14, className: styles.spinner }) })), successBanner && (_jsxs("div", { className: styles.headerSuccess, children: [_jsx(Check, { size: 14 }), _jsx("span", { children: successBanner.message })] }))] }), _jsxs("div", { className: styles.headerActions, style: { gap: '16px' }, children: [_jsxs("div", { className: styles.searchContainer, style: { width: '240px' }, children: [_jsx(Search, { size: 16, className: styles.searchIcon }), _jsx("input", { type: "text", className: styles.searchInput, placeholder: t('standalone.searchPlaceholder'), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) }), searchQuery && (_jsx("button", { className: styles.clearSearchBtn, onClick: () => setSearchQuery(''), title: t('standalone.clearSearchTitle'), children: _jsx(X, { size: 14 }) }))] }), _jsxs("div", { className: styles.groupByContainer, children: [_jsxs("span", { className: styles.groupByLabel, children: [_jsx(ArrowUpDown, { size: 12 }), " ", t('standalone.sortLabel')] }), _jsxs("select", { className: `${styles.select} ${styles.groupBySelect} `, value: sortBy, onChange: (e) => setSortBy(e.target.value), children: [_jsx("option", { value: "created", children: t('standalone.sortCreated') }), _jsx("option", { value: "updated", children: t('standalone.sortUpdated') }), _jsx("option", { value: "priority", children: t('standalone.sortPriority') }), _jsx("option", { value: "complexity", children: t('standalone.sortComplexity') })] }), _jsx("button", { className: `${styles.headerActionBtn} ${styles.sortDirectionBtn}`, onClick: () => props.toggleSortOrder(), title: props.sortOrder === 'desc' ? t('standalone.sortDirectionDescTitle') : t('standalone.sortDirectionAscTitle'), children: props.sortOrder === 'desc' ? _jsx(ArrowDown, { size: 14 }) : _jsx(ArrowUp, { size: 14 }) })] }), _jsx("div", { className: styles.headerDivider }), groupBy !== 'docs' && (_jsxs("div", { className: styles.groupByContainer, children: [_jsxs("span", { className: styles.groupByLabel, children: [_jsx(Layers, { size: 12 }), " ", t('standalone.groupLabel')] }), _jsxs("select", { className: `${styles.select} ${styles.groupBySelect} `, value: groupBy, onChange: (e) => setGroupBy(e.target.value), children: [_jsx("option", { value: "category", children: t('standalone.groupCategory') }), _jsx("option", { value: "type", children: t('standalone.groupType') }), _jsx("option", { value: "priority", children: t('standalone.groupPriority') }), _jsx("option", { value: "complexity", children: t('standalone.groupComplexity') }), _jsx("option", { value: "approach", children: t('standalone.groupApproach') }), _jsx("option", { value: "assignee", children: t('standalone.groupAssignee') }), _jsx("option", { value: "status", children: t('standalone.groupStatus') }), _jsx("option", { value: "hierarchy", children: t('standalone.groupHierarchy') }), _jsx("option", { value: "schedule", children: t('standalone.groupSchedule') })] })] })), _jsx("button", { className: `${styles.headerActionBtn} ${groupBy === 'docs' ? styles.headerActionBtnActive : ''}`, onClick: () => setGroupBy(groupBy === 'docs' ? 'category' : 'docs'), title: groupBy === 'docs' ? 'Exit Docs view' : 'Open Docs view', children: _jsx(FileText, { size: 15 }) }), _jsxs("button", { className: `${styles.headerActionBtn} ${emptyColumnMode !== 'show' ? styles.headerActionBtnActive : ''} `, onClick: () => {
1290
- setEmptyColumnMode(prev => {
1291
- if (prev === 'show')
1292
- return 'collapse';
1293
- if (prev === 'collapse')
1294
- return 'hide';
1295
- return 'show';
1296
- });
1297
- }, title: emptyColumnMode === 'show' ? t('standalone.showEmptyColumns') :
1298
- emptyColumnMode === 'collapse' ? t('standalone.compressEmptyColumns') :
1299
- t('standalone.hideEmptyColumns'), children: [emptyColumnMode === 'show' && _jsx(Maximize2, { size: 16 }), emptyColumnMode === 'collapse' && _jsx(Minimize2, { size: 16 }), emptyColumnMode === 'hide' && _jsx(EyeOff, { size: 16 })] }), _jsx("button", { className: `${styles.headerActionBtn} ${compressedCards ? styles.headerActionBtnActive : ''}`, onClick: () => setCompressedCards(!compressedCards), title: compressedCards ? t('standalone.expandCards') : t('standalone.compressCards'), children: compressedCards ? _jsx(ChevronsDown, { size: 16 }) : _jsx(ChevronsUp, { size: 16 }) }), _jsx("button", { className: `${styles.headerActionBtn} ${zenMode ? styles.headerActionBtnActive : ''}`, onClick: () => setZenMode(), title: zenMode ? t('standalone.exitZenMode') : t('standalone.enterZenMode'), children: _jsx(Zap, { size: 16, fill: zenMode ? "currentColor" : "none" }) }), _jsx("div", { className: styles.headerDivider }), _jsx("button", { className: `${styles.headerActionBtn} ${showFilters ? styles.headerActionBtnActive : ''} ${isFiltered ? styles.filterGlow : ''}`, onClick: () => setShowFilters(!showFilters), title: t('standalone.toggleFilters'), children: _jsx(Filter, { size: 16 }) }), _jsxs("button", { className: styles.primaryUpdateBtn, onClick: () => {
1300
- resetForm();
1301
- setActiveTab('add');
1302
- }, children: [_jsx(Plus, { size: 16 }), " ", t('standalone.addTask')] }), _jsxs("div", { className: styles.accountMenuWrap, ref: accountMenuRef, children: [_jsx("button", { className: `${styles.headerActionBtn} ${styles.avatarBtn}`, onClick: () => setShowAccountMenu(prev => !prev), title: isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-label": isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-haspopup": "menu", "aria-expanded": showAccountMenu, children: _jsx("span", { className: styles.avatarBadge, "aria-hidden": "true", children: isAuthenticated ? 'U' : '?' }) }), showAccountMenu && (_jsxs("div", { className: styles.accountMenu, role: "menu", "aria-label": "Account menu", children: [canManageCloudWorkspaces && (_jsxs("div", { className: styles.accountMenuSection, children: [_jsx("div", { className: styles.accountMenuSectionLabel, children: "Workspaces" }), availableWorkspaces.length === 0 && (_jsx("div", { className: styles.accountMenuHint, children: "No workspaces found for this account yet." })), availableWorkspaces.map((workspace) => (_jsxs("button", { className: `${styles.accountMenuItem} ${workspace.id === currentWorkspaceId ? styles.accountMenuItemActive : ''}`, onClick: () => handleSwitchWorkspace(workspace.id), role: "menuitem", disabled: workspaceActionBusy || workspace.id === currentWorkspaceId, title: workspace.description || workspace.name, children: [_jsx(Folder, { size: 15 }), _jsxs("span", { style: { display: 'flex', flexDirection: 'column', gap: '2px' }, children: [_jsx("span", { children: workspace.name }), _jsx("span", { className: styles.accountMenuMeta, children: workspace.role })] })] }, workspace.id))), _jsxs("button", { className: styles.accountMenuItem, onClick: () => {
1303
- setWorkspaceActionError('');
1304
- setWorkspacePanelOpen((prev) => !prev);
1305
- }, role: "menuitem", disabled: workspaceActionBusy, children: [_jsx(Plus, { size: 15 }), workspacePanelOpen ? 'Close Workspace Form' : 'Create Workspace'] }), workspacePanelOpen && (_jsxs("div", { className: styles.accountMenuWorkspaceForm, children: [_jsx("input", { className: styles.input, value: workspaceFormName, onChange: (event) => setWorkspaceFormName(event.target.value), placeholder: "Workspace name", disabled: workspaceActionBusy }), _jsx("input", { className: styles.input, value: workspaceFormDescription, onChange: (event) => setWorkspaceFormDescription(event.target.value), placeholder: "Workspace description (optional)", disabled: workspaceActionBusy }), _jsx("button", { className: styles.primaryUpdateBtn, onClick: handleCreateWorkspace, disabled: workspaceActionBusy, children: workspaceActionBusy ? 'Saving...' : 'Save Workspace' })] })), workspaceActionError && (_jsx("div", { className: styles.accountMenuError, children: workspaceActionError }))] })), _jsxs("button", { className: styles.accountMenuItem, onClick: () => {
1306
- setShowAccountMenu(false);
1307
- setShowAccountHub(true);
1308
- }, role: "menuitem", children: [_jsx(User, { size: 15 }), "Account Hub"] }), _jsxs("button", { className: styles.accountMenuItem, onClick: () => {
1309
- setShowAccountMenu(false);
1310
- setActiveTab('settings');
1311
- setSettingsSection('general');
1312
- }, role: "menuitem", children: [_jsx(Settings, { size: 15 }), "Workspace Settings"] }), _jsxs("button", { className: styles.accountMenuItem, onClick: () => {
1313
- setShowAccountMenu(false);
1314
- setShowHelpModal(true);
1315
- }, role: "menuitem", children: [_jsx(HelpCircle, { size: 15 }), "Help & Tutorial"] }), runtimeMode === 'local' && !isAuthenticated && (_jsxs("button", { className: styles.accountMenuItem, onClick: () => {
1316
- setShowAccountMenu(false);
1317
- openCloudSignIn();
1318
- }, role: "menuitem", children: [_jsx(User, { size: 15 }), "Sign-In"] })), isAuthenticated && (_jsxs("button", { className: styles.accountMenuItem, onClick: async () => {
1319
- setShowAccountMenu(false);
1320
- await logout();
1321
- }, role: "menuitem", children: [_jsx(LogOut, { size: 15 }), "Sign Out"] }))] }))] })] })] }), authBlocked && (_jsx("div", { className: styles.authBlockedBanner, children: "Authentication required for this environment. Use the Account menu to sign in." })), showFilters && (_jsxs("div", { className: styles.filterToolbar, style: {
1322
- padding: '8px 24px',
1323
- borderBottom: '1px solid var(--border-color)',
1324
- background: 'var(--bg-secondary)',
1325
- display: 'flex',
1326
- alignItems: 'center',
1327
- gap: '12px',
1328
- flexWrap: 'wrap',
1329
- position: 'relative',
1330
- zIndex: 50
1331
- }, children: [_jsx("span", { style: { fontSize: '12px', fontWeight: 600, color: 'var(--text-secondary)', marginRight: '4px' }, children: t('standalone.filtersCaps') }), _jsx(MultiSelectFilter, { label: t('standalone.categoryLabel'), options: activeCategories.filter(c => !c.disabled), selected: filterCategories, onChange: (vals) => setFilterCategories(vals), variant: "value" }), _jsx(MultiSelectFilter, { label: t('standalone.typeLabel'), options: activeTypes.map(t => ({ value: t.value, label: t.label })), selected: filterTypes, onChange: (vals) => setFilterTypes(vals), variant: "value" }), _jsx(MultiSelectFilter, { label: t('standalone.priorityLabel'), options: priorities, selected: filterPriorities, onChange: (vals) => setFilterPriorities(vals), variant: "value" }), _jsx(MultiSelectFilter, { label: t('standalone.statusLabel'), options: STATUS_OPTIONS, selected: filterStatus, onChange: (vals) => setFilterStatus(vals), variant: "value" }), assigneeFilterEnabled && (_jsx(MultiSelectFilter, { label: t('standalone.assigneeLabel'), options: [
1332
- { value: 'agent', label: 'AI' },
1333
- { value: 'user', label: 'User' },
1334
- { value: 'unassigned', label: 'Unassigned' }
1335
- ], selected: filterAssignees, onChange: (vals) => setFilterAssignees(vals), variant: "value" })), _jsx("div", { className: styles.headerDivider, style: { height: '16px', margin: '0 8px' } }), _jsxs("div", { className: styles.groupByContainer, children: [_jsxs("span", { className: styles.groupByLabel, children: [_jsx(Layers, { size: 12 }), " ", t('standalone.linksLabel')] }), _jsxs("select", { className: `${styles.select} ${styles.groupBySelect}`, value: parentTaskFilterMode, onChange: (e) => setParentTaskFilterMode(e.target.value), title: t('standalone.chooseLinksTitle'), children: [_jsx("option", { value: "all", children: t('standalone.linksAll') }), _jsx("option", { value: "parents", children: t('standalone.linksParents') }), _jsx("option", { value: "linked", children: t('standalone.linksLinked') }), _jsx("option", { value: "unlinked", children: t('standalone.linksUnlinked') })] })] }), _jsxs("label", { className: styles.archiveToggle, title: t('standalone.includeArchiveTitle'), children: [_jsx("input", { type: "checkbox", checked: showArchive, onChange: (e) => {
1336
- setShowArchive(e.target.checked);
1337
- if (e.target.checked)
1338
- fetchArchive();
1339
- } }), _jsx("span", { children: t('standalone.includeArchive') })] }), _jsx("div", { style: { flex: 1 } }), _jsxs("button", { onClick: clearFilters, style: {
1340
- background: 'none',
1341
- border: 'none',
1342
- color: 'var(--text-secondary)',
1343
- cursor: 'pointer',
1344
- fontSize: '12px',
1345
- display: 'flex',
1346
- alignItems: 'center',
1347
- gap: '4px'
1348
- }, children: [_jsx(X, { size: 12 }), " ", t('standalone.clearFilters')] })] })), groupBy === 'docs' ? (_jsx("div", { className: `${styles.standalonePage} ${styles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden' }, children: _jsx(DocumentWorkspace, { tasks: tasks, apiBaseUrl: props.config?.apiBaseUrl || '', requestedDocPath: requestedDocPath, onRequestedDocHandled: () => setRequestedDocPath(null) }) })) : (_jsxs("div", { className: `${styles.standalonePage} ${styles.standaloneContent} `, style: {
1349
- position: 'relative',
1350
- opacity: props.loadingTasks ? 0.7 : 1,
1351
- transition: 'opacity 0.2s ease, padding-right 220ms cubic-bezier(0.4, 0, 0.2, 1)',
1352
- display: 'flex',
1353
- flex: 1,
1354
- minHeight: 0,
1355
- paddingRight: (groupBy === 'schedule' && scheduleSidebarOpen) || (groupBy === 'hierarchy' && hierarchySidebarOpen) ? '332px' : 0
1356
- }, children: [_jsxs("div", { style: { position: 'relative', width: '100%', minWidth: 0, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [_jsx("div", { style: {
1357
- position: 'absolute',
1358
- top: 0,
1359
- right: 0,
1360
- width: '100%',
1361
- height: '100%',
1362
- backgroundImage: `url(${taskforceBg})`,
1363
- backgroundRepeat: 'no-repeat',
1364
- backgroundPosition: 'top right',
1365
- backgroundSize: '60%',
1366
- opacity: 0.2,
1367
- pointerEvents: 'none',
1368
- zIndex: 0
1369
- } }), boardVisibleTasks.length === 0 && groupBy !== 'schedule' ? (_jsxs("div", { className: styles.emptyState, children: [_jsx(Layers, { size: 48 }), _jsx("p", { children: groupBy === 'hierarchy' && hierarchyRootTaskId ? 'No tasks match this subtree with current filters.' : t('standalone.noTasksMatchFilters') }), _jsx("p", { style: { fontSize: '12px', color: 'var(--text-secondary)' }, children: groupBy === 'hierarchy' && hierarchyRootTaskId
1370
- ? `Focused on ${selectedHierarchyRootTask?.title || hierarchyRootTaskId}. Try clearing subtree focus or broadening filters.`
1371
- : t('standalone.showingWithLinksHint', { parentFilterLabel }) })] })) : (_jsx(TaskKanban, { tasks: boardVisibleTasks, allTasks: kanbanAllTasks, hierarchyTasks: hierarchyTasks, columns: kanbanColumns, groupBy: groupBy, scheduleDates: scheduleDates, searchQuery: searchQuery, filterCategories: filterCategories, filterTypes: filterTypes, filterPriorities: filterPriorities, filterStatus: filterStatus, filterAssignees: filterAssignees, assigneeFilterEnabled: assigneeFilterEnabled, scheduleFilteredTaskIds: Array.from(scheduleFilteredTaskIds), copiedId: copiedId, availableSpecialists: availableSpecialists, taxonomies: taxonomies, priorities: priorities, approaches: approaches, onUpdateTask: handleUpdateTask, onTaskClick: (task) => handleEdit(task), onOpenTaskById: handleOpenTaskById, onCopyId: handleCopyId, onToggleInProgress: handleToggleInProgress, onToggleReview: handleToggleReview, onToggleComplete: handleToggleComplete, onToggleCancel: handleToggleCancel, onArchiveTask: handleArchiveTask, onUnarchive: handleUnarchive, onDelete: handleDelete, onUnlinkChildTask: handleUnlinkChildTask, onClearParentTask: handleClearParentTask, onAddTaskToColumn: handleAddTaskToColumn, onScheduleParentDrop: handleScheduleParentDrop, onScheduleDaySelected: (dateOnly) => {
1372
- setScheduleSelectedDate(dateOnly);
1373
- const parsed = parseDateOnlyLocal(dateOnly);
1374
- if (parsed) {
1375
- setScheduleCalendarMonth(`${parsed.getFullYear()}-${String(parsed.getMonth() + 1).padStart(2, '0')}`);
1376
- }
1377
- }, persistedScrollLeft: groupBy === 'schedule' ? scheduleScrollLeft : undefined, onScrollLeftChange: (scrollLeft) => {
1378
- if (groupBy !== 'schedule')
1379
- return;
1380
- setScheduleScrollLeft(scrollLeft);
1381
- }, emptyColumnMode: emptyColumnMode, categories: activeCategories, compressed: compressedCards, recentlyChangedTaskIds: props.recentlyChangedTaskIds, hierarchyChildOrderMode: hierarchyChildOrderMode, sortBy: sortBy, sortOrder: props.sortOrder }, `${groupBy}-${kanbanColumns.map(c => String(c.value)).join('|')}-${scheduleDates.mon}`)), groupBy === 'schedule' && !scheduleSidebarOpen && (_jsx("button", { type: "button", className: styles.headerActionBtn, onClick: () => setScheduleSidebarOpen(true), title: "Show Schedule Sidebar", style: {
1382
- position: 'absolute',
1383
- top: '10px',
1384
- right: '10px',
1385
- zIndex: 20,
1386
- border: '1px solid var(--border-color)',
1387
- background: 'var(--bg-secondary)'
1388
- }, children: _jsx(PanelRightOpen, { size: 16 }) })), groupBy === 'hierarchy' && !hierarchySidebarOpen && (_jsx("button", { type: "button", className: styles.headerActionBtn, onClick: () => setHierarchySidebarOpen(true), title: "Show Hierarchy Sidebar", style: {
1389
- position: 'absolute',
1390
- top: '10px',
1391
- right: '10px',
1392
- zIndex: 20,
1393
- border: '1px solid var(--border-color)',
1394
- background: 'var(--bg-secondary)'
1395
- }, children: _jsx(PanelRightOpen, { size: 16 }) }))] }), groupBy === 'hierarchy' && (_jsxs("aside", { className: styles.appScrollbar, style: {
1396
- position: 'absolute',
1397
- top: 0,
1398
- right: 0,
1399
- bottom: 0,
1400
- width: '320px',
1401
- minWidth: '320px',
1402
- borderLeft: '1px solid var(--border-color)',
1403
- background: 'var(--bg-secondary)',
1404
- padding: '12px',
1405
- display: 'flex',
1406
- flexDirection: 'column',
1407
- gap: '12px',
1408
- zIndex: 40,
1409
- overflowY: 'auto',
1410
- transform: hierarchySidebarOpen ? 'translateX(0)' : 'translateX(108%)',
1411
- pointerEvents: hierarchySidebarOpen ? 'auto' : 'none',
1412
- transition: 'transform 220ms cubic-bezier(0.4, 0, 0.2, 1)',
1413
- willChange: 'transform'
1414
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px', fontWeight: 600 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx(Layers, { size: 16 }), _jsx("span", { children: "Hierarchy Controls" })] }), _jsx("button", { type: "button", className: styles.headerActionBtn, onClick: () => setHierarchySidebarOpen(false), title: "Hide Hierarchy Sidebar", children: _jsx(PanelRightClose, { size: 16 }) })] }), _jsxs("div", { style: {
1415
- border: '1px solid var(--border-color)',
1416
- borderRadius: '10px',
1417
- padding: '10px',
1418
- display: 'flex',
1419
- flexDirection: 'column',
1420
- gap: '8px'
1421
- }, children: [_jsx("div", { style: { fontSize: '12px', fontWeight: 600 }, children: "Focus Subtree" }), _jsx("input", { type: "text", className: styles.input, placeholder: "Search parent tasks...", value: hierarchyRootSearch, onChange: (e) => setHierarchyRootSearch(e.target.value), onKeyDown: (e) => {
1422
- if (e.key === 'Enter') {
1423
- e.preventDefault();
1424
- applyHierarchySearchSelection();
1425
- }
1426
- } }), _jsx("div", { style: {
1427
- border: '1px solid var(--border-color)',
1428
- borderRadius: '8px',
1429
- padding: '8px',
1430
- display: 'flex',
1431
- flexDirection: 'column',
1432
- gap: '6px',
1433
- minHeight: '190px'
1434
- }, children: hierarchyRootSearch.trim().length > 0 ? (_jsxs("div", { className: styles.appScrollbar, style: {
1435
- maxHeight: '180px',
1436
- minHeight: '180px',
1437
- overflowY: 'auto',
1438
- border: '1px solid var(--border-color)',
1439
- borderRadius: '8px',
1440
- padding: '6px',
1441
- display: 'flex',
1442
- flexDirection: 'column',
1443
- gap: '6px'
1444
- }, children: [hierarchySearchMatches.slice(0, 24).map((task) => (_jsxs("button", { type: "button", className: styles.headerActionBtn, onClick: () => {
1445
- setHierarchyRootTaskId(task.id);
1446
- setHierarchyRootSearch('');
1447
- if (parentTaskFilterMode === 'unlinked') {
1448
- setParentTaskFilterMode('all');
1449
- }
1450
- }, style: { justifyContent: 'space-between', border: '1px solid var(--border-color)' }, title: task.title, children: [_jsx("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: task.title }), _jsx("span", { style: { opacity: 0.75 }, children: task.id.split('-').slice(-1)[0] })] }, task.id))), hierarchySearchMatches.length === 0 && (_jsxs("div", { style: { fontSize: '12px', color: 'var(--text-secondary)', padding: '4px 2px' }, children: ["No matches for \"", hierarchyRootSearch, "\"."] }))] })) : hierarchyRootTaskId ? (_jsxs(_Fragment, { children: [_jsx("div", { style: { fontSize: '13px', fontWeight: 600, color: 'var(--text-primary)' }, title: selectedHierarchyRootTask?.title || hierarchyRootTaskId, children: selectedHierarchyRootTask?.title || hierarchyRootTaskId }), hierarchySubtreeStats && (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '6px', fontSize: '12px', color: 'var(--text-secondary)' }, children: [_jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchySubtreeStats.total }), " total"] }), _jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchySubtreeStats.active }), " active"] }), _jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchySubtreeStats.terminal }), " done/cancelled"] }), _jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: hierarchySubtreeStats.overdue > 0 ? 'var(--color-error, #ef4444)' : 'var(--text-primary)' }, children: hierarchySubtreeStats.overdue }), " overdue"] }), _jsxs("div", { style: { gridColumn: '1 / -1', border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchySubtreeStats.depth }), " levels deep"] })] })), _jsx("button", { className: styles.headerActionBtn, onClick: () => {
1451
- setHierarchyRootTaskId('');
1452
- setHierarchyRootSearch('');
1453
- }, style: { justifyContent: 'center', border: '1px solid var(--border-color)', background: 'rgba(59,130,246,0.12)' }, children: "Clear subtree focus" })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '6px', fontSize: '12px', color: 'var(--text-secondary)' }, children: [_jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchyVisibleTasks.length }), " visible"] }), _jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchyVisibleRootCount }), " root parents"] }), _jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchyVisibleUnlinkedCount }), " unlinked"] }), _jsxs("div", { style: { border: '1px solid var(--border-color)', borderRadius: '8px', padding: '6px' }, children: [_jsx("strong", { style: { color: 'var(--text-primary)' }, children: hierarchyDepthTasks.length > 0 ? maxHierarchyDepth + 1 : 0 }), " levels"] })] }), _jsx("div", { style: { fontSize: '12px', color: 'var(--text-secondary)' }, children: hierarchyVisibleLevelCounts.length > 0
1454
- ? hierarchyVisibleLevelCounts.map((entry) => `L${entry.level}: ${entry.count}`).join(' • ')
1455
- : 'No linked hierarchy tasks in current filters.' })] })) })] }), _jsxs("div", { style: {
1456
- border: '1px solid var(--border-color)',
1457
- borderRadius: '10px',
1458
- padding: '10px',
1459
- display: 'flex',
1460
- flexDirection: 'column',
1461
- gap: '8px'
1462
- }, children: [_jsx("div", { style: { fontSize: '12px', fontWeight: 600 }, children: "Display" }), _jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px' }, children: [_jsx("input", { type: "checkbox", checked: hierarchyShowUnlinkedColumn, onChange: (e) => {
1463
- const next = e.target.checked;
1464
- setHierarchyShowUnlinkedColumn(next);
1465
- if (!next && parentTaskFilterMode === 'unlinked') {
1466
- setParentTaskFilterMode('all');
1467
- }
1468
- } }), "Show unlinked column"] }), _jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px' }, children: [_jsx("input", { type: "checkbox", checked: hierarchyChildOrderMode === 'manual', onChange: (e) => setHierarchyChildOrderMode(e.target.checked ? 'manual' : 'auto') }), "Sort by parent task order"] }), _jsx("div", { style: { fontSize: '11px', color: 'var(--text-tertiary)' }, children: "Keeps siblings in the order defined on the parent task." })] })] })), groupBy === 'schedule' && (_jsxs("aside", { className: styles.appScrollbar, style: {
1469
- position: 'absolute',
1470
- top: 0,
1471
- right: 0,
1472
- bottom: 0,
1473
- width: '320px',
1474
- minWidth: '320px',
1475
- borderLeft: '1px solid var(--border-color)',
1476
- background: 'var(--bg-secondary)',
1477
- padding: '12px',
1478
- display: 'flex',
1479
- flexDirection: 'column',
1480
- gap: '12px',
1481
- zIndex: 40,
1482
- overflowY: 'auto',
1483
- transform: scheduleSidebarOpen ? 'translateX(0)' : 'translateX(108%)',
1484
- pointerEvents: scheduleSidebarOpen ? 'auto' : 'none',
1485
- transition: 'transform 220ms cubic-bezier(0.4, 0, 0.2, 1)',
1486
- willChange: 'transform'
1487
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '8px', fontWeight: 600 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx(CalendarDays, { size: 16 }), _jsx("span", { children: "Schedule Controls" })] }), _jsx("button", { type: "button", className: styles.headerActionBtn, onClick: () => setScheduleSidebarOpen(false), title: "Hide Schedule Sidebar", children: _jsx(PanelRightClose, { size: 16 }) })] }), _jsxs("div", { style: { fontSize: '12px', color: 'var(--text-secondary)' }, children: ["Week of ", scheduleWeekLabel] }), _jsxs("div", { style: {
1488
- border: '1px solid var(--border-color)',
1489
- borderRadius: '10px',
1490
- padding: '10px'
1491
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '8px' }, children: [_jsx("button", { className: styles.headerActionBtn, onClick: () => {
1492
- const prev = new Date(scheduleMonthDate);
1493
- prev.setMonth(scheduleMonthDate.getMonth() - 1);
1494
- setScheduleCalendarMonth(`${prev.getFullYear()}-${String(prev.getMonth() + 1).padStart(2, '0')}`);
1495
- }, title: "Previous month", children: _jsx(ChevronLeft, { size: 14 }) }), _jsx("div", { style: { fontSize: '12px', fontWeight: 600 }, children: scheduleCalendarMonthLabel }), _jsx("button", { className: styles.headerActionBtn, onClick: () => {
1496
- const next = new Date(scheduleMonthDate);
1497
- next.setMonth(scheduleMonthDate.getMonth() + 1);
1498
- setScheduleCalendarMonth(`${next.getFullYear()}-${String(next.getMonth() + 1).padStart(2, '0')}`);
1499
- }, title: "Next month", children: _jsx(ChevronRight, { size: 14 }) })] }), _jsx("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(7, minmax(0, 1fr))', gap: '4px', marginBottom: '4px' }, children: calendarWeekdayLabels.map((label) => (_jsx("div", { style: { fontSize: '11px', color: 'var(--text-secondary)', textAlign: 'center' }, children: label }, label))) }), _jsx("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(7, minmax(0, 1fr))', gap: '4px' }, children: calendarCells.map((date) => {
1500
- const dateOnly = toDateOnlyLocal(date);
1501
- const isOutsideMonth = date.getMonth() !== scheduleMonthDate.getMonth();
1502
- const weekStartForCell = startOfWeek(date, globalWeekStartsOn);
1503
- const isSelectedWeek = toDateOnlyLocal(weekStartForCell) === toDateOnlyLocal(scheduleWeekStart);
1504
- const isSelectedDate = dateOnly === scheduleSelectedDate;
1505
- const isToday = dateOnly === todayDateOnly;
1506
- const isPast = dateOnly < todayDateOnly;
1507
- const signal = calendarTaskSignals.get(dateOnly);
1508
- const hasScheduledTasks = !!signal;
1509
- const hasExpiredScheduledTasks = !!signal?.hasExpired;
1510
- return (_jsxs("button", { onClick: () => {
1511
- setScheduleSelectedDate(dateOnly);
1512
- setScheduleCalendarMonth(`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`);
1513
- }, style: {
1514
- border: isSelectedDate
1515
- ? '1px solid #2563eb'
1516
- : isToday
1517
- ? '1px solid rgba(245, 158, 11, 0.95)'
1518
- : '1px solid transparent',
1519
- borderRadius: '8px',
1520
- padding: '6px 0',
1521
- fontSize: '12px',
1522
- position: 'relative',
1523
- background: isSelectedDate
1524
- ? 'rgba(59,130,246,0.22)'
1525
- : isToday
1526
- ? 'rgba(245,158,11,0.16)'
1527
- : isSelectedWeek
1528
- ? 'rgba(59,130,246,0.18)'
1529
- : 'transparent',
1530
- color: isOutsideMonth ? 'var(--text-tertiary)' : 'var(--text-primary)',
1531
- cursor: 'pointer',
1532
- fontWeight: isSelectedDate || isToday ? 700 : 500,
1533
- opacity: isPast ? 0.42 : 1
1534
- }, title: `${isToday ? `${dateOnly} (Today)` : dateOnly}`
1535
- + (hasScheduledTasks ? ` • ${signal?.count} scheduled` : '')
1536
- + (hasExpiredScheduledTasks ? ' • includes expired' : ''), children: [date.getDate(), hasScheduledTasks && (_jsx("span", { style: {
1537
- position: 'absolute',
1538
- left: '50%',
1539
- bottom: '3px',
1540
- transform: 'translateX(-50%)',
1541
- width: '5px',
1542
- height: '5px',
1543
- borderRadius: '999px',
1544
- background: hasExpiredScheduledTasks ? '#ef4444' : '#3b82f6',
1545
- opacity: isOutsideMonth ? 0.6 : 0.95
1546
- } }))] }, dateOnly));
1547
- }) }), _jsx("div", { style: { display: 'flex', justifyContent: 'space-between', marginTop: '10px' }, children: _jsx("button", { className: styles.headerActionBtn, onClick: () => {
1548
- const now = new Date();
1549
- setScheduleSelectedDate(toDateOnlyLocal(now));
1550
- setScheduleCalendarMonth(`${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`);
1551
- }, title: "Jump to current week", children: "Today" }) })] }), _jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px' }, children: [_jsx("input", { type: "checkbox", checked: scheduleShowWeekends, onChange: (e) => setScheduleShowWeekends(e.target.checked) }), "Show weekends"] }), _jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px' }, children: [_jsx("input", { type: "checkbox", checked: scheduleShowBacklog, onChange: (e) => setScheduleShowBacklog(e.target.checked) }), "Show backlog"] }), _jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px' }, children: [_jsx("input", { type: "checkbox", checked: scheduleOnlyExpired, onChange: (e) => setScheduleOnlyExpired(e.target.checked) }), "Only expired/overdue"] }), expiredScheduledCount > 0 && (_jsxs("div", { style: {
1552
- border: '1px solid var(--border-color)',
1553
- borderRadius: '10px',
1554
- padding: '10px',
1555
- display: 'flex',
1556
- flexDirection: 'column',
1557
- gap: '8px'
1558
- }, children: [_jsx("div", { style: { fontSize: '12px', fontWeight: 600 }, children: "Expired Tasks" }), _jsxs("div", { style: { fontSize: '12px', color: 'var(--text-secondary)', display: 'flex', flexDirection: 'column', gap: '2px' }, children: [_jsxs("span", { children: [expiredScheduledCount, " expired"] }), _jsxs("span", { children: [overdueDueCount, " overdue"] })] }), _jsx("button", { className: styles.headerActionBtn, onClick: handleMoveExpiredToSelectedWeek, disabled: scheduleBulkBusy || expiredLeafCandidates.length === 0, title: "Move expired leaf tasks to the selected week while keeping weekday alignment", style: { justifyContent: 'flex-start', border: '1px solid var(--border-color)' }, children: scheduleBulkBusy ? 'Working...' : 'Schedule to selected week' }), _jsx("button", { className: styles.headerActionBtn, onClick: handleMoveExpiredToBacklog, disabled: scheduleBulkBusy || expiredRecoveryCandidates.length === 0, title: "Unschedule expired/overdue tasks back to backlog", style: { justifyContent: 'flex-start', border: '1px solid var(--border-color)' }, children: scheduleBulkBusy ? 'Working...' : 'Unschedule to backlog' })] }))] }))] })), _jsxs(Modal, { isOpen: activeTab === 'add', onClose: handleCloseModal, title: editingTaskId ? 'Edit Task' : 'New Task', size: "md", theme: currentTheme, draggable: true, closeOnOverlayClick: false, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, title: title, currentTask: currentTask, handleSubmit: handleSubmit, resetForm: resetForm, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleArchiveTask: handleArchiveTask }), _jsx(TaskForm, { editingTaskId: editingTaskId, error: error, title: title, description: description, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, approach: approach, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, parentTaskIdInput: parentTaskIdInput, addChildTaskIdInput: addChildTaskIdInput, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), onParentTaskIdInputChange: setParentTaskIdInput, onAddChildTaskIdInputChange: setAddChildTaskIdInput, taxonomies: taxonomies, selectedSpecialists: selectedSpecialists, comments: comments, newCommentText: newCommentText, contextFiles: screenshots, contextLinkBrowsePath: contextLinkBrowsePath, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, showSpecialists: showSpecialists, showChecklist: showChecklist, checklistEnabled: checklistDropdownEnabled, showTaskRelationships: showTaskRelationships, showChildTasks: showChildTasks, showComments: showComments, categories: activeCategories, types: activeTypes, priorities: priorities, approaches: approaches, availableSpecialists: availableSpecialists, copiedId: copiedId, onTitleChange: setTitle, onDescriptionChange: setDescription, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onApproachChange: (val) => { setApproach(val); setFormTaxonomies(prev => ({ ...prev, approach: val })); }, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onSelectedSpecialistsChange: setSelectedSpecialists, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onShowSpecialistsChange: setShowSpecialists, onShowChecklistChange: setShowChecklist, onShowTaskRelationshipsChange: setShowTaskRelationships, onShowChildTasksChange: setShowChildTasks, onShowCommentsChange: setShowComments, onOpenSettings: (section) => {
1559
- setSettingsSection(section);
1560
- setActiveTab('settings');
1561
- }, onSubmit: handleSubmit, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), onSetParentForCurrentTask: handleSetParentForCurrentTask, onAddChildToCurrentTask: handleAddChildToCurrentTask, onCreateChildForCurrentTask: handleCreateChildForCurrentTask, onUnlinkChildTask: handleUnlinkChildTask, onReorderChildTasks: handleReorderChildTasks, onOpenTaskById: handleOpenTaskById, onAddContextFile: (file) => {
1562
- setScreenshots(prev => [...prev, file]);
1563
- }, onBrowseContextLinkPath: () => {
1564
- setBrowserTarget({ type: 'context-link' });
1565
- fetchFolders('');
1566
- setShowFolderBrowser(true);
1567
- }, onRemoveContextFile: async (index) => {
1568
- const screenshot = screenshots[index];
1569
- const path = typeof screenshot === 'string' ? screenshot : screenshot.path;
1570
- setScreenshots(prev => prev.filter((_, i) => i !== index));
1571
- if (typeof path === 'string' && path.startsWith('/api/taskforce/context/')) {
1572
- try {
1573
- await fetch(path, { method: 'DELETE' });
1574
- }
1575
- catch { }
1576
- }
1577
- }, onUpdateContextCaption: (index, caption) => {
1578
- setScreenshots(prev => prev.map((s, i) => {
1579
- if (i !== index)
1580
- return s;
1581
- if (typeof s === 'string')
1582
- return { path: s, caption, timestamp: new Date().toISOString() };
1583
- return { ...s, caption };
1584
- }));
1585
- }, onCopyId: handleCopyId, onToggleInProgress: handleToggleInProgress, onToggleReview: handleToggleReview, onToggleComplete: handleToggleComplete, onToggleCancel: handleToggleCancel, onArchiveTask: handleArchiveTask, onUnarchive: handleUnarchive, currentTask: currentTask, currentTaskParent: currentTaskParent, currentTaskChildren: currentTaskChildren })] }), _jsx(Modal, { isOpen: activeTab === 'settings', onClose: handleCloseModal, title: "Settings", size: "md", theme: currentTheme, draggable: true, isSettings: true, closeOnOverlayClick: false, children: _jsx(TaskSettings, { settingsModel: settingsModel, onSectionChange: setSettingsSection }) }), _jsx(Modal, { isOpen: !!scheduleWarningPrompt, onClose: cancelScheduleWarning, title: "Date Warning", size: "sm", theme: currentTheme, draggable: false, closeOnOverlayClick: false, children: _jsxs("div", { className: styles.form, style: { padding: '16px', gap: '12px' }, children: [_jsx("p", { style: { margin: 0, fontSize: '13px', color: 'var(--text-secondary)' }, children: "Due date is before scheduled date." }), scheduleWarningPrompt && (_jsxs("p", { style: { margin: 0, fontSize: '12px', color: 'var(--text-muted)' }, children: ["Due: ", scheduleWarningPrompt.dueDate, " \u00B7 Scheduled: ", scheduleWarningPrompt.scheduledDate] })), _jsxs("div", { className: styles.formActions, children: [_jsx("button", { className: styles.cancelBtn, onClick: cancelScheduleWarning, children: "Go Back" }), _jsx("button", { className: styles.submitBtn, onClick: confirmScheduleWarning, children: "Save Anyway" })] })] }) }), _jsx(Modal, { isOpen: !!scheduleParentDropPrompt, onClose: cancelScheduleParentDrop, title: "Schedule Descendants", size: "sm", theme: currentTheme, draggable: false, closeOnOverlayClick: false, children: _jsxs("div", { className: styles.form, style: { padding: '16px', gap: '12px' }, children: [scheduleParentDropPrompt && (_jsxs(_Fragment, { children: [_jsxs("p", { style: { margin: 0, fontSize: '13px', color: 'var(--text-secondary)' }, children: ["Schedule unscheduled leaf tasks under ", _jsx("strong", { children: scheduleParentDropPrompt.parentTitle }), " to ", _jsx("strong", { children: scheduleParentDropPrompt.targetDate }), "?"] }), _jsxs("p", { style: { margin: 0, fontSize: '12px', color: 'var(--text-muted)' }, children: [scheduleParentDropPrompt.toScheduleLeafTaskIds.length, " leaf task", scheduleParentDropPrompt.toScheduleLeafTaskIds.length === 1 ? '' : 's', " will be scheduled.", scheduleParentDropPrompt.alreadyScheduledLeafCount > 0 ? ` ${scheduleParentDropPrompt.alreadyScheduledLeafCount} already scheduled leaf task${scheduleParentDropPrompt.alreadyScheduledLeafCount === 1 ? '' : 's'} will be skipped.` : ''] })] })), _jsxs("div", { className: styles.formActions, children: [_jsx("button", { className: styles.cancelBtn, onClick: cancelScheduleParentDrop, disabled: scheduleParentDropBusy, children: "Cancel" }), _jsx("button", { className: styles.submitBtn, onClick: confirmScheduleParentDrop, disabled: scheduleParentDropBusy, children: scheduleParentDropBusy ? 'Scheduling...' : 'Schedule' })] })] }) }), _jsx(Modal, { isOpen: showHelpModal, onClose: () => setShowHelpModal(false), title: "Quick Start", size: "md", theme: currentTheme, draggable: true, children: _jsxs("div", { className: modalStyles.form, style: { paddingTop: '18px' }, children: [_jsx("p", { style: { margin: 0, color: 'var(--text-secondary)' }, children: "Use this quick guide to get productive in Taskforce dashboard mode." }), _jsxs("div", { children: [_jsx("strong", { children: "1. Capture work" }), _jsxs("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: ["Click ", _jsx("code", { children: "Add Task" }), ", write a short title, and save."] })] }), _jsxs("div", { children: [_jsx("strong", { children: "2. Plan the board" }), _jsxs("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: ["Use ", _jsx("code", { children: "Sort" }), ", ", _jsx("code", { children: "Group" }), ", and ", _jsx("code", { children: "Filters" }), " in the header."] })] }), _jsxs("div", { children: [_jsx("strong", { children: "3. Execute and stage" }), _jsxs("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: ["Move tasks through ", _jsx("code", { children: "Task" }), ", ", _jsx("code", { children: "In Progress" }), ", ", _jsx("code", { children: "Review" }), ", and ", _jsx("code", { children: "Done" }), "."] })] }), _jsxs("div", { children: [_jsx("strong", { children: "4. Archive finished work" }), _jsx("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: "Archive completed/cancelled tasks to keep active board signal high." })] }), _jsxs("div", { className: modalStyles.formActions, style: { display: 'flex', justifyContent: 'flex-end', gap: '10px' }, children: [_jsx("button", { className: styles.cancelBtn, onClick: () => {
1586
- setShowHelpModal(false);
1587
- setActiveTab('settings');
1588
- setSettingsSection('general');
1589
- }, children: "Open Settings" }), _jsx("button", { className: styles.submitBtn, onClick: () => setShowHelpModal(false), children: "Close Tutorial" })] })] }) }), _jsx(Modal, { isOpen: showCloudSignInModal, onClose: closeCloudSignInModal, title: "Sign-In", size: "md", theme: currentTheme, draggable: true, children: _jsxs("div", { className: modalStyles.form, style: { paddingTop: '18px' }, children: [_jsx("p", { style: { margin: 0, color: 'var(--text-secondary)' }, children: "Sign in with your cloud account to enable sync for local runtime." }), !cloudAuthConfigured && (_jsx("p", { className: styles.loginError, children: "Cloud auth endpoint is not configured." })), _jsx("input", { className: styles.input, type: "email", value: cloudSignInEmail, placeholder: "Email", onChange: (event) => setCloudSignInEmail(event.target.value), disabled: cloudSignInBusy }), _jsx("input", { className: styles.input, type: "password", value: cloudSignInPassword, placeholder: "Password", onChange: (event) => setCloudSignInPassword(event.target.value), disabled: cloudSignInBusy }), cloudSignInError && _jsx("p", { className: styles.loginError, children: cloudSignInError }), _jsxs("div", { className: modalStyles.formActions, style: { display: 'flex', justifyContent: 'flex-end', gap: '10px' }, children: [_jsx("button", { className: styles.cancelBtn, onClick: closeCloudSignInModal, disabled: cloudSignInBusy, children: "Close" }), _jsx("button", { className: styles.submitBtn, disabled: cloudSignInBusy || !cloudSignInEmail.trim() || !cloudSignInPassword.trim(), onClick: async () => {
1590
- setCloudSignInBusy(true);
1591
- setCloudSignInError(null);
1592
- const result = await loginWithCredentials(cloudSignInEmail, cloudSignInPassword);
1593
- if (!result.success) {
1594
- setCloudSignInError(result.error || 'Sign in failed.');
1595
- setCloudSignInBusy(false);
1596
- return;
1597
- }
1598
- if (await routeToWorkspaceSetupIfNeeded(false)) {
1599
- setCloudSignInBusy(false);
1600
- return;
1601
- }
1602
- setCloudSignInBusy(false);
1603
- setShowCloudSignInModal(false);
1604
- }, children: cloudSignInBusy ? 'Signing in...' : 'Sign In' })] })] }) }), _jsx(Modal, { isOpen: showAccountHub, onClose: () => setShowAccountHub(false), title: "Account Hub", size: "md", theme: currentTheme, draggable: true, children: _jsxs("div", { className: modalStyles.form, style: { paddingTop: '18px' }, children: [_jsx("p", { style: { margin: 0, color: 'var(--text-secondary)' }, children: "Manage sign in, profile, and workspace controls from one place." }), _jsxs("div", { className: styles.accountHubCard, children: [_jsx("strong", { children: "Authentication" }), _jsx("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: runtimeMode === 'cloud'
1605
- ? (authRequiredForApi
1606
- ? (isAuthenticated ? 'Signed in. API access is enabled.' : 'Cloud mode requires sign in before app usage.')
1607
- : 'Cloud runtime with optional authentication.')
1608
- : 'Local runtime allows guest usage without sign in.' }), runtimeMode === 'cloud' && authRequiredForApi && !isAuthenticated && (_jsx("p", { style: { marginTop: '10px', color: 'var(--text-secondary)' }, children: "Use the `/login` screen to sign in." }))] }), _jsxs("div", { className: styles.accountHubCard, children: [_jsx("strong", { children: "Profile & Account" }), _jsx("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: "Profile editing and account preferences will live here." })] }), _jsxs("div", { className: styles.accountHubCard, children: [_jsx("strong", { children: "Workspace Settings" }), _jsx("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: "Existing project settings remain fully available." })] }), _jsxs("div", { className: styles.accountHubCard, children: [_jsx("strong", { children: "Workspace Cloud Sync" }), _jsx("p", { style: { margin: '4px 0 0 0', color: 'var(--text-secondary)' }, children: canManageWorkspaceSync
1609
- ? (workspaceCloudSyncEnabled
1610
- ? `Enabled${workspaceSyncSourceOfTruth ? ` · Source: ${workspaceSyncSourceOfTruth}` : ''}`
1611
- : 'Disabled')
1612
- : 'Sign in to cloud account to enable workspace sync.' }), workspaceSyncError && (_jsx("p", { className: styles.loginError, style: { marginTop: '8px' }, children: workspaceSyncError })), _jsx("div", { style: { marginTop: '10px', display: 'flex', gap: '10px', justifyContent: 'flex-end' }, children: _jsx("button", { className: styles.cancelBtn, disabled: !canManageWorkspaceSync || workspaceSyncBusy, onClick: async () => {
1613
- if (!canManageWorkspaceSync)
1614
- return;
1615
- setWorkspaceSyncError(null);
1616
- if (!workspaceCloudSyncEnabled) {
1617
- setWorkspaceSyncBusy(true);
1618
- const result = await saveWorkspaceCloudSyncSettings({
1619
- enabled: true,
1620
- // I6: start false; the orchestrator marks it true after first successful pull.
1621
- onboardingCompleted: false
1622
- });
1623
- if (!result.success)
1624
- setWorkspaceSyncError(result.error || 'Failed to enable sync.');
1625
- setWorkspaceSyncBusy(false);
1626
- return;
1627
- }
1628
- setWorkspaceSyncBusy(true);
1629
- const result = await saveWorkspaceCloudSyncSettings({
1630
- enabled: false,
1631
- sourceOfTruth: workspaceSyncSourceOfTruth,
1632
- onboardingCompleted: workspaceSyncOnboardingCompleted
1633
- });
1634
- if (!result.success)
1635
- setWorkspaceSyncError(result.error || 'Failed to disable sync.');
1636
- setWorkspaceSyncBusy(false);
1637
- }, children: workspaceCloudSyncEnabled ? 'Disable Sync' : 'Enable Sync' }) })] }), _jsxs("div", { className: modalStyles.formActions, style: { display: 'flex', justifyContent: 'flex-end', gap: '10px' }, children: [_jsx("button", { className: styles.cancelBtn, onClick: () => {
1638
- setShowAccountHub(false);
1639
- setShowHelpModal(true);
1640
- }, children: "Help & Tutorial" }), _jsx("button", { className: styles.cancelBtn, onClick: () => {
1641
- setShowAccountHub(false);
1642
- setActiveTab('settings');
1643
- setSettingsSection('general');
1644
- }, children: "Workspace Settings" }), _jsx("button", { className: styles.submitBtn, onClick: () => setShowAccountHub(false), children: "Close" })] })] }) }), _jsx(Modal, { isOpen: showSyncStatusModal, onClose: () => {
1645
- setShowSyncStatusModal(false);
1646
- }, title: "Cloud Sync Status", size: "md", theme: currentTheme, draggable: true, children: _jsxs("div", { className: `${modalStyles.form} ${styles.syncStatusModal}`, children: [_jsxs("div", { className: styles.syncStatusTop, children: [_jsxs("div", { children: [_jsx("div", { className: styles.syncStatusHeading, children: "Current Status" }), _jsx("div", { className: styles.syncStatusSubtext, children: _jsx("code", { children: currentWorkspaceId }) }), workspaceBootstrapSyncInProgress && (_jsxs("div", { className: styles.syncStatusPausedHint, children: ["Initial sync in progress: ", workspaceBootstrapSyncAppliedChanges, " changes across ", workspaceBootstrapSyncPages, " page", workspaceBootstrapSyncPages === 1 ? '' : 's', "."] })), runtimeMode === 'local' && !isAuthenticated && (_jsx("div", { className: styles.syncStatusPausedHint, children: "Sync is paused. Sign in on cloud to resume." }))] }), _jsx("div", { className: styles.syncStatusBadge, style: {
1647
- borderColor: modalSyncStatusMeta.border,
1648
- background: modalSyncStatusMeta.background,
1649
- color: modalSyncStatusMeta.color
1650
- }, children: modalSyncStatusMeta.label })] }), _jsxs("div", { className: styles.syncStatusGrid, children: [_jsxs("div", { className: styles.syncStatusItem, children: [_jsx("span", { className: styles.syncStatusLabel, children: "Last successful sync" }), _jsx("span", { className: styles.syncStatusValue, children: formattedLastSyncTime })] }), _jsxs("div", { className: styles.syncStatusItem, children: [_jsx("span", { className: styles.syncStatusLabel, children: "Pending local changes" }), _jsx("span", { className: styles.syncStatusValue, children: userGlobalSyncPendingChanges })] }), _jsxs("div", { className: styles.syncStatusItem, children: [_jsx("span", { className: styles.syncStatusLabel, children: "Last pull from cloud" }), _jsx("span", { className: styles.syncStatusValue, children: formattedLastPullTime })] }), _jsxs("div", { className: styles.syncStatusItem, children: [_jsx("span", { className: styles.syncStatusLabel, children: "Last push to cloud" }), _jsx("span", { className: styles.syncStatusValue, children: formattedLastPushTime })] }), _jsxs("div", { className: styles.syncStatusItem, children: [_jsx("span", { className: styles.syncStatusLabel, children: "Scheduled retry" }), _jsx("span", { className: styles.syncStatusValue, children: workspaceRetryAt ? formattedRetryTime : 'None' })] }), _jsxs("div", { className: styles.syncStatusItem, children: [_jsx("span", { className: styles.syncStatusLabel, children: "Last error time" }), _jsx("span", { className: styles.syncStatusValue, children: workspaceLastErrorAt ? formattedLastErrorTime : 'None' })] })] }), _jsxs("div", { className: styles.syncStatusDetailsGrid, children: [_jsx("div", { className: styles.syncStatusTableWrap, children: _jsx("table", { className: styles.syncStatusTable, children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("th", { children: "Runtime mode" }), _jsx("td", { children: runtimeMode })] }), _jsxs("tr", { children: [_jsx("th", { children: "Sync source of truth" }), _jsx("td", { children: workspaceSyncSourceOfTruth || 'unset' })] }), _jsxs("tr", { children: [_jsx("th", { children: "Ready" }), _jsx("td", { children: workspaceSyncReady ? 'yes' : 'no' })] }), _jsxs("tr", { children: [_jsx("th", { children: "Hydrated" }), _jsx("td", { children: workspaceCloudHydrated ? 'yes' : 'no' })] }), _jsxs("tr", { children: [_jsx("th", { children: "Failure count" }), _jsx("td", { children: workspaceSyncFailureCount })] })] }) }) }), _jsx("div", { className: styles.syncStatusTableWrap, children: _jsx("table", { className: styles.syncStatusTable, children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("th", { children: "Auth failures" }), _jsx("td", { children: workspaceSyncAuthFailureCount })] }), _jsxs("tr", { children: [_jsx("th", { children: "Last failure source" }), _jsx("td", { children: workspaceSyncLastFailureSource || 'none' })] }), _jsxs("tr", { children: [_jsx("th", { children: "Last failure status" }), _jsx("td", { children: workspaceSyncLastFailureStatusCode ?? 'none' })] }), _jsxs("tr", { children: [_jsx("th", { children: "Retries scheduled" }), _jsx("td", { children: workspaceSyncRetryScheduledCount })] })] }) }) })] }), _jsx("div", { className: styles.syncStatusTableWrap, children: _jsx("table", { className: styles.syncStatusTable, children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("th", { className: styles.syncStatusTableNarrowLabel, children: "Last error" }), _jsx("td", { className: styles.syncStatusTableError, style: { color: (workspaceLastErrorMessage || userGlobalSyncError) ? '#fda4af' : 'var(--text-secondary)' }, children: workspaceLastErrorMessage || userGlobalSyncError || 'None' })] }), _jsxs("tr", { children: [_jsx("th", { className: styles.syncStatusTableNarrowLabel, children: "Last warning" }), _jsx("td", { style: { color: workspaceLastWarningMessage ? '#fcd34d' : 'var(--text-secondary)' }, children: workspaceLastWarningMessage || 'None' })] })] }) }) }), _jsxs("div", { className: `${modalStyles.formActions} ${styles.syncStatusActions}`, children: [_jsx("button", { className: styles.cancelBtn, onClick: () => void resetWorkspaceSyncCursorAndPull(), disabled: userGlobalSyncStatus === 'syncing', title: "Clear pull cursor and fetch full cloud state into local workspace", children: "Reset Cursor + Full Pull" }), runtimeMode === 'local' && !isAuthenticated && (_jsx("button", { className: styles.submitBtn, onClick: () => {
1651
- setShowSyncStatusModal(false);
1652
- openCloudSignIn();
1653
- }, children: "Sign-In" })), _jsx("button", { className: styles.cancelBtn, onClick: () => {
1654
- setShowSyncStatusModal(false);
1655
- }, children: "Close" }), _jsx("button", { className: styles.submitBtn, onClick: () => void retryWorkspaceCloudSync(), disabled: userGlobalSyncStatus === 'syncing', children: userGlobalSyncStatus === 'syncing' ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 14, className: styles.spinner }), "Syncing..."] })) : (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { size: 14 }), "Retry Now"] })) })] })] }) }), unsavedModalOpen && createPortal(_jsx("div", { className: `${modalStyles.overlay} ${modalStyles.unsavedOverlay}`, style: { zIndex: 2000 }, children: _jsxs("div", { className: `${modalStyles.modal} ${modalStyles.unsavedModal}`, "data-theme": currentTheme, children: [_jsx("div", { className: `${modalStyles.header} ${modalStyles.unsavedHeader}`, children: _jsxs("div", { className: `${modalStyles.headerTitle} ${modalStyles.unsavedTitle}`, children: [_jsx(AlertTriangle, { size: 20 }), "Unsaved Changes"] }) }), _jsx("div", { className: `${modalStyles.form} ${modalStyles.unsavedContent}`, children: _jsx("p", { className: modalStyles.unsavedText, children: "You have unsaved changes. Would you like to save them?" }) }), _jsxs("div", { className: `${modalStyles.formActions} ${modalStyles.unsavedActions}`, children: [_jsx("button", { className: styles.cancelBtn, onClick: () => setUnsavedModalOpen(false), title: "Close dialog and continue editing", children: "Keep Editing" }), _jsx("button", { className: styles.destructiveBtn, onClick: handleDiscard, title: "Discard unsaved changes and leave", children: "Discard" }), _jsxs("button", { className: styles.submitBtn, onClick: handleSaveAndNavigate, disabled: loading, title: "Save changes and leave", children: [loading ? _jsx(Loader2, { size: 16, className: styles.spinner }) : _jsx(Save, { size: 16 }), "Save"] })] })] }) }), document.body), showFolderBrowser && createPortal(_jsx("div", { className: styles.folderBrowserOverlay, children: _jsxs("div", { className: styles.folderBrowser, children: [_jsxs("div", { className: styles.browserHeader, children: [_jsxs("div", { className: styles.browserPathInfo, children: [_jsx(Folder, { size: 14 }), _jsx("span", { children: currentBrowsePath || 'Project Root' })] }), _jsxs("div", { className: styles.browserActions, children: [currentBrowsePath && (_jsx("button", { className: styles.helpLink, onClick: () => {
1656
- const parts = currentBrowsePath.split('/').filter(Boolean);
1657
- parts.pop();
1658
- fetchFolders(parts.length ? parts.join('/') + '/' : '');
1659
- }, children: "Back" })), _jsx("button", { className: styles.helpLink, onClick: () => setShowFolderBrowser(false), children: "Close" })] })] }), _jsxs("div", { className: styles.browserList, children: [browserTarget && typeof browserTarget === 'object' && browserTarget.type !== 'context-link' && (_jsxs("div", { className: `${styles.browserItem} ${styles.browserItemFile} ${styles.browserSelectCurrent}`, onClick: () => handleSelectPath(currentBrowsePath), children: [_jsx(Check, { size: 14 }), " Select Current: ./", currentBrowsePath || '(root)'] })), folders.map(folder => (_jsxs("div", { className: styles.browserItem, onClick: () => fetchFolders(currentBrowsePath + folder + '/'), children: [_jsx(Folder, { size: 14 }), " ", folder, "/"] }, folder))), files.map(file => (_jsxs("div", { className: `${styles.browserItem} ${styles.browserItemFile}`, onClick: () => handleSelectPath(currentBrowsePath + file), children: [_jsx(FileText, { size: 14 }), " ", file] }, file))), folders.length === 0 && files.length === 0 && (_jsx("div", { className: `${styles.browserItem} ${styles.browserEmpty}`, children: "No items found" }))] })] }) }), document.body), _jsx(Modal, { isOpen: !!cancellationPromptTask, onClose: handleCancelCancellation, title: "Cancel Task", size: "sm", theme: currentTheme, draggable: true, footer: _jsxs(_Fragment, { children: [_jsx("button", { className: styles.cancelBtn, onClick: handleCancelCancellation, title: "Close and continue working on this task", children: "Back" }), _jsxs("button", { className: `${styles.warningBtn} ${styles.cancelTaskConfirmBtn}`, onClick: handleConfirmCancellation, title: "Keep the task, set status to cancelled, and save a cancellation reason", style: { gap: '8px' }, children: [_jsx(Ban, { size: 16 }), " Confirm Cancellation"] }), _jsxs("button", { className: `${styles.destructiveBtn} ${styles.cancelTaskDeleteBtn}`, onClick: handleDeleteFromCancellation, title: "Permanently delete this task and all of its data", style: { gap: '8px' }, children: [_jsx(Trash2, { size: 16 }), " Delete Permanently"] })] }), children: _jsxs("div", { className: styles.form, style: { padding: '20px 24px', display: 'flex', flexDirection: 'column', gap: '8px', overflow: 'hidden' }, children: [_jsx("p", { style: { margin: 0, fontSize: '14px', color: 'var(--text-secondary)' }, children: "Why is this task being cancelled?" }), _jsx("textarea", { className: styles.textarea, placeholder: "Reason for record (e.g., No longer relevant, duplicate, etc.)", value: localCancellationReason, onChange: (e) => setLocalCancellationReason(e.target.value), autoFocus: true, style: { minHeight: '60px', width: '100%', resize: 'none', boxSizing: 'border-box' }, rows: 2 })] }) })] }));
1660
- }