@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
@@ -1,4 +1,4 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
3
  import { Image, Loader2, MessageSquareText } from 'lucide-react';
4
4
  import { fetchTaskforceApi } from '../../utils/taskforceApiClient';
@@ -29,19 +29,19 @@ export function TaskImageReviews({ taskId, taskReferenceLabel, workspaceId, apiB
29
29
  }, [apiBaseUrl, taskId, workspaceId]);
30
30
  if (reviews !== null && reviews.length === 0)
31
31
  return null;
32
- return (_jsxs("section", { className: styles.group, "aria-label": "Image reviews", children: [_jsxs("div", { className: "tf-heading-section", children: ["Image reviews", reviews ? ` (${reviews.length})` : ''] }), reviews === null ? (_jsxs("div", { className: styles.loading, "aria-live": "polite", children: [_jsx(Loader2, { size: 14 }), " Loading image reviews"] })) : (_jsx("div", { className: styles.list, children: reviews.map((review) => {
33
- const image = review.image;
34
- const markerCount = review.annotations.length;
35
- const canOpen = Boolean(image?.assetId && image.apiUrl);
36
- return (_jsxs("button", { type: "button", className: styles.review, disabled: !canOpen, onClick: () => {
37
- if (!image)
38
- return;
39
- dispatchOpenAnnotatedAttachment({
40
- assetId: image.assetId,
41
- path: image.apiUrl,
42
- displayName: image.displayName,
43
- referenceLabel: image.referenceLabel || undefined,
44
- }, { taskId, taskReferenceLabel, sessionId: review.id });
45
- }, children: [_jsx("span", { className: styles.icon, children: _jsx(Image, { size: 14 }) }), _jsxs("span", { className: styles.copy, children: [_jsx("span", { className: "tf-heading-card", children: reviewTitle(review) }), _jsxs("span", { className: "tf-text-meta", children: [markerCount, " ", markerCount === 1 ? 'marker' : 'markers'] })] }), _jsx(MessageSquareText, { className: styles.openIcon, size: 14, "aria-hidden": "true" })] }, review.id));
46
- }) }))] }));
32
+ return (_jsx("section", { className: styles.group, "aria-label": "Image reviews", children: reviews === null ? (_jsxs("div", { className: styles.loading, "aria-live": "polite", children: [_jsx(Loader2, { size: 14 }), " Loading image reviews"] })) : (_jsx("div", { className: styles.list, children: reviews.map((review) => {
33
+ const image = review.image;
34
+ const markerCount = review.annotations.length;
35
+ const canOpen = Boolean(image?.assetId && image.apiUrl);
36
+ return (_jsxs("button", { type: "button", className: styles.review, disabled: !canOpen, onClick: () => {
37
+ if (!image)
38
+ return;
39
+ dispatchOpenAnnotatedAttachment({
40
+ assetId: image.assetId,
41
+ path: image.apiUrl,
42
+ displayName: image.displayName,
43
+ referenceLabel: image.referenceLabel || undefined,
44
+ }, { taskId, taskReferenceLabel, sessionId: review.id });
45
+ }, children: [_jsx("span", { className: styles.icon, children: _jsx(Image, { size: 14 }) }), _jsxs("span", { className: styles.copy, children: [_jsx("span", { className: styles.kindLabel, children: "Image review session" }), _jsx("span", { className: `${styles.title} tf-heading-card`, children: reviewTitle(review) }), _jsxs("span", { className: "tf-text-meta", children: [markerCount, " ", markerCount === 1 ? 'marker' : 'markers'] })] }), _jsx(MessageSquareText, { className: styles.openIcon, size: 14, "aria-hidden": "true" })] }, review.id));
46
+ }) })) }));
47
47
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Archive, RotateCcw } from 'lucide-react';
2
+ import { RotateCcw } from 'lucide-react';
3
3
  import styles from '../../Taskforce.module.css';
4
4
  import { resolveColor, STATUS_DEFINITIONS } from '../../utils/constants';
5
5
  import { TaxonomyDropdown } from '../ui/TaxonomyDropdown';
@@ -23,7 +23,16 @@ export function TaskStatusActions({ task, status, disabled = false, actionDisabl
23
23
  '--field-focus-border': statusAccent,
24
24
  '--field-focus-ring': `color-mix(in srgb, ${statusAccent} 18%, transparent)`
25
25
  };
26
- return (_jsxs("div", { className: `${styles.statusActionsGroup} ${compressed ? styles.statusActionsGroupCompact : ''}`, children: [resolvedArchiveActionMode === 'archive' && (_jsx("button", { type: "button", className: `${styles.actionBtn} ${styles.archiveTaskBtn}`, onClick: () => task && !resolvedActionDisabled && onArchiveTask?.(task), disabled: resolvedActionDisabled, title: "Archive Now", "aria-label": "Archive task", children: _jsx(Archive, { size: compressed ? 12 : 16 }) })), resolvedArchiveActionMode === 'unarchive' && (_jsx("button", { type: "button", className: `${styles.actionBtn} ${styles.archiveTaskBtn}`, onClick: () => task && !resolvedActionDisabled && onUnarchiveTask?.(task), disabled: resolvedActionDisabled, title: "Unarchive task", "aria-label": "Unarchive task", children: _jsx(RotateCcw, { size: compressed ? 12 : 16 }) })), _jsx("div", { className: `${styles.statusSelectWrap} ${styles.statusTaxonomyDropdownWrap}`, style: statusAccentStyle, children: _jsx(TaxonomyDropdown, { value: currentStatus, options: statusOptions, disabled: resolvedStatusDisabled || (!task && !onStatusChange), ariaLabel: "Status", optionLabelColor: "var(--text-primary)", hideSelectedLabel: !showLabel, hideChevron: !showLabel, className: `${styles.statusTaxonomyDropdown} ${compressed ? styles.statusTaxonomyDropdownCompact : ''} ${!showLabel ? styles.statusTaxonomyDropdownIconOnly : ''}`, panelClassName: !showLabel ? styles.statusTaxonomyDropdownIconOnlyPanel : '', portalPanel: !showLabel, panelMinWidth: !showLabel ? 144 : undefined, onChange: (value) => {
26
+ const statusPanelActions = resolvedArchiveActionMode === 'archive' && task
27
+ ? [{
28
+ id: 'archive-task',
29
+ label: 'Archive task',
30
+ icon: 'Archive',
31
+ disabled: resolvedActionDisabled || !onArchiveTask,
32
+ onSelect: () => onArchiveTask?.(task),
33
+ }]
34
+ : [];
35
+ return (_jsxs("div", { className: `${styles.statusActionsGroup} ${compressed ? styles.statusActionsGroupCompact : ''}`, children: [resolvedArchiveActionMode === 'unarchive' && (_jsx("button", { type: "button", className: `${styles.actionBtn} ${styles.restoreTaskBtn}`, onClick: () => task && !resolvedActionDisabled && onUnarchiveTask?.(task), disabled: resolvedActionDisabled, title: "Unarchive task", "aria-label": "Unarchive task", children: _jsx(RotateCcw, { size: compressed ? 12 : 16 }) })), _jsx("div", { className: `${styles.statusSelectWrap} ${styles.statusTaxonomyDropdownWrap}`, style: statusAccentStyle, children: _jsx(TaxonomyDropdown, { value: currentStatus, options: statusOptions, disabled: resolvedStatusDisabled || (!task && !onStatusChange), ariaLabel: "Status", optionLabelColor: "var(--text-primary)", hideSelectedLabel: !showLabel, hideChevron: !showLabel, className: `${styles.statusTaxonomyDropdown} ${compressed ? styles.statusTaxonomyDropdownCompact : ''} ${!showLabel ? styles.statusTaxonomyDropdownIconOnly : ''}`, panelClassName: !showLabel ? styles.statusTaxonomyDropdownIconOnlyPanel : '', portalPanel: !showLabel, panelMinWidth: !showLabel ? 144 : undefined, panelActions: statusPanelActions, onChange: (value) => {
27
36
  const nextStatus = value;
28
37
  if (task) {
29
38
  onSetStatus?.(task, nextStatus);
@@ -4,6 +4,7 @@ import { Link2 } from 'lucide-react';
4
4
  import { getWorkstreamReferenceLabel } from '../../utils/planningReferences';
5
5
  import { TaxonomyDropdown } from '../ui/TaxonomyDropdown';
6
6
  import styles from '../../Taskforce.module.css';
7
+ import { PlanningVisualIdentity } from '../features/planning/PlanningVisualIdentity';
7
8
  export function TaskWorkstreamPicker({ workstreams, onSelect, disabled = false, }) {
8
9
  const availableWorkstreams = React.useMemo(() => workstreams.filter((workstream) => !workstream.isArchived), [workstreams]);
9
10
  const workstreamById = React.useMemo(() => new Map(availableWorkstreams.map((workstream) => [workstream.id, workstream])), [availableWorkstreams]);
@@ -19,6 +20,6 @@ export function TaskWorkstreamPicker({ workstreams, onSelect, disabled = false,
19
20
  const workstream = workstreamById.get(String(option.value));
20
21
  if (!workstream)
21
22
  return option.label;
22
- return (_jsxs("span", { className: styles.taskWorkstreamPickerOption, children: [_jsx("span", { children: getWorkstreamReferenceLabel(workstream) || workstream.id }), _jsx("span", { children: workstream.title })] }));
23
+ return (_jsxs("span", { className: styles.taskWorkstreamPickerOption, children: [_jsx(PlanningVisualIdentity, { entityType: "workstream", entityId: workstream.id, icon: workstream.icon, color: workstream.color, size: "inline", disabled: true }), _jsx("span", { children: getWorkstreamReferenceLabel(workstream) || workstream.id }), _jsx("span", { children: workstream.title })] }));
23
24
  } }));
24
25
  }
@@ -0,0 +1,7 @@
1
+ interface DocumentTypeIconProps {
2
+ label: string;
3
+ compact?: boolean;
4
+ accentColor?: string;
5
+ }
6
+ export declare function DocumentTypeIcon({ label, compact, accentColor, }: DocumentTypeIconProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styles from './DocumentTypeIcon.module.css';
3
+ export function DocumentTypeIcon({ label, compact = false, accentColor, }) {
4
+ const style = accentColor
5
+ ? { '--document-type-accent': accentColor }
6
+ : undefined;
7
+ return (_jsxs("span", { className: `${styles.root} ${compact ? styles.compact : ''}`.trim(), style: style, "aria-hidden": "true", children: [_jsxs("svg", { className: styles.outline, viewBox: "0 0 28 28", focusable: "false", children: [_jsx("path", { d: "M2 0.75h18.25l7 7V26q0 1.25-1.25 1.25H2Q0.75 27.25 0.75 26V2Q0.75 0.75 2 0.75Z" }), _jsx("path", { className: styles.foldFill, d: "M20.25 0.75v7h7Z" }), _jsx("path", { className: styles.foldLine, d: "M20.25 0.75v7h7" })] }), _jsx("span", { className: styles.label, children: label })] }));
8
+ }
@@ -5,6 +5,13 @@ export interface TaxonomyOption {
5
5
  icon?: string;
6
6
  color?: string;
7
7
  }
8
+ export interface TaxonomyDropdownAction {
9
+ id: string;
10
+ label: string;
11
+ icon?: string;
12
+ disabled?: boolean;
13
+ onSelect: () => void;
14
+ }
8
15
  export interface TaxonomyDropdownProps {
9
16
  value: string | number;
10
17
  options: TaxonomyOption[];
@@ -28,5 +35,6 @@ export interface TaxonomyDropdownProps {
28
35
  searchable?: boolean;
29
36
  searchPlaceholder?: string;
30
37
  noResultsText?: string;
38
+ panelActions?: TaxonomyDropdownAction[];
31
39
  }
32
- export declare function TaxonomyDropdown({ value, options, onChange, placeholder, required, disabled, className, ariaLabelledBy, ariaLabel, title, hideSelectedLabel, hideChevron, panelClassName, portalPanel, panelMinWidth, panelAlign, renderOptionContent: customRenderOptionContent, triggerContent, optionLabelColor, searchable, searchPlaceholder, noResultsText, }: TaxonomyDropdownProps): import("react/jsx-runtime").JSX.Element;
40
+ export declare function TaxonomyDropdown({ value, options, onChange, placeholder, required, disabled, className, ariaLabelledBy, ariaLabel, title, hideSelectedLabel, hideChevron, panelClassName, portalPanel, panelMinWidth, panelAlign, renderOptionContent: customRenderOptionContent, triggerContent, optionLabelColor, searchable, searchPlaceholder, noResultsText, panelActions, }: TaxonomyDropdownProps): import("react/jsx-runtime").JSX.Element;
@@ -12,7 +12,7 @@ function resolveTint(color, opacity) {
12
12
  }
13
13
  return `color-mix(in srgb, ${resolved} ${Math.round(opacity * 100)}%, transparent)`;
14
14
  }
15
- export function TaxonomyDropdown({ value, options, onChange, placeholder = 'Select...', required = false, disabled = false, className = '', ariaLabelledBy, ariaLabel, title, hideSelectedLabel = false, hideChevron = false, panelClassName = '', portalPanel = false, panelMinWidth, panelAlign = 'end', renderOptionContent: customRenderOptionContent, triggerContent, optionLabelColor, searchable = false, searchPlaceholder = 'Search options...', noResultsText = 'No matching options.', }) {
15
+ export function TaxonomyDropdown({ value, options, onChange, placeholder = 'Select...', required = false, disabled = false, className = '', ariaLabelledBy, ariaLabel, title, hideSelectedLabel = false, hideChevron = false, panelClassName = '', portalPanel = false, panelMinWidth, panelAlign = 'end', renderOptionContent: customRenderOptionContent, triggerContent, optionLabelColor, searchable = false, searchPlaceholder = 'Search options...', noResultsText = 'No matching options.', panelActions = [], }) {
16
16
  const [isOpen, setIsOpen] = useState(false);
17
17
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
18
18
  const [panelPosition, setPanelPosition] = useState({});
@@ -23,6 +23,7 @@ export function TaxonomyDropdown({ value, options, onChange, placeholder = 'Sele
23
23
  const panelRef = useRef(null);
24
24
  const portalPanelWidthRef = useRef(null);
25
25
  const optionRefs = useRef([]);
26
+ const panelActionRefs = useRef([]);
26
27
  const searchInputRef = useRef(null);
27
28
  const listboxId = `taxonomy-listbox-${React.useId().replace(/:/g, '')}`;
28
29
  // Find the currently selected option
@@ -147,6 +148,14 @@ export function TaxonomyDropdown({ value, options, onChange, placeholder = 'Sele
147
148
  setIsOpen(false);
148
149
  buttonRef.current?.focus();
149
150
  };
151
+ const handlePanelAction = (action) => {
152
+ if (action.disabled)
153
+ return;
154
+ action.onSelect();
155
+ setSearchQuery('');
156
+ setIsOpen(false);
157
+ buttonRef.current?.focus();
158
+ };
150
159
  const handleKeyDown = (e) => {
151
160
  if (disabled)
152
161
  return;
@@ -222,7 +231,11 @@ export function TaxonomyDropdown({ value, options, onChange, placeholder = 'Sele
222
231
  }
223
232
  break;
224
233
  case 'Tab':
225
- // Allow natural tab behavior
234
+ if (isOpen && !e.shiftKey && panelActions.length > 0) {
235
+ e.preventDefault();
236
+ panelActionRefs.current[0]?.focus();
237
+ break;
238
+ }
226
239
  setIsOpen(false);
227
240
  break;
228
241
  default:
@@ -256,7 +269,21 @@ export function TaxonomyDropdown({ value, options, onChange, placeholder = 'Sele
256
269
  '--option-bg': resolveTint(accent, 0.06)
257
270
  };
258
271
  })(), children: renderOptionContent(option, { labelColor: optionLabelColor }) }, String(option.value)));
259
- }) }), visibleOptions.length === 0 ? (_jsx("div", { className: styles.taxonomyDropdownEmpty, role: "status", children: noResultsText })) : null] })) : null;
272
+ }) }), visibleOptions.length === 0 ? (_jsx("div", { className: styles.taxonomyDropdownEmpty, role: "status", children: noResultsText })) : null, panelActions.length > 0 ? (_jsx("div", { className: styles.taxonomyDropdownActions, role: "group", "aria-label": "Actions", children: panelActions.map((action, index) => {
273
+ const ActionIcon = action.icon && Icons[action.icon]
274
+ ? Icons[action.icon]
275
+ : null;
276
+ return (_jsxs("button", { ref: (node) => { panelActionRefs.current[index] = node; }, type: "button", className: styles.taxonomyDropdownAction, disabled: action.disabled, onClick: () => handlePanelAction(action), onKeyDown: (event) => {
277
+ if (event.key === 'Escape') {
278
+ event.preventDefault();
279
+ setIsOpen(false);
280
+ buttonRef.current?.focus();
281
+ }
282
+ else if (event.key === 'Tab' && !event.shiftKey) {
283
+ setIsOpen(false);
284
+ }
285
+ }, children: [ActionIcon ? _jsx(ActionIcon, { size: 16, "aria-hidden": "true" }) : null, _jsx("span", { children: action.label })] }, action.id));
286
+ }) })) : null] })) : null;
260
287
  return (_jsxs("div", { ref: dropdownRef, className: `taxonomyDropdown ${styles.taxonomyDropdown} ${isOpen ? `taxonomyDropdownActive ${styles.taxonomyDropdownActive}` : ''} ${className}`, children: [_jsxs("button", { ref: buttonRef, type: "button", className: `taxonomyDropdownButton ${styles.taxonomyDropdownButton} ${isOpen ? `taxonomyDropdownOpen ${styles.taxonomyDropdownOpen}` : ''}`, onClick: handleToggle, onKeyDown: handleKeyDown, disabled: disabled, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-controls": listboxId, "aria-activedescendant": isOpen && highlightedIndex >= 0 ? `${listboxId}-option-${highlightedIndex}` : undefined, "aria-labelledby": ariaLabelledBy, "aria-label": ariaLabel, title: title, style: (() => {
261
288
  if (!selectedOption)
262
289
  return {};
@@ -169,9 +169,9 @@ export function StandaloneLayout(props) {
169
169
  // State
170
170
  activeTab, setActiveTab, activeCategories, groupBy, setGroupBy, activeWorkspaceModule, setActiveWorkspaceModule, emptyColumnMode, setEmptyColumnMode, zenMode, setZenMode, filterStatus, setFilterStatus,
171
171
  // Data & Actions
172
- tasks, handleEdit, handleSubmit, resetForm, handleUpdateTask, handleSetStatus: handleSetStatusDurably,
172
+ tasks, handleEdit, handleSubmit, resetForm, discardDescriptionImageDraft, handleUpdateTask, handleSetStatus: handleSetStatusDurably,
173
173
  // Form State (destructure all needed for TaskForm)
174
- editingTaskId, loading, error, title, setTitle, setTitleDraft, description, setDescription, setDescriptionDraft, checklistItems, setChecklistItems, category, setCategory, type, setType, priority, setPriority, complexity, setComplexity, status, setStatus, assignee, setAssignee, scheduledDate, setScheduledDate, dueDate, setDueDate, workstreamInput, setWorkstreamInput, manualComplexityEnabled, checklistDropdownEnabled, showTaskCardStatusLabel, formTaxonomies, setFormTaxonomies, comments, newCommentText, setNewCommentText, attachments, setAttachments, setAttachmentsDirty, descriptionFocused, setDescriptionFocused, showMarkdownHelp, setShowMarkdownHelp,
174
+ editingTaskId, loading, error, title, setTitle, setTitleDraft, description, setDescription, setDescriptionDraft, checklistItems, setChecklistItems, category, setCategory, type, setType, priority, setPriority, complexity, setComplexity, status, setStatus, assignee, setAssignee, scheduledDate, setScheduledDate, dueDate, setDueDate, workstreamInput, setWorkstreamInput, manualComplexityEnabled, checklistDropdownEnabled, showTaskCardStatusLabel, formTaxonomies, setFormTaxonomies, comments, newCommentText, setNewCommentText, attachments, setAttachments, attachmentsDirty, setAttachmentsDirty, descriptionImageUploadPending, descriptionImageDraftId, registerDescriptionImageUpload, descriptionFocused, setDescriptionFocused, showMarkdownHelp, setShowMarkdownHelp,
175
175
  // Form Actions
176
176
  handleAddComment, handleSetWorkstreamForCurrentTask, handleOpenTaskById,
177
177
  // Other Props for Form
@@ -206,6 +206,9 @@ export function StandaloneLayout(props) {
206
206
  // Handlers
207
207
  const handleDiscard = () => {
208
208
  setUnsavedModalOpen(false);
209
+ if (activeTab === 'add' && !editingTaskId) {
210
+ void discardDescriptionImageDraft();
211
+ }
209
212
  if (pendingNavigation) {
210
213
  if (activeTab === 'add')
211
214
  resetForm();
@@ -271,6 +274,8 @@ export function StandaloneLayout(props) {
271
274
  const [planningDraftDescription, setPlanningDraftDescription] = useState('');
272
275
  const [planningDraftOwner, setPlanningDraftOwner] = useState('');
273
276
  const [planningDraftInitiativeId, setPlanningDraftInitiativeId] = useState('');
277
+ const [planningDraftIcon, setPlanningDraftIcon] = useState(null);
278
+ const [planningDraftColor, setPlanningDraftColor] = useState(null);
274
279
  const [isSubmittingPlanningEditor, setIsSubmittingPlanningEditor] = useState(false);
275
280
  const taskContextAttachmentDraftRef = useRef({
276
281
  taskId: null,
@@ -1173,6 +1178,8 @@ export function StandaloneLayout(props) {
1173
1178
  description: String(workstream.description || '').trim() || undefined,
1174
1179
  ownerId: workstream.ownerId ? String(workstream.ownerId) : null,
1175
1180
  ownerLabel: workstream.ownerId ? assigneeLabelByValue.get(String(workstream.ownerId)) || String(workstream.ownerId) : null,
1181
+ icon: workstream.icon ?? null,
1182
+ color: workstream.color ?? null,
1176
1183
  ...taskCounts,
1177
1184
  statusCounts: workstreamStatusCountsById.get(workstream.id) || summarizeTaskStatuses([]),
1178
1185
  initiativeId: workstream.initiativeId || null,
@@ -1217,6 +1224,8 @@ export function StandaloneLayout(props) {
1217
1224
  description: String(initiative.description || '').trim() || undefined,
1218
1225
  ownerId: initiative.ownerId ? String(initiative.ownerId) : null,
1219
1226
  ownerLabel: initiative.ownerId ? assigneeLabelByValue.get(String(initiative.ownerId)) || String(initiative.ownerId) : null,
1227
+ icon: initiative.icon ?? null,
1228
+ color: initiative.color ?? null,
1220
1229
  ...initiativeTaskCounts,
1221
1230
  statusCounts: combineTaskStatuses(allWorkstreamsForInitiative),
1222
1231
  workstreamCount: workstreams.length,
@@ -1281,6 +1290,8 @@ export function StandaloneLayout(props) {
1281
1290
  id: initiative.id,
1282
1291
  referenceLabel: formatInitiativeReference(initiative) || initiative.id,
1283
1292
  title: initiative.title,
1293
+ icon: initiative.icon,
1294
+ color: initiative.color,
1284
1295
  meta: `${initiative.workstreamCount || 0} workstream${initiative.workstreamCount === 1 ? '' : 's'}`,
1285
1296
  }))
1286
1297
  .sort(sortByTitle);
@@ -1290,6 +1301,8 @@ export function StandaloneLayout(props) {
1290
1301
  id: workstream.id,
1291
1302
  referenceLabel: formatWorkstreamReference(workstream) || workstream.id,
1292
1303
  title: workstream.title,
1304
+ icon: workstream.icon,
1305
+ color: workstream.color,
1293
1306
  meta: workstream.initiativeId
1294
1307
  ? `In ${planningStructure.allInitiativeById.get(workstream.initiativeId)?.title || 'another initiative'}`
1295
1308
  : 'Standalone workstream',
@@ -3034,6 +3047,8 @@ export function StandaloneLayout(props) {
3034
3047
  setPlanningDraftTitle('');
3035
3048
  setPlanningDraftDescription('');
3036
3049
  setPlanningDraftOwner('');
3050
+ setPlanningDraftIcon(null);
3051
+ setPlanningDraftColor(null);
3037
3052
  const selectedInitiative = editor.entityType === 'workstream' && selectedPlanningInitiativeId
3038
3053
  ? planningStructure.initiativeById.get(selectedPlanningInitiativeId) || null
3039
3054
  : null;
@@ -3048,6 +3063,8 @@ export function StandaloneLayout(props) {
3048
3063
  setPlanningDraftTitle('');
3049
3064
  setPlanningDraftDescription('');
3050
3065
  setPlanningDraftOwner('');
3066
+ setPlanningDraftIcon(null);
3067
+ setPlanningDraftColor(null);
3051
3068
  const selectedInitiative = editor.entityType === 'workstream'
3052
3069
  ? ((initiativeId ? planningStructure.initiativeById.get(initiativeId) : null)
3053
3070
  || (selectedPlanningInitiativeId ? planningStructure.initiativeById.get(selectedPlanningInitiativeId) || null : null))
@@ -3062,6 +3079,8 @@ export function StandaloneLayout(props) {
3062
3079
  setPlanningDraftTitle('');
3063
3080
  setPlanningDraftDescription('');
3064
3081
  setPlanningDraftOwner('');
3082
+ setPlanningDraftIcon(null);
3083
+ setPlanningDraftColor(null);
3065
3084
  setPlanningDraftInitiativeId('');
3066
3085
  }, []);
3067
3086
  const closePlanningSecondaryEditor = useCallback(() => {
@@ -3071,6 +3090,8 @@ export function StandaloneLayout(props) {
3071
3090
  setPlanningDraftTitle('');
3072
3091
  setPlanningDraftDescription('');
3073
3092
  setPlanningDraftOwner('');
3093
+ setPlanningDraftIcon(null);
3094
+ setPlanningDraftColor(null);
3074
3095
  setPlanningDraftInitiativeId('');
3075
3096
  }, []);
3076
3097
  const submitPlanningEditor = useCallback(async () => {
@@ -3099,6 +3120,10 @@ export function StandaloneLayout(props) {
3099
3120
  title,
3100
3121
  description: planningDraftDescription.trim() || null,
3101
3122
  ownerId,
3123
+ ...(planningDraftIcon || planningDraftColor ? {
3124
+ icon: planningDraftIcon,
3125
+ color: planningDraftColor,
3126
+ } : {}),
3102
3127
  });
3103
3128
  setPlanningDrawerDetail({ type: 'initiative', id: created.id });
3104
3129
  setPlanningNestedWorkstreamDetailId(null);
@@ -3129,7 +3154,13 @@ export function StandaloneLayout(props) {
3129
3154
  pushNotice('Workstream updated', 'success');
3130
3155
  }
3131
3156
  else {
3132
- const created = await props.createWorkstream(patch);
3157
+ const created = await props.createWorkstream({
3158
+ ...patch,
3159
+ ...(planningDraftIcon || planningDraftColor ? {
3160
+ icon: planningDraftIcon,
3161
+ color: planningDraftColor,
3162
+ } : {}),
3163
+ });
3133
3164
  if (isSecondaryEditor) {
3134
3165
  setPlanningNestedWorkstreamDetailId(created.id);
3135
3166
  }
@@ -3159,6 +3190,8 @@ export function StandaloneLayout(props) {
3159
3190
  closePlanningSecondaryEditor,
3160
3191
  planningDraftDescription,
3161
3192
  planningDraftInitiativeId,
3193
+ planningDraftIcon,
3194
+ planningDraftColor,
3162
3195
  planningDraftOwner,
3163
3196
  planningDraftTitle,
3164
3197
  planningEditor,
@@ -3462,6 +3495,15 @@ export function StandaloneLayout(props) {
3462
3495
  throw error;
3463
3496
  }
3464
3497
  }, [props, pushNotice]);
3498
+ const handleChangePlanningIdentity = useCallback(async (entityType, entityId, patch) => {
3499
+ try {
3500
+ await props.updatePlanningIdentity(entityType, entityId, patch);
3501
+ }
3502
+ catch (error) {
3503
+ pushNotice(error instanceof Error ? error.message : 'Failed to update visual identity.', 'error');
3504
+ throw error;
3505
+ }
3506
+ }, [props.updatePlanningIdentity, pushNotice]);
3465
3507
  const handleAssignInitiativeToWorkstream = useCallback(async (workstreamId, initiativeReferenceOverride) => {
3466
3508
  const workstream = props.workstreams.find((item) => item.id === workstreamId);
3467
3509
  if (!workstream) {
@@ -4069,6 +4111,7 @@ export function StandaloneLayout(props) {
4069
4111
  title,
4070
4112
  description: input.description?.trim() || null,
4071
4113
  ownerId: input.ownerId?.trim() || null,
4114
+ ...(input.icon || input.color ? { icon: input.icon ?? null, color: input.color ?? null } : {}),
4072
4115
  });
4073
4116
  pushNotice('Initiative created', 'success');
4074
4117
  return { id: created.id };
@@ -4078,6 +4121,7 @@ export function StandaloneLayout(props) {
4078
4121
  description: input.description?.trim() || null,
4079
4122
  ownerId: input.ownerId?.trim() || null,
4080
4123
  initiativeId: input.initiativeId?.trim() || null,
4124
+ ...(input.icon || input.color ? { icon: input.icon ?? null, color: input.color ?? null } : {}),
4081
4125
  });
4082
4126
  pushNotice('Workstream created', 'success');
4083
4127
  return { id: created.id };
@@ -4138,6 +4182,7 @@ export function StandaloneLayout(props) {
4138
4182
  archiveEntity: handleArchivePlanningEntity,
4139
4183
  unarchiveEntity: handleUnarchivePlanningEntity,
4140
4184
  changeOwner: handleChangePlanningOwner,
4185
+ changeIdentity: handleChangePlanningIdentity,
4141
4186
  createEntity: createPlanningWorkspaceEntity,
4142
4187
  updateEntity: updatePlanningWorkspaceEntity,
4143
4188
  addContextFile: handleAddPlanningContextFile,
@@ -4151,6 +4196,7 @@ export function StandaloneLayout(props) {
4151
4196
  currentWorkspaceId,
4152
4197
  currentTheme,
4153
4198
  handleChangePlanningOwner,
4199
+ handleChangePlanningIdentity,
4154
4200
  handleAssignInitiativeToWorkstream,
4155
4201
  handleAssignTaskToWorkstream,
4156
4202
  handleAttachTaskToWorkstreamByReference,
@@ -4198,12 +4244,12 @@ export function StandaloneLayout(props) {
4198
4244
  surfaceType: option.surfaceType ?? null,
4199
4245
  providerMetadata: option.providerMetadata ?? null,
4200
4246
  archivedAt: option.archivedAt ?? null
4201
- })), draftInitiativeSummary: planningDraftInitiativeSummary, draftTitle: planningDraftTitle, draftDescription: planningDraftDescription, draftOwner: planningDraftOwner, draftInitiativeId: planningDraftInitiativeId, onChangeDraftTitle: setPlanningDraftTitle, onChangeDraftDescription: setPlanningDraftDescription, onChangeDraftOwner: setPlanningDraftOwner, onChangeDraftInitiativeId: setPlanningDraftInitiativeId, onCollapseTreePane: () => setPlanningTreeCollapsed(true), onExpandTreePane: () => setPlanningTreeCollapsed(false), onCollapsePrimaryPane: () => setPlanningPrimaryCollapsed(true), onExpandPrimaryPane: () => setPlanningPrimaryCollapsed(false), onCollapseSecondaryPane: () => setPlanningSecondaryCollapsed(true), onExpandSecondaryPane: () => setPlanningSecondaryCollapsed(false), onBackFromSecondary: () => {
4247
+ })), draftInitiativeSummary: planningDraftInitiativeSummary, draftTitle: planningDraftTitle, draftDescription: planningDraftDescription, draftOwner: planningDraftOwner, draftInitiativeId: planningDraftInitiativeId, draftIcon: planningDraftIcon, draftColor: planningDraftColor, onChangeDraftTitle: setPlanningDraftTitle, onChangeDraftDescription: setPlanningDraftDescription, onChangeDraftOwner: setPlanningDraftOwner, onChangeDraftInitiativeId: setPlanningDraftInitiativeId, onChangeDraftIcon: setPlanningDraftIcon, onChangeDraftColor: setPlanningDraftColor, onCollapseTreePane: () => setPlanningTreeCollapsed(true), onExpandTreePane: () => setPlanningTreeCollapsed(false), onCollapsePrimaryPane: () => setPlanningPrimaryCollapsed(true), onExpandPrimaryPane: () => setPlanningPrimaryCollapsed(false), onCollapseSecondaryPane: () => setPlanningSecondaryCollapsed(true), onExpandSecondaryPane: () => setPlanningSecondaryCollapsed(false), onBackFromSecondary: () => {
4202
4248
  planningEditorSubmitInFlightRef.current = false;
4203
4249
  setIsSubmittingPlanningEditor(false);
4204
4250
  setPlanningSecondaryEditor(null);
4205
4251
  setPlanningNestedWorkstreamDetailId(null);
4206
- }, treeCollapsed: planningTreeCollapsed, primaryCollapsed: planningPrimaryCollapsed, secondaryCollapsed: planningSecondaryCollapsed, onCancelEditor: closePlanningEditor, onCancelSecondaryEditor: closePlanningSecondaryEditor, onSubmitEditor: submitPlanningEditor, isSubmittingEditor: isSubmittingPlanningEditor, onCreateInitiative: () => openPlanningCreateEditor('initiative'), onCreateWorkstream: () => openPlanningCreateEditor('workstream'), onCreateTaskInWorkstream: openAddTaskModalForWorkstream, onCreateWorkstreamInInitiative: (initiativeId) => openPlanningCreateEditor('workstream', initiativeId), onAssignInitiativeToWorkstream: handleAssignInitiativeToWorkstream, onOpenTaskById: planningWorkspaceModel.openTask, onSetTaskStatus: handleSetPlanningTaskStatus, onChangeTaskAssignee: handleChangePlanningTaskAssignee, onArchivePlanningTask: handleArchivePlanningTask, onArchiveResolvedWorkstream: handleArchiveResolvedWorkstream, onArchiveResolvedInitiative: handleArchiveResolvedInitiative, taskReferences: taskReferences, onAssignTaskToWorkstream: handleAssignTaskToWorkstream, onAttachTaskToWorkstreamByReference: handleAttachTaskToWorkstreamByReference, onAttachWorkstreamToInitiativeByReference: handleAttachWorkstreamToInitiativeByReference, onAddPlanningContextFile: handleAddPlanningContextFile, onRemovePlanningContextFile: handleRemovePlanningContextFile, onUpdatePlanningContextCaption: handleUpdatePlanningContextCaption, onToggleInitiative: togglePlanningInitiative, onSelectInitiative: selectPlanningInitiative, onSelectWorkstream: selectPlanningWorkstream, onOpenInitiativeDetails: openInitiativeDetails, onOpenWorkstreamDetails: openWorkstreamDetails, onOpenNestedWorkstreamDetails: openNestedWorkstreamDetails, onEditInitiative: (initiativeId) => openPlanningEditDialog('initiative', initiativeId), onEditWorkstream: (workstreamId) => openPlanningEditDialog('workstream', workstreamId), onChangePlanningOwner: handleChangePlanningOwner, onArchiveInitiative: (initiativeId) => {
4252
+ }, treeCollapsed: planningTreeCollapsed, primaryCollapsed: planningPrimaryCollapsed, secondaryCollapsed: planningSecondaryCollapsed, onCancelEditor: closePlanningEditor, onCancelSecondaryEditor: closePlanningSecondaryEditor, onSubmitEditor: submitPlanningEditor, isSubmittingEditor: isSubmittingPlanningEditor, onCreateInitiative: () => openPlanningCreateEditor('initiative'), onCreateWorkstream: () => openPlanningCreateEditor('workstream'), onCreateTaskInWorkstream: openAddTaskModalForWorkstream, onCreateWorkstreamInInitiative: (initiativeId) => openPlanningCreateEditor('workstream', initiativeId), onAssignInitiativeToWorkstream: handleAssignInitiativeToWorkstream, onOpenTaskById: planningWorkspaceModel.openTask, onSetTaskStatus: handleSetPlanningTaskStatus, onChangeTaskAssignee: handleChangePlanningTaskAssignee, onArchivePlanningTask: handleArchivePlanningTask, onArchiveResolvedWorkstream: handleArchiveResolvedWorkstream, onArchiveResolvedInitiative: handleArchiveResolvedInitiative, taskReferences: taskReferences, onAssignTaskToWorkstream: handleAssignTaskToWorkstream, onAttachTaskToWorkstreamByReference: handleAttachTaskToWorkstreamByReference, onAttachWorkstreamToInitiativeByReference: handleAttachWorkstreamToInitiativeByReference, onAddPlanningContextFile: handleAddPlanningContextFile, onRemovePlanningContextFile: handleRemovePlanningContextFile, onUpdatePlanningContextCaption: handleUpdatePlanningContextCaption, onToggleInitiative: togglePlanningInitiative, onSelectInitiative: selectPlanningInitiative, onSelectWorkstream: selectPlanningWorkstream, onOpenInitiativeDetails: openInitiativeDetails, onOpenWorkstreamDetails: openWorkstreamDetails, onOpenNestedWorkstreamDetails: openNestedWorkstreamDetails, onEditInitiative: (initiativeId) => openPlanningEditDialog('initiative', initiativeId), onEditWorkstream: (workstreamId) => openPlanningEditDialog('workstream', workstreamId), onChangePlanningOwner: handleChangePlanningOwner, onChangePlanningIdentity: handleChangePlanningIdentity, onArchiveInitiative: (initiativeId) => {
4207
4253
  void props.archiveInitiative(initiativeId).then(() => {
4208
4254
  pushNotice('Initiative archived', 'success');
4209
4255
  }).catch((error) => {
@@ -4327,7 +4373,7 @@ export function StandaloneLayout(props) {
4327
4373
  : taskforceAgentDrawerNode, _jsxs(Modal, { isOpen: activeTab === 'add', onClose: handleCloseModal, title: editingTaskId ? (currentTask?.isDeleted ? 'Deleted Task' : 'Edit Task') : 'New Task', size: taskModalFullscreen ? 'full' : 'xl', theme: currentTheme, className: `${styles.taskforceTaskModalOverlay} ${taskforceAgentDrawerOpen ? styles.taskforceModalWithAssistantPanel : ''} ${taskforceAgentPanelCollapsed ? styles.taskforceModalWithAssistantPanelCollapsed : ''}`.trim(), overlayStyle: {
4328
4374
  '--taskforce-task-modal-backdrop-top': `${taskforceAgentDrawerTop}px`,
4329
4375
  '--taskforce-task-modal-backdrop-left': `${WORKSPACE_TOOL_RAIL_WIDTH}px`,
4330
- }, headerActions: (_jsxs(_Fragment, { children: [!editingTaskId ? (_jsxs("button", { type: "button", onClick: (event) => handleSubmit(event), disabled: loading || !title.trim(), className: styles.primaryUpdateBtn, title: t('actionHeader.addTaskTitle'), children: [loading ? _jsx(Loader2, { size: 16, className: styles.spinner }) : _jsx(Plus, { size: 16 }), t('actionHeader.addTask')] })) : null, _jsx("button", { className: "tf-control-icon", onClick: () => setTaskModalFullscreen((value) => !value), title: taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', "aria-label": taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', children: taskModalFullscreen ? _jsx(Minimize2, { size: 18 }) : _jsx(Maximize2, { size: 18 }) })] })), draggable: !taskModalFullscreen, closeOnOverlayClick: false, children: [_jsxs("div", { className: styles.taskNoticeAnchor, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, autoSaveState: autoSaveState, title: title, status: status, onStatusChange: setStatus, showCreateSubmit: false, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreams: props.workstreams, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleUnarchiveTask: (taskId) => {
4376
+ }, headerActions: (_jsxs(_Fragment, { children: [!editingTaskId ? (_jsxs("button", { type: "button", onClick: (event) => handleSubmit(event), disabled: loading || !title.trim(), className: styles.primaryUpdateBtn, title: t('actionHeader.addTaskTitle'), children: [loading ? _jsx(Loader2, { size: 16, className: styles.spinner }) : _jsx(Plus, { size: 16 }), t('actionHeader.addTask')] })) : null, _jsx("button", { className: "tf-control-icon", onClick: () => setTaskModalFullscreen((value) => !value), title: taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', "aria-label": taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', children: taskModalFullscreen ? _jsx(Minimize2, { size: 18 }) : _jsx(Maximize2, { size: 18 }) })] })), draggable: !taskModalFullscreen, closeOnOverlayClick: false, children: [_jsxs("div", { className: styles.taskNoticeAnchor, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, submitDisabled: descriptionImageUploadPending, autoSaveState: autoSaveState, title: title, status: status, onStatusChange: setStatus, showCreateSubmit: false, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreams: props.workstreams, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleUnarchiveTask: (taskId) => {
4331
4377
  if (currentTask?.isDeleted) {
4332
4378
  const deletedRecord = deletedTaskRecordByTaskId.get(taskId);
4333
4379
  if (!deletedRecord)
@@ -4353,10 +4399,10 @@ export function StandaloneLayout(props) {
4353
4399
  : undefined, onAskAgent: handleAskTaskforceAgentForTask }), _jsx(TopNoticeLayer, { notice: error ? { message: error, tone: 'error' } : uiNotice, onDismiss: () => {
4354
4400
  clearTaskError();
4355
4401
  clearNotice();
4356
- }, placement: "task" })] }), _jsx(TaskForm, { editingTaskId: editingTaskId, initialActivityEntryId: props.initialActivityEntryId, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, currentActorId: authUserId, apiBaseUrl: apiBaseUrl, runtimeMode: runtimeMode, showImageReviews: true, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, checklistEnabled: checklistDropdownEnabled, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, initiatives: props.initiatives, copiedId: copiedId, onTitleChange: setTitle, onTitleDraftChange: setTitleDraft, onDescriptionChange: setDescription, onDescriptionDraftChange: setDescriptionDraft, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onOpenSettings: (section) => {
4402
+ }, placement: "task" })] }), _jsx(TaskForm, { editingTaskId: editingTaskId, initialActivityEntryId: props.initialActivityEntryId, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, descriptionImageDraftId: descriptionImageDraftId, currentActorId: authUserId, apiBaseUrl: apiBaseUrl, runtimeMode: runtimeMode, showImageReviews: true, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, checklistEnabled: checklistDropdownEnabled, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, initiatives: props.initiatives, copiedId: copiedId, onTitleChange: setTitle, onTitleDraftChange: setTitleDraft, onDescriptionChange: setDescription, onDescriptionDraftChange: setDescriptionDraft, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onOpenSettings: (section) => {
4357
4403
  setSettingsSection(section);
4358
4404
  setActiveTab('settings');
4359
- }, onSubmit: handleSubmit, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), taskReferences: taskTextReferences, onAddContextFile: (file) => {
4405
+ }, onSubmit: handleSubmit, onDescriptionImageUploadStart: registerDescriptionImageUpload, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), taskReferences: taskTextReferences, onAddContextFile: (file) => {
4360
4406
  updateTaskContextAttachments((current) => [...current, file]);
4361
4407
  }, onRemoveContextFile: async (index) => {
4362
4408
  updateTaskContextAttachments((current) => current.filter((_, i) => i !== index));
@@ -4368,7 +4414,14 @@ export function StandaloneLayout(props) {
4368
4414
  return { path: s, caption, timestamp: new Date().toISOString() };
4369
4415
  return { ...s, caption };
4370
4416
  }));
4371
- }, onOpenContextImage: (attachment) => {
4417
+ }, onSetCardCover: async (assetId) => {
4418
+ if (!editingTaskId)
4419
+ return;
4420
+ const saved = await handleUpdateTask(editingTaskId, { cardCoverAssetId: assetId });
4421
+ if (saved === false) {
4422
+ throw new Error('Unable to update the task card image.');
4423
+ }
4424
+ }, cardCoverDisabled: attachmentsDirty, onOpenContextImage: (attachment) => {
4372
4425
  dispatchPreviewContextAttachment(attachment, {
4373
4426
  ownerType: 'task',
4374
4427
  ownerId: editingTaskId,
@@ -42,9 +42,9 @@ export function WidgetView(props) {
42
42
  // Actions
43
43
  handleEdit, handleDelete, handleCopyId, handleUpdateTask, handleToggleComplete, handleToggleCancel, handleToggleInProgress, handleToggleReview, handleSetStatus, handleArchiveTask, handleBulkArchive, handleUnarchive, handleRestoreDeletedTask, handleRestoreSelectedDeletedTasks, handlePermanentlyDeleteDeletedTask, handleEmptyDeletedTasks, fetchArchive,
44
44
  // Form State
45
- editingTaskId, loading, error, clearTaskError, title, setTitle, setTitleDraft, description, setDescription, setDescriptionDraft, checklistItems, setChecklistItems, category, setCategory, type, setType, priority, setPriority, complexity, setComplexity, status, setStatus, manualComplexityEnabled, checklistDropdownEnabled, showTaskCardStatusLabel, assignee, setAssignee, scheduledDate, setScheduledDate, dueDate, setDueDate, workstreamInput, setWorkstreamInput, formTaxonomies, setFormTaxonomies, comments, newCommentText, setNewCommentText, attachments, setAttachments, setAttachmentsDirty, descriptionFocused, setDescriptionFocused, showMarkdownHelp, setShowMarkdownHelp,
45
+ editingTaskId, loading, error, clearTaskError, title, setTitle, setTitleDraft, description, setDescription, setDescriptionDraft, checklistItems, setChecklistItems, category, setCategory, type, setType, priority, setPriority, complexity, setComplexity, status, setStatus, manualComplexityEnabled, checklistDropdownEnabled, showTaskCardStatusLabel, assignee, setAssignee, scheduledDate, setScheduledDate, dueDate, setDueDate, workstreamInput, setWorkstreamInput, formTaxonomies, setFormTaxonomies, comments, newCommentText, setNewCommentText, attachments, setAttachments, setAttachmentsDirty, descriptionImageUploadPending, descriptionImageDraftId, registerDescriptionImageUpload, descriptionFocused, setDescriptionFocused, showMarkdownHelp, setShowMarkdownHelp,
46
46
  // Form Actions
47
- handleSubmit, resetForm, handleAddComment, handleSetWorkstreamForCurrentTask, handleOpenTaskById,
47
+ handleSubmit, resetForm, discardDescriptionImageDraft, handleAddComment, handleSetWorkstreamForCurrentTask, handleOpenTaskById,
48
48
  // Modals
49
49
  autoSaveState, unsavedModalOpen, setUnsavedModalOpen, pendingNavigation, handleNavigation, handleClose, scheduleWarningPrompt, confirmScheduleWarning, cancelScheduleWarning,
50
50
  // Misc
@@ -188,6 +188,9 @@ export function WidgetView(props) {
188
188
  };
189
189
  const handleDiscard = () => {
190
190
  setUnsavedModalOpen(false);
191
+ if (activeTab === 'add' && !editingTaskId) {
192
+ void discardDescriptionImageDraft();
193
+ }
191
194
  if (pendingNavigation) {
192
195
  // If we are discarding, we just execute pending nav.
193
196
  // Core logic had `if (activeTab === 'add' && !returnTab) resetForm();`
@@ -322,7 +325,7 @@ export function WidgetView(props) {
322
325
  handleNavigation(() => {
323
326
  setActiveTab('settings');
324
327
  });
325
- }, title: "Settings", "aria-label": "Settings", children: _jsx(Settings, { size: 18 }) }), _jsx("button", { className: "tf-control-icon", onClick: handleXClick, title: activeTab === 'tasks' ? "Close" : "Back to Tasks", "aria-label": activeTab === 'tasks' ? "Close" : "Back to Tasks", children: activeTab === 'tasks' ? _jsx(X, { size: 20 }) : _jsx(ArrowLeft, { size: 20 }) })] })] }), _jsx(TopNoticeLayer, { notice: activeTab === 'add' ? null : uiNotice, onDismiss: clearNotice }), _jsx(AttachmentPreviewHost, { theme: currentTheme }), activeTab === 'add' && (_jsxs("div", { className: styles.taskNoticeAnchor, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, autoSaveState: autoSaveState, title: title, status: status, onStatusChange: setStatus, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreams: props.workstreams, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleUnarchiveTask: (taskId) => {
328
+ }, title: "Settings", "aria-label": "Settings", children: _jsx(Settings, { size: 18 }) }), _jsx("button", { className: "tf-control-icon", onClick: handleXClick, title: activeTab === 'tasks' ? "Close" : "Back to Tasks", "aria-label": activeTab === 'tasks' ? "Close" : "Back to Tasks", children: activeTab === 'tasks' ? _jsx(X, { size: 20 }) : _jsx(ArrowLeft, { size: 20 }) })] })] }), _jsx(TopNoticeLayer, { notice: activeTab === 'add' ? null : uiNotice, onDismiss: clearNotice }), _jsx(AttachmentPreviewHost, { theme: currentTheme }), activeTab === 'add' && (_jsxs("div", { className: styles.taskNoticeAnchor, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, submitDisabled: descriptionImageUploadPending, autoSaveState: autoSaveState, title: title, status: status, onStatusChange: setStatus, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreams: props.workstreams, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleUnarchiveTask: (taskId) => {
326
329
  if (currentTask?.isDeleted) {
327
330
  const deletedRecord = deletedRecordByTaskId.get(taskId);
328
331
  if (deletedRecord) {
@@ -359,12 +362,12 @@ export function WidgetView(props) {
359
362
  void handleDelete(taskId);
360
363
  }, onDeleteAllDeleted: () => {
361
364
  void handleEmptyDeletedTasks();
362
- }, onFetchArchive: fetchArchive, onAddTaskToCategory: handleAddTaskToCategory, supplementalTasks: deletedScopeTasks })), activeTab === 'add' && (_jsx(TaskForm, { editingTaskId: editingTaskId, initialActivityEntryId: props.initialActivityEntryId, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, formTaxonomies: formTaxonomies, onTaxonomyChange: onTaxonomyChange, taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, currentActorId: authUserId, apiBaseUrl: "", descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, checklistEnabled: checklistDropdownEnabled, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, initiatives: props.initiatives, copiedId: copiedId, onTitleChange: setTitle, onTitleDraftChange: setTitleDraft, onDescriptionChange: setDescription, onDescriptionDraftChange: setDescriptionDraft, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onOpenSettings: (section) => {
365
+ }, onFetchArchive: fetchArchive, onAddTaskToCategory: handleAddTaskToCategory, supplementalTasks: deletedScopeTasks })), activeTab === 'add' && (_jsx(TaskForm, { editingTaskId: editingTaskId, initialActivityEntryId: props.initialActivityEntryId, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, formTaxonomies: formTaxonomies, onTaxonomyChange: onTaxonomyChange, taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, descriptionImageDraftId: descriptionImageDraftId, currentActorId: authUserId, apiBaseUrl: "", descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, checklistEnabled: checklistDropdownEnabled, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, initiatives: props.initiatives, copiedId: copiedId, onTitleChange: setTitle, onTitleDraftChange: setTitleDraft, onDescriptionChange: setDescription, onDescriptionDraftChange: setDescriptionDraft, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onOpenSettings: (section) => {
363
366
  handleNavigation(() => {
364
367
  setSettingsSection(section);
365
368
  setActiveTab('settings');
366
369
  });
367
- }, onSubmit: handleSubmit, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), taskReferences: taskTextReferences, onAddContextFile: (file) => {
370
+ }, onSubmit: handleSubmit, onDescriptionImageUploadStart: registerDescriptionImageUpload, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), taskReferences: taskTextReferences, onAddContextFile: (file) => {
368
371
  setAttachmentsDirty(true);
369
372
  setAttachments(prev => [...prev, file]);
370
373
  }, onRemoveContextFile: async (index) => {
@@ -6,6 +6,7 @@ import { type PlanningFavorite } from '../../../utils/planningFavorites';
6
6
  import type { PlanningTaskScope } from '../planningScope';
7
7
  import type { PlanningInitiativeSummary, PlanningLinkOptions, PlanningWorkstreamSummary } from '../../features/planning/planningWorkspaceModel';
8
8
  import type { PlanningEntityHydrationState } from '../../features/planning/planningWorkspaceModel';
9
+ import { type PlanningIdentityPatch } from '../../features/planning/PlanningVisualIdentity';
9
10
  import { type PlanningTaskArrangeMode } from '../../features/planning/planningTaskArrangement';
10
11
  import { type PlanningOwnerOption } from '../../features/planning/PlanningOwnerDropdown';
11
12
  import { type PlanningNavigatorSort } from '../../features/planning/planningNavigator';
@@ -93,10 +94,14 @@ type PlanningDrawerProps = {
93
94
  draftDescription: string;
94
95
  draftOwner: string;
95
96
  draftInitiativeId: string;
97
+ draftIcon?: Exclude<PlanningIdentityPatch['icon'], undefined>;
98
+ draftColor?: Exclude<PlanningIdentityPatch['color'], undefined>;
96
99
  onChangeDraftTitle: (value: string) => void;
97
100
  onChangeDraftDescription: (value: string) => void;
98
101
  onChangeDraftOwner: (value: string) => void;
99
102
  onChangeDraftInitiativeId: (value: string) => void;
103
+ onChangeDraftIcon?: (value: Exclude<PlanningIdentityPatch['icon'], undefined>) => void;
104
+ onChangeDraftColor?: (value: Exclude<PlanningIdentityPatch['color'], undefined>) => void;
100
105
  onCollapseTreePane: () => void;
101
106
  onExpandTreePane: () => void;
102
107
  onCollapsePrimaryPane: () => void;
@@ -122,6 +127,7 @@ type PlanningDrawerProps = {
122
127
  onEditInitiative: (initiativeId: string) => void;
123
128
  onEditWorkstream: (workstreamId: string) => void;
124
129
  onChangePlanningOwner: (entityType: 'initiative' | 'workstream', entityId: string, ownerId: string) => void | Promise<void>;
130
+ onChangePlanningIdentity?: (entityType: 'initiative' | 'workstream', entityId: string, patch: PlanningIdentityPatch) => void | Promise<void>;
125
131
  onChangeTaskAssignee?: (taskId: string, assignee: string) => void | Promise<void>;
126
132
  onArchiveInitiative: (initiativeId: string) => void;
127
133
  onUnarchiveInitiative: (initiativeId: string) => void;
@@ -143,4 +149,4 @@ type PlanningDrawerProps = {
143
149
  onRemovePlanningContextFile?: (entityType: 'initiative' | 'workstream', entityId: string, index: number) => void;
144
150
  onUpdatePlanningContextCaption?: (entityType: 'initiative' | 'workstream', entityId: string, index: number, caption: string) => void;
145
151
  };
146
- export declare function PlanningDrawer({ open, leftOffset, returnFocusRef, onWidthChange, initiatives, standaloneWorkstreams, planningLoadState, onRetryPlanning, taskScope, activeInitiativeId, activeWorkstreamId, navigatorSort, navigatorSortReady, onNavigatorSortChange, taskArrangeMode, onTaskArrangeModeChange, onReorderWorkstreamTasks, planningFavorites, onTogglePlanningFavorite, favoritesSectionCollapsed, initiativesSectionCollapsed, workstreamsSectionCollapsed, onToggleFavoritesSection, onToggleInitiativesSection, onToggleWorkstreamsSection, expandedInitiativeIds, detail, editor, secondaryEditor, secondaryPane, primaryHydrationState, secondaryHydrationState, onRetryPrimaryHydration, onRetrySecondaryHydration, currentWorkspaceId, currentOwnerId, theme, assigneeOptions, linkOptions, showTaskCardStatusLabel, 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, }: PlanningDrawerProps): import("react/jsx-runtime").JSX.Element;
152
+ export declare function PlanningDrawer({ open, leftOffset, returnFocusRef, onWidthChange, initiatives, standaloneWorkstreams, planningLoadState, onRetryPlanning, taskScope, activeInitiativeId, activeWorkstreamId, navigatorSort, navigatorSortReady, onNavigatorSortChange, taskArrangeMode, onTaskArrangeModeChange, onReorderWorkstreamTasks, planningFavorites, onTogglePlanningFavorite, favoritesSectionCollapsed, initiativesSectionCollapsed, workstreamsSectionCollapsed, onToggleFavoritesSection, onToggleInitiativesSection, onToggleWorkstreamsSection, expandedInitiativeIds, detail, editor, secondaryEditor, secondaryPane, primaryHydrationState, secondaryHydrationState, onRetryPrimaryHydration, onRetrySecondaryHydration, currentWorkspaceId, currentOwnerId, theme, assigneeOptions, linkOptions, showTaskCardStatusLabel, draftInitiativeSummary, draftTitle, draftDescription, draftOwner, draftInitiativeId, draftIcon, draftColor, 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, }: PlanningDrawerProps): import("react/jsx-runtime").JSX.Element;