@taskforcehq/taskforce 0.3.327 → 0.3.328

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 (187) hide show
  1. package/dist/Taskforce.module.css +24 -53
  2. package/dist/components/activity/EntityActivityTimeline.js +15 -5
  3. package/dist/components/context/AttachmentPreviewHost.js +1 -1
  4. package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
  5. package/dist/components/context/ContextAttachmentManager.js +116 -20
  6. package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
  7. package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
  8. package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
  9. package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
  10. package/dist/components/features/planning/PlanningModule.js +26 -9
  11. package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
  12. package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
  13. package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
  14. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  15. package/dist/components/task/TaskActionHeader.js +2 -2
  16. package/dist/components/task/TaskCard.js +37 -4
  17. package/dist/components/task/TaskContextUpload.d.ts +3 -0
  18. package/dist/components/task/TaskContextUpload.js +2 -2
  19. package/dist/components/task/TaskForm.d.ts +4 -0
  20. package/dist/components/task/TaskForm.js +32 -7
  21. package/dist/components/task/TaskImageReviews.js +16 -16
  22. package/dist/components/task/TaskStatusActions.js +11 -2
  23. package/dist/components/task/TaskWorkstreamPicker.js +2 -1
  24. package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
  25. package/dist/components/ui/DocumentTypeIcon.js +8 -0
  26. package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
  27. package/dist/components/ui/TaxonomyDropdown.js +30 -3
  28. package/dist/components/views/StandaloneLayout.js +62 -9
  29. package/dist/components/views/WidgetView.js +8 -5
  30. package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
  31. package/dist/components/views/panels/PlanningDrawer.js +48 -44
  32. package/dist/config/envSchema.js +1 -0
  33. package/dist/config/localServiceCloudTarget.d.ts +10 -0
  34. package/dist/config/localServiceCloudTarget.js +76 -0
  35. package/dist/core/AiProfileService.d.ts +1 -0
  36. package/dist/core/AiProfileService.js +2 -1
  37. package/dist/core/AttachmentLinkService.js +7 -4
  38. package/dist/core/DeletedTaskLifecycleService.d.ts +4 -0
  39. package/dist/core/DeletedTaskLifecycleService.js +21 -0
  40. package/dist/core/McpTokenService.d.ts +4 -0
  41. package/dist/core/McpTokenService.js +52 -0
  42. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +5 -0
  43. package/dist/core/TaskAttachmentLinksDurableMutationService.js +20 -11
  44. package/dist/core/Taskforce.d.ts +63 -1
  45. package/dist/core/Taskforce.js +558 -73
  46. package/dist/core/types.d.ts +2 -1
  47. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
  48. package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
  49. package/dist/documentReviews/service.d.ts +4 -0
  50. package/dist/documentReviews/service.js +141 -46
  51. package/dist/hooks/tasks/useTaskFormActions.d.ts +3 -0
  52. package/dist/hooks/tasks/useTaskFormActions.js +33 -7
  53. package/dist/hooks/useTaskforce.d.ts +59 -50
  54. package/dist/hooks/useTaskforce.js +103 -1
  55. package/dist/mcp/canonicalAssetHelpers.d.ts +13 -0
  56. package/dist/mcp/canonicalAssetHelpers.js +39 -5
  57. package/dist/mcp/collaborationRegistrar.js +15 -13
  58. package/dist/mcp/documentAssetRegistrar.js +16 -9
  59. package/dist/mcp/localServiceProxy.js +4 -1
  60. package/dist/mcp/runtime.d.ts +16 -0
  61. package/dist/mcp/runtime.js +566 -171
  62. package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
  63. package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
  64. package/dist/mcp/taskPlanningRegistrar.js +42 -34
  65. package/dist/mcp/toolRegistry.js +2 -2
  66. package/dist/migrations/taskSchemaMigrations.js +35 -0
  67. package/dist/runtime/appGateDefinitions.d.ts +2 -2
  68. package/dist/runtime/appGateDefinitions.js +2 -2
  69. package/dist/server/appAccess.d.ts +12 -0
  70. package/dist/server/appAccess.js +21 -0
  71. package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
  72. package/dist/server/authorizedWorkspaceAccess.js +40 -0
  73. package/dist/server/cloudCollectionRead.d.ts +25 -0
  74. package/dist/server/cloudCollectionRead.js +120 -0
  75. package/dist/server/cloudCollectionReadPool.d.ts +52 -0
  76. package/dist/server/cloudCollectionReadPool.js +140 -0
  77. package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
  78. package/dist/server/cloudCollectionReadWorker.js +36 -0
  79. package/dist/server/index.d.ts +3 -11
  80. package/dist/server/index.js +53 -40
  81. package/dist/server/localServiceLease.d.ts +3 -0
  82. package/dist/server/localServiceLease.js +9 -1
  83. package/dist/server/routes/documents.d.ts +5 -2
  84. package/dist/server/routes/documents.js +160 -13
  85. package/dist/server/routes/durableTaskHttpRouters.d.ts +2 -0
  86. package/dist/server/routes/durableTaskHttpRouters.js +2 -2
  87. package/dist/server/routes/localService.js +2 -0
  88. package/dist/server/routes/primitives.d.ts +2 -0
  89. package/dist/server/routes/shared.d.ts +24 -0
  90. package/dist/server/routes/shared.js +114 -18
  91. package/dist/server/routes/sync.js +22 -0
  92. package/dist/server/routes/syncV3FeedRoutes.js +4 -2
  93. package/dist/server/routes/syncV3LocalCaptureRoutes.js +20 -2
  94. package/dist/server/routes/syncV3OperationRoutes.js +17 -2
  95. package/dist/server/routes/tasks.js +199 -89
  96. package/dist/server/routes.js +35 -7
  97. package/dist/service/localServiceCli.js +36 -25
  98. package/dist/service/localServiceClientLifecycle.js +67 -6
  99. package/dist/shared/planningIdentity.d.ts +20 -0
  100. package/dist/shared/planningIdentity.js +79 -0
  101. package/dist/storage/postgresAdapter.js +4 -0
  102. package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
  103. package/dist/storage/postgresRequestDiagnostics.js +24 -0
  104. package/dist/storage/workspaceAssetStore.d.ts +32 -0
  105. package/dist/storage/workspaceAssetStore.js +70 -0
  106. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +16 -0
  107. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +70 -22
  108. package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
  109. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +5 -0
  110. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
  111. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +15 -0
  112. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +26 -3
  113. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
  114. package/dist/sync/syncApplyHandlers.d.ts +3 -1
  115. package/dist/sync/syncApplyHandlers.js +29 -0
  116. package/dist/sync/syncService.js +9 -0
  117. package/dist/sync/taskSyncPayload.d.ts +1 -0
  118. package/dist/sync/taskSyncPayload.js +6 -0
  119. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +1 -0
  120. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +21 -3
  121. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +17 -4
  122. package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
  123. package/dist/sync/v3/localOutboxDispatcher.js +5 -1
  124. package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
  125. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +1 -0
  126. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +15 -3
  127. package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
  128. package/dist/sync/v3/syncDurabilityStore.d.ts +8 -0
  129. package/dist/sync/v3/syncDurabilityStore.js +171 -33
  130. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +1 -0
  131. package/dist/sync/v3/taskAttachmentLinksMutationService.js +18 -2
  132. package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
  133. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +1 -9
  134. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +1 -0
  135. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +7 -1
  136. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +15 -3
  137. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +4 -0
  138. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +29 -6
  139. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +1 -0
  140. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +29 -7
  141. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +62 -7
  142. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +1 -0
  143. package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
  144. package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -0
  145. package/dist/sync/v3/workspaceSyncV3TaskRootProjection.d.ts +1 -1
  146. package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
  147. package/dist/sync/workspacePullFeed.d.ts +6 -1
  148. package/dist/sync/workspacePullFeed.js +172 -161
  149. package/dist/sync/workspaceSyncModel.d.ts +11 -0
  150. package/dist/sync/workspaceSyncModel.js +27 -2
  151. package/dist/types.d.ts +8 -0
  152. package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-MZs7lVED.js} +1 -1
  153. package/dist/ui/assets/{AiProfilesModule-DPxQeF9N.js → AiProfilesModule-C3i0LOxe.js} +1 -1
  154. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-DHNYaNg6.js → AnnotatedAttachmentWorkspace-DVZk5Tln.js} +1 -1
  155. package/dist/ui/assets/AssetTraySortControl-Kf1pelSy.js +1 -0
  156. package/dist/ui/assets/ContextAttachmentManager-B8boOs6Q.js +3 -0
  157. package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-DXH4XUsB.js} +4 -4
  158. package/dist/ui/assets/EntityActivityTimeline-BtSTq0ON.js +1 -0
  159. package/dist/ui/assets/PlanningModule-BPVyEa-f.js +1 -0
  160. package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
  161. package/dist/ui/assets/{PlansPage-BVH_NfgT.js → PlansPage-ChqgxALc.js} +1 -1
  162. package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +1 -0
  163. package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
  164. package/dist/ui/assets/{TaskSettings-xVsxSa0g.js → TaskSettings-g4ECKNOz.js} +1 -1
  165. package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BazdUwxZ.js} +1 -1
  166. package/dist/ui/assets/WorkflowManagerModule-DWFspC-o.js +1 -0
  167. package/dist/ui/assets/index-BUplSsv_.js +7 -0
  168. package/dist/ui/assets/index-gz2EXuoK.css +1 -0
  169. package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-BkFLXavV.js} +1 -1
  170. package/dist/ui/index.html +3 -3
  171. package/dist/utils/constants.d.ts +2 -2
  172. package/dist/utils/constants.js +1 -1
  173. package/dist/utils/contextAttachmentUpload.d.ts +2 -0
  174. package/dist/utils/contextAttachmentUpload.js +7 -0
  175. package/dist/utils/contextFiles.d.ts +1 -1
  176. package/dist/utils/contextFiles.js +4 -4
  177. package/package.json +6 -1
  178. package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
  179. package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
  180. package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
  181. package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
  182. package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
  183. package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
  184. package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
  185. package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
  186. package/dist/ui/assets/index-BzJlVnNS.css +0 -1
  187. package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
@@ -16,6 +16,7 @@ import { getPlanningFavoriteKey, } from '../../../utils/planningFavorites';
16
16
  import { TASK_ASSIGNEE_UNASSIGNED_COLOR, TASK_ASSIGNEE_UNASSIGNED_ICON, } from '../../../utils/assignees';
17
17
  import { PlanningEntityActivity, PlanningEntityContext, PlanningEntityDescription, } from '../../features/planning/PlanningEntityDetails';
18
18
  import { PlanningEntitySummary, PlanningNoTasks, PlanningProgress, PlanningReferenceBadge, PlanningSummaryMeta, } from '../../features/planning/PlanningEntitySummary';
19
+ import { PlanningVisualIdentity } from '../../features/planning/PlanningVisualIdentity';
19
20
  import { PlanningTaskCard } from '../../features/planning/PlanningTaskCard';
20
21
  import { PlanningTaskArrangeControl } from '../../features/planning/PlanningTaskArrangeControl';
21
22
  import planningDropdownStyles from '../../features/planning/PlanningDropdownControl.module.css';
@@ -72,11 +73,10 @@ function countArchivedDetailChildren(detail) {
72
73
  }
73
74
  return (detail.item.tasks || []).filter((task) => Boolean(task.isArchived)).length;
74
75
  }
75
- function PlanningRow({ rowId, rowType, referenceLabel, item, ownerOption, ownerOptions, workstreamCount, active, isArchived = false, detailOpen = false, canExpand = false, expanded = false, controlsId, onToggleExpand, onToggleScope, onOpenDetails, onChangeOwner, initiativeLinkOptions = [], onLinkInitiative, favorite, favoriteReady, onToggleFavorite, onArchiveReady, hierarchyInteractions = true, }) {
76
+ function PlanningRow({ rowId, rowType, referenceLabel, item, ownerOption, ownerOptions, workstreamCount, active, isArchived = false, detailOpen = false, canExpand = false, expanded = false, controlsId, onToggleExpand, onToggleScope, onOpenDetails, onChangeOwner, onChangeIdentity, initiativeLinkOptions = [], onLinkInitiative, favorite, favoriteReady, onToggleFavorite, onArchiveReady, hierarchyInteractions = true, }) {
76
77
  const { title } = item;
77
78
  const [archiveConfirmationVisible, setArchiveConfirmationVisible] = React.useState(false);
78
79
  const [archiveBusy, setArchiveBusy] = React.useState(false);
79
- const [initiativePickerVisible, setInitiativePickerVisible] = React.useState(false);
80
80
  const [initiativeLinkBusy, setInitiativeLinkBusy] = React.useState(false);
81
81
  const { active: dndActive } = useDndContext();
82
82
  const dragType = String(dndActive?.data?.current?.type || '');
@@ -91,7 +91,7 @@ function PlanningRow({ rowId, rowType, referenceLabel, item, ownerOption, ownerO
91
91
  disabled: !hierarchyInteractions,
92
92
  });
93
93
  const draggable = hierarchyInteractions && rowType === 'workstream';
94
- const { attributes, listeners, setNodeRef: setDragRef, transform, isDragging, } = useDraggable({
94
+ const { attributes, listeners, setNodeRef: setDragRef, setActivatorNodeRef, transform, isDragging, } = useDraggable({
95
95
  id: `planning-workstream:${rowId}`,
96
96
  data: { type: 'planning-workstream', workstreamId: rowId },
97
97
  disabled: !draggable,
@@ -163,9 +163,7 @@ function PlanningRow({ rowId, rowType, referenceLabel, item, ownerOption, ownerO
163
163
  return;
164
164
  setInitiativeLinkBusy(true);
165
165
  try {
166
- const result = await onLinkInitiative(option);
167
- if (result !== false)
168
- setInitiativePickerVisible(false);
166
+ await onLinkInitiative(option);
169
167
  }
170
168
  finally {
171
169
  setInitiativeLinkBusy(false);
@@ -178,29 +176,26 @@ function PlanningRow({ rowId, rowType, referenceLabel, item, ownerOption, ownerO
178
176
  : initiativeLinkOptions.length === 0
179
177
  ? 'No initiatives available'
180
178
  : 'Link initiative';
181
- return (_jsx("div", { ref: setDropRef, style: dragStyle, className: `${panelStyles.treeRow} ${isArchived ? panelStyles.treeRowArchived : ''} ${detailOpen ? panelStyles.treeRowDetailOpen : ''} ${showDropReady ? panelStyles.treeRowDropReady : ''} ${isOver ? panelStyles.treeRowDropActive : ''} ${isDragging ? panelStyles.treeRowDragging : ''} ${showDropReady ? panelStyles.treeRowDropMode : ''}`, "data-board-scoped": active || undefined, children: _jsxs("div", { className: panelStyles.rowContent, children: [_jsxs("div", { className: panelStyles.rowTopRow, children: [_jsxs("div", { className: panelStyles.rowReferenceActions, children: [canLinkInitiative ? (_jsx(HierarchyActionBadge, { disabled: initiativeLinkDisabled, onClick: (event) => {
182
- event.stopPropagation();
183
- setInitiativePickerVisible((current) => !current);
184
- }, title: initiativeLinkTitle, ariaLabel: "Link initiative", ariaExpanded: initiativePickerVisible, children: _jsx(Link2, { size: 14, "aria-hidden": "true" }) })) : null, _jsx(PlanningReferenceBadge, { label: referenceLabel || 'Reference pending', entityType: rowType, entityName: title, pending: !referenceLabel })] }), _jsxs("div", { className: panelStyles.rowActions, role: "toolbar", "aria-label": `${rowType === 'initiative' ? 'Initiative' : 'Workstream'} actions for ${title}`, "aria-orientation": "horizontal", onKeyDown: handleRowActionKeyDown, children: [_jsx("button", { type: "button", ref: (node) => {
185
- rowActionRefs.current.favorite = node;
186
- }, className: `tf-control-icon tf-control-icon-compact ${panelStyles.favoriteButton} ${favorite ? 'tf-control-icon-active' : ''}`.trim(), onClick: onToggleFavorite, onFocus: () => handleRowActionFocus('favorite'), disabled: !favoriteReady, tabIndex: effectiveActiveRowActionId === 'favorite' ? 0 : -1, "data-planning-row-action": "favorite", title: !favoriteReady
187
- ? 'Loading Favorites'
188
- : favorite ? `Remove ${rowType} from Favorites` : `Add ${rowType} to Favorites`, "aria-label": !favoriteReady
189
- ? `Loading Favorites for ${rowType} ${title}`
190
- : favorite ? `Remove ${rowType} ${title} from Favorites` : `Add ${rowType} ${title} to Favorites`, "aria-pressed": favorite, children: _jsx(Star, { size: 14, fill: favorite ? 'currentColor' : 'none', "aria-hidden": "true" }) }), archiveActionVisible ? (_jsx("button", { type: "button", ref: (node) => {
191
- rowActionRefs.current.archive = node;
192
- }, className: "tf-control-icon tf-control-icon-compact", onClick: () => setArchiveConfirmationVisible(true), onFocus: () => handleRowActionFocus('archive'), tabIndex: effectiveActiveRowActionId === 'archive' ? 0 : -1, "data-planning-row-action": "archive", title: `Archive completed ${rowType}`, "aria-label": `Archive completed ${rowType} ${title}`, "aria-expanded": archiveConfirmationVisible, children: _jsx(Archive, { size: 14, "aria-hidden": "true" }) })) : null, _jsx("button", { type: "button", ref: (node) => {
193
- rowActionRefs.current.scope = node;
194
- }, className: `tf-control-icon tf-control-icon-compact ${panelStyles.scopeButton} ${active ? 'tf-control-icon-active' : ''}`.trim(), onClick: onToggleScope, onFocus: () => handleRowActionFocus('scope'), tabIndex: effectiveActiveRowActionId === 'scope' ? 0 : -1, "data-planning-row-action": "scope", title: active ? 'Clear board scope' : 'Scope board to this item', "aria-label": active ? `Clear board scope for ${title}` : `Scope board to ${title}`, "aria-pressed": active, children: _jsx(Kanban, { size: 14, "aria-hidden": "true" }) }), _jsx("button", { type: "button", ref: (node) => {
195
- rowActionRefs.current.disclosure = node;
196
- }, className: `tf-control-icon tf-control-icon-compact ${panelStyles.treeChevron}`.trim(), onClick: expansionEnabled ? onToggleExpand : undefined, onFocus: () => handleRowActionFocus('disclosure'), tabIndex: effectiveActiveRowActionId === 'disclosure' ? 0 : -1, "data-planning-row-action": "disclosure", title: expansionLabel, "aria-label": expansionLabel, "aria-expanded": expansionEnabled ? expanded : false, "aria-controls": expansionEnabled && expanded ? controlsId : undefined, disabled: !expansionEnabled, children: expanded && expansionEnabled
197
- ? _jsx(ChevronDown, { size: 14, "aria-hidden": "true" })
198
- : _jsx(ChevronRight, { size: 14, "aria-hidden": "true" }) })] })] }), canLinkInitiative && initiativePickerVisible ? (_jsxs("div", { className: `${panelStyles.relationshipPickerRow} ${panelStyles.rowRelationshipPicker}`.trim(), role: "group", "aria-label": `Link ${title} to initiative`, children: [_jsx(PlanningLinkPicker, { options: initiativeLinkOptions, entityLabel: "initiative", onSelect: (option) => void handleLinkInitiative(option), disabled: initiativeLinkBusy }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", disabled: initiativeLinkBusy, onClick: () => setInitiativePickerVisible(false), title: "Cancel initiative link", "aria-label": "Cancel initiative link", children: _jsx(X, { size: 14, "aria-hidden": "true" }) })] })) : null, _jsxs("div", { className: panelStyles.rowBody, children: [draggable ? (_jsx("div", { className: panelStyles.rowLeadingActions, "data-planning-leading-actions": "true", children: _jsx("button", { type: "button", ref: setDragRef, className: panelStyles.dragHandle, title: "Drag workstream", "aria-label": `Drag workstream ${title}`, "data-planning-drag-handle": "true", ...attributes, ...listeners, children: _jsx(GripVertical, { size: 15, "aria-hidden": "true" }) }) })) : null, _jsx("div", { role: "button", tabIndex: 0, className: `${panelStyles.rowButton} ${draggable ? panelStyles.rowButtonWithGrip : ''}`.trim(), onClick: onOpenDetails, onKeyDown: (event) => {
199
- if (event.key !== 'Enter' && event.key !== ' ')
200
- return;
201
- event.preventDefault();
202
- onOpenDetails();
203
- }, "aria-label": `View ${rowType} details for ${title}`, "aria-pressed": detailOpen, children: _jsx(PlanningEntitySummary, { item: item, entityType: rowType, workstreamCount: workstreamCount, ownerOption: ownerOption ? toPlanningAssigneeOption(ownerOption) : undefined, ownerOptions: ownerOptions.map(toPlanningAssigneeOption), onChangeOwner: onChangeOwner }) })] }), archiveConfirmationVisible ? (_jsx(PlanningArchiveConfirmation, { entityType: rowType, title: title, activeTaskCount: item.archiveActiveTaskCount, activeWorkstreamCount: item.archiveActiveWorkstreamCount, busy: archiveBusy, onCancel: () => setArchiveConfirmationVisible(false), onConfirm: () => void handleConfirmArchive() })) : null] }) }));
179
+ return (_jsxs("div", { ref: setDragRef, style: dragStyle, className: `${panelStyles.treeRowShell} ${draggable ? panelStyles.treeRowShellDraggable : ''} ${isDragging ? panelStyles.treeRowDragging : ''} ${showDropReady ? panelStyles.treeRowShellDropMode : ''}`.trim(), "data-planning-draggable-row": draggable || undefined, children: [draggable ? (_jsx("div", { className: panelStyles.rowDragGutter, "data-planning-drag-gutter": "true", children: _jsx("button", { type: "button", ref: setActivatorNodeRef, className: panelStyles.dragHandle, title: "Drag onto an initiative to move this workstream", "aria-label": `Move workstream ${title} to an initiative`, "data-planning-drag-handle": "true", ...attributes, ...listeners, children: _jsx(GripVertical, { size: 15, "aria-hidden": "true" }) }) })) : null, _jsx("div", { ref: setDropRef, className: `${panelStyles.treeRow} ${isArchived ? panelStyles.treeRowArchived : ''} ${detailOpen ? panelStyles.treeRowDetailOpen : ''} ${showDropReady ? panelStyles.treeRowDropReady : ''} ${isOver ? panelStyles.treeRowDropActive : ''} ${showDropReady ? panelStyles.treeRowDropMode : ''}`, "data-board-scoped": active || undefined, children: _jsxs("div", { className: panelStyles.rowContent, children: [_jsxs("div", { className: panelStyles.rowTopRow, children: [_jsxs("div", { className: panelStyles.rowReferenceActions, children: [canLinkInitiative ? (_jsx(PlanningLinkPicker, { options: initiativeLinkOptions, entityLabel: "initiative", onSelect: (option) => void handleLinkInitiative(option), disabled: initiativeLinkDisabled, iconTrigger: true, triggerTitle: initiativeLinkTitle })) : null, _jsx(PlanningReferenceBadge, { label: referenceLabel || 'Reference pending', entityType: rowType, entityName: title, pending: !referenceLabel })] }), _jsxs("div", { className: panelStyles.rowActions, role: "toolbar", "aria-label": `${rowType === 'initiative' ? 'Initiative' : 'Workstream'} actions for ${title}`, "aria-orientation": "horizontal", onKeyDown: handleRowActionKeyDown, children: [_jsx("button", { type: "button", ref: (node) => {
180
+ rowActionRefs.current.favorite = node;
181
+ }, className: `tf-control-icon tf-control-icon-compact ${panelStyles.favoriteButton} ${favorite ? 'tf-control-icon-active' : ''}`.trim(), onClick: onToggleFavorite, onFocus: () => handleRowActionFocus('favorite'), disabled: !favoriteReady, tabIndex: effectiveActiveRowActionId === 'favorite' ? 0 : -1, "data-planning-row-action": "favorite", title: !favoriteReady
182
+ ? 'Loading Favorites'
183
+ : favorite ? `Remove ${rowType} from Favorites` : `Add ${rowType} to Favorites`, "aria-label": !favoriteReady
184
+ ? `Loading Favorites for ${rowType} ${title}`
185
+ : favorite ? `Remove ${rowType} ${title} from Favorites` : `Add ${rowType} ${title} to Favorites`, "aria-pressed": favorite, children: _jsx(Star, { size: 14, fill: favorite ? 'currentColor' : 'none', "aria-hidden": "true" }) }), archiveActionVisible ? (_jsx("button", { type: "button", ref: (node) => {
186
+ rowActionRefs.current.archive = node;
187
+ }, className: "tf-control-icon tf-control-icon-compact", onClick: () => setArchiveConfirmationVisible(true), onFocus: () => handleRowActionFocus('archive'), tabIndex: effectiveActiveRowActionId === 'archive' ? 0 : -1, "data-planning-row-action": "archive", title: `Archive completed ${rowType}`, "aria-label": `Archive completed ${rowType} ${title}`, "aria-expanded": archiveConfirmationVisible, children: _jsx(Archive, { size: 14, "aria-hidden": "true" }) })) : null, _jsx("button", { type: "button", ref: (node) => {
188
+ rowActionRefs.current.scope = node;
189
+ }, className: `tf-control-icon tf-control-icon-compact ${panelStyles.scopeButton} ${active ? 'tf-control-icon-active' : ''}`.trim(), onClick: onToggleScope, onFocus: () => handleRowActionFocus('scope'), tabIndex: effectiveActiveRowActionId === 'scope' ? 0 : -1, "data-planning-row-action": "scope", title: active ? 'Clear board scope' : 'Scope board to this item', "aria-label": active ? `Clear board scope for ${title}` : `Scope board to ${title}`, "aria-pressed": active, children: _jsx(Kanban, { size: 14, "aria-hidden": "true" }) }), _jsx("button", { type: "button", ref: (node) => {
190
+ rowActionRefs.current.disclosure = node;
191
+ }, className: `tf-control-icon tf-control-icon-compact ${panelStyles.treeChevron}`.trim(), onClick: expansionEnabled ? onToggleExpand : undefined, onFocus: () => handleRowActionFocus('disclosure'), tabIndex: effectiveActiveRowActionId === 'disclosure' ? 0 : -1, "data-planning-row-action": "disclosure", title: expansionLabel, "aria-label": expansionLabel, "aria-expanded": expansionEnabled ? expanded : false, "aria-controls": expansionEnabled && expanded ? controlsId : undefined, disabled: !expansionEnabled, children: expanded && expansionEnabled
192
+ ? _jsx(ChevronDown, { size: 14, "aria-hidden": "true" })
193
+ : _jsx(ChevronRight, { size: 14, "aria-hidden": "true" }) })] })] }), _jsx("div", { className: panelStyles.rowBody, children: _jsx("div", { role: "button", tabIndex: 0, className: panelStyles.rowButton, onClick: onOpenDetails, onKeyDown: (event) => {
194
+ if (event.key !== 'Enter' && event.key !== ' ')
195
+ return;
196
+ event.preventDefault();
197
+ onOpenDetails();
198
+ }, "aria-label": `View ${rowType} details for ${title}`, "aria-pressed": detailOpen, children: _jsx(PlanningEntitySummary, { item: item, entityType: rowType, workstreamCount: workstreamCount, ownerOption: ownerOption ? toPlanningAssigneeOption(ownerOption) : undefined, ownerOptions: ownerOptions.map(toPlanningAssigneeOption), onChangeOwner: onChangeOwner, onChangeIdentity: onChangeIdentity }) }) }), archiveConfirmationVisible ? (_jsx(PlanningArchiveConfirmation, { entityType: rowType, title: title, activeTaskCount: item.archiveActiveTaskCount, activeWorkstreamCount: item.archiveActiveWorkstreamCount, busy: archiveBusy, onCancel: () => setArchiveConfirmationVisible(false), onConfirm: () => void handleConfirmArchive() })) : null] }) })] }));
204
199
  }
205
200
  function PlanningTreeTaskCard({ task, assigneeOption, assigneeOptions, showTaskCardStatusLabel, onOpenTaskById, onChangeTaskAssignee, onSetTaskStatus, onArchivePlanningTask, }) {
206
201
  const [archiveBusy, setArchiveBusy] = React.useState(false);
@@ -233,7 +228,7 @@ function RelationshipPane({ label, title, description, onCollapse, action, paneR
233
228
  maxWidth: `${PLANNING_DRAWER_DETAIL_WIDTH_PX}px`,
234
229
  }, children: [_jsxs("div", { className: panelStyles.paneHeader, children: [_jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: label }), _jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapse, "aria-label": `Collapse ${label} pane`, title: `Collapse ${label} pane`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })] }), _jsx("div", { className: `${panelStyles.paneContent} ${isEmptyState ? panelStyles.relationshipPaneContentEmpty : ''}`.trim(), children: _jsxs("div", { className: `${panelStyles.relationshipState} ${isEmptyState ? panelStyles.relationshipStateEmpty : ''}`.trim(), "data-relationship-display": isEmptyState ? 'empty' : 'detail', children: [_jsx("span", { className: panelStyles.relationshipStateTitle, children: title }), description ? _jsx("p", { className: panelStyles.relationshipStateText, children: description }) : null, action ? (_jsx("button", { type: "button", className: "tf-button-secondary tf-button-compact", onClick: action.onClick, children: action.label })) : null] }) })] }));
235
230
  }
236
- function PlanningDrawerList({ initiatives, standaloneWorkstreams, planningLoadState, taskScope, showArchivedPlanning, currentOwnerId, assigneeOptions, showTaskCardStatusLabel = false, taskArrangeMode = 'execution', activeInitiativeId, activeWorkstreamId, navigatorSort, navigatorSortReady, onNavigatorSortChange, planningFavorites, onTogglePlanningFavorite, favoritesSectionCollapsed, initiativesSectionCollapsed, workstreamsSectionCollapsed, onToggleFavoritesSection, onToggleInitiativesSection, onToggleWorkstreamsSection, expandedInitiativeIds, detail, secondaryPane, onCreateInitiative, onCreateWorkstream, onToggleInitiative, onSelectInitiative, onSelectWorkstream, onOpenInitiativeDetails, onOpenWorkstreamDetails, onOpenNestedWorkstreamDetails, onOpenTaskById, onSetTaskStatus, onChangePlanningOwner, onChangeTaskAssignee, onArchivePlanningTask, onArchiveResolvedWorkstream, onArchiveResolvedInitiative, linkOptions, onAssignInitiativeToWorkstream, onRetryPlanning, }) {
231
+ function PlanningDrawerList({ initiatives, standaloneWorkstreams, planningLoadState, taskScope, showArchivedPlanning, currentOwnerId, assigneeOptions, showTaskCardStatusLabel = false, taskArrangeMode = 'execution', activeInitiativeId, activeWorkstreamId, navigatorSort, navigatorSortReady, onNavigatorSortChange, planningFavorites, onTogglePlanningFavorite, favoritesSectionCollapsed, initiativesSectionCollapsed, workstreamsSectionCollapsed, onToggleFavoritesSection, onToggleInitiativesSection, onToggleWorkstreamsSection, expandedInitiativeIds, detail, secondaryPane, onCreateInitiative, onCreateWorkstream, onToggleInitiative, onSelectInitiative, onSelectWorkstream, onOpenInitiativeDetails, onOpenWorkstreamDetails, onOpenNestedWorkstreamDetails, onOpenTaskById, onSetTaskStatus, onChangePlanningOwner, onChangePlanningIdentity = () => { }, onChangeTaskAssignee, onArchivePlanningTask, onArchiveResolvedWorkstream, onArchiveResolvedInitiative, linkOptions, onAssignInitiativeToWorkstream, onRetryPlanning, }) {
237
232
  const [searchQuery, setSearchQuery] = React.useState('');
238
233
  const [ownerFilter, setOwnerFilter] = React.useState('all');
239
234
  const [filtersExpanded, setFiltersExpanded] = React.useState(false);
@@ -435,7 +430,7 @@ function PlanningDrawerList({ initiatives, standaloneWorkstreams, planningLoadSt
435
430
  const favoriteControlsId = `planning-${favoriteBranchKey.replaceAll(':', '-')}-children`;
436
431
  return (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: `favorite:${favorite.type}:${item.id}`, rowType: favorite.type, referenceLabel: favorite.type === 'initiative'
437
432
  ? formatInitiativeReference(item)
438
- : formatWorkstreamReference(item), item: item, ownerOption: item.ownerId ? assigneeOptionByValue.get(item.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner(favorite.type, item.id, ownerId === 'unassigned' ? '' : ownerId), workstreamCount: favoriteInitiative
433
+ : formatWorkstreamReference(item), item: item, ownerOption: item.ownerId ? assigneeOptionByValue.get(item.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner(favorite.type, item.id, ownerId === 'unassigned' ? '' : ownerId), onChangeIdentity: (patch) => onChangePlanningIdentity(favorite.type, item.id, patch), workstreamCount: favoriteInitiative
439
434
  ? visibleInitiativeWorkstreams.length
440
435
  : undefined, active: favorite.type === 'initiative'
441
436
  ? activeInitiativeId === item.id && !activeWorkstreamId
@@ -476,7 +471,7 @@ function PlanningDrawerList({ initiatives, standaloneWorkstreams, planningLoadSt
476
471
  const childControlsId = `planning-${childBranchKey.replaceAll(':', '-')}-children`;
477
472
  return (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: childBranchKey, rowType: "workstream", referenceLabel: formatWorkstreamReference(workstream), item: workstream, ownerOption: workstream.ownerId
478
473
  ? assigneeOptionByValue.get(workstream.ownerId)
479
- : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId), active: activeWorkstreamId === workstream.id, isArchived: Boolean(workstream.isArchived), detailOpen: (detail?.type === 'workstream' && detail.item.id === workstream.id)
474
+ : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId), onChangeIdentity: (patch) => onChangePlanningIdentity('workstream', workstream.id, patch), active: activeWorkstreamId === workstream.id, isArchived: Boolean(workstream.isArchived), detailOpen: (detail?.type === 'workstream' && detail.item.id === workstream.id)
480
475
  || (secondaryPane?.kind === 'detail'
481
476
  && secondaryPane.detail.item.id === workstream.id), canExpand: Boolean(workstream.tasks?.length), expanded: childExpanded, controlsId: childControlsId, onToggleExpand: () => toggleFavoriteBranch(childBranchKey), onToggleScope: () => onSelectWorkstream(workstream.id, favoriteInitiative.id), onOpenDetails: () => {
482
477
  onOpenInitiativeDetails(favoriteInitiative.id);
@@ -503,16 +498,16 @@ function PlanningDrawerList({ initiatives, standaloneWorkstreams, planningLoadSt
503
498
  const expanded = navigatorResults.hasCriteria
504
499
  ? displayedWorkstreams.length > 0
505
500
  : expandedInitiativeIds.has(initiative.id);
506
- return (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: initiative.id, rowType: "initiative", referenceLabel: formatInitiativeReference(initiative), item: initiative, ownerOption: initiative.ownerId ? assigneeOptionByValue.get(initiative.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('initiative', initiative.id, ownerId === 'unassigned' ? '' : ownerId), workstreamCount: treeWorkstreams.length, active: activeInitiativeId === initiative.id && !activeWorkstreamId, isArchived: Boolean(initiative.isArchived), detailOpen: detail?.type === 'initiative' && detail.item.id === initiative.id, canExpand: allWorkstreams.length > 0, expanded: expanded, controlsId: `planning-children-${initiative.id}`, onToggleExpand: () => onToggleInitiative(initiative.id), onToggleScope: () => onSelectInitiative(initiative.id), onOpenDetails: () => onOpenInitiativeDetails(initiative.id), favorite: planningFavoriteKeys.has(getPlanningFavoriteKey({ type: 'initiative', id: initiative.id })), favoriteReady: navigatorSortReady, onToggleFavorite: () => onTogglePlanningFavorite({ type: 'initiative', id: initiative.id }), onArchiveReady: onArchiveResolvedInitiative
501
+ return (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: initiative.id, rowType: "initiative", referenceLabel: formatInitiativeReference(initiative), item: initiative, ownerOption: initiative.ownerId ? assigneeOptionByValue.get(initiative.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('initiative', initiative.id, ownerId === 'unassigned' ? '' : ownerId), onChangeIdentity: (patch) => onChangePlanningIdentity('initiative', initiative.id, patch), workstreamCount: treeWorkstreams.length, active: activeInitiativeId === initiative.id && !activeWorkstreamId, isArchived: Boolean(initiative.isArchived), detailOpen: detail?.type === 'initiative' && detail.item.id === initiative.id, canExpand: allWorkstreams.length > 0, expanded: expanded, controlsId: `planning-children-${initiative.id}`, onToggleExpand: () => onToggleInitiative(initiative.id), onToggleScope: () => onSelectInitiative(initiative.id), onOpenDetails: () => onOpenInitiativeDetails(initiative.id), favorite: planningFavoriteKeys.has(getPlanningFavoriteKey({ type: 'initiative', id: initiative.id })), favoriteReady: navigatorSortReady, onToggleFavorite: () => onTogglePlanningFavorite({ type: 'initiative', id: initiative.id }), onArchiveReady: onArchiveResolvedInitiative
507
502
  ? () => onArchiveResolvedInitiative(initiative.id)
508
- : undefined }), expanded && displayedWorkstreams.length > 0 && (_jsx("ul", { id: `planning-children-${initiative.id}`, className: panelStyles.treeChildren, "aria-label": `Workstreams in ${initiative.title}`, children: displayedWorkstreams.map((workstream) => (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: workstream.id, rowType: "workstream", referenceLabel: formatWorkstreamReference(workstream), item: workstream, ownerOption: workstream.ownerId ? assigneeOptionByValue.get(workstream.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId), active: activeWorkstreamId === workstream.id, isArchived: Boolean(workstream.isArchived), detailOpen: (detail?.type === 'workstream' && detail.item.id === workstream.id)
503
+ : undefined }), expanded && displayedWorkstreams.length > 0 && (_jsx("ul", { id: `planning-children-${initiative.id}`, className: panelStyles.treeChildren, "aria-label": `Workstreams in ${initiative.title}`, children: displayedWorkstreams.map((workstream) => (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: workstream.id, rowType: "workstream", referenceLabel: formatWorkstreamReference(workstream), item: workstream, ownerOption: workstream.ownerId ? assigneeOptionByValue.get(workstream.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId), onChangeIdentity: (patch) => onChangePlanningIdentity('workstream', workstream.id, patch), active: activeWorkstreamId === workstream.id, isArchived: Boolean(workstream.isArchived), detailOpen: (detail?.type === 'workstream' && detail.item.id === workstream.id)
509
504
  || (secondaryPane?.kind === 'detail' && secondaryPane.detail.item.id === workstream.id), canExpand: (workstream.tasks || []).length > 0, expanded: expandedWorkstreamIds.has(workstream.id), controlsId: `planning-tasks-${workstream.id}`, onToggleExpand: () => toggleWorkstreamTasks(workstream.id), onToggleScope: () => onSelectWorkstream(workstream.id, initiative.id), onOpenDetails: () => {
510
505
  onOpenInitiativeDetails(initiative.id);
511
506
  onOpenNestedWorkstreamDetails(workstream.id);
512
507
  }, favorite: planningFavoriteKeys.has(getPlanningFavoriteKey({ type: 'workstream', id: workstream.id })), favoriteReady: navigatorSortReady, onToggleFavorite: () => onTogglePlanningFavorite({ type: 'workstream', id: workstream.id }), onArchiveReady: onArchiveResolvedWorkstream
513
508
  ? () => onArchiveResolvedWorkstream(workstream.id)
514
509
  : undefined }), renderWorkstreamTasks(workstream)] }, workstream.id))) }))] }, initiative.id));
515
- }) })) : null] }), _jsxs("div", { className: panelStyles.sectionGroup, children: [_jsx(DisclosureSectionHeader, { label: "Workstreams", count: navigatorResults.standaloneWorkstreams.length, showZeroCount: true, actions: (planningLoadState.collections.workstreams === 'ready' ? (_jsx("button", { type: "button", className: "tf-control-icon", title: "Create workstream", "aria-label": "Create workstream", onClick: onCreateWorkstream, children: _jsx(Plus, { size: 15 }) })) : null), expanded: !workstreamsSectionCollapsed, expandedTitle: "Collapse workstreams", collapsedTitle: "Expand workstreams", onToggle: onToggleWorkstreamsSection, controlsId: !workstreamsSectionCollapsed ? 'planning-workstreams-section' : undefined }), !workstreamsSectionCollapsed ? (_jsx("ul", { id: "planning-workstreams-section", className: panelStyles.treeList, "aria-label": "Standalone workstreams", children: planningLoadState.collections.workstreams === 'error' ? (_jsx("li", { children: _jsx(PlanningFailureState, { compact: true, title: "Workstreams unavailable", message: "Workstreams could not be loaded.", retrying: planningLoadState.isRefreshing, onRetry: onRetryPlanning }) })) : navigatorResults.standaloneWorkstreams.length === 0 ? (_jsxs("li", { className: panelStyles.emptyPanel, children: [_jsx("div", { className: panelStyles.emptyPanelTitle, children: workstreamEmptyTitle }), _jsx("div", { className: panelStyles.emptyPanelText, children: workstreamEmptyText })] })) : navigatorResults.standaloneWorkstreams.map((workstream) => (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: workstream.id, rowType: "workstream", referenceLabel: formatWorkstreamReference(workstream), item: workstream, ownerOption: workstream.ownerId ? assigneeOptionByValue.get(workstream.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId), active: activeWorkstreamId === workstream.id, isArchived: Boolean(workstream.isArchived), detailOpen: (detail?.type === 'workstream' && detail.item.id === workstream.id)
510
+ }) })) : null] }), _jsxs("div", { className: panelStyles.sectionGroup, children: [_jsx(DisclosureSectionHeader, { label: "Workstreams", count: navigatorResults.standaloneWorkstreams.length, showZeroCount: true, actions: (planningLoadState.collections.workstreams === 'ready' ? (_jsx("button", { type: "button", className: "tf-control-icon", title: "Create workstream", "aria-label": "Create workstream", onClick: onCreateWorkstream, children: _jsx(Plus, { size: 15 }) })) : null), expanded: !workstreamsSectionCollapsed, expandedTitle: "Collapse workstreams", collapsedTitle: "Expand workstreams", onToggle: onToggleWorkstreamsSection, controlsId: !workstreamsSectionCollapsed ? 'planning-workstreams-section' : undefined }), !workstreamsSectionCollapsed ? (_jsx("ul", { id: "planning-workstreams-section", className: panelStyles.treeList, "aria-label": "Standalone workstreams", children: planningLoadState.collections.workstreams === 'error' ? (_jsx("li", { children: _jsx(PlanningFailureState, { compact: true, title: "Workstreams unavailable", message: "Workstreams could not be loaded.", retrying: planningLoadState.isRefreshing, onRetry: onRetryPlanning }) })) : navigatorResults.standaloneWorkstreams.length === 0 ? (_jsxs("li", { className: panelStyles.emptyPanel, children: [_jsx("div", { className: panelStyles.emptyPanelTitle, children: workstreamEmptyTitle }), _jsx("div", { className: panelStyles.emptyPanelText, children: workstreamEmptyText })] })) : navigatorResults.standaloneWorkstreams.map((workstream) => (_jsxs("li", { children: [_jsx(PlanningRow, { rowId: workstream.id, rowType: "workstream", referenceLabel: formatWorkstreamReference(workstream), item: workstream, ownerOption: workstream.ownerId ? assigneeOptionByValue.get(workstream.ownerId) : undefined, ownerOptions: assigneeOptions, onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId), onChangeIdentity: (patch) => onChangePlanningIdentity('workstream', workstream.id, patch), active: activeWorkstreamId === workstream.id, isArchived: Boolean(workstream.isArchived), detailOpen: (detail?.type === 'workstream' && detail.item.id === workstream.id)
516
511
  || (secondaryPane?.kind === 'detail' && secondaryPane.detail.item.id === workstream.id), canExpand: (workstream.tasks || []).length > 0, expanded: expandedWorkstreamIds.has(workstream.id), controlsId: `planning-tasks-${workstream.id}`, onToggleExpand: () => toggleWorkstreamTasks(workstream.id), onToggleScope: () => onSelectWorkstream(workstream.id, null), onOpenDetails: () => onOpenWorkstreamDetails(workstream.id), favorite: planningFavoriteKeys.has(getPlanningFavoriteKey({ type: 'workstream', id: workstream.id })), favoriteReady: navigatorSortReady, onToggleFavorite: () => onTogglePlanningFavorite({ type: 'workstream', id: workstream.id }), onArchiveReady: onArchiveResolvedWorkstream
517
512
  ? () => onArchiveResolvedWorkstream(workstream.id)
518
513
  : undefined, initiativeLinkOptions: linkOptions.initiatives, onLinkInitiative: (option) => onAssignInitiativeToWorkstream(workstream.id, option.referenceLabel) }), renderWorkstreamTasks(workstream)] }, workstream.id))) })) : null] })] }))] }));
@@ -523,7 +518,7 @@ function PlanningLoadingState() {
523
518
  function PlanningFailureState({ title, message, retrying, onRetry, compact = false, }) {
524
519
  return (_jsxs("div", { className: `${panelStyles.failureState} ${compact ? panelStyles.failureStateCompact : ''} tf-surface-inset`.trim(), role: "alert", children: [_jsxs("div", { className: panelStyles.failureCopy, children: [_jsx("strong", { children: title }), _jsx("span", { children: message })] }), _jsx("button", { type: "button", className: "tf-button-ghost tf-button-compact", disabled: retrying, onClick: onRetry, children: retrying ? 'Retrying…' : 'Retry' })] }));
525
520
  }
526
- function PlanningDrawerDetailView({ detail, showArchivedChildren, inlineEditor, selectedChildWorkstreamId, currentWorkspaceId, currentActorId, theme, onOpenNestedWorkstreamDetails, onArchivePlanningTask, onArchiveResolvedWorkstream, onArchiveResolvedEntity, onEdit, onChangeOwner, onChangePlanningOwner, onArchive, onUnarchive, onCreateTaskInWorkstream, onCreateWorkstreamInInitiative, onOpenTaskById, onChangeTaskAssignee, taskReferences, onAssignTaskToWorkstream, onAssignInitiativeToWorkstream, onAttachTaskToWorkstreamByReference, onAttachWorkstreamToInitiativeByReference, onAddPlanningContextFile, onRemovePlanningContextFile, onUpdatePlanningContextCaption, parentInitiative = null, assigneeOptions, linkOptions, showTaskCardStatusLabel = false, taskArrangeMode = 'execution', onTaskArrangeModeChange = () => { }, onReorderWorkstreamTasks, onSetTaskStatus, hydrationState, onRetryHydration, }) {
521
+ function PlanningDrawerDetailView({ detail, showArchivedChildren, inlineEditor, selectedChildWorkstreamId, currentWorkspaceId, currentActorId, theme, onOpenNestedWorkstreamDetails, onArchivePlanningTask, onArchiveResolvedWorkstream, onArchiveResolvedEntity, onEdit, onChangeOwner, onChangePlanningOwner, onChangePlanningIdentity, onArchive, onUnarchive, onCreateTaskInWorkstream, onCreateWorkstreamInInitiative, onOpenTaskById, onChangeTaskAssignee, taskReferences, onAssignTaskToWorkstream, onAssignInitiativeToWorkstream, onAttachTaskToWorkstreamByReference, onAttachWorkstreamToInitiativeByReference, onAddPlanningContextFile, onRemovePlanningContextFile, onUpdatePlanningContextCaption, parentInitiative = null, assigneeOptions, linkOptions, showTaskCardStatusLabel = false, taskArrangeMode = 'execution', onTaskArrangeModeChange = () => { }, onReorderWorkstreamTasks, onSetTaskStatus, hydrationState, onRetryHydration, }) {
527
522
  const inlineEditorFormId = React.useId();
528
523
  const [isAttachingReference, setIsAttachingReference] = React.useState(false);
529
524
  const [showParentLinkPicker, setShowParentLinkPicker] = React.useState(false);
@@ -784,7 +779,9 @@ function PlanningDrawerDetailView({ detail, showArchivedChildren, inlineEditor,
784
779
  : _jsx(Archive, { size: 14, "aria-hidden": "true" }) }), _jsx("button", { type: "button", className: "tf-control-icon", onClick: () => {
785
780
  setShowParentLinkPicker(false);
786
781
  onEdit();
787
- }, title: `Edit ${detailLabel.toLowerCase()} details`, "aria-label": `Edit ${detailLabel.toLowerCase()} details`, children: _jsx(Pencil, { size: 14, "aria-hidden": "true" }) })] })) })] }), archiveEntityConfirmationVisible && archiveDetailState.mode === 'ready' ? (_jsx(PlanningArchiveConfirmation, { entityType: detail.type, title: detail.item.title, activeTaskCount: detail.item.archiveActiveTaskCount, activeWorkstreamCount: detail.item.archiveActiveWorkstreamCount, busy: archiveEntityBusy, onCancel: () => setArchiveEntityConfirmationVisible(false), onConfirm: () => void handleConfirmArchiveEntity() })) : null, detail.type === 'workstream' ? renderRelationshipFeedback('workstream', detail.item.id) : null, detail.type === 'workstream' && !parentInitiativeReferenceLabel && showParentLinkPicker ? (_jsxs("div", { className: panelStyles.relationshipPickerRow, role: "group", "aria-label": "Link workstream to initiative", children: [_jsx(PlanningLinkPicker, { options: linkOptions.initiatives, entityLabel: "initiative", onSelect: handleLinkInitiative, disabled: !onAssignInitiativeToWorkstream || isChangingRelationship }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", disabled: isChangingRelationship, onClick: () => setShowParentLinkPicker(false), title: "Cancel initiative link", "aria-label": "Cancel initiative link", children: _jsx(X, { size: 14, "aria-hidden": "true" }) })] })) : null, inlineEditor ? (_jsx(PlanningDrawerEditor, { editor: inlineEditor.editor, draftTitle: inlineEditor.draftTitle, draftDescription: inlineEditor.draftDescription, draftOwner: inlineEditor.draftOwner, draftInitiativeId: inlineEditor.draftInitiativeId, assigneeOptions: assigneeOptions, initiativeLinkOptions: linkOptions.initiatives, draftInitiativeSummary: inlineEditor.draftInitiativeSummary, onChangeDraftTitle: inlineEditor.onChangeDraftTitle, onChangeDraftDescription: inlineEditor.onChangeDraftDescription, onChangeDraftOwner: inlineEditor.onChangeDraftOwner, onChangeDraftInitiativeId: inlineEditor.onChangeDraftInitiativeId, onCancel: inlineEditor.onCancel, onSubmit: inlineEditor.onSubmit, isSubmitting: inlineEditor.isSubmitting, inline: true, formId: inlineEditorFormId })) : (_jsxs(_Fragment, { children: [_jsx("h3", { className: panelStyles.detailTitle, children: detail.item.title }), _jsx(PlanningEntityDescription, { description: detail.item.description, label: detailLabel, taskReferences: taskReferences, className: `${panelStyles.detailDescription} ${styles.appScrollbar} tf-scrollbar`.trim(), markdownClassName: panelStyles.detailDescriptionMarkdown })] })), _jsxs("div", { className: panelStyles.detailOwnerField, children: [_jsx("span", { className: panelStyles.detailOwnerLabel, children: "Owner" }), _jsx(PlanningOwnerDropdown, { value: ownerValue, disabled: !onChangeOwner || isSavingOwner, onChange: (nextOwnerId) => void handleOwnerChange(nextOwnerId), ariaLabel: `${detailLabel} owner`, options: assigneeOptions, className: `${planningDropdownStyles.control} ${panelStyles.ownerSelect}` })] }), detail.item.taskCount > 0 ? (_jsx(PlanningProgress, { value: detail.item.progressPercent, label: `${detail.item.progressPercent}% resolved`, statusCounts: detail.item.statusCounts })) : (_jsx(PlanningNoTasks, {})), _jsx(PlanningSummaryMeta, { item: detail.item, workstreamCount: detail.type === 'initiative'
782
+ }, title: `Edit ${detailLabel.toLowerCase()} details`, "aria-label": `Edit ${detailLabel.toLowerCase()} details`, children: _jsx(Pencil, { size: 14, "aria-hidden": "true" }) })] })) })] }), archiveEntityConfirmationVisible && archiveDetailState.mode === 'ready' ? (_jsx(PlanningArchiveConfirmation, { entityType: detail.type, title: detail.item.title, activeTaskCount: detail.item.archiveActiveTaskCount, activeWorkstreamCount: detail.item.archiveActiveWorkstreamCount, busy: archiveEntityBusy, onCancel: () => setArchiveEntityConfirmationVisible(false), onConfirm: () => void handleConfirmArchiveEntity() })) : null, detail.type === 'workstream' ? renderRelationshipFeedback('workstream', detail.item.id) : null, detail.type === 'workstream' && !parentInitiativeReferenceLabel && showParentLinkPicker ? (_jsxs("div", { className: panelStyles.relationshipPickerRow, role: "group", "aria-label": "Link workstream to initiative", children: [_jsx(PlanningLinkPicker, { options: linkOptions.initiatives, entityLabel: "initiative", onSelect: handleLinkInitiative, disabled: !onAssignInitiativeToWorkstream || isChangingRelationship }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", disabled: isChangingRelationship, onClick: () => setShowParentLinkPicker(false), title: "Cancel initiative link", "aria-label": "Cancel initiative link", children: _jsx(X, { size: 14, "aria-hidden": "true" }) })] })) : null, inlineEditor ? (_jsx(PlanningDrawerEditor, { editor: inlineEditor.editor, draftTitle: inlineEditor.draftTitle, draftDescription: inlineEditor.draftDescription, draftOwner: inlineEditor.draftOwner, draftInitiativeId: inlineEditor.draftInitiativeId, assigneeOptions: assigneeOptions, initiativeLinkOptions: linkOptions.initiatives, draftInitiativeSummary: inlineEditor.draftInitiativeSummary, onChangeDraftTitle: inlineEditor.onChangeDraftTitle, onChangeDraftDescription: inlineEditor.onChangeDraftDescription, onChangeDraftOwner: inlineEditor.onChangeDraftOwner, onChangeDraftInitiativeId: inlineEditor.onChangeDraftInitiativeId, onCancel: inlineEditor.onCancel, onSubmit: inlineEditor.onSubmit, isSubmitting: inlineEditor.isSubmitting, inline: true, formId: inlineEditorFormId })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: panelStyles.detailTitleRow, children: [_jsx(PlanningVisualIdentity, { entityType: detail.type, entityId: detail.item.id, icon: detail.item.icon, color: detail.item.color, size: "detail", disabled: Boolean(detail.item.isArchived), onChange: onChangePlanningIdentity
783
+ ? (patch) => onChangePlanningIdentity(detail.type, detail.item.id, patch)
784
+ : undefined }), _jsx("h3", { className: panelStyles.detailTitle, children: detail.item.title })] }), _jsx(PlanningEntityDescription, { description: detail.item.description, label: detailLabel, taskReferences: taskReferences, className: `${panelStyles.detailDescription} ${styles.appScrollbar} tf-scrollbar`.trim(), markdownClassName: panelStyles.detailDescriptionMarkdown })] })), _jsxs("div", { className: panelStyles.detailOwnerField, children: [_jsx("span", { className: panelStyles.detailOwnerLabel, children: "Owner" }), _jsx(PlanningOwnerDropdown, { value: ownerValue, disabled: !onChangeOwner || isSavingOwner, onChange: (nextOwnerId) => void handleOwnerChange(nextOwnerId), ariaLabel: `${detailLabel} owner`, options: assigneeOptions, className: `${planningDropdownStyles.control} ${panelStyles.ownerSelect}` })] }), detail.item.taskCount > 0 ? (_jsx(PlanningProgress, { value: detail.item.progressPercent, label: `${detail.item.progressPercent}% resolved`, statusCounts: detail.item.statusCounts })) : (_jsx(PlanningNoTasks, {})), _jsx(PlanningSummaryMeta, { item: detail.item, workstreamCount: detail.type === 'initiative'
788
785
  ? detail.item.workstreamCount ?? detail.item.workstreams.length
789
786
  : undefined, className: panelStyles.detailSummaryMeta }), detail.item.taskCount > 0 ? (_jsx("span", { className: panelStyles.passiveGuidance, children: "Lifetime progress includes archived tasks." })) : null] }), _jsxs("div", { ref: setChildDropRef, className: `${panelStyles.listCard} ${canDropTask || canDropWorkstream ? panelStyles.sectionDropReady : ''} ${isChildDropOver ? panelStyles.sectionDropActive : ''} ${canDropTask || canDropWorkstream ? panelStyles.sectionDropMode : ''}`.trim(), children: [_jsxs("div", { className: panelStyles.sectionHeaderRow, children: [_jsxs("div", { className: panelStyles.sectionTitle, children: [childLabel, " (", visibleChildCount, ")"] }), _jsx("div", { className: panelStyles.headerActionGroup, children: detail.type === 'initiative' ? (_jsx("button", { type: "button", className: "tf-control-icon", title: "Create workstream in this initiative", "aria-label": "Create workstream in this initiative", onClick: () => onCreateWorkstreamInInitiative?.(detail.item.id), children: _jsx(Plus, { size: 15 }) })) : (_jsx("button", { type: "button", className: "tf-control-icon", title: "Create task in this workstream", "aria-label": "Create task in this workstream", onClick: () => onCreateTaskInWorkstream?.(detail.item.id), children: _jsx(Plus, { size: 15 }) })) })] }), _jsx("div", { className: panelStyles.linkPickerRow, children: _jsx(PlanningLinkPicker, { options: availableLinkOptions, entityLabel: detail.type === 'initiative' ? 'workstream' : 'task', onSelect: handleAttachReference, disabled: !hasAttachReferenceHandler || isAttachingReference }) }), detail.type === 'workstream' ? (_jsx(PlanningTaskArrangeControl, { value: taskArrangeMode, onChange: onTaskArrangeModeChange })) : null, detail.type === 'initiative' ? (visibleChildItems.length > 0 ? visibleChildItems.map((workstream) => {
790
787
  const workstreamReferenceLabel = formatWorkstreamReference(workstream);
@@ -822,6 +819,8 @@ function PlanningDrawerDetailView({ detail, showArchivedChildren, inlineEditor,
822
819
  ? toPlanningAssigneeOption(assigneeOptionByValue.get(workstream.ownerId))
823
820
  : undefined, ownerOptions: assigneeOptions.map(toPlanningAssigneeOption), onChangeOwner: onChangePlanningOwner
824
821
  ? (ownerId) => onChangePlanningOwner('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId)
822
+ : undefined, onChangeIdentity: onChangePlanningIdentity
823
+ ? (patch) => onChangePlanningIdentity('workstream', workstream.id, patch)
825
824
  : undefined }) })] }) }, workstream.id));
826
825
  }) : (_jsx("div", { className: panelStyles.passiveGuidance, children: "No workstreams are linked to this initiative." }))) : (visibleTaskItems.length > 0 ? (_jsx(PlanningTaskOrderList, { tasks: visibleTaskItems, mode: taskArrangeMode, onReorder: onReorderWorkstreamTasks
827
826
  ? (taskIds) => onReorderWorkstreamTasks(detail.item.id, mergeVisiblePlanningTaskOrder(arrangePlanningTasks(taskItems, 'execution'), taskIds))
@@ -855,7 +854,7 @@ function PlanningDrawerDetailView({ detail, showArchivedChildren, inlineEditor,
855
854
  }, title: "Archive task", "aria-label": `Archive task ${referenceLabel || task.title}`, children: _jsx(Archive, { size: 14, "aria-hidden": "true" }) })) : undefined }) }, task.id));
856
855
  } })) : (_jsx("div", { className: panelStyles.passiveGuidance, children: "No tasks are linked to this workstream." }))), detachedRelationshipRecovery] }), _jsx("div", { className: panelStyles.listCard, children: _jsx(PlanningEntityContext, { entityType: detail.type, entityId: detail.item.id, referenceLabel: detailReferenceLabel, workspaceId: currentWorkspaceId, attachments: detail.item.attachments, readOnly: Boolean(detail.item.isArchived), onAddAttachment: (file) => onAddPlanningContextFile?.(detail.type, detail.item.id, file), onRemoveAttachment: (index) => onRemovePlanningContextFile?.(detail.type, detail.item.id, index), onUpdateAttachmentCaption: (index, caption) => (onUpdatePlanningContextCaption?.(detail.type, detail.item.id, index, caption)) }) }), _jsx("div", { className: panelStyles.listCard, children: _jsx(PlanningEntityActivity, { entityType: detail.type, item: detail.item, assigneeOptions: assigneeOptions.map(toPlanningAssigneeOption), currentActorId: currentActorId, taskReferences: taskReferences, parentInitiative: parentInitiative, listClassName: panelStyles.activityTimelineList, emptyClassName: panelStyles.activityTimelineEmpty, hydrationState: hydrationState, onRetryHydration: onRetryHydration }) }), _jsx(PlanningUnlinkConfirmation, { item: pendingUnlink, busy: isChangingRelationship, theme: theme, onCancel: () => setPendingUnlink(null), onConfirm: () => void handleConfirmUnlink() })] }));
857
856
  }
858
- function PlanningDrawerEditor({ editor, draftTitle, draftDescription, draftOwner, draftInitiativeId, assigneeOptions, initiativeLinkOptions, draftInitiativeSummary, onChangeDraftTitle, onChangeDraftDescription, onChangeDraftOwner, onChangeDraftInitiativeId, onCancel, onSubmit, isSubmitting, inline = false, formId, }) {
857
+ function PlanningDrawerEditor({ editor, draftTitle, draftDescription, draftOwner, draftInitiativeId, draftIcon, draftColor, assigneeOptions, initiativeLinkOptions, draftInitiativeSummary, onChangeDraftTitle, onChangeDraftDescription, onChangeDraftOwner, onChangeDraftInitiativeId, onChangeDraftIcon, onChangeDraftColor, onCancel, onSubmit, isSubmitting, inline = false, formId, }) {
859
858
  const entityLabel = editor.entityType === 'initiative' ? 'Initiative' : 'Workstream';
860
859
  const titleInputId = React.useId();
861
860
  const titleErrorId = React.useId();
@@ -881,7 +880,12 @@ function PlanningDrawerEditor({ editor, draftTitle, draftDescription, draftOwner
881
880
  event.preventDefault();
882
881
  onCancel();
883
882
  }, [inline, isSubmitting, onCancel]);
884
- return (_jsxs("form", { id: formId, className: `${panelStyles.editorCard} ${inline ? panelStyles.inlineEditorCard : ''}`.trim(), onSubmit: handleSubmit, onKeyDown: handleKeyDown, noValidate: true, children: [_jsxs("div", { className: panelStyles.editorField, children: [_jsxs("label", { className: panelStyles.editorLabel, htmlFor: titleInputId, children: [entityLabel, " title"] }), _jsx("input", { ref: titleInputRef, id: titleInputId, "data-planning-editor-title": true, className: styles.input, disabled: isSubmitting, required: true, "aria-invalid": titleError ? 'true' : undefined, "aria-describedby": titleError ? titleErrorId : undefined, value: draftTitle, onChange: (event) => {
883
+ return (_jsxs("form", { id: formId, className: `${panelStyles.editorCard} ${inline ? panelStyles.inlineEditorCard : ''}`.trim(), onSubmit: handleSubmit, onKeyDown: handleKeyDown, noValidate: true, children: [editor.mode === 'create' && onChangeDraftIcon && onChangeDraftColor ? (_jsxs("div", { className: panelStyles.editorIdentityField, children: [_jsx(PlanningVisualIdentity, { entityType: editor.entityType, entityId: "create-preview", icon: draftIcon, color: draftColor || 'blue', size: "detail", onChange: (patch) => {
884
+ if (Object.prototype.hasOwnProperty.call(patch, 'icon'))
885
+ onChangeDraftIcon(patch.icon ?? null);
886
+ if (Object.prototype.hasOwnProperty.call(patch, 'color'))
887
+ onChangeDraftColor(patch.color ?? null);
888
+ } }), _jsx("span", { children: "Choose an icon and color" })] })) : null, _jsxs("div", { className: panelStyles.editorField, children: [_jsxs("label", { className: panelStyles.editorLabel, htmlFor: titleInputId, children: [entityLabel, " title"] }), _jsx("input", { ref: titleInputRef, id: titleInputId, "data-planning-editor-title": true, className: styles.input, disabled: isSubmitting, required: true, "aria-invalid": titleError ? 'true' : undefined, "aria-describedby": titleError ? titleErrorId : undefined, value: draftTitle, onChange: (event) => {
885
889
  if (titleError)
886
890
  setTitleError(null);
887
891
  onChangeDraftTitle(event.target.value);
@@ -889,7 +893,7 @@ function PlanningDrawerEditor({ editor, draftTitle, draftDescription, draftOwner
889
893
  ? 'Describe the broader outcome this initiative is meant to achieve.'
890
894
  : 'Describe the lane of work this workstream will coordinate.', rows: 5 })] }), editor.entityType === 'workstream' && (_jsxs("div", { className: panelStyles.editorField, children: [_jsx("span", { className: panelStyles.editorLabel, children: "Initiative" }), _jsxs("div", { className: panelStyles.editorRelationshipRow, children: [_jsx(PlanningLinkPicker, { options: initiativeLinkOptions, selectedId: draftInitiativeSummary?.id || '', entityLabel: "initiative", disabled: isSubmitting, onSelect: (option) => onChangeDraftInitiativeId(option.referenceLabel) }), draftInitiativeId.trim() ? (_jsx("button", { type: "button", className: "tf-button-ghost tf-button-compact", disabled: isSubmitting, onClick: () => onChangeDraftInitiativeId(''), children: "Remove" })) : null] })] })), !inline ? _jsxs("div", { className: panelStyles.editorField, children: [_jsxs("span", { className: panelStyles.editorLabel, children: [entityLabel, " owner"] }), _jsx(PlanningOwnerDropdown, { disabled: isSubmitting, value: draftOwner, onChange: onChangeDraftOwner, ariaLabel: `${entityLabel} owner`, options: assigneeOptions, className: panelStyles.editorSelect })] }) : null, !inline ? _jsxs("div", { className: panelStyles.editorActions, children: [_jsx("button", { type: "button", className: styles.secondaryHeaderBtn, onClick: onCancel, disabled: isSubmitting, children: "Cancel" }), _jsx("button", { type: "submit", className: styles.primaryUpdateBtn, disabled: isSubmitting, children: submitLabel })] }) : null] }));
891
895
  }
892
- export function PlanningDrawer({ open, leftOffset = 0, returnFocusRef, onWidthChange, initiatives, standaloneWorkstreams, planningLoadState, onRetryPlanning, taskScope, activeInitiativeId, activeWorkstreamId, navigatorSort, navigatorSortReady, onNavigatorSortChange, taskArrangeMode = 'execution', onTaskArrangeModeChange = () => { }, onReorderWorkstreamTasks, planningFavorites, onTogglePlanningFavorite, favoritesSectionCollapsed, initiativesSectionCollapsed, workstreamsSectionCollapsed, onToggleFavoritesSection, onToggleInitiativesSection, onToggleWorkstreamsSection, expandedInitiativeIds, detail, editor, secondaryEditor = null, secondaryPane, primaryHydrationState, secondaryHydrationState, onRetryPrimaryHydration, onRetrySecondaryHydration, currentWorkspaceId, currentOwnerId, theme, assigneeOptions, linkOptions, showTaskCardStatusLabel = false, draftInitiativeSummary, draftTitle, draftDescription, draftOwner, draftInitiativeId, onChangeDraftTitle, onChangeDraftDescription, onChangeDraftOwner, onChangeDraftInitiativeId, onCollapseTreePane, onExpandTreePane, onCollapsePrimaryPane, onExpandPrimaryPane, onCollapseSecondaryPane, onExpandSecondaryPane, onBackFromSecondary, treeCollapsed, primaryCollapsed, secondaryCollapsed, onCancelEditor, onCancelSecondaryEditor, onSubmitEditor, isSubmittingEditor, onCreateInitiative, onCreateWorkstream, onToggleInitiative, onSelectInitiative, onSelectWorkstream, onOpenInitiativeDetails, onOpenWorkstreamDetails, onOpenNestedWorkstreamDetails, onEditInitiative, onEditWorkstream, onChangePlanningOwner, onChangeTaskAssignee, onArchiveInitiative, onUnarchiveInitiative, onArchiveWorkstream, onUnarchiveWorkstream, onArchivePlanningTask, onArchiveResolvedWorkstream, onArchiveResolvedInitiative, onCreateTaskInWorkstream, onCreateWorkstreamInInitiative, onAssignInitiativeToWorkstream, onOpenTaskById, onSetTaskStatus, taskReferences, onAssignTaskToWorkstream, onAttachTaskToWorkstreamByReference, onAttachWorkstreamToInitiativeByReference, onAddPlanningContextFile, onRemovePlanningContextFile, onUpdatePlanningContextCaption, }) {
896
+ export function PlanningDrawer({ open, leftOffset = 0, returnFocusRef, onWidthChange, initiatives, standaloneWorkstreams, planningLoadState, onRetryPlanning, taskScope, activeInitiativeId, activeWorkstreamId, navigatorSort, navigatorSortReady, onNavigatorSortChange, taskArrangeMode = 'execution', onTaskArrangeModeChange = () => { }, onReorderWorkstreamTasks, planningFavorites, onTogglePlanningFavorite, favoritesSectionCollapsed, initiativesSectionCollapsed, workstreamsSectionCollapsed, onToggleFavoritesSection, onToggleInitiativesSection, onToggleWorkstreamsSection, expandedInitiativeIds, detail, editor, secondaryEditor = null, secondaryPane, primaryHydrationState, secondaryHydrationState, onRetryPrimaryHydration, onRetrySecondaryHydration, currentWorkspaceId, currentOwnerId, theme, assigneeOptions, linkOptions, showTaskCardStatusLabel = false, draftInitiativeSummary, draftTitle, draftDescription, draftOwner, draftInitiativeId, draftIcon = null, draftColor = null, onChangeDraftTitle, onChangeDraftDescription, onChangeDraftOwner, onChangeDraftInitiativeId, onChangeDraftIcon = () => { }, onChangeDraftColor = () => { }, onCollapseTreePane, onExpandTreePane, onCollapsePrimaryPane, onExpandPrimaryPane, onCollapseSecondaryPane, onExpandSecondaryPane, onBackFromSecondary, treeCollapsed, primaryCollapsed, secondaryCollapsed, onCancelEditor, onCancelSecondaryEditor, onSubmitEditor, isSubmittingEditor, onCreateInitiative, onCreateWorkstream, onToggleInitiative, onSelectInitiative, onSelectWorkstream, onOpenInitiativeDetails, onOpenWorkstreamDetails, onOpenNestedWorkstreamDetails, onEditInitiative, onEditWorkstream, onChangePlanningOwner, onChangePlanningIdentity = () => { }, onChangeTaskAssignee, onArchiveInitiative, onUnarchiveInitiative, onArchiveWorkstream, onUnarchiveWorkstream, onArchivePlanningTask, onArchiveResolvedWorkstream, onArchiveResolvedInitiative, onCreateTaskInWorkstream, onCreateWorkstreamInInitiative, onAssignInitiativeToWorkstream, onOpenTaskById, onSetTaskStatus, taskReferences, onAssignTaskToWorkstream, onAttachTaskToWorkstreamByReference, onAttachWorkstreamToInitiativeByReference, onAddPlanningContextFile, onRemovePlanningContextFile, onUpdatePlanningContextCaption, }) {
893
897
  const primaryInlineEditor = editor?.mode === 'edit'
894
898
  && detail
895
899
  && editor.entityType === detail.type
@@ -1088,7 +1092,7 @@ export function PlanningDrawer({ open, leftOffset = 0, returnFocusRef, onWidthCh
1088
1092
  pointerEvents: open ? 'auto' : 'none',
1089
1093
  transition: 'left 220ms cubic-bezier(0.4, 0, 0.2, 1)',
1090
1094
  willChange: 'left',
1091
- }, children: _jsxs("div", { className: panelStyles.drawerBody, children: [showTreePane && (effectiveTreeCollapsed ? (_jsx(CollapsedPane, { label: "Planning", onExpand: onExpandTreePane })) : (_jsxs("div", { ref: treePaneRef, "data-planning-pane": "tree", className: `${panelStyles.paneShell} ${styles.appScrollbar} tf-scrollbar ${panelStyles.treePane} ${hasPrimaryPane && !primaryCollapsed ? panelStyles.treePaneSplit : ''}`.trim(), style: paneWidthStyle(layoutMode === 'narrow' ? drawerWidth : PLANNING_DRAWER_TREE_WIDTH_PX), children: [_jsxs("div", { className: panelStyles.paneHeader, children: [_jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: "Planning" }), _jsxs("div", { className: panelStyles.headerActionGroup, children: [_jsx(ArchiveVisibilityToggle, { visible: showArchivedPlanning, disabled: taskScope === 'deleted' || archivedPlanningItemCount === 0, disabledLabel: taskScope === 'deleted' ? 'Archive visibility unavailable in Trash' : undefined, itemLabel: "planning items", onToggle: () => setShowArchivedPlanning((current) => !current) }), wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapseTreePane, "aria-label": "Collapse Planning pane", title: "Collapse Planning pane", children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null] })] }), _jsx("div", { className: panelStyles.paneContent, "aria-busy": planningLoadState.status === 'loading' || planningLoadState.isRefreshing, children: _jsx(PlanningDrawerList, { initiatives: initiatives, standaloneWorkstreams: standaloneWorkstreams, planningLoadState: planningLoadState, taskScope: taskScope, showArchivedPlanning: showArchivedPlanning, currentOwnerId: currentOwnerId, assigneeOptions: assigneeOptions, showTaskCardStatusLabel: showTaskCardStatusLabel, taskArrangeMode: taskArrangeMode, activeInitiativeId: activeInitiativeId, activeWorkstreamId: activeWorkstreamId, navigatorSort: navigatorSort, navigatorSortReady: navigatorSortReady, onNavigatorSortChange: onNavigatorSortChange, planningFavorites: planningFavorites, onTogglePlanningFavorite: onTogglePlanningFavorite, favoritesSectionCollapsed: favoritesSectionCollapsed, initiativesSectionCollapsed: initiativesSectionCollapsed, workstreamsSectionCollapsed: workstreamsSectionCollapsed, onToggleFavoritesSection: onToggleFavoritesSection, onToggleInitiativesSection: onToggleInitiativesSection, onToggleWorkstreamsSection: onToggleWorkstreamsSection, expandedInitiativeIds: expandedInitiativeIds, detail: detail, secondaryPane: secondaryPane, onCreateInitiative: onCreateInitiative, onCreateWorkstream: onCreateWorkstream, onToggleInitiative: onToggleInitiative, onSelectInitiative: onSelectInitiative, onSelectWorkstream: onSelectWorkstream, onOpenInitiativeDetails: onOpenInitiativeDetails, onOpenWorkstreamDetails: onOpenWorkstreamDetails, onOpenNestedWorkstreamDetails: onOpenNestedWorkstreamDetails, onOpenTaskById: onOpenTaskById, onSetTaskStatus: onSetTaskStatus, onChangePlanningOwner: onChangePlanningOwner, onChangeTaskAssignee: onChangeTaskAssignee, onArchivePlanningTask: onArchivePlanningTask, onArchiveResolvedWorkstream: onArchiveResolvedWorkstream, onArchiveResolvedInitiative: onArchiveResolvedInitiative, linkOptions: linkOptions, onAssignInitiativeToWorkstream: onAssignInitiativeToWorkstream, onRetryPlanning: onRetryPlanning }) })] }))), wideLayout && !primaryIsInitiative && (initiativeRelationshipExpanded ? (_jsx(RelationshipPane, { label: "Initiative", title: initiativeRelationship.title, description: initiativeRelationship.description, action: initiativeRelationship.action, onCollapse: () => setInitiativeRelationshipExpanded(false), paneRef: initiativeRelationshipPaneRef })) : (_jsx(CollapsedPane, { label: "Initiative", muted: !hasInitiativeRelationship, onExpand: () => setInitiativeRelationshipExpanded(true) }))), showPrimaryPane && (effectivePrimaryCollapsed ? (_jsx(CollapsedPane, { label: primaryEntityType === 'initiative' ? 'Initiative' : 'Workstream', onExpand: onExpandPrimaryPane })) : (_jsxs("div", { ref: primaryPaneRef, "data-planning-pane": "primary", className: `${panelStyles.paneShell} ${styles.appScrollbar} tf-scrollbar ${panelStyles.detailPane}`.trim(), style: paneWidthStyle(wideLayout ? PLANNING_DRAWER_DETAIL_WIDTH_PX : adaptiveDetailWidth), children: [_jsxs("div", { className: panelStyles.paneHeader, children: [layoutMode === 'narrow' ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: handleBackFromPrimary, "aria-label": "Back to Planning", title: "Back to Planning", children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null, _jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: primaryPaneLabel }), _jsxs("div", { className: panelStyles.headerActionGroup, children: [primaryArchiveDetail ? (_jsx(ArchiveVisibilityToggle, { visible: archivedDetailVisibility[primaryArchiveDetail.type], disabled: countArchivedDetailChildren(primaryArchiveDetail) === 0, itemLabel: primaryArchiveDetail.type === 'initiative' ? 'workstreams' : 'tasks', onToggle: () => toggleArchivedDetailVisibility(primaryArchiveDetail.type) })) : null, wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapsePrimaryPane, "aria-label": `Collapse ${primaryPaneLabel} pane`, title: `Collapse ${primaryPaneLabel} pane`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null] })] }), _jsx("div", { className: panelStyles.paneContent, "aria-busy": primaryHydrationState?.status === 'loading', children: dedicatedPrimaryEditor ? (_jsx(PlanningDrawerEditor, { editor: dedicatedPrimaryEditor, draftTitle: draftTitle, draftDescription: draftDescription, draftOwner: draftOwner, draftInitiativeId: draftInitiativeId, assigneeOptions: assigneeOptions, initiativeLinkOptions: linkOptions.initiatives, draftInitiativeSummary: draftInitiativeSummary, onChangeDraftTitle: onChangeDraftTitle, onChangeDraftDescription: onChangeDraftDescription, onChangeDraftOwner: onChangeDraftOwner, onChangeDraftInitiativeId: onChangeDraftInitiativeId, onCancel: onCancelEditor, onSubmit: onSubmitEditor, isSubmitting: isSubmittingEditor })) : detail ? (_jsx(PlanningDrawerDetailView, { detail: detail, showArchivedChildren: archivedDetailVisibility[detail.type], inlineEditor: primaryInlineEditor ? {
1095
+ }, children: _jsxs("div", { className: panelStyles.drawerBody, children: [showTreePane && (effectiveTreeCollapsed ? (_jsx(CollapsedPane, { label: "Planning", onExpand: onExpandTreePane })) : (_jsxs("div", { ref: treePaneRef, "data-planning-pane": "tree", className: `${panelStyles.paneShell} ${styles.appScrollbar} tf-scrollbar ${panelStyles.treePane} ${hasPrimaryPane && !primaryCollapsed ? panelStyles.treePaneSplit : ''}`.trim(), style: paneWidthStyle(layoutMode === 'narrow' ? drawerWidth : PLANNING_DRAWER_TREE_WIDTH_PX), children: [_jsxs("div", { className: panelStyles.paneHeader, children: [_jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: "Planning" }), _jsxs("div", { className: panelStyles.headerActionGroup, children: [_jsx(ArchiveVisibilityToggle, { visible: showArchivedPlanning, disabled: taskScope === 'deleted' || archivedPlanningItemCount === 0, disabledLabel: taskScope === 'deleted' ? 'Archive visibility unavailable in Trash' : undefined, itemLabel: "planning items", onToggle: () => setShowArchivedPlanning((current) => !current) }), wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapseTreePane, "aria-label": "Collapse Planning pane", title: "Collapse Planning pane", children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null] })] }), _jsx("div", { className: panelStyles.paneContent, "aria-busy": planningLoadState.status === 'loading' || planningLoadState.isRefreshing, children: _jsx(PlanningDrawerList, { initiatives: initiatives, standaloneWorkstreams: standaloneWorkstreams, planningLoadState: planningLoadState, taskScope: taskScope, showArchivedPlanning: showArchivedPlanning, currentOwnerId: currentOwnerId, assigneeOptions: assigneeOptions, showTaskCardStatusLabel: showTaskCardStatusLabel, taskArrangeMode: taskArrangeMode, activeInitiativeId: activeInitiativeId, activeWorkstreamId: activeWorkstreamId, navigatorSort: navigatorSort, navigatorSortReady: navigatorSortReady, onNavigatorSortChange: onNavigatorSortChange, planningFavorites: planningFavorites, onTogglePlanningFavorite: onTogglePlanningFavorite, favoritesSectionCollapsed: favoritesSectionCollapsed, initiativesSectionCollapsed: initiativesSectionCollapsed, workstreamsSectionCollapsed: workstreamsSectionCollapsed, onToggleFavoritesSection: onToggleFavoritesSection, onToggleInitiativesSection: onToggleInitiativesSection, onToggleWorkstreamsSection: onToggleWorkstreamsSection, expandedInitiativeIds: expandedInitiativeIds, detail: detail, secondaryPane: secondaryPane, onCreateInitiative: onCreateInitiative, onCreateWorkstream: onCreateWorkstream, onToggleInitiative: onToggleInitiative, onSelectInitiative: onSelectInitiative, onSelectWorkstream: onSelectWorkstream, onOpenInitiativeDetails: onOpenInitiativeDetails, onOpenWorkstreamDetails: onOpenWorkstreamDetails, onOpenNestedWorkstreamDetails: onOpenNestedWorkstreamDetails, onOpenTaskById: onOpenTaskById, onSetTaskStatus: onSetTaskStatus, onChangePlanningOwner: onChangePlanningOwner, onChangePlanningIdentity: onChangePlanningIdentity, onChangeTaskAssignee: onChangeTaskAssignee, onArchivePlanningTask: onArchivePlanningTask, onArchiveResolvedWorkstream: onArchiveResolvedWorkstream, onArchiveResolvedInitiative: onArchiveResolvedInitiative, linkOptions: linkOptions, onAssignInitiativeToWorkstream: onAssignInitiativeToWorkstream, onRetryPlanning: onRetryPlanning }) })] }))), wideLayout && !primaryIsInitiative && (initiativeRelationshipExpanded ? (_jsx(RelationshipPane, { label: "Initiative", title: initiativeRelationship.title, description: initiativeRelationship.description, action: initiativeRelationship.action, onCollapse: () => setInitiativeRelationshipExpanded(false), paneRef: initiativeRelationshipPaneRef })) : (_jsx(CollapsedPane, { label: "Initiative", muted: !hasInitiativeRelationship, onExpand: () => setInitiativeRelationshipExpanded(true) }))), showPrimaryPane && (effectivePrimaryCollapsed ? (_jsx(CollapsedPane, { label: primaryEntityType === 'initiative' ? 'Initiative' : 'Workstream', onExpand: onExpandPrimaryPane })) : (_jsxs("div", { ref: primaryPaneRef, "data-planning-pane": "primary", className: `${panelStyles.paneShell} ${styles.appScrollbar} tf-scrollbar ${panelStyles.detailPane}`.trim(), style: paneWidthStyle(wideLayout ? PLANNING_DRAWER_DETAIL_WIDTH_PX : adaptiveDetailWidth), children: [_jsxs("div", { className: panelStyles.paneHeader, children: [layoutMode === 'narrow' ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: handleBackFromPrimary, "aria-label": "Back to Planning", title: "Back to Planning", children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null, _jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: primaryPaneLabel }), _jsxs("div", { className: panelStyles.headerActionGroup, children: [primaryArchiveDetail ? (_jsx(ArchiveVisibilityToggle, { visible: archivedDetailVisibility[primaryArchiveDetail.type], disabled: countArchivedDetailChildren(primaryArchiveDetail) === 0, itemLabel: primaryArchiveDetail.type === 'initiative' ? 'workstreams' : 'tasks', onToggle: () => toggleArchivedDetailVisibility(primaryArchiveDetail.type) })) : null, wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapsePrimaryPane, "aria-label": `Collapse ${primaryPaneLabel} pane`, title: `Collapse ${primaryPaneLabel} pane`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null] })] }), _jsx("div", { className: panelStyles.paneContent, "aria-busy": primaryHydrationState?.status === 'loading', children: dedicatedPrimaryEditor ? (_jsx(PlanningDrawerEditor, { editor: dedicatedPrimaryEditor, draftTitle: draftTitle, draftDescription: draftDescription, draftOwner: draftOwner, draftInitiativeId: draftInitiativeId, draftIcon: draftIcon, draftColor: draftColor, assigneeOptions: assigneeOptions, initiativeLinkOptions: linkOptions.initiatives, draftInitiativeSummary: draftInitiativeSummary, onChangeDraftTitle: onChangeDraftTitle, onChangeDraftDescription: onChangeDraftDescription, onChangeDraftOwner: onChangeDraftOwner, onChangeDraftInitiativeId: onChangeDraftInitiativeId, onChangeDraftIcon: onChangeDraftIcon, onChangeDraftColor: onChangeDraftColor, onCancel: onCancelEditor, onSubmit: onSubmitEditor, isSubmitting: isSubmittingEditor })) : detail ? (_jsx(PlanningDrawerDetailView, { detail: detail, showArchivedChildren: archivedDetailVisibility[detail.type], inlineEditor: primaryInlineEditor ? {
1092
1096
  editor: primaryInlineEditor,
1093
1097
  draftTitle,
1094
1098
  draftDescription,
@@ -1108,13 +1112,13 @@ export function PlanningDrawer({ open, leftOffset = 0, returnFocusRef, onWidthCh
1108
1112
  ? onArchiveResolvedInitiative
1109
1113
  : onArchiveResolvedWorkstream, onOpenNestedWorkstreamDetails: detail.type === 'initiative' ? onOpenNestedWorkstreamDetails : undefined, onCreateTaskInWorkstream: detail.type === 'workstream' ? onCreateTaskInWorkstream : undefined, onCreateWorkstreamInInitiative: detail.type === 'initiative' ? onCreateWorkstreamInInitiative : undefined, onOpenTaskById: detail.type === 'workstream' ? onOpenTaskById : undefined, onChangeTaskAssignee: detail.type === 'workstream' ? onChangeTaskAssignee : undefined, taskReferences: taskReferences, onAssignTaskToWorkstream: detail.type === 'workstream' ? onAssignTaskToWorkstream : undefined, onAssignInitiativeToWorkstream: onAssignInitiativeToWorkstream, onAttachTaskToWorkstreamByReference: detail.type === 'workstream' ? onAttachTaskToWorkstreamByReference : undefined, onAttachWorkstreamToInitiativeByReference: detail.type === 'initiative' ? onAttachWorkstreamToInitiativeByReference : undefined, parentInitiative: detail.type === 'workstream' ? resolveParentInitiative(detail.item) : null, onEdit: () => detail.type === 'initiative'
1110
1114
  ? onEditInitiative(detail.item.id)
1111
- : onEditWorkstream(detail.item.id), onChangeOwner: (ownerId) => onChangePlanningOwner(detail.type, detail.item.id, ownerId), onChangePlanningOwner: onChangePlanningOwner, onArchive: () => detail.type === 'initiative'
1115
+ : onEditWorkstream(detail.item.id), onChangeOwner: (ownerId) => onChangePlanningOwner(detail.type, detail.item.id, ownerId), onChangePlanningOwner: onChangePlanningOwner, onChangePlanningIdentity: onChangePlanningIdentity, onArchive: () => detail.type === 'initiative'
1112
1116
  ? onArchiveInitiative(detail.item.id)
1113
1117
  : onArchiveWorkstream(detail.item.id), onUnarchive: () => detail.type === 'initiative'
1114
1118
  ? onUnarchiveInitiative(detail.item.id)
1115
1119
  : onUnarchiveWorkstream(detail.item.id), onAddPlanningContextFile: onAddPlanningContextFile, onRemovePlanningContextFile: onRemovePlanningContextFile, onUpdatePlanningContextCaption: onUpdatePlanningContextCaption })) : null })] }))), wideLayout && !primaryIsWorkstream && !hasSecondaryPane && (workstreamRelationshipExpanded ? (_jsx(RelationshipPane, { label: "Workstream", title: workstreamRelationship.title, description: workstreamRelationship.description, action: workstreamRelationship.action, onCollapse: () => setWorkstreamRelationshipExpanded(false), paneRef: workstreamRelationshipPaneRef })) : (_jsx(CollapsedPane, { label: "Workstream", muted: true, onExpand: () => setWorkstreamRelationshipExpanded(true) }))), showSecondaryPane && (effectiveSecondaryCollapsed ? (_jsx(CollapsedPane, { label: "Workstream", onExpand: onExpandSecondaryPane })) : (_jsxs("div", { ref: secondaryPaneRef, "data-planning-pane": "secondary", className: `${panelStyles.paneShell} ${styles.appScrollbar} tf-scrollbar ${panelStyles.detailPane}`.trim(), style: paneWidthStyle(wideLayout ? PLANNING_DRAWER_DETAIL_WIDTH_PX : adaptiveDetailWidth), children: [_jsxs("div", { className: panelStyles.paneHeader, children: [!wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: secondaryInlineEditor
1116
1120
  ? (onCancelSecondaryEditor || onBackFromSecondary)
1117
- : onBackFromSecondary, "aria-label": secondaryInlineEditor ? 'Cancel workstream editing' : `Back to ${primaryPaneLabel}`, title: secondaryInlineEditor ? 'Cancel workstream editing' : `Back to ${primaryPaneLabel}`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null, _jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: secondaryPaneLabel }), _jsxs("div", { className: panelStyles.headerActionGroup, children: [secondaryArchiveDetail ? (_jsx(ArchiveVisibilityToggle, { visible: archivedDetailVisibility.workstream, disabled: countArchivedDetailChildren(secondaryArchiveDetail) === 0, itemLabel: "tasks", onToggle: () => toggleArchivedDetailVisibility('workstream') })) : null, wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapseSecondaryPane, "aria-label": `Collapse ${secondaryPaneLabel} pane`, title: `Collapse ${secondaryPaneLabel} pane`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null] })] }), _jsx("div", { className: panelStyles.paneContent, "aria-busy": secondaryHydrationState?.status === 'loading', children: secondaryPane?.kind === 'editor' ? (_jsx(PlanningDrawerEditor, { editor: secondaryPane.editor, draftTitle: draftTitle, draftDescription: draftDescription, draftOwner: draftOwner, draftInitiativeId: draftInitiativeId, assigneeOptions: assigneeOptions, initiativeLinkOptions: linkOptions.initiatives, draftInitiativeSummary: draftInitiativeSummary, onChangeDraftTitle: onChangeDraftTitle, onChangeDraftDescription: onChangeDraftDescription, onChangeDraftOwner: onChangeDraftOwner, onChangeDraftInitiativeId: onChangeDraftInitiativeId, onCancel: onBackFromSecondary, onSubmit: onSubmitEditor, isSubmitting: isSubmittingEditor })) : secondaryPane ? (_jsx(PlanningDrawerDetailView, { detail: secondaryPane.detail, showArchivedChildren: archivedDetailVisibility.workstream, inlineEditor: secondaryInlineEditor ? {
1121
+ : onBackFromSecondary, "aria-label": secondaryInlineEditor ? 'Cancel workstream editing' : `Back to ${primaryPaneLabel}`, title: secondaryInlineEditor ? 'Cancel workstream editing' : `Back to ${primaryPaneLabel}`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null, _jsx("h2", { className: panelStyles.paneHeaderLabel, tabIndex: -1, "data-planning-pane-heading": true, children: secondaryPaneLabel }), _jsxs("div", { className: panelStyles.headerActionGroup, children: [secondaryArchiveDetail ? (_jsx(ArchiveVisibilityToggle, { visible: archivedDetailVisibility.workstream, disabled: countArchivedDetailChildren(secondaryArchiveDetail) === 0, itemLabel: "tasks", onToggle: () => toggleArchivedDetailVisibility('workstream') })) : null, wideLayout ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: onCollapseSecondaryPane, "aria-label": `Collapse ${secondaryPaneLabel} pane`, title: `Collapse ${secondaryPaneLabel} pane`, children: _jsx(ChevronLeft, { size: 16, "aria-hidden": "true" }) })) : null] })] }), _jsx("div", { className: panelStyles.paneContent, "aria-busy": secondaryHydrationState?.status === 'loading', children: secondaryPane?.kind === 'editor' ? (_jsx(PlanningDrawerEditor, { editor: secondaryPane.editor, draftTitle: draftTitle, draftDescription: draftDescription, draftOwner: draftOwner, draftInitiativeId: draftInitiativeId, draftIcon: draftIcon, draftColor: draftColor, assigneeOptions: assigneeOptions, initiativeLinkOptions: linkOptions.initiatives, draftInitiativeSummary: draftInitiativeSummary, onChangeDraftTitle: onChangeDraftTitle, onChangeDraftDescription: onChangeDraftDescription, onChangeDraftOwner: onChangeDraftOwner, onChangeDraftInitiativeId: onChangeDraftInitiativeId, onChangeDraftIcon: onChangeDraftIcon, onChangeDraftColor: onChangeDraftColor, onCancel: onBackFromSecondary, onSubmit: onSubmitEditor, isSubmitting: isSubmittingEditor })) : secondaryPane ? (_jsx(PlanningDrawerDetailView, { detail: secondaryPane.detail, showArchivedChildren: archivedDetailVisibility.workstream, inlineEditor: secondaryInlineEditor ? {
1118
1122
  editor: secondaryInlineEditor,
1119
1123
  draftTitle,
1120
1124
  draftDescription,
@@ -1128,5 +1132,5 @@ export function PlanningDrawer({ open, leftOffset = 0, returnFocusRef, onWidthCh
1128
1132
  onCancel: onCancelSecondaryEditor || onBackFromSecondary,
1129
1133
  onSubmit: onSubmitEditor,
1130
1134
  isSubmitting: isSubmittingEditor,
1131
- } : null, currentWorkspaceId: currentWorkspaceId, currentActorId: currentOwnerId, theme: theme, assigneeOptions: assigneeOptions, linkOptions: linkOptions, showTaskCardStatusLabel: showTaskCardStatusLabel, taskArrangeMode: taskArrangeMode, onTaskArrangeModeChange: onTaskArrangeModeChange, onReorderWorkstreamTasks: onReorderWorkstreamTasks, hydrationState: secondaryHydrationState, onRetryHydration: onRetrySecondaryHydration, onSetTaskStatus: onSetTaskStatus, onArchivePlanningTask: onArchivePlanningTask, onArchiveResolvedEntity: onArchiveResolvedWorkstream, onCreateTaskInWorkstream: onCreateTaskInWorkstream, onOpenTaskById: onOpenTaskById, onChangeTaskAssignee: onChangeTaskAssignee, taskReferences: taskReferences, onAssignTaskToWorkstream: onAssignTaskToWorkstream, onAssignInitiativeToWorkstream: onAssignInitiativeToWorkstream, onAttachTaskToWorkstreamByReference: onAttachTaskToWorkstreamByReference, parentInitiative: resolveParentInitiative(secondaryPane.detail.item), onEdit: () => onEditWorkstream(secondaryPane.detail.item.id), onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', secondaryPane.detail.item.id, ownerId), onChangePlanningOwner: onChangePlanningOwner, onArchive: () => onArchiveWorkstream(secondaryPane.detail.item.id), onUnarchive: () => onUnarchiveWorkstream(secondaryPane.detail.item.id), onAddPlanningContextFile: onAddPlanningContextFile, onRemovePlanningContextFile: onRemovePlanningContextFile, onUpdatePlanningContextCaption: onUpdatePlanningContextCaption })) : null })] })))] }) }));
1135
+ } : null, currentWorkspaceId: currentWorkspaceId, currentActorId: currentOwnerId, theme: theme, assigneeOptions: assigneeOptions, linkOptions: linkOptions, showTaskCardStatusLabel: showTaskCardStatusLabel, taskArrangeMode: taskArrangeMode, onTaskArrangeModeChange: onTaskArrangeModeChange, onReorderWorkstreamTasks: onReorderWorkstreamTasks, hydrationState: secondaryHydrationState, onRetryHydration: onRetrySecondaryHydration, onSetTaskStatus: onSetTaskStatus, onArchivePlanningTask: onArchivePlanningTask, onArchiveResolvedEntity: onArchiveResolvedWorkstream, onCreateTaskInWorkstream: onCreateTaskInWorkstream, onOpenTaskById: onOpenTaskById, onChangeTaskAssignee: onChangeTaskAssignee, taskReferences: taskReferences, onAssignTaskToWorkstream: onAssignTaskToWorkstream, onAssignInitiativeToWorkstream: onAssignInitiativeToWorkstream, onAttachTaskToWorkstreamByReference: onAttachTaskToWorkstreamByReference, parentInitiative: resolveParentInitiative(secondaryPane.detail.item), onEdit: () => onEditWorkstream(secondaryPane.detail.item.id), onChangeOwner: (ownerId) => onChangePlanningOwner('workstream', secondaryPane.detail.item.id, ownerId), onChangePlanningOwner: onChangePlanningOwner, onChangePlanningIdentity: onChangePlanningIdentity, onArchive: () => onArchiveWorkstream(secondaryPane.detail.item.id), onUnarchive: () => onUnarchiveWorkstream(secondaryPane.detail.item.id), onAddPlanningContextFile: onAddPlanningContextFile, onRemovePlanningContextFile: onRemovePlanningContextFile, onUpdatePlanningContextCaption: onUpdatePlanningContextCaption })) : null })] })))] }) }));
1132
1136
  }
@@ -11,6 +11,7 @@ const SPECS = [
11
11
  { key: 'TASKFORCE_DB_PROVIDER', description: 'Database provider (sqlite|postgres).', category: 'Core', defaultValue: 'sqlite', example: 'postgres', targets: ['server', 'all'] },
12
12
  { key: 'TASKFORCE_BILLING_ENABLED', description: 'Enable Stripe billing routes and webhook processing.', category: 'Core', defaultValue: 'false', targets: ['server', 'all'] },
13
13
  { key: 'TASKFORCE_DATABASE_URL', description: 'Postgres connection string when provider=postgres.', category: 'Core', example: 'postgresql://user:pass@host:5432/db', secret: true, targets: ['server', 'all'] },
14
+ { key: 'TASKFORCE_CLOUD_READ_WORKERS', description: 'Bounded cloud collection-read worker count (1-8, or 0 to disable).', category: 'Core', defaultValue: '2', targets: ['server', 'all'] },
14
15
  { key: 'TASKFORCE_ALLOW_SQLITE_IN_CLOUD', description: 'Emergency override to allow sqlite in cloud runtime.', category: 'Core', defaultValue: 'false', targets: ['server', 'all'] },
15
16
  { key: 'TASKFORCE_FORCE_SETUP', description: 'Force local setup gate for development.', category: 'Core', defaultValue: 'false', targets: ['server', 'all'] },
16
17
  { key: 'TASKFORCE_FORCE_GLOBAL_SETUP', description: 'Force global setup step for development.', category: 'Core', defaultValue: 'false', targets: ['server', 'all'] },
@@ -0,0 +1,10 @@
1
+ import { type TaskforceCloudEnvironment } from './cloudEnvironment.js';
2
+ export interface LocalServiceCloudTarget {
3
+ environment: TaskforceCloudEnvironment | null;
4
+ cloudProxyBaseUrl: string;
5
+ cloudAuthBaseUrl: string;
6
+ }
7
+ export declare function resolveLocalServiceCloudTarget(env: NodeJS.ProcessEnv): LocalServiceCloudTarget;
8
+ export declare function applyLocalServiceCloudTarget(env: NodeJS.ProcessEnv, target: LocalServiceCloudTarget): void;
9
+ export declare function parseLocalServiceCloudTarget(value: unknown): LocalServiceCloudTarget | null;
10
+ export declare function localServiceCloudTargetsEqual(left: LocalServiceCloudTarget | null | undefined, right: LocalServiceCloudTarget | null | undefined): boolean;
@@ -0,0 +1,76 @@
1
+ import { TASKFORCE_CLOUD_ENVIRONMENTS, parseTaskforceCloudEnvironment, resolveTaskforceCloudEnvironmentFromBaseUrl, } from './cloudEnvironment.js';
2
+ import { resolveDeploymentConfig } from './deployment.js';
3
+ function normalizeCloudBaseUrl(raw, label) {
4
+ let parsed;
5
+ try {
6
+ parsed = new URL(String(raw || '').trim());
7
+ }
8
+ catch {
9
+ throw new Error(`${label} must be a valid HTTP(S) URL.`);
10
+ }
11
+ if (!['http:', 'https:'].includes(parsed.protocol) || parsed.username || parsed.password) {
12
+ throw new Error(`${label} must be an HTTP(S) URL without embedded credentials.`);
13
+ }
14
+ if (parsed.search || parsed.hash) {
15
+ throw new Error(`${label} must not include a query string or fragment.`);
16
+ }
17
+ const pathname = parsed.pathname.replace(/\/+$/, '');
18
+ return pathname ? `${parsed.origin}${pathname}` : parsed.origin;
19
+ }
20
+ export function resolveLocalServiceCloudTarget(env) {
21
+ const rawEnvironment = String(env.TASKFORCE_CLOUD_ENVIRONMENT || '').trim();
22
+ const explicitEnvironment = parseTaskforceCloudEnvironment(rawEnvironment);
23
+ if (rawEnvironment && !explicitEnvironment) {
24
+ throw new Error(`Unknown Taskforce cloud environment: ${rawEnvironment}.`);
25
+ }
26
+ const deployment = resolveDeploymentConfig(env);
27
+ const productionOrigin = TASKFORCE_CLOUD_ENVIRONMENTS.production.appBaseUrl;
28
+ const cloudProxyBaseUrl = normalizeCloudBaseUrl(deployment.cloudBaseUrl || productionOrigin, 'Taskforce cloud proxy URL');
29
+ const cloudAuthBaseUrl = normalizeCloudBaseUrl(deployment.cloudAuthBaseUrl || cloudProxyBaseUrl, 'Taskforce cloud auth URL');
30
+ const proxyEnvironment = resolveTaskforceCloudEnvironmentFromBaseUrl(cloudProxyBaseUrl);
31
+ const authEnvironment = resolveTaskforceCloudEnvironmentFromBaseUrl(cloudAuthBaseUrl);
32
+ const knownEnvironments = [explicitEnvironment, proxyEnvironment, authEnvironment]
33
+ .filter((value) => Boolean(value));
34
+ if (new Set(knownEnvironments).size > 1) {
35
+ throw new Error('Taskforce cloud environment, proxy URL, and auth URL must identify the same cloud target.');
36
+ }
37
+ return {
38
+ environment: explicitEnvironment || proxyEnvironment || authEnvironment,
39
+ cloudProxyBaseUrl,
40
+ cloudAuthBaseUrl,
41
+ };
42
+ }
43
+ export function applyLocalServiceCloudTarget(env, target) {
44
+ if (target.environment)
45
+ env.TASKFORCE_CLOUD_ENVIRONMENT = target.environment;
46
+ env.TASKFORCE_CLOUD_PROXY_BASE_URL ||= target.cloudProxyBaseUrl;
47
+ env.VITE_TASKFORCE_CLOUD_AUTH_BASE_URL ||= target.cloudAuthBaseUrl;
48
+ }
49
+ export function parseLocalServiceCloudTarget(value) {
50
+ if (!value || typeof value !== 'object' || Array.isArray(value))
51
+ return null;
52
+ const record = value;
53
+ const environment = record.environment === null
54
+ ? null
55
+ : parseTaskforceCloudEnvironment(record.environment);
56
+ if (record.environment !== null && !environment)
57
+ return null;
58
+ if (typeof record.cloudProxyBaseUrl !== 'string' || typeof record.cloudAuthBaseUrl !== 'string')
59
+ return null;
60
+ try {
61
+ const cloudProxyBaseUrl = normalizeCloudBaseUrl(record.cloudProxyBaseUrl, 'Taskforce cloud proxy base URL');
62
+ const cloudAuthBaseUrl = normalizeCloudBaseUrl(record.cloudAuthBaseUrl, 'Taskforce cloud auth base URL');
63
+ if (cloudProxyBaseUrl !== record.cloudProxyBaseUrl || cloudAuthBaseUrl !== record.cloudAuthBaseUrl)
64
+ return null;
65
+ return { environment, cloudProxyBaseUrl, cloudAuthBaseUrl };
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ export function localServiceCloudTargetsEqual(left, right) {
72
+ return Boolean(left && right
73
+ && left.environment === right.environment
74
+ && left.cloudProxyBaseUrl === right.cloudProxyBaseUrl
75
+ && left.cloudAuthBaseUrl === right.cloudAuthBaseUrl);
76
+ }
@@ -138,6 +138,7 @@ export declare function getAiProfileByConnectionService(deps: AiProfileServiceDe
138
138
  workspaceId: string;
139
139
  connectionId: string;
140
140
  seatScope?: AiProfileSeatScope | null;
141
+ repairLegacyBinding?: boolean;
141
142
  }): AiProfileRecordLike | null;
142
143
  export declare function archiveAiProfileService(deps: AiProfileServiceDeps, input: {
143
144
  workspaceId: string;
@@ -1367,8 +1367,9 @@ export function getAiProfileByConnectionService(deps, input) {
1367
1367
  if (legacyRows.length === 0)
1368
1368
  return null;
1369
1369
  const record = hydrateAiProfileRecord(deps, legacyRows[0]);
1370
- if (!record.archivedAt)
1370
+ if (!record.archivedAt && input.repairLegacyBinding !== false) {
1371
1371
  bindAiProfileConnectionService(deps, { workspaceId, profileId: record.id, connectionId });
1372
+ }
1372
1373
  return record;
1373
1374
  }
1374
1375
  export function archiveAiProfileService(deps, input) {
@@ -262,11 +262,14 @@ export function syncCanonicalAttachmentLinksForTargetService(deps, targetType, t
262
262
  : String(row?.kind || '').trim() === 'image'
263
263
  ? 'image'
264
264
  : 'attachment';
265
- const displayName = String(row?.kind || '').trim() === 'document' && !isExternalStorageKey
265
+ const displayName = typeof attachment === 'string'
266
266
  ? null
267
- : (typeof attachment === 'string'
268
- ? null
269
- : buildAttachmentDisplayName(attachment, isExternalStorageKey || !storageKey ? null : path.basename(storageKey)));
267
+ : safeTargetType === 'task'
268
+ ? String(attachment.displayName || attachment.originalFilename || attachment.caption
269
+ || (isExternalStorageKey || !storageKey ? '' : path.basename(storageKey))).trim() || null
270
+ : String(row?.kind || '').trim() === 'document' && !isExternalStorageKey
271
+ ? null
272
+ : buildAttachmentDisplayName(attachment, isExternalStorageKey || !storageKey ? null : path.basename(storageKey));
270
273
  const timestamp = typeof attachment === 'string' ? new Date().toISOString() : (attachment.timestamp || new Date().toISOString());
271
274
  upsertLink.run(deps.tenantId, normalizedWorkspaceId, assetId, safeTargetType, normalizedTargetId, role, displayName, index, timestamp, timestamp);
272
275
  });
@@ -16,6 +16,7 @@ export interface DeletedTaskLifecycleServiceDeps {
16
16
  actorProfile: TaskActor | null;
17
17
  };
18
18
  runRetentionPurgeTransaction: <T>(workspaceId: string | null, apply: (durableDeleteOwnedKeys: ReadonlySet<string>) => T) => T;
19
+ listDurableDeleteOwnedTaskIds: (workspaceId: string) => ReadonlySet<string>;
19
20
  }
20
21
  export declare function normalizeTaskSnapshotForRestoreService(deps: DeletedTaskLifecycleServiceDeps, task: TaskItem): TaskItem;
21
22
  export declare function normalizeDeletedTaskRestoreLifecycleService(deps: DeletedTaskLifecycleServiceDeps, task: TaskItem): Pick<TaskItem, 'status' | 'isArchived' | 'completedAt' | 'canceledReason'>;
@@ -33,4 +34,7 @@ export declare function addDeletedTaskRecordService(deps: DeletedTaskLifecycleSe
33
34
  export declare function listDeletedTasksService(deps: DeletedTaskLifecycleServiceDeps, workspaceId?: string): {
34
35
  deleted: DeletedTaskRecord[];
35
36
  };
37
+ export declare function listDeletedTasksReadOnlyService(deps: DeletedTaskLifecycleServiceDeps, workspaceId?: string): {
38
+ deleted: DeletedTaskRecord[];
39
+ };
36
40
  export declare function getDeletedTaskService(deps: DeletedTaskLifecycleServiceDeps, id: string, workspaceId?: string): DeletedTaskRecord | null;
@@ -225,6 +225,27 @@ export function listDeletedTasksService(deps, workspaceId) {
225
225
  .filter((row) => Boolean(row))
226
226
  };
227
227
  }
228
+ export function listDeletedTasksReadOnlyService(deps, workspaceId) {
229
+ const normalizedWorkspaceId = deps.normalizeWorkspaceId(workspaceId);
230
+ const cutoff = new Date(Date.now() - (DELETED_TASK_RETENTION_DAYS * 24 * 60 * 60 * 1000)).toISOString();
231
+ const durableDeleteOwnedTaskIds = deps.listDurableDeleteOwnedTaskIds(normalizedWorkspaceId);
232
+ const listSql = deps.db.provider === 'postgres'
233
+ ? deletedTaskListSnapshotSelect()
234
+ : `
235
+ SELECT *
236
+ FROM deleted_tasks
237
+ WHERE tenant_id = ?
238
+ AND workspace_id = ?
239
+ ORDER BY deleted_at DESC, id DESC
240
+ `;
241
+ const rows = deps.db.prepare(listSql).all(deps.tenantId, normalizedWorkspaceId);
242
+ return {
243
+ deleted: rows
244
+ .map((row) => mapDeletedTaskRowService(deps, row))
245
+ .filter((row) => Boolean(row))
246
+ .filter((row) => row.deletedAt >= cutoff || durableDeleteOwnedTaskIds.has(row.taskId))
247
+ };
248
+ }
228
249
  export function getDeletedTaskService(deps, id, workspaceId) {
229
250
  const normalizedWorkspaceId = deps.normalizeWorkspaceId(workspaceId);
230
251
  const normalizedId = String(id || '').trim();
@@ -124,6 +124,10 @@ export declare class McpTokenService {
124
124
  profileToken: string;
125
125
  profileName: string;
126
126
  }): boolean;
127
+ listMcpOAuthRestorableAiProfileIds(input: {
128
+ grantId: string;
129
+ workspaceId: string;
130
+ }): string[];
127
131
  recordMcpOAuthConnectorGrantUsage(input: {
128
132
  grantId: string;
129
133
  workspaceId: string;