@taskforcehq/taskforce 0.3.327 → 0.3.329
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Taskforce.module.css +257 -87
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/activity/EntityActivityTimeline.js +15 -5
- package/dist/components/context/AttachmentPreviewHost.js +1 -1
- package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
- package/dist/components/context/ContextAttachmentManager.js +116 -20
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +147 -40
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
- package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
- package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
- package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
- package/dist/components/features/planning/PlanningModule.js +28 -14
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
- package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +2 -2
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +101 -13
- package/dist/components/task/TaskContextUpload.d.ts +3 -0
- package/dist/components/task/TaskContextUpload.js +2 -2
- package/dist/components/task/TaskForm.d.ts +4 -0
- package/dist/components/task/TaskForm.js +32 -7
- package/dist/components/task/TaskImageReviews.js +28 -19
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/task/TaskStatusActions.js +11 -2
- package/dist/components/task/TaskWorkstreamPicker.js +2 -1
- package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
- package/dist/components/ui/DocumentTypeIcon.js +8 -0
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
- package/dist/components/ui/TaxonomyDropdown.js +30 -3
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +68 -39
- package/dist/components/views/WidgetView.js +10 -7
- package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
- package/dist/components/views/panels/PlanningDrawer.js +51 -54
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +13 -0
- package/dist/config/localServiceCloudTarget.d.ts +10 -0
- package/dist/config/localServiceCloudTarget.js +76 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.d.ts +1 -0
- package/dist/core/AiProfileService.js +48 -9
- package/dist/core/AttachmentLinkService.js +7 -4
- package/dist/core/DeletedTaskLifecycleService.d.ts +5 -0
- package/dist/core/DeletedTaskLifecycleService.js +55 -3
- package/dist/core/McpTokenService.d.ts +4 -0
- package/dist/core/McpTokenService.js +52 -0
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +8 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +51 -18
- package/dist/core/Taskforce.d.ts +124 -2
- package/dist/core/Taskforce.js +1175 -87
- package/dist/core/types.d.ts +8 -1
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
- package/dist/documentReviews/service.d.ts +4 -0
- package/dist/documentReviews/service.js +141 -46
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +9 -0
- package/dist/hooks/tasks/useTaskFormActions.js +96 -17
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useTaskData.d.ts +10 -1
- package/dist/hooks/useTaskData.js +216 -7
- package/dist/hooks/useTaskMutations.d.ts +10 -2
- package/dist/hooks/useTaskMutations.js +223 -43
- package/dist/hooks/useTaskforce.d.ts +94 -57
- package/dist/hooks/useTaskforce.js +428 -16
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/canonicalAssetHelpers.d.ts +13 -0
- package/dist/mcp/canonicalAssetHelpers.js +39 -5
- package/dist/mcp/collaborationRegistrar.js +15 -13
- package/dist/mcp/documentAssetRegistrar.js +60 -44
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/localServiceProxy.js +4 -1
- package/dist/mcp/runtime.d.ts +16 -0
- package/dist/mcp/runtime.js +735 -210
- package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
- package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
- package/dist/mcp/taskPlanningRegistrar.js +78 -67
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +2 -2
- package/dist/migrations/taskSchemaMigrations.js +47 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +12 -13
- package/dist/runtime/appGates.js +29 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/appAccess.d.ts +12 -0
- package/dist/server/appAccess.js +21 -0
- package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
- package/dist/server/authorizedWorkspaceAccess.js +40 -0
- package/dist/server/cloudCollectionRead.d.ts +25 -0
- package/dist/server/cloudCollectionRead.js +120 -0
- package/dist/server/cloudCollectionReadPool.d.ts +52 -0
- package/dist/server/cloudCollectionReadPool.js +140 -0
- package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
- package/dist/server/cloudCollectionReadWorker.js +36 -0
- package/dist/server/index.d.ts +6 -11
- package/dist/server/index.js +67 -42
- package/dist/server/localServiceLease.d.ts +6 -0
- package/dist/server/localServiceLease.js +17 -1
- package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.js +1 -0
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.js +118 -16
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/documents.d.ts +5 -2
- package/dist/server/routes/documents.js +160 -13
- package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
- package/dist/server/routes/durableTaskHttpRouters.js +2 -2
- package/dist/server/routes/localService.js +4 -0
- package/dist/server/routes/primitives.d.ts +4 -0
- package/dist/server/routes/shared.d.ts +24 -0
- package/dist/server/routes/shared.js +114 -18
- package/dist/server/routes/sync.js +22 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +22 -18
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +48 -4
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +27 -2
- package/dist/server/routes/tasks.js +299 -97
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/routes.js +35 -7
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +52 -25
- package/dist/service/localServiceClientLifecycle.js +93 -6
- package/dist/services/codexAppServerModelGateway.d.ts +112 -0
- package/dist/services/codexAppServerModelGateway.js +438 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
- package/dist/services/taskforceAgentMcpBridge.js +23 -3
- package/dist/shared/planningIdentity.d.ts +20 -0
- package/dist/shared/planningIdentity.js +79 -0
- package/dist/shared/taskforceAgentDefinition.js +7 -1
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +30 -1
- package/dist/storage/postgresAdapter.d.ts +20 -3
- package/dist/storage/postgresAdapter.js +110 -14
- package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
- package/dist/storage/postgresRequestDiagnostics.js +24 -0
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/storage/workspaceAssetStore.d.ts +32 -0
- package/dist/storage/workspaceAssetStore.js +70 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +17 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +77 -23
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +16 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +46 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +51 -11
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
- package/dist/sync/syncApplyHandlers.d.ts +3 -1
- package/dist/sync/syncApplyHandlers.js +29 -0
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/taskSyncPayload.d.ts +1 -0
- package/dist/sync/taskSyncPayload.js +6 -0
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +3 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +31 -3
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +47 -12
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
- package/dist/sync/v3/localOutboxDispatcher.js +5 -1
- package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +3 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +62 -10
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
- package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
- package/dist/sync/v3/syncDurabilityStore.d.ts +15 -0
- package/dist/sync/v3/syncDurabilityStore.js +201 -43
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +7 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +37 -12
- package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
- package/dist/sync/v3/taskChecklistMutationService.js +4 -0
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
- package/dist/sync/v3/taskStatusMutationService.js +4 -0
- package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
- package/dist/sync/v3/workflowAssignmentSync.js +3 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +14 -12
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +10 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +15 -4
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +66 -13
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +57 -22
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +10 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -51
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +120 -28
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -0
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
- package/dist/sync/workspacePullFeed.d.ts +6 -1
- package/dist/sync/workspacePullFeed.js +174 -162
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/sync/workspaceSyncModel.d.ts +11 -0
- package/dist/sync/workspaceSyncModel.js +27 -2
- package/dist/types.d.ts +55 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/AssetTraySortControl-C8Rztyal.js +1 -0
- package/dist/ui/assets/ContextAttachmentManager-Cj3c7X9y.js +3 -0
- package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-B5uvzems.js} +4 -4
- package/dist/ui/assets/EntityActivityTimeline-BVFvCB5R.js +1 -0
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/WorkflowManagerModule-DEr5di_r.js +1 -0
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.js +1 -1
- package/dist/utils/contextAttachmentUpload.d.ts +2 -0
- package/dist/utils/contextAttachmentUpload.js +7 -0
- package/dist/utils/contextFiles.d.ts +1 -1
- package/dist/utils/contextFiles.js +4 -4
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/package.json +21 -4
- package/dist/ui/assets/AiProfilesModule-DPxQeF9N.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DHNYaNg6.js +0 -3
- package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
- package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
- package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
- package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
- package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
- package/dist/ui/assets/PlansPage-BVH_NfgT.js +0 -1
- package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
- package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
- package/dist/ui/assets/TaskSettings-xVsxSa0g.js +0 -12
- package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
- package/dist/ui/assets/index-BzJlVnNS.css +0 -1
- package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { AlertTriangle, Archive, ArrowUpDown, ChevronLeft, Eye, EyeOff, Filter,
|
|
3
|
+
import { AlertTriangle, Archive, ArrowUpDown, ChevronLeft, Eye, EyeOff, Filter, Loader2, Pencil, Plus, RotateCcw, Search, Unlink, X, } from 'lucide-react';
|
|
4
4
|
import { TASK_ASSIGNEE_UNASSIGNED_COLOR, TASK_ASSIGNEE_UNASSIGNED_ICON, } from '../../../utils/assignees';
|
|
5
5
|
import { resolvePlanningArchiveDetailState } from '../../../utils/planningArchivePresentation';
|
|
6
6
|
import { formatInitiativeReference, formatWorkstreamReference, } from '../../../utils/planningReferences';
|
|
@@ -10,6 +10,7 @@ import { TaxonomyDropdown } from '../../ui/TaxonomyDropdown';
|
|
|
10
10
|
import { PlanningOwnerDropdown, normalizePlanningOwnerOptions, } from './PlanningOwnerDropdown';
|
|
11
11
|
import { buildPlanningNavigatorResults, PLANNING_NAVIGATOR_SORT_OPTIONS, } from './planningNavigator';
|
|
12
12
|
import { PlanningEntitySummary, PlanningReferenceBadge, } from './PlanningEntitySummary';
|
|
13
|
+
import { PlanningVisualIdentity } from './PlanningVisualIdentity';
|
|
13
14
|
import { PlanningTaskCard } from './PlanningTaskCard';
|
|
14
15
|
import { PlanningTaskArrangeControl } from './PlanningTaskArrangeControl';
|
|
15
16
|
import planningDropdownStyles from './PlanningDropdownControl.module.css';
|
|
@@ -29,6 +30,8 @@ function PlanningWorkspaceEditor({ entityType, mode, initialTitle = '', initialD
|
|
|
29
30
|
const [title, setTitle] = React.useState(initialTitle);
|
|
30
31
|
const [description, setDescription] = React.useState(initialDescription);
|
|
31
32
|
const [ownerId, setOwnerId] = React.useState('');
|
|
33
|
+
const [icon, setIcon] = React.useState(null);
|
|
34
|
+
const [color, setColor] = React.useState(null);
|
|
32
35
|
const [titleError, setTitleError] = React.useState(null);
|
|
33
36
|
const [saveError, setSaveError] = React.useState(null);
|
|
34
37
|
const [isSaving, setIsSaving] = React.useState(false);
|
|
@@ -57,6 +60,7 @@ function PlanningWorkspaceEditor({ entityType, mode, initialTitle = '', initialD
|
|
|
57
60
|
...(entityType === 'workstream' && mode === 'create'
|
|
58
61
|
? { initiativeId: fixedInitiativeId || null }
|
|
59
62
|
: {}),
|
|
63
|
+
...(mode === 'create' && (icon || color) ? { icon, color } : {}),
|
|
60
64
|
});
|
|
61
65
|
}
|
|
62
66
|
catch (error) {
|
|
@@ -72,7 +76,12 @@ function PlanningWorkspaceEditor({ entityType, mode, initialTitle = '', initialD
|
|
|
72
76
|
return;
|
|
73
77
|
event.preventDefault();
|
|
74
78
|
onCancel();
|
|
75
|
-
}, noValidate: true, children: [_jsxs("div", { className: styles.
|
|
79
|
+
}, noValidate: true, children: [mode === 'create' ? (_jsxs("div", { className: styles.workspaceEditorIdentity, children: [_jsx(PlanningVisualIdentity, { entityType: entityType, entityId: "create-preview", icon: icon, color: color || 'blue', size: "detail", onChange: (patch) => {
|
|
80
|
+
if (Object.prototype.hasOwnProperty.call(patch, 'icon'))
|
|
81
|
+
setIcon(patch.icon ?? null);
|
|
82
|
+
if (Object.prototype.hasOwnProperty.call(patch, 'color'))
|
|
83
|
+
setColor(patch.color ?? null);
|
|
84
|
+
} }), _jsx("span", { children: "Choose an icon and color" })] })) : null, _jsxs("div", { className: styles.workspaceEditorField, children: [_jsxs("label", { htmlFor: titleInputId, children: [label, " title"] }), _jsx("input", { ref: titleInputRef, id: titleInputId, value: title, disabled: isSaving, required: true, "aria-invalid": titleError ? 'true' : undefined, "aria-describedby": titleError ? titleErrorId : undefined, onChange: (event) => {
|
|
76
85
|
setTitle(event.target.value);
|
|
77
86
|
if (titleError)
|
|
78
87
|
setTitleError(null);
|
|
@@ -80,24 +89,24 @@ function PlanningWorkspaceEditor({ entityType, mode, initialTitle = '', initialD
|
|
|
80
89
|
? 'Describe the broader outcome this initiative is meant to achieve.'
|
|
81
90
|
: 'Describe the lane of work this workstream will coordinate.' })] }), mode === 'create' && ownerOptions ? (_jsxs("div", { className: styles.workspaceEditorField, children: [_jsxs("span", { children: [label, " owner"] }), _jsx(PlanningOwnerDropdown, { value: ownerId, options: ownerOptions, onChange: setOwnerId, disabled: isSaving, ariaLabel: `${label} owner`, className: `${planningDropdownStyles.control} ${styles.selectedEntityOwnerDropdown}` })] })) : null, saveError ? _jsx("p", { className: "tf-text-error", role: "alert", children: saveError }) : null, showActions ? _jsxs("div", { className: styles.workspaceEditorActions, children: [_jsx("button", { type: "button", className: "tf-button-secondary tf-button-compact", onClick: onCancel, disabled: isSaving, children: "Cancel" }), _jsxs("button", { type: "submit", className: "tf-button-primary tf-button-compact", disabled: isSaving, children: [isSaving ? _jsx(Loader2, { size: 14, className: styles.spinner, "aria-hidden": "true" }) : null, mode === 'create' ? `Create ${label}` : 'Save'] })] }) : null] }));
|
|
82
91
|
}
|
|
83
|
-
function InitiativeButton({ initiative, ownerOption, ownerOptions, workstreamCount, selected, onSelect, onChangeOwner, }) {
|
|
92
|
+
function InitiativeButton({ initiative, ownerOption, ownerOptions, workstreamCount, selected, onSelect, onChangeOwner, onChangeIdentity, }) {
|
|
84
93
|
return (_jsxs("div", { className: `${styles.entityCard} ${initiative.isArchived ? styles.entityCardArchived : ''} ${selected ? styles.entityCardSelected : ''}`.trim(), children: [_jsx(PlanningReferenceBadge, { label: formatInitiativeReference(initiative), entityType: "initiative", entityName: initiative.title, interactive: false }), _jsx("div", { className: styles.entityCardBody, children: _jsx("div", { role: "button", tabIndex: 0, className: styles.entityCardContentButton, onClick: onSelect, onKeyDown: (event) => {
|
|
85
94
|
if (event.key !== 'Enter' && event.key !== ' ')
|
|
86
95
|
return;
|
|
87
96
|
event.preventDefault();
|
|
88
97
|
onSelect();
|
|
89
|
-
}, "aria-pressed": selected, children: _jsx(PlanningEntitySummary, { item: initiative, entityType: "initiative", workstreamCount: workstreamCount, ownerOption: ownerOption, ownerOptions: ownerOptions, onChangeOwner: onChangeOwner }) }) })] }));
|
|
98
|
+
}, "aria-pressed": selected, children: _jsx(PlanningEntitySummary, { item: initiative, entityType: "initiative", workstreamCount: workstreamCount, ownerOption: ownerOption, ownerOptions: ownerOptions, onChangeOwner: onChangeOwner, onChangeIdentity: onChangeIdentity }) }) })] }));
|
|
90
99
|
}
|
|
91
|
-
function WorkstreamButton({ workstream, ownerOption, ownerOptions, selected, onSelect, onChangeOwner, referenceAction, feedback, }) {
|
|
100
|
+
function WorkstreamButton({ workstream, ownerOption, ownerOptions, selected, onSelect, onChangeOwner, onChangeIdentity, referenceAction, feedback, }) {
|
|
92
101
|
const referenceLabel = formatWorkstreamReference(workstream);
|
|
93
102
|
return (_jsxs("div", { className: `${styles.entityCard} ${workstream.isArchived ? styles.entityCardArchived : ''} ${selected ? styles.entityCardSelected : ''}`.trim(), children: [_jsxs("div", { className: styles.entityCardTopRow, children: [referenceAction, _jsx(PlanningReferenceBadge, { label: referenceLabel || 'Reference pending', entityType: "workstream", entityName: workstream.title, interactive: false, pending: !referenceLabel })] }), feedback, _jsx("div", { className: styles.entityCardBody, children: _jsx("div", { role: "button", tabIndex: 0, className: styles.entityCardContentButton, onClick: onSelect, onKeyDown: (event) => {
|
|
94
103
|
if (event.key !== 'Enter' && event.key !== ' ')
|
|
95
104
|
return;
|
|
96
105
|
event.preventDefault();
|
|
97
106
|
onSelect();
|
|
98
|
-
}, "aria-pressed": selected, children: _jsx(PlanningEntitySummary, { item: workstream, entityType: "workstream", ownerOption: ownerOption, ownerOptions: ownerOptions, onChangeOwner: onChangeOwner }) }) })] }));
|
|
107
|
+
}, "aria-pressed": selected, children: _jsx(PlanningEntitySummary, { item: workstream, entityType: "workstream", ownerOption: ownerOption, ownerOptions: ownerOptions, onChangeOwner: onChangeOwner, onChangeIdentity: onChangeIdentity }) }) })] }));
|
|
99
108
|
}
|
|
100
|
-
function SelectedEntityContext({ item, entityType, ownerOptions, onChangeOwner, workspaceId, currentActorId, taskReferences, hydrationState, onRetryHydration, onAddContextFile, onRemoveContextFile, onUpdateContextCaption, onUpdate, onArchive, onUnarchive, referenceAction, relationshipActions, relationshipContent, }) {
|
|
109
|
+
function SelectedEntityContext({ item, entityType, ownerOptions, onChangeOwner, onChangeIdentity, workspaceId, currentActorId, taskReferences, hydrationState, onRetryHydration, onAddContextFile, onRemoveContextFile, onUpdateContextCaption, onUpdate, onArchive, onUnarchive, referenceAction, relationshipActions, relationshipContent, }) {
|
|
101
110
|
const label = entityType === 'initiative' ? 'Initiative' : 'Workstream';
|
|
102
111
|
const referenceLabel = entityType === 'initiative'
|
|
103
112
|
? formatInitiativeReference(item)
|
|
@@ -181,7 +190,9 @@ function SelectedEntityContext({ item, entityType, ownerOptions, onChangeOwner,
|
|
|
181
190
|
setArchiveBusy(false);
|
|
182
191
|
}
|
|
183
192
|
};
|
|
184
|
-
return (_jsxs("section", { className: `${styles.selectedEntityContext} ${item.isArchived ? styles.selectedEntityContextArchived : ''}`.trim(), "aria-label": `Selected ${label.toLowerCase()}`, "aria-busy": hydrationState?.status === 'loading', children: [_jsxs("div", { className: styles.selectedEntityReferenceRow, children: [_jsxs("div", { className: styles.selectedEntityReferenceIdentity, children: [
|
|
193
|
+
return (_jsxs("section", { className: `${styles.selectedEntityContext} ${item.isArchived ? styles.selectedEntityContextArchived : ''}`.trim(), "aria-label": `Selected ${label.toLowerCase()}`, "aria-busy": hydrationState?.status === 'loading', children: [_jsxs("div", { className: styles.selectedEntityReferenceRow, children: [_jsxs("div", { className: styles.selectedEntityReferenceIdentity, children: [_jsx(PlanningVisualIdentity, { entityType: entityType, entityId: item.id, icon: item.icon, color: item.color, size: "detail", disabled: Boolean(item.isArchived), onChange: onChangeIdentity
|
|
194
|
+
? (patch) => onChangeIdentity(entityType, item.id, patch)
|
|
195
|
+
: undefined }), referenceAction, _jsx(PlanningReferenceBadge, { label: referenceLabel || 'Reference pending', entityType: entityType, entityName: item.title, interactive: false, pending: !referenceLabel })] }), _jsxs("div", { className: styles.selectedEntityReferenceActions, children: [_jsx("span", { children: label }), relationshipActions, !isEditing && (onArchive || onUnarchive) ? (_jsx("button", { type: "button", className: "tf-control-icon", disabled: archiveBusy
|
|
185
196
|
|| archiveState.mode === 'blocked'
|
|
186
197
|
|| archiveState.mode === 'checking'
|
|
187
198
|
|| (archiveState.mode === 'archived' ? !onUnarchive : !onArchive), onClick: () => void handleArchiveAction(), "aria-label": archiveActionLabel, title: archiveActionLabel, "aria-expanded": archiveState.mode === 'ready'
|
|
@@ -212,7 +223,6 @@ export function PlanningModule({ model }) {
|
|
|
212
223
|
const [showArchivedPlanning, setShowArchivedPlanning] = React.useState(false);
|
|
213
224
|
const taskArrangeMode = model.taskArrangeMode || 'execution';
|
|
214
225
|
const [createState, setCreateState] = React.useState(null);
|
|
215
|
-
const [showParentLinkPicker, setShowParentLinkPicker] = React.useState(false);
|
|
216
226
|
const [pendingUnlink, setPendingUnlink] = React.useState(null);
|
|
217
227
|
const [relationshipRecovery, setRelationshipRecovery] = React.useState(null);
|
|
218
228
|
const [isChangingRelationship, setIsChangingRelationship] = React.useState(false);
|
|
@@ -338,7 +348,6 @@ export function PlanningModule({ model }) {
|
|
|
338
348
|
void model.hydrateEntity(selectedEntityType, selectedEntityId);
|
|
339
349
|
}, [model.hydrateEntity, selectedEntityId, selectedEntityType]);
|
|
340
350
|
React.useEffect(() => {
|
|
341
|
-
setShowParentLinkPicker(false);
|
|
342
351
|
setPendingUnlink(null);
|
|
343
352
|
setRelationshipRecovery(null);
|
|
344
353
|
setIsChangingRelationship(false);
|
|
@@ -423,7 +432,6 @@ export function PlanningModule({ model }) {
|
|
|
423
432
|
const result = await model.assignWorkstreamToInitiative(selectedWorkstream.id, option.referenceLabel);
|
|
424
433
|
if (result !== false) {
|
|
425
434
|
setSelectedInitiativeId(option.id);
|
|
426
|
-
setShowParentLinkPicker(false);
|
|
427
435
|
}
|
|
428
436
|
}
|
|
429
437
|
finally {
|
|
@@ -500,12 +508,16 @@ export function PlanningModule({ model }) {
|
|
|
500
508
|
return (_jsxs("main", { className: styles.module, "aria-label": "Planning workspace", "aria-busy": model.loadState.isRefreshing, children: [model.loadState.isRefreshing ? (_jsx("span", { className: styles.visuallyHidden, role: "status", "aria-live": "polite", children: "Refreshing planning" })) : null, (model.loadState.status === 'partial' || model.loadState.status === 'error') && (_jsxs("div", { className: styles.inlineError, role: "alert", children: [_jsx(AlertTriangle, { size: 16 }), _jsx("span", { children: model.loadState.error || 'Some planning information could not be loaded.' }), _jsx("button", { type: "button", className: "tf-button-secondary tf-button-compact", onClick: model.retry, children: "Retry" })] })), _jsxs("div", { className: styles.columns, "data-active-pane": activePane, children: [_jsxs("section", { className: `${styles.column} ${styles.columnPortfolio} ${activePane === 'portfolio' ? styles.columnActive : ''}`.trim(), "aria-labelledby": "planning-portfolio-heading", children: [_jsxs("div", { className: styles.columnHeader, children: [_jsx("h2", { ref: portfolioHeadingRef, id: "planning-portfolio-heading", className: `tf-heading-section ${styles.paneHeading}`, tabIndex: -1, children: "Portfolio" }), _jsxs("div", { className: styles.headerActions, children: [_jsx("span", { children: visibleInitiatives.length + visibleStandaloneWorkstreams.length }), _jsx("button", { type: "button", className: `tf-control-icon ${showArchivedPlanning ? styles.controlActive : ''}`.trim(), onClick: () => setShowArchivedPlanning((current) => !current), disabled: !hasArchivedPlanning, "aria-label": showArchivedPlanning ? 'Hide archived planning items' : 'Show archived planning items', "aria-pressed": showArchivedPlanning, title: hasArchivedPlanning ? (showArchivedPlanning ? 'Hide archived planning items' : 'Show archived planning items') : 'No archived planning items', children: showArchivedPlanning ? _jsx(EyeOff, { size: 15, "aria-hidden": "true" }) : _jsx(Eye, { size: 15, "aria-hidden": "true" }) })] })] }), _jsxs("div", { className: styles.portfolioControls, children: [_jsxs("div", { className: styles.searchRow, children: [_jsxs("div", { className: styles.searchShell, children: [_jsx(Search, { size: 14, "aria-hidden": "true" }), _jsx("input", { type: "search", value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: "Search initiatives and workstreams", "aria-label": "Search planning" }), searchQuery ? (_jsx("button", { type: "button", className: styles.clearSearch, onClick: () => setSearchQuery(''), "aria-label": "Clear planning search", title: "Clear search", children: _jsx(X, { size: 13, "aria-hidden": "true" }) })) : null] }), _jsx("button", { type: "button", className: `tf-control-icon ${filtersExpanded || ownerFilter !== 'all' || sort !== 'default' ? styles.controlActive : ''}`.trim(), "aria-label": "Filter and sort planning", title: "Filter and sort planning", "aria-expanded": filtersExpanded, "aria-controls": "planning-workspace-navigator-options", onClick: () => setFiltersExpanded((current) => !current), children: _jsx(Filter, { size: 15, "aria-hidden": "true" }) })] }), filtersExpanded ? (_jsxs("div", { id: "planning-workspace-navigator-options", className: styles.filterPanel, children: [_jsxs("div", { className: styles.filterField, children: [_jsx("span", { className: styles.filterLabel, children: "Owner" }), _jsx(PlanningOwnerDropdown, { value: ownerFilter, options: model.assigneeOptions, leadingOptions: ownerFilterLeadingOptions, includeUnassigned: false, onChange: setOwnerFilter, disabled: false, ariaLabel: "Filter planning by owner", className: styles.filterDropdown })] }), _jsxs("div", { className: styles.filterField, children: [_jsx("span", { className: styles.filterLabel, children: "Sort" }), _jsx(TaxonomyDropdown, { value: sort, options: PLANNING_NAVIGATOR_SORT_OPTIONS, onChange: (value) => setSort(String(value)), ariaLabel: "Sort planning", className: styles.filterDropdown, portalPanel: true, panelAlign: "start", triggerContent: (_jsxs("span", { className: styles.sortTrigger, children: [_jsx(ArrowUpDown, { size: 14, "aria-hidden": "true" }), _jsx("span", { children: PLANNING_NAVIGATOR_SORT_OPTIONS.find((option) => option.value === sort)?.label })] })), renderOptionContent: (option) => option.label })] }), _jsx("button", { type: "button", className: "tf-control-icon", onClick: clearNavigator, disabled: !hasAdjustedNavigator, "aria-label": "Reset planning filters and sort", title: "Reset planning filters and sort", children: _jsx(RotateCcw, { size: 14, "aria-hidden": "true" }) })] })) : null] }), _jsxs("div", { className: styles.scrollRegion, children: [_jsxs("div", { className: styles.sectionHeadingRow, children: [_jsx("h3", { className: `tf-heading-section ${styles.sectionLabel}`, children: "Initiatives" }), model.createEntity ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: () => setCreateState({ entityType: 'initiative' }), "aria-label": "Create initiative", title: "Create initiative", children: _jsx(Plus, { size: 15, "aria-hidden": "true" }) })) : null] }), createState?.entityType === 'initiative' ? (_jsx(PlanningWorkspaceEditor, { entityType: "initiative", mode: "create", ownerOptions: model.assigneeOptions, onCancel: () => setCreateState(null), onSave: createPlanningEntity })) : null, navigatorResults.initiatives.map(({ initiative, workstreams: resultWorkstreams }) => {
|
|
501
509
|
return (_jsx(InitiativeButton, { initiative: initiative, workstreamCount: resultWorkstreams.length, ownerOption: initiative.ownerId ? assigneeOptionByValue.get(initiative.ownerId) : undefined, ownerOptions: model.assigneeOptions, selected: selectedInitiativeId === initiative.id, onSelect: () => selectInitiative(initiative.id), onChangeOwner: model.changeOwner
|
|
502
510
|
? (ownerId) => model.changeOwner?.('initiative', initiative.id, ownerId === 'unassigned' ? '' : ownerId)
|
|
511
|
+
: undefined, onChangeIdentity: model.changeIdentity
|
|
512
|
+
? (patch) => model.changeIdentity?.('initiative', initiative.id, patch)
|
|
503
513
|
: undefined }, initiative.id));
|
|
504
514
|
}), _jsxs("div", { className: styles.sectionHeadingRow, children: [_jsx("h3", { className: `tf-heading-section ${styles.sectionLabel}`, children: "Standalone workstreams" }), model.createEntity ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: () => setCreateState({ entityType: 'workstream', initiativeId: null }), "aria-label": "Create standalone workstream", title: "Create standalone workstream", children: _jsx(Plus, { size: 15, "aria-hidden": "true" }) })) : null] }), createState?.entityType === 'workstream' && !createState.initiativeId ? (_jsx(PlanningWorkspaceEditor, { entityType: "workstream", mode: "create", ownerOptions: model.assigneeOptions, fixedInitiativeId: null, onCancel: () => setCreateState(null), onSave: createPlanningEntity })) : null, visibleStandaloneWorkstreams.map((workstream) => (_jsx(WorkstreamButton, { workstream: workstream, ownerOption: workstream.ownerId ? assigneeOptionByValue.get(workstream.ownerId) : undefined, ownerOptions: model.assigneeOptions, selected: selectedWorkstreamId === workstream.id, onSelect: () => selectWorkstream(workstream), onChangeOwner: model.changeOwner
|
|
505
515
|
? (ownerId) => model.changeOwner?.('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId)
|
|
516
|
+
: undefined, onChangeIdentity: model.changeIdentity
|
|
517
|
+
? (patch) => model.changeIdentity?.('workstream', workstream.id, patch)
|
|
506
518
|
: undefined }, workstream.id))), visibleInitiatives.length === 0 && visibleStandaloneWorkstreams.length === 0 && (_jsx("p", { className: `tf-text-helper ${styles.empty}`, children: navigatorResults.hasCriteria ? 'No planning matches.' : 'No planning items yet.' }))] })] }), _jsxs("section", { className: `${styles.column} ${styles.columnWorkstreams} ${activePane === 'workstreams' ? styles.columnActive : ''}`.trim(), "aria-labelledby": "planning-workstreams-heading", children: [_jsxs("div", { className: styles.columnHeader, children: [_jsxs("div", { className: styles.columnHeadingGroup, children: [_jsx("button", { type: "button", className: `tf-control-icon ${styles.responsiveBack}`.trim(), onClick: () => navigateToPane('portfolio'), "aria-label": "Back to Portfolio", title: "Back to Portfolio", children: _jsx(ChevronLeft, { size: 15, "aria-hidden": "true" }) }), _jsxs("h2", { ref: workstreamsHeadingRef, id: "planning-workstreams-heading", className: `tf-heading-section ${styles.paneHeading}`, tabIndex: -1, children: ["Workstreams (", workstreams.length, ")"] })] }), _jsx("div", { className: styles.headerActions, children: selectedInitiative && model.createEntity ? (_jsx("button", { type: "button", className: "tf-control-icon", onClick: () => setCreateState({ entityType: 'workstream', initiativeId: selectedInitiative.id }), "aria-label": `Create workstream in ${selectedInitiative.title}`, title: "Create workstream", children: _jsx(Plus, { size: 15, "aria-hidden": "true" }) })) : null })] }), _jsxs("div", { className: styles.scrollRegion, children: [selectedInitiative ? (_jsxs(_Fragment, { children: [_jsx(SelectedEntityContext, { item: selectedInitiative, entityType: "initiative", ownerOptions: model.assigneeOptions, onChangeOwner: model.changeOwner
|
|
507
519
|
? (ownerId) => model.changeOwner?.('initiative', selectedInitiative.id, ownerId)
|
|
508
|
-
: undefined, workspaceId: model.currentWorkspaceId, currentActorId: model.currentOwnerId, taskReferences: model.taskReferences, hydrationState: selectedWorkstream ? undefined : selectedEntityHydrationState, onRetryHydration: model.hydrateEntity
|
|
520
|
+
: undefined, onChangeIdentity: model.changeIdentity, workspaceId: model.currentWorkspaceId, currentActorId: model.currentOwnerId, taskReferences: model.taskReferences, hydrationState: selectedWorkstream ? undefined : selectedEntityHydrationState, onRetryHydration: model.hydrateEntity
|
|
509
521
|
? () => { void model.hydrateEntity?.('initiative', selectedInitiative.id); }
|
|
510
522
|
: undefined, onAddContextFile: model.addContextFile, onRemoveContextFile: model.removeContextFile, onUpdateContextCaption: model.updateContextCaption, onUpdate: model.updateEntity
|
|
511
523
|
? (input) => model.updateEntity('initiative', selectedInitiative.id, input)
|
|
@@ -515,6 +527,8 @@ export function PlanningModule({ model }) {
|
|
|
515
527
|
? () => model.unarchiveEntity('initiative', selectedInitiative.id)
|
|
516
528
|
: undefined }), _jsx(PlanningLinkPicker, { options: availableWorkstreamLinks, entityLabel: "workstream", onSelect: (option) => attachRelationship('workstream', option), disabled: !model.attachWorkstreamToInitiative || isChangingRelationship })] })) : null, createState?.entityType === 'workstream' && createState.initiativeId === selectedInitiative?.id ? (_jsx(PlanningWorkspaceEditor, { entityType: "workstream", mode: "create", ownerOptions: model.assigneeOptions, fixedInitiativeId: selectedInitiative.id, onCancel: () => setCreateState(null), onSave: createPlanningEntity })) : null, workstreams.map((workstream) => (_jsx(WorkstreamButton, { workstream: workstream, ownerOption: workstream.ownerId ? assigneeOptionByValue.get(workstream.ownerId) : undefined, ownerOptions: model.assigneeOptions, selected: selectedWorkstreamId === workstream.id, onSelect: () => selectWorkstream(workstream), onChangeOwner: model.changeOwner
|
|
517
529
|
? (ownerId) => model.changeOwner?.('workstream', workstream.id, ownerId === 'unassigned' ? '' : ownerId)
|
|
530
|
+
: undefined, onChangeIdentity: model.changeIdentity
|
|
531
|
+
? (patch) => model.changeIdentity?.('workstream', workstream.id, patch)
|
|
518
532
|
: undefined, referenceAction: selectedInitiative ? (_jsx(HierarchyActionBadge, { disabled: !model.assignWorkstreamToInitiative || isChangingRelationship, onClick: () => setPendingUnlink({
|
|
519
533
|
entityType: 'workstream',
|
|
520
534
|
id: workstream.id,
|
|
@@ -545,7 +559,7 @@ export function PlanningModule({ model }) {
|
|
|
545
559
|
? `${formatInitiativeReference(selectedInitiative)} ${selectedInitiative.title}`.trim()
|
|
546
560
|
: 'its initiative',
|
|
547
561
|
});
|
|
548
|
-
}, title: "Unlink workstream from initiative", ariaLabel: "Unlink workstream from initiative", children: _jsx(Unlink, { size: 14, "aria-hidden": "true" }) })) : (_jsx(
|
|
562
|
+
}, title: "Unlink workstream from initiative", ariaLabel: "Unlink workstream from initiative", children: _jsx(Unlink, { size: 14, "aria-hidden": "true" }) })) : (_jsx(PlanningLinkPicker, { options: model.linkOptions.initiatives, entityLabel: "initiative", onSelect: linkSelectedWorkstreamToInitiative, disabled: !model.assignWorkstreamToInitiative || isChangingRelationship, iconTrigger: true, triggerTitle: "Link initiative" })) }), _jsx(PlanningLinkPicker, { options: availableTaskLinks, entityLabel: "task", onSelect: (option) => attachRelationship('task', option), disabled: !model.attachTaskToWorkstream || isChangingRelationship }), model.setTaskArrangeMode ? (_jsx(PlanningTaskArrangeControl, { value: taskArrangeMode, onChange: model.setTaskArrangeMode })) : null] })) : null, _jsx(PlanningTaskOrderList, { tasks: visibleTasks, mode: taskArrangeMode, onReorder: selectedWorkstream && model.reorderWorkstreamTasks
|
|
549
563
|
? (taskIds) => model.reorderWorkstreamTasks?.(selectedWorkstream.id, mergeVisiblePlanningTaskOrder(arrangePlanningTasks(selectedWorkstream.tasks ?? [], 'execution'), taskIds))
|
|
550
564
|
: undefined, children: (task) => {
|
|
551
565
|
const referenceLabel = getTaskReferenceLabel(task);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { PlanningTaskPreview } from './planningWorkspaceModel';
|
|
3
|
-
import type
|
|
3
|
+
import { type PlanningTaskArrangeMode } from './planningTaskArrangement';
|
|
4
4
|
export declare function PlanningTaskOrderList(props: {
|
|
5
5
|
tasks: PlanningTaskPreview[];
|
|
6
6
|
mode: PlanningTaskArrangeMode;
|
|
@@ -4,10 +4,14 @@ import { DndContext, KeyboardSensor, PointerSensor, closestCenter, useSensor, us
|
|
|
4
4
|
import { SortableContext, arrayMove, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable';
|
|
5
5
|
import { CSS } from '@dnd-kit/utilities';
|
|
6
6
|
import { GripVertical } from 'lucide-react';
|
|
7
|
+
import { isPlanningTaskTerminal } from './planningTaskArrangement';
|
|
7
8
|
import styles from './PlanningTaskOrderList.module.css';
|
|
8
9
|
function SortableTask(props) {
|
|
9
10
|
const sortable = useSortable({ id: props.task.id, disabled: props.disabled });
|
|
10
|
-
|
|
11
|
+
const reorderLabel = props.disabledReason
|
|
12
|
+
? `Reorder ${props.task.title} — ${props.disabledReason}`
|
|
13
|
+
: `Reorder ${props.task.title}`;
|
|
14
|
+
return (_jsxs("div", { ref: sortable.setNodeRef, className: styles.item, style: { transform: CSS.Transform.toString(sortable.transform), transition: sortable.transition }, children: [_jsx("button", { ref: sortable.setActivatorNodeRef, type: "button", className: styles.grip, disabled: props.disabled, "aria-label": reorderLabel, title: props.disabledReason || 'Drag to change execution order', ...sortable.attributes, ...sortable.listeners, children: _jsx(GripVertical, { size: 15, "aria-hidden": "true" }) }), _jsx("div", { className: styles.card, children: props.children })] }));
|
|
11
15
|
}
|
|
12
16
|
export function PlanningTaskOrderList(props) {
|
|
13
17
|
const [orderedIds, setOrderedIds] = React.useState(() => props.tasks.map((task) => task.id));
|
|
@@ -19,7 +23,8 @@ export function PlanningTaskOrderList(props) {
|
|
|
19
23
|
const byId = new Map(props.tasks.map((task) => [task.id, task]));
|
|
20
24
|
return orderedIds.map((id) => byId.get(id)).filter((task) => Boolean(task));
|
|
21
25
|
}, [orderedIds, props.tasks]);
|
|
22
|
-
const
|
|
26
|
+
const hasReorderAction = Boolean(props.onReorder);
|
|
27
|
+
const draggable = props.mode === 'execution' && hasReorderAction;
|
|
23
28
|
const handleDragEnd = React.useCallback(async (event) => {
|
|
24
29
|
if (!draggable || saving || !event.over || event.active.id === event.over.id)
|
|
25
30
|
return;
|
|
@@ -29,8 +34,11 @@ export function PlanningTaskOrderList(props) {
|
|
|
29
34
|
if (from < 0 || to < 0)
|
|
30
35
|
return;
|
|
31
36
|
const byId = new Map(orderedTasks.map((task) => [task.id, task]));
|
|
32
|
-
const
|
|
33
|
-
|
|
37
|
+
const sourceTask = byId.get(previous[from]);
|
|
38
|
+
const targetTask = byId.get(previous[to]);
|
|
39
|
+
if (!sourceTask || !targetTask)
|
|
40
|
+
return;
|
|
41
|
+
if (isPlanningTaskTerminal(sourceTask) !== isPlanningTaskTerminal(targetTask))
|
|
34
42
|
return;
|
|
35
43
|
const next = arrayMove(previous, from, to);
|
|
36
44
|
setOrderedIds(next);
|
|
@@ -45,8 +53,11 @@ export function PlanningTaskOrderList(props) {
|
|
|
45
53
|
setSaving(false);
|
|
46
54
|
}
|
|
47
55
|
}, [draggable, orderedIds, orderedTasks, props, saving]);
|
|
48
|
-
if (!
|
|
56
|
+
if (!hasReorderAction) {
|
|
49
57
|
return _jsx("div", { className: `${styles.list} ${props.className || ''}`.trim(), children: props.tasks.map((task) => (_jsx(React.Fragment, { children: props.children(task) }, task.id))) });
|
|
50
58
|
}
|
|
51
|
-
|
|
59
|
+
const disabledReason = props.mode === 'execution'
|
|
60
|
+
? undefined
|
|
61
|
+
: 'Switch to Execution order to reorder tasks';
|
|
62
|
+
return (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: (event) => void handleDragEnd(event), children: _jsx(SortableContext, { items: orderedIds, strategy: verticalListSortingStrategy, children: _jsx("div", { className: `${styles.list} ${props.className || ''}`.trim(), "aria-busy": saving || undefined, children: orderedTasks.map((task) => (_jsx(SortableTask, { task: task, disabled: !draggable || saving, disabledReason: disabledReason || (saving ? 'Saving execution order' : undefined), children: props.children(task) }, task.id))) }) }) }));
|
|
52
63
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type PlanningIdentityColor, type PlanningIdentityEntityType, type PlanningIdentityIcon } from '../../../shared/planningIdentity';
|
|
2
|
+
export type PlanningIdentityPatch = {
|
|
3
|
+
icon?: PlanningIdentityIcon | null;
|
|
4
|
+
color?: PlanningIdentityColor | null;
|
|
5
|
+
};
|
|
6
|
+
export declare function PlanningVisualIdentity({ entityType, entityId, icon, color, disabled, size, onChange, }: {
|
|
7
|
+
entityType: PlanningIdentityEntityType;
|
|
8
|
+
entityId: string;
|
|
9
|
+
icon?: PlanningIdentityIcon | null;
|
|
10
|
+
color?: PlanningIdentityColor | null;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
size?: 'card' | 'inline' | 'detail';
|
|
13
|
+
onChange?: (patch: PlanningIdentityPatch) => void | Promise<void>;
|
|
14
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { BookOpen, Briefcase, Bug, Camera, Code, Compass, Flag, FlaskConical, Folder, Globe, Heart, Landmark, Layers, Lightbulb, Map, Music, Palette, Rocket, Route, Shield, Sparkles, Target, Users, Wrench, } from 'lucide-react';
|
|
5
|
+
import { PLANNING_IDENTITY_COLORS, PLANNING_IDENTITY_ICONS, planningIdentityColorToken, resolvePlanningIdentity, } from '../../../shared/planningIdentity';
|
|
6
|
+
import styles from './PlanningVisualIdentity.module.css';
|
|
7
|
+
const ICONS = {
|
|
8
|
+
Target, Route, Flag, Rocket, Briefcase, Folder, Layers, Map, Compass, Landmark,
|
|
9
|
+
BookOpen, Lightbulb, Wrench, Shield, Bug, Palette, Camera, Music, Heart, Globe,
|
|
10
|
+
Users, Sparkles, FlaskConical, Code,
|
|
11
|
+
};
|
|
12
|
+
export function PlanningVisualIdentity({ entityType, entityId, icon, color, disabled = false, size = 'card', onChange, }) {
|
|
13
|
+
const [open, setOpen] = React.useState(false);
|
|
14
|
+
const [pending, setPending] = React.useState(false);
|
|
15
|
+
const [optimisticPatch, setOptimisticPatch] = React.useState(null);
|
|
16
|
+
const [portalTheme, setPortalTheme] = React.useState();
|
|
17
|
+
const [popoverPosition, setPopoverPosition] = React.useState({ top: 0, left: 0 });
|
|
18
|
+
const rootRef = React.useRef(null);
|
|
19
|
+
const triggerRef = React.useRef(null);
|
|
20
|
+
const popoverRef = React.useRef(null);
|
|
21
|
+
const optimisticIcon = optimisticPatch && Object.prototype.hasOwnProperty.call(optimisticPatch, 'icon')
|
|
22
|
+
? optimisticPatch.icon
|
|
23
|
+
: icon;
|
|
24
|
+
const optimisticColor = optimisticPatch && Object.prototype.hasOwnProperty.call(optimisticPatch, 'color')
|
|
25
|
+
? optimisticPatch.color
|
|
26
|
+
: color;
|
|
27
|
+
const resolved = resolvePlanningIdentity({
|
|
28
|
+
entityType,
|
|
29
|
+
entityId,
|
|
30
|
+
icon: optimisticIcon,
|
|
31
|
+
color: optimisticColor,
|
|
32
|
+
});
|
|
33
|
+
const Icon = ICONS[resolved.icon];
|
|
34
|
+
const editable = !disabled && Boolean(onChange);
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (!open)
|
|
37
|
+
return undefined;
|
|
38
|
+
const close = (event) => {
|
|
39
|
+
const target = event.target;
|
|
40
|
+
if (!rootRef.current?.contains(target) && !popoverRef.current?.contains(target))
|
|
41
|
+
setOpen(false);
|
|
42
|
+
};
|
|
43
|
+
document.addEventListener('pointerdown', close);
|
|
44
|
+
return () => document.removeEventListener('pointerdown', close);
|
|
45
|
+
}, [open]);
|
|
46
|
+
React.useLayoutEffect(() => {
|
|
47
|
+
if (!open)
|
|
48
|
+
return undefined;
|
|
49
|
+
const positionPopover = () => {
|
|
50
|
+
const triggerRect = triggerRef.current?.getBoundingClientRect();
|
|
51
|
+
if (!triggerRect)
|
|
52
|
+
return;
|
|
53
|
+
setPortalTheme(triggerRef.current?.closest('[data-theme]')?.dataset.theme);
|
|
54
|
+
const popoverRect = popoverRef.current?.getBoundingClientRect();
|
|
55
|
+
const width = popoverRect?.width || 248;
|
|
56
|
+
const height = popoverRect?.height || 320;
|
|
57
|
+
const gap = 8;
|
|
58
|
+
const viewportPadding = 8;
|
|
59
|
+
const left = Math.max(viewportPadding, Math.min(triggerRect.left, window.innerWidth - width - viewportPadding));
|
|
60
|
+
const preferredTop = triggerRect.bottom + gap;
|
|
61
|
+
const top = preferredTop + height <= window.innerHeight - viewportPadding
|
|
62
|
+
? preferredTop
|
|
63
|
+
: Math.max(viewportPadding, triggerRect.top - height - gap);
|
|
64
|
+
setPopoverPosition({ top, left });
|
|
65
|
+
};
|
|
66
|
+
positionPopover();
|
|
67
|
+
window.addEventListener('resize', positionPopover);
|
|
68
|
+
window.addEventListener('scroll', positionPopover, true);
|
|
69
|
+
return () => {
|
|
70
|
+
window.removeEventListener('resize', positionPopover);
|
|
71
|
+
window.removeEventListener('scroll', positionPopover, true);
|
|
72
|
+
};
|
|
73
|
+
}, [open]);
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
if (!optimisticPatch)
|
|
76
|
+
return;
|
|
77
|
+
const iconSettled = !Object.prototype.hasOwnProperty.call(optimisticPatch, 'icon')
|
|
78
|
+
|| (optimisticPatch.icon ?? null) === (icon ?? null);
|
|
79
|
+
const colorSettled = !Object.prototype.hasOwnProperty.call(optimisticPatch, 'color')
|
|
80
|
+
|| (optimisticPatch.color ?? null) === (color ?? null);
|
|
81
|
+
if (iconSettled && colorSettled)
|
|
82
|
+
setOptimisticPatch(null);
|
|
83
|
+
}, [color, icon, optimisticPatch]);
|
|
84
|
+
const commit = async (patch) => {
|
|
85
|
+
if (!onChange || pending)
|
|
86
|
+
return;
|
|
87
|
+
setOptimisticPatch((current) => ({ ...current, ...patch }));
|
|
88
|
+
setPending(true);
|
|
89
|
+
try {
|
|
90
|
+
await onChange(patch);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
setOptimisticPatch(null);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
setPending(false);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const marker = (_jsx("span", { className: `${styles.marker} ${styles[size]} ${disabled ? styles.disabled : ''}`.trim(), style: { color: planningIdentityColorToken(resolved.color) }, "aria-hidden": "true", children: _jsx(Icon, { size: size === 'detail' ? 26 : size === 'inline' ? 18 : 24, strokeWidth: 1.9 }) }));
|
|
100
|
+
if (!editable)
|
|
101
|
+
return marker;
|
|
102
|
+
return (_jsxs("div", { ref: rootRef, className: styles.root, onClick: (event) => event.stopPropagation(), children: [_jsx("button", { ref: triggerRef, type: "button", className: styles.trigger, onClick: () => setOpen((current) => !current), onKeyDown: (event) => event.stopPropagation(), "aria-label": `Change ${entityType} icon and color`, "aria-expanded": open, disabled: pending, children: marker }), open ? createPortal((_jsxs("div", { ref: popoverRef, className: styles.popover, role: "dialog", "aria-label": `${entityType} icon and color`, "aria-busy": pending, "data-theme": portalTheme, style: popoverPosition, onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: [_jsx("div", { className: styles.colorGrid, "aria-label": "Colors", children: PLANNING_IDENTITY_COLORS.map((option) => (_jsx("button", { type: "button", className: `${styles.colorOption} ${resolved.color === option ? styles.selected : ''}`.trim(), style: { backgroundColor: planningIdentityColorToken(option) }, onClick: () => void commit({ color: option }), "aria-label": `${option} color`, "aria-pressed": resolved.color === option, disabled: pending }, option))) }), _jsx("div", { className: styles.divider }), _jsx("div", { className: styles.iconGrid, "aria-label": "Icons", children: PLANNING_IDENTITY_ICONS.map((option) => {
|
|
103
|
+
const OptionIcon = ICONS[option];
|
|
104
|
+
return (_jsx("button", { type: "button", className: `${styles.iconOption} ${resolved.icon === option ? styles.selected : ''}`.trim(), onClick: () => void commit({ icon: option }), "aria-label": option, "aria-pressed": resolved.icon === option, disabled: pending, children: _jsx(OptionIcon, { size: 18, strokeWidth: 1.8 }) }, option));
|
|
105
|
+
}) }), _jsx("div", { className: styles.divider }), _jsx("button", { type: "button", className: styles.reset, onClick: () => void commit({ icon: null, color: null }), disabled: !resolved.customized || pending, children: "Reset to default" })] })), document.body) : null] }));
|
|
106
|
+
}
|
|
@@ -15,4 +15,5 @@ export declare const PLANNING_TASK_ARRANGE_OPTIONS: readonly ({
|
|
|
15
15
|
})[];
|
|
16
16
|
export declare function normalizePlanningTaskArrangeMode(value: unknown): PlanningTaskArrangeMode;
|
|
17
17
|
export declare function mergeVisiblePlanningTaskOrder(allTasks: readonly PlanningTaskPreview[], reorderedVisibleTaskIds: readonly string[]): string[];
|
|
18
|
+
export declare function isPlanningTaskTerminal(task: PlanningTaskPreview): boolean;
|
|
18
19
|
export declare function arrangePlanningTasks(tasks: readonly PlanningTaskPreview[], mode: PlanningTaskArrangeMode): PlanningTaskPreview[];
|
|
@@ -19,7 +19,7 @@ export function mergeVisiblePlanningTaskOrder(allTasks, reorderedVisibleTaskIds)
|
|
|
19
19
|
let visibleIndex = 0;
|
|
20
20
|
return allTasks.map((task) => (visible.has(task.id) ? reorderedVisibleTaskIds[visibleIndex++] : task.id));
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
export function isPlanningTaskTerminal(task) {
|
|
23
23
|
const status = getStatusDefinition(task.status).value;
|
|
24
24
|
return status === 'done' || status === 'cancelled';
|
|
25
25
|
}
|
|
@@ -50,7 +50,7 @@ function arrangeBlockedTasks(tasks, allTasksById) {
|
|
|
50
50
|
for (const task of tasks) {
|
|
51
51
|
for (const prerequisiteId of task.prerequisiteTaskIds || []) {
|
|
52
52
|
const prerequisite = allTasksById.get(prerequisiteId);
|
|
53
|
-
if (!prerequisite ||
|
|
53
|
+
if (!prerequisite || isPlanningTaskTerminal(prerequisite) || !taskIds.has(prerequisiteId))
|
|
54
54
|
continue;
|
|
55
55
|
dependentsByPrerequisite.set(prerequisiteId, [
|
|
56
56
|
...(dependentsByPrerequisite.get(prerequisiteId) || []),
|
|
@@ -85,15 +85,15 @@ function arrangeBlockedTasks(tasks, allTasksById) {
|
|
|
85
85
|
export function arrangePlanningTasks(tasks, mode) {
|
|
86
86
|
const taskById = new Map(tasks.map((task) => [task.id, task]));
|
|
87
87
|
if (mode === 'ready') {
|
|
88
|
-
const active = tasks.filter((task) => !
|
|
88
|
+
const active = tasks.filter((task) => !isPlanningTaskTerminal(task));
|
|
89
89
|
const ready = sortByExecutionOrder(active.filter((task) => isReady(task, taskById)));
|
|
90
90
|
const blocked = arrangeBlockedTasks(active.filter((task) => !isReady(task, taskById)), taskById);
|
|
91
|
-
return [...ready, ...blocked, ...sortByExecutionOrder(tasks.filter(
|
|
91
|
+
return [...ready, ...blocked, ...sortByExecutionOrder(tasks.filter(isPlanningTaskTerminal))];
|
|
92
92
|
}
|
|
93
93
|
return tasks.map((task, index) => ({ task, index })).sort((leftEntry, rightEntry) => {
|
|
94
94
|
const left = leftEntry.task;
|
|
95
95
|
const right = rightEntry.task;
|
|
96
|
-
const terminalComparison = Number(
|
|
96
|
+
const terminalComparison = Number(isPlanningTaskTerminal(left)) - Number(isPlanningTaskTerminal(right));
|
|
97
97
|
if (terminalComparison)
|
|
98
98
|
return terminalComparison;
|
|
99
99
|
if (mode === 'priority') {
|
|
@@ -3,6 +3,7 @@ import type { TaskAssigneeOption } from '../../../utils/assignees';
|
|
|
3
3
|
import type { TaskReferenceContract } from '../../../utils/taskReferences';
|
|
4
4
|
import type { TaskforceTheme } from '../../../utils/theme';
|
|
5
5
|
import type { PlanningTaskArrangeMode } from './planningTaskArrangement';
|
|
6
|
+
import type { PlanningIdentityColor, PlanningIdentityIcon } from '../../../shared/planningIdentity';
|
|
6
7
|
export type PlanningStatusCounts = Record<TaskStatus, number>;
|
|
7
8
|
export declare function shouldUsePlanningBootstrapTaskSummaries(input: {
|
|
8
9
|
taskScope: 'open' | 'archived' | 'deleted';
|
|
@@ -34,6 +35,8 @@ export type PlanningNodeSummary = {
|
|
|
34
35
|
description?: string;
|
|
35
36
|
ownerId?: string | null;
|
|
36
37
|
ownerLabel?: string | null;
|
|
38
|
+
icon?: PlanningIdentityIcon | null;
|
|
39
|
+
color?: PlanningIdentityColor | null;
|
|
37
40
|
progressPercent: number;
|
|
38
41
|
taskCount: number;
|
|
39
42
|
completedTaskCount: number;
|
|
@@ -67,12 +70,16 @@ export type PlanningEntitySaveInput = {
|
|
|
67
70
|
description: string | null;
|
|
68
71
|
ownerId?: string | null;
|
|
69
72
|
initiativeId?: string | null;
|
|
73
|
+
icon?: PlanningIdentityIcon | null;
|
|
74
|
+
color?: PlanningIdentityColor | null;
|
|
70
75
|
};
|
|
71
76
|
export type PlanningLinkOption = {
|
|
72
77
|
id: string;
|
|
73
78
|
referenceLabel: string;
|
|
74
79
|
title: string;
|
|
75
80
|
meta?: string;
|
|
81
|
+
icon?: PlanningIdentityIcon | null;
|
|
82
|
+
color?: PlanningIdentityColor | null;
|
|
76
83
|
};
|
|
77
84
|
export type PlanningLinkOptions = {
|
|
78
85
|
initiatives: PlanningLinkOption[];
|
|
@@ -107,6 +114,10 @@ export type PlanningWorkspaceModel = {
|
|
|
107
114
|
archiveEntity?: (entityType: 'initiative' | 'workstream', entityId: string) => boolean | Promise<boolean>;
|
|
108
115
|
unarchiveEntity?: (entityType: 'initiative' | 'workstream', entityId: string) => boolean | Promise<boolean>;
|
|
109
116
|
changeOwner?: (entityType: 'initiative' | 'workstream', entityId: string, ownerId: string) => void | Promise<void>;
|
|
117
|
+
changeIdentity?: (entityType: 'initiative' | 'workstream', entityId: string, patch: {
|
|
118
|
+
icon?: PlanningIdentityIcon | null;
|
|
119
|
+
color?: PlanningIdentityColor | null;
|
|
120
|
+
}) => void | Promise<void>;
|
|
110
121
|
createEntity?: (entityType: 'initiative' | 'workstream', input: PlanningEntitySaveInput) => Promise<{
|
|
111
122
|
id: string;
|
|
112
123
|
}>;
|
|
@@ -96,6 +96,7 @@ export function buildTaskforceAgentDefinitionFromDraft(input) {
|
|
|
96
96
|
const artStyle = selectedAvatarArtStyle(draft.avatarArtStyleSelection, draft.avatarArtStyleCustom);
|
|
97
97
|
const requestedCapabilities = draft.requestedCapabilities
|
|
98
98
|
.filter((capability) => DEFAULT_AGENT_TOOL_CAPABILITY_SET.has(capability));
|
|
99
|
+
const selectedModel = getTaskforceAgentModel(input.modelKey);
|
|
99
100
|
return {
|
|
100
101
|
...(baseDefinition || {}),
|
|
101
102
|
schemaVersion: AGENT_DEFINITION_SCHEMA_VERSION,
|
|
@@ -104,8 +105,9 @@ export function buildTaskforceAgentDefinitionFromDraft(input) {
|
|
|
104
105
|
model: {
|
|
105
106
|
providerKey: input.providerKey,
|
|
106
107
|
modelKey: input.modelKey,
|
|
107
|
-
modelSource:
|
|
108
|
+
modelSource: selectedModel?.source || 'bedrock',
|
|
108
109
|
tier: input.tier,
|
|
110
|
+
...(selectedModel?.source === 'subscription_dev' ? { connectionScope: 'local_dev' } : {}),
|
|
109
111
|
},
|
|
110
112
|
behavior: {
|
|
111
113
|
...(personality ? { personality } : {}),
|
|
@@ -4,6 +4,7 @@ import type { TaskAutoSaveState } from '../../hooks/tasks/useTaskFormActions';
|
|
|
4
4
|
interface TaskActionHeaderProps {
|
|
5
5
|
editingTaskId: string | null;
|
|
6
6
|
loading: boolean;
|
|
7
|
+
submitDisabled?: boolean;
|
|
7
8
|
autoSaveState?: TaskAutoSaveState;
|
|
8
9
|
title: string;
|
|
9
10
|
status?: TaskStatus;
|
|
@@ -30,5 +31,5 @@ interface TaskActionHeaderProps {
|
|
|
30
31
|
handlePermanentlyDeleteDeletedTask?: (deletedRecordId: string) => void;
|
|
31
32
|
onAskAgent?: (task: TaskItem) => void;
|
|
32
33
|
}
|
|
33
|
-
export declare function TaskActionHeader({ editingTaskId, loading, autoSaveState, title, status, onStatusChange, showCreateSubmit, handleSubmit, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreams, onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleUnarchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask, onAskAgent }: TaskActionHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export declare function TaskActionHeader({ editingTaskId, loading, submitDisabled, autoSaveState, title, status, onStatusChange, showCreateSubmit, handleSubmit, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreams, onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleUnarchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask, onAskAgent }: TaskActionHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
34
35
|
export {};
|
|
@@ -9,7 +9,7 @@ import { TaskReferenceBadge } from './TaskReferenceBadge';
|
|
|
9
9
|
import { HierarchyActionBadge } from '../ui/HierarchyActionBadge';
|
|
10
10
|
import { formatInitiativeReference, getWorkstreamReferenceLabel } from '../../utils/planningReferences';
|
|
11
11
|
import { TaskWorkstreamPicker } from './TaskWorkstreamPicker';
|
|
12
|
-
export function TaskActionHeader({ editingTaskId, loading, autoSaveState = 'idle', title, status = 'task', onStatusChange, showCreateSubmit = true, handleSubmit, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreams = [], onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleUnarchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask, onAskAgent }) {
|
|
12
|
+
export function TaskActionHeader({ editingTaskId, loading, submitDisabled = false, autoSaveState = 'idle', title, status = 'task', onStatusChange, showCreateSubmit = true, handleSubmit, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreams = [], onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleUnarchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask, onAskAgent }) {
|
|
13
13
|
const currentTask = currentTaskProp ?? (editingTaskId ? tasks.find(t => t.id === editingTaskId) || null : null);
|
|
14
14
|
const isArchivedReadOnly = Boolean(currentTask?.isArchived);
|
|
15
15
|
const isDeletedReadOnly = Boolean(currentTask?.isDeleted);
|
|
@@ -67,5 +67,5 @@ export function TaskActionHeader({ editingTaskId, loading, autoSaveState = 'idle
|
|
|
67
67
|
if (status === 'cancelled') {
|
|
68
68
|
handleToggleCancel(task);
|
|
69
69
|
}
|
|
70
|
-
}, onArchiveTask: handleArchiveTask, onUnarchiveTask: (task) => handleUnarchiveTask?.(task.id) }))] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.taskSaveStatusCenter }), _jsxs("div", { className: styles.editActionsGroup, children: [_jsx(TaskStatusActions, { status: status, disabled: loading, archiveActionMode: "none", onStatusChange: onStatusChange }), showCreateSubmit ? (_jsxs("button", { type: "button", onClick: (e) => handleSubmit(e), 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] })] }))] }));
|
|
70
|
+
}, onArchiveTask: handleArchiveTask, onUnarchiveTask: (task) => handleUnarchiveTask?.(task.id) }))] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.taskSaveStatusCenter }), _jsxs("div", { className: styles.editActionsGroup, children: [_jsx(TaskStatusActions, { status: status, disabled: loading, archiveActionMode: "none", onStatusChange: onStatusChange }), showCreateSubmit ? (_jsxs("button", { type: "button", onClick: (e) => handleSubmit(e), disabled: loading || submitDisabled || !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] })] }))] }));
|
|
71
71
|
}
|
|
@@ -48,6 +48,11 @@ interface TaskCardProps {
|
|
|
48
48
|
onWorkstreamChange?: (task: TaskItem, workstreamId: string | null) => boolean | void | Promise<boolean | void>;
|
|
49
49
|
compressed?: boolean;
|
|
50
50
|
showStatusLabel?: boolean;
|
|
51
|
+
showDescription?: boolean;
|
|
52
|
+
showAttachments?: boolean;
|
|
53
|
+
showChecklistProgress?: boolean;
|
|
54
|
+
showLatestActivity?: boolean;
|
|
55
|
+
tintActivityBackground?: boolean;
|
|
51
56
|
}
|
|
52
57
|
export declare const TaskCard: React.NamedExoticComponent<TaskCardProps>;
|
|
53
58
|
export {};
|