@parhelia/core 0.1.12912 → 0.1.12917
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/agents-view/AgentGalleryCard.js +1 -1
- package/dist/agents-view/AgentGalleryCard.js.map +1 -1
- package/dist/agents-view/AgentsWorkspaceView.js +15 -2
- package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
- package/dist/components/MarkdownViewerPopover.d.ts +73 -0
- package/dist/components/MarkdownViewerPopover.js +109 -0
- package/dist/components/MarkdownViewerPopover.js.map +1 -0
- package/dist/components/PageHeader.d.ts +5 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/PageHeader.js.map +1 -1
- package/dist/components/SearchInput.js +1 -1
- package/dist/components/ui/UserPicker.js +1 -1
- package/dist/components/ui/UserPicker.js.map +1 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/select.js.map +1 -1
- package/dist/config/config.js +17 -2
- package/dist/config/config.js.map +1 -1
- package/dist/config/types/workspace.d.ts +6 -2
- package/dist/editor/ConfirmationDialog.d.ts +3 -0
- package/dist/editor/ConfirmationDialog.js +5 -1
- package/dist/editor/ConfirmationDialog.js.map +1 -1
- package/dist/editor/ContentTree.d.ts +7 -1
- package/dist/editor/ContentTree.js +13 -1
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/ContextMenu.js +6 -2
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/FieldHistory.js +2 -1
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/FieldListField.js +4 -3
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/GlobalMenuBar.js +5 -2
- package/dist/editor/GlobalMenuBar.js.map +1 -1
- package/dist/editor/MobileLayout.js +4 -1
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/ScrollingContentTree.d.ts +2 -1
- package/dist/editor/ScrollingContentTree.js +2 -2
- package/dist/editor/ScrollingContentTree.js.map +1 -1
- package/dist/editor/Titlebar.d.ts +2 -1
- package/dist/editor/Titlebar.js +4 -9
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/WorkspaceTitleSwitcher.d.ts +2 -1
- package/dist/editor/WorkspaceTitleSwitcher.js +4 -3
- package/dist/editor/WorkspaceTitleSwitcher.js.map +1 -1
- package/dist/editor/ai/AgentProfileSelector.js +3 -3
- package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
- package/dist/editor/ai/Agents.js +15 -4
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/InlineAiTrigger.js +5 -1
- package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
- package/dist/editor/ai/agentActivitySummary.js +17 -9
- package/dist/editor/ai/agentActivitySummary.js.map +1 -1
- package/dist/editor/ai/dialogs/capturePageScreenshot.d.ts +18 -1
- package/dist/editor/ai/dialogs/capturePageScreenshot.js +60 -13
- package/dist/editor/ai/dialogs/capturePageScreenshot.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentDocumentList.js +6 -3
- package/dist/editor/ai/terminal/components/AgentDocumentList.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentFullPromptControls.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentFullPromptControls.js +9 -6
- package/dist/editor/ai/terminal/components/AgentFullPromptControls.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentModeSelector.js +8 -7
- package/dist/editor/ai/terminal/components/AgentModeSelector.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js +4 -1
- package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentSummaryPromptActions.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentSummaryPromptActions.js +7 -2
- package/dist/editor/ai/terminal/components/AgentSummaryPromptActions.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentTerminalSummaryLayout.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentTerminalSummaryLayout.js +2 -2
- package/dist/editor/ai/terminal/components/AgentTerminalSummaryLayout.js.map +1 -1
- package/dist/editor/ai/terminal/components/ContextInfoBar.js +35 -8
- package/dist/editor/ai/terminal/components/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/terminal/components/UserMessage.js +4 -4
- package/dist/editor/ai/terminal/components/UserMessage.js.map +1 -1
- package/dist/editor/ai/terminal/projectTemplateContext.d.ts +11 -0
- package/dist/editor/ai/terminal/projectTemplateContext.js +64 -0
- package/dist/editor/ai/terminal/projectTemplateContext.js.map +1 -0
- package/dist/editor/ai/terminal/useAgentLoadPipeline.js +1 -0
- package/dist/editor/ai/terminal/useAgentLoadPipeline.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentLoader.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentLoader.js +14 -2
- package/dist/editor/ai/terminal/useAgentLoader.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentSettingsData.js +1 -0
- package/dist/editor/ai/terminal/useAgentSettingsData.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentSubmitHandlers.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentSubmitHandlers.js +19 -1
- package/dist/editor/ai/terminal/useAgentSubmitHandlers.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentTerminalController.js +4 -1
- package/dist/editor/ai/terminal/useAgentTerminalController.js.map +1 -1
- package/dist/editor/ai/useInlineAiPosition.d.ts +2 -1
- package/dist/editor/ai/useInlineAiPosition.js +10 -3
- package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
- package/dist/editor/bridge/protocol.d.ts +22 -1
- package/dist/editor/bridge/protocol.js +3 -1
- package/dist/editor/bridge/protocol.js.map +1 -1
- package/dist/editor/client/EditorShell.js +45 -22
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +1 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.d.ts +1 -0
- package/dist/editor/client/pageModelBuilder.js +9 -2
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/client/ui/FullscreenControls.js +1 -1
- package/dist/editor/client/ui/FullscreenControls.js.map +1 -1
- package/dist/editor/commands/componentCommands.d.ts +1 -0
- package/dist/editor/commands/componentCommands.js +139 -2
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/content-tree/TreeSettingsMenu.js +1 -1
- package/dist/editor/content-tree/TreeSettingsMenu.js.map +1 -1
- package/dist/editor/fieldTypeConfiguration.d.ts +2 -0
- package/dist/editor/fieldTypeConfiguration.js +7 -0
- package/dist/editor/fieldTypeConfiguration.js.map +1 -0
- package/dist/editor/menubar/PageSelector.js +8 -1
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/DeviceSwitchToolbar.d.ts +2 -1
- package/dist/editor/menubar/toolbar-sections/DeviceSwitchToolbar.js +2 -2
- package/dist/editor/menubar/toolbar-sections/DeviceSwitchToolbar.js.map +1 -1
- package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js +7 -1
- package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +53 -19
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +3 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +4 -3
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/bridgeInlineFormatToolbarLayout.d.ts +2 -1
- package/dist/editor/page-editor-chrome/bridgeInlineFormatToolbarLayout.js +2 -0
- package/dist/editor/page-editor-chrome/bridgeInlineFormatToolbarLayout.js.map +1 -1
- package/dist/editor/page-editor-chrome/insertTargetLabel.d.ts +1 -0
- package/dist/editor/page-editor-chrome/insertTargetLabel.js +14 -1
- package/dist/editor/page-editor-chrome/insertTargetLabel.js.map +1 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +13 -3
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
- package/dist/editor/page-editor-chrome/useComponentDragHandle.js +11 -5
- package/dist/editor/page-editor-chrome/useComponentDragHandle.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.js +5 -4
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +53 -3
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/bridgeFieldPatch.d.ts +3 -1
- package/dist/editor/page-viewer/bridgeFieldPatch.js +24 -1
- package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.d.ts +4 -1
- package/dist/editor/page-viewer/pageViewContext.js +4 -1
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/page-viewer/parentBridgeInjection.d.ts +23 -0
- package/dist/editor/page-viewer/parentBridgeInjection.js +251 -0
- package/dist/editor/page-viewer/parentBridgeInjection.js.map +1 -0
- package/dist/editor/page-viewer/renderUrl.js +4 -2
- package/dist/editor/page-viewer/renderUrl.js.map +1 -1
- package/dist/editor/pageModel.d.ts +1 -0
- package/dist/editor/reviews/MultiReviewManager.js +3 -22
- package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
- package/dist/editor/reviews/openCommentsFeedback.js +2 -0
- package/dist/editor/reviews/openCommentsFeedback.js.map +1 -1
- package/dist/editor/services/agentService.js +6 -2
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/editService.d.ts +15 -0
- package/dist/editor/services/editService.js +3 -0
- package/dist/editor/services/editService.js.map +1 -1
- package/dist/editor/settings/SettingsBreadcrumb.js +5 -2
- package/dist/editor/settings/SettingsBreadcrumb.js.map +1 -1
- package/dist/editor/settings/SettingsHeaderActionsContext.d.ts +4 -0
- package/dist/editor/settings/SettingsHeaderActionsContext.js.map +1 -1
- package/dist/editor/settings/SettingsTitlebar.d.ts +1 -0
- package/dist/editor/settings/SettingsTitlebar.js +18 -0
- package/dist/editor/settings/SettingsTitlebar.js.map +1 -0
- package/dist/editor/settings/SettingsView.js +64 -18
- package/dist/editor/settings/SettingsView.js.map +1 -1
- package/dist/editor/settings/panels/ModelsPanel.js +4 -3
- package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.d.ts +8 -1
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js +75 -9
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplateSelectorList.js +1 -1
- package/dist/editor/settings/panels/ProjectTemplateSelectorList.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +515 -50
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProvidersPanel.js +1 -1
- package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
- package/dist/editor/settings/settingsNavigationStore.d.ts +12 -0
- package/dist/editor/settings/settingsNavigationStore.js +32 -0
- package/dist/editor/settings/settingsNavigationStore.js.map +1 -0
- package/dist/editor/setup-wizard/steps/ProviderStep.js +6 -2
- package/dist/editor/setup-wizard/steps/ProviderStep.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +10 -4
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +12 -12
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/ContentTreePanel.js +1 -1
- package/dist/editor/sidebar/ContentTreePanel.js.map +1 -1
- package/dist/editor/sidebar/SidebarPanel.js +1 -1
- package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
- package/dist/editor/sidebar/WorkspaceRailMobile.d.ts +0 -1
- package/dist/editor/sidebar/WorkspaceRailMobile.js +4 -14
- package/dist/editor/sidebar/WorkspaceRailMobile.js.map +1 -1
- package/dist/editor/ui/ComponentThumbnailDialog.d.ts +14 -0
- package/dist/editor/ui/ComponentThumbnailDialog.js +75 -0
- package/dist/editor/ui/ComponentThumbnailDialog.js.map +1 -0
- package/dist/editor/ui/PublishRestrictionsDialog.js +77 -9
- package/dist/editor/ui/PublishRestrictionsDialog.js.map +1 -1
- package/dist/editor/ui/Splitter.d.ts +3 -0
- package/dist/editor/ui/Splitter.js +30 -16
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/editor/utils/itemutils.js +2 -0
- package/dist/editor/utils/itemutils.js.map +1 -1
- package/dist/editor/views/ItemEditorPane.js +1 -1
- package/dist/editor/views/ItemEditorPane.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +73 -5
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/components/CreateProjectDialog.d.ts +0 -1
- package/dist/task-board/components/CreateProjectDialog.js +1 -4
- package/dist/task-board/components/CreateProjectDialog.js.map +1 -1
- package/dist/task-board/components/GoalDialog.d.ts +9 -0
- package/dist/task-board/components/GoalDialog.js +149 -0
- package/dist/task-board/components/GoalDialog.js.map +1 -0
- package/dist/task-board/components/ProjectDashboard.d.ts +10 -0
- package/dist/task-board/components/ProjectDashboard.js +3 -3
- package/dist/task-board/components/ProjectDashboard.js.map +1 -1
- package/dist/task-board/components/ProjectGoalsPanel.d.ts +16 -0
- package/dist/task-board/components/ProjectGoalsPanel.js +310 -0
- package/dist/task-board/components/ProjectGoalsPanel.js.map +1 -0
- package/dist/task-board/components/ProjectPropertiesPanel.js +5 -3
- package/dist/task-board/components/ProjectPropertiesPanel.js.map +1 -1
- package/dist/task-board/components/TaskAssigneePicker.js +1 -1
- package/dist/task-board/components/TaskAssigneePicker.js.map +1 -1
- package/dist/task-board/components/TaskAttachmentDropZone.d.ts +1 -0
- package/dist/task-board/components/TaskAttachmentDropZone.js +5 -3
- package/dist/task-board/components/TaskAttachmentDropZone.js.map +1 -1
- package/dist/task-board/components/TaskAttachmentsSection.js +8 -1
- package/dist/task-board/components/TaskAttachmentsSection.js.map +1 -1
- package/dist/task-board/components/WizardCommunicationCenter.js +1 -10
- package/dist/task-board/components/WizardCommunicationCenter.js.map +1 -1
- package/dist/task-board/services/goalService.d.ts +65 -0
- package/dist/task-board/services/goalService.js +37 -0
- package/dist/task-board/services/goalService.js.map +1 -0
- package/dist/task-board/types.d.ts +68 -3
- package/dist/task-board/views/DependencyGraphView.js +121 -31
- package/dist/task-board/views/DependencyGraphView.js.map +1 -1
- package/package.json +2 -2
- package/dist/editor/sidebar/MobileWorkspacePopover.d.ts +0 -16
- package/dist/editor/sidebar/MobileWorkspacePopover.js +0 -35
- package/dist/editor/sidebar/MobileWorkspacePopover.js.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, Link2, Plus, RefreshCw, Settings2, Shield, X, } from "lucide-react";
|
|
2
|
+
import { ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, Link2, PanelRightOpen, Plus, RefreshCw, Settings2, Shield, Trash2, X, } from "lucide-react";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState, Suspense, lazy, } from "react";
|
|
4
4
|
import { toast } from "sonner";
|
|
5
5
|
import { Badge } from "../../../components/ui/badge";
|
|
6
6
|
import { Button } from "../../../components/ui/button";
|
|
7
|
+
import { CloseButton } from "../../../components/ui/close-button";
|
|
7
8
|
import { DeleteIcon } from "../../../components/ui/delete-icon";
|
|
8
9
|
import { Dialog, DialogContent, DialogFooter, } from "../../../components/ui/dialog";
|
|
9
10
|
import { Input } from "../../../components/ui/input";
|
|
@@ -21,7 +22,7 @@ const DependencyGraphView = lazy(() => import("../../../task-board/views/Depende
|
|
|
21
22
|
})));
|
|
22
23
|
import { useEditContext } from "../../client/editContext";
|
|
23
24
|
import { useSearchParams } from "../../client/navigation";
|
|
24
|
-
import { updateAgentContext } from "../../services/agentService";
|
|
25
|
+
import { updateAgentContext, } from "../../services/agentService";
|
|
25
26
|
import { getAiProfilesErrorMessage, loadAiProfiles, } from "../../services/aiService";
|
|
26
27
|
import { localStorageService } from "../../services/localStorageService";
|
|
27
28
|
import { ItemNameDialog, } from "../../ui/ItemNameDialogNew";
|
|
@@ -93,6 +94,9 @@ function normalizeTaskTemplate(task) {
|
|
|
93
94
|
const rawAssigneeId = task.assigneeId?.trim() || null;
|
|
94
95
|
const rawAgentProfileId = task.agentProfileId?.trim() || null;
|
|
95
96
|
const rawParentTaskId = task.parentTaskId?.trim() || null;
|
|
97
|
+
const dependencyIds = Array.from(new Set((task.dependencyIds ?? [])
|
|
98
|
+
.map((dependencyId) => dependencyId?.trim())
|
|
99
|
+
.filter((dependencyId) => !!dependencyId)));
|
|
96
100
|
const disabled = task.disabled === true;
|
|
97
101
|
const taskType = String(task.taskType ?? "").toLowerCase() === "decisionpoint"
|
|
98
102
|
? "DecisionPoint"
|
|
@@ -114,6 +118,7 @@ function normalizeTaskTemplate(task) {
|
|
|
114
118
|
assigneeId: canonicalAgentId,
|
|
115
119
|
agentProfileId: canonicalAgentId,
|
|
116
120
|
parentTaskId: rawParentTaskId,
|
|
121
|
+
dependencyIds,
|
|
117
122
|
};
|
|
118
123
|
}
|
|
119
124
|
if (assigneeType === "user" || assigneeType === "Role") {
|
|
@@ -126,6 +131,7 @@ function normalizeTaskTemplate(task) {
|
|
|
126
131
|
assigneeId: rawAssigneeId,
|
|
127
132
|
agentProfileId: null,
|
|
128
133
|
parentTaskId: rawParentTaskId,
|
|
134
|
+
dependencyIds,
|
|
129
135
|
};
|
|
130
136
|
}
|
|
131
137
|
return {
|
|
@@ -137,6 +143,7 @@ function normalizeTaskTemplate(task) {
|
|
|
137
143
|
assigneeId: rawAssigneeId,
|
|
138
144
|
agentProfileId: null,
|
|
139
145
|
parentTaskId: rawParentTaskId,
|
|
146
|
+
dependencyIds,
|
|
140
147
|
};
|
|
141
148
|
}
|
|
142
149
|
function normalizeGraphOrientation(orientation) {
|
|
@@ -146,7 +153,6 @@ function normalizeProjectTemplate(template) {
|
|
|
146
153
|
return {
|
|
147
154
|
...template,
|
|
148
155
|
hideFromCreateDialog: template.hideFromCreateDialog === true,
|
|
149
|
-
openInWizardMode: template.openInWizardMode === true,
|
|
150
156
|
graphLayout: template.graphLayout
|
|
151
157
|
? {
|
|
152
158
|
...template.graphLayout,
|
|
@@ -154,6 +160,10 @@ function normalizeProjectTemplate(template) {
|
|
|
154
160
|
}
|
|
155
161
|
: null,
|
|
156
162
|
taskTemplates: (template.taskTemplates ?? []).map(normalizeTaskTemplate),
|
|
163
|
+
goalTemplates: (template.goalTemplates ?? []).map((goal) => ({
|
|
164
|
+
...goal,
|
|
165
|
+
disabled: goal.disabled === true,
|
|
166
|
+
})),
|
|
157
167
|
};
|
|
158
168
|
}
|
|
159
169
|
function createEmptyTemplate() {
|
|
@@ -163,11 +173,11 @@ function createEmptyTemplate() {
|
|
|
163
173
|
description: "",
|
|
164
174
|
disabled: false,
|
|
165
175
|
hideFromCreateDialog: false,
|
|
166
|
-
openInWizardMode: false,
|
|
167
176
|
isSystem: false,
|
|
168
177
|
defaultCostLimit: null,
|
|
169
178
|
graphLayout: null,
|
|
170
179
|
taskTemplates: [],
|
|
180
|
+
goalTemplates: [],
|
|
171
181
|
};
|
|
172
182
|
}
|
|
173
183
|
function createEmptyTaskTemplate(taskCount, title) {
|
|
@@ -187,6 +197,17 @@ function createEmptyTaskTemplate(taskCount, title) {
|
|
|
187
197
|
dependencyIds: [],
|
|
188
198
|
};
|
|
189
199
|
}
|
|
200
|
+
function createEmptyGoalDefinition(goalCount, title) {
|
|
201
|
+
return {
|
|
202
|
+
id: crypto.randomUUID(),
|
|
203
|
+
title: title?.trim() || `Goal ${goalCount + 1}`,
|
|
204
|
+
description: "",
|
|
205
|
+
disabled: false,
|
|
206
|
+
sortOrder: goalCount * 100,
|
|
207
|
+
defaultScopeJson: null,
|
|
208
|
+
dataShape: null,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
190
211
|
function sortTemplates(templates) {
|
|
191
212
|
return [...templates].sort((left, right) => left.name.localeCompare(right.name, undefined, { sensitivity: "base" }));
|
|
192
213
|
}
|
|
@@ -194,10 +215,9 @@ function buildUpsertTemplateRequest(template) {
|
|
|
194
215
|
return {
|
|
195
216
|
projectTemplateId: template.id,
|
|
196
217
|
name: template.name.trim(),
|
|
197
|
-
description: template.description
|
|
218
|
+
description: template.description || null,
|
|
198
219
|
disabled: template.disabled === true,
|
|
199
220
|
hideFromCreateDialog: template.hideFromCreateDialog === true,
|
|
200
|
-
openInWizardMode: template.openInWizardMode === true,
|
|
201
221
|
defaultCostLimit: template.defaultCostLimit == null ||
|
|
202
222
|
Number.isNaN(template.defaultCostLimit)
|
|
203
223
|
? null
|
|
@@ -215,7 +235,7 @@ function buildUpsertTemplateRequest(template) {
|
|
|
215
235
|
return {
|
|
216
236
|
...normalizedTask,
|
|
217
237
|
title: normalizedTask.title.trim(),
|
|
218
|
-
description: normalizedTask.description
|
|
238
|
+
description: normalizedTask.description || null,
|
|
219
239
|
disabled: normalizedTask.disabled === true,
|
|
220
240
|
taskType: normalizedTask.taskType ?? "Task",
|
|
221
241
|
decisionMode: normalizedTask.taskType === "DecisionPoint"
|
|
@@ -230,10 +250,35 @@ function buildUpsertTemplateRequest(template) {
|
|
|
230
250
|
dependencyIds: Array.from(new Set(normalizedTask.dependencyIds || [])),
|
|
231
251
|
};
|
|
232
252
|
}),
|
|
253
|
+
goalTemplates: (template.goalTemplates ?? []).map((goal, index) => ({
|
|
254
|
+
id: goal.id,
|
|
255
|
+
title: goal.title.trim(),
|
|
256
|
+
description: goal.description || null,
|
|
257
|
+
disabled: goal.disabled === true,
|
|
258
|
+
sortOrder: goal.sortOrder || index * 100,
|
|
259
|
+
defaultScopeJson: goal.defaultScopeJson?.trim() || null,
|
|
260
|
+
dataShape: goal.dataShape?.trim() || null,
|
|
261
|
+
})),
|
|
233
262
|
};
|
|
234
263
|
}
|
|
235
264
|
function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
236
265
|
const requestedTaskById = new Map((request.taskTemplates ?? []).map((task) => [task.id, task]));
|
|
266
|
+
const requestedGoalById = new Map((request.goalTemplates ?? []).map((goal) => [goal.id, goal]));
|
|
267
|
+
// Server re-reads goals after BeginEdit/EndEdit; if a just-written goal is
|
|
268
|
+
// briefly missing from the response, keep it from the request so the next
|
|
269
|
+
// autosave does not delete it.
|
|
270
|
+
const serverGoals = serverTemplate.goalTemplates ?? [];
|
|
271
|
+
const serverGoalIds = new Set(serverGoals.map((goal) => goal.id));
|
|
272
|
+
const mergedGoalTemplates = [
|
|
273
|
+
...serverGoals.map((goal) => {
|
|
274
|
+
const requested = requestedGoalById.get(goal.id);
|
|
275
|
+
return {
|
|
276
|
+
...goal,
|
|
277
|
+
description: requested?.description ?? goal.description,
|
|
278
|
+
};
|
|
279
|
+
}),
|
|
280
|
+
...(request.goalTemplates ?? []).filter((goal) => !serverGoalIds.has(goal.id)),
|
|
281
|
+
];
|
|
237
282
|
const mergedGraphLayout = request.graphLayout === undefined
|
|
238
283
|
? serverTemplate.graphLayout
|
|
239
284
|
: request.graphLayout === null
|
|
@@ -246,7 +291,9 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
|
246
291
|
};
|
|
247
292
|
return normalizeProjectTemplate({
|
|
248
293
|
...serverTemplate,
|
|
294
|
+
description: request.description ?? serverTemplate.description,
|
|
249
295
|
graphLayout: mergedGraphLayout,
|
|
296
|
+
goalTemplates: mergedGoalTemplates,
|
|
250
297
|
taskTemplates: (serverTemplate.taskTemplates ?? []).map((task) => {
|
|
251
298
|
const requested = requestedTaskById.get(task.id);
|
|
252
299
|
// Sitecore item-cache reads after BeginEdit/EndEdit can briefly omit
|
|
@@ -257,6 +304,7 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
|
257
304
|
const requestedDeps = requested?.dependencyIds ?? [];
|
|
258
305
|
return {
|
|
259
306
|
...task,
|
|
307
|
+
description: requested?.description ?? task.description,
|
|
260
308
|
parentTaskId: task.parentTaskId ?? requested?.parentTaskId ?? null,
|
|
261
309
|
dependencyIds: serverDeps.length === 0 && requestedDeps.length > 0
|
|
262
310
|
? Array.from(new Set(requestedDeps))
|
|
@@ -265,6 +313,61 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
|
265
313
|
}),
|
|
266
314
|
});
|
|
267
315
|
}
|
|
316
|
+
function getActiveDescriptionDraftField(selectedTaskId, selectedGoalId) {
|
|
317
|
+
if (typeof document === "undefined") {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const activeElement = document.activeElement;
|
|
321
|
+
if (!(activeElement instanceof HTMLElement)) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
switch (activeElement.dataset.testid) {
|
|
325
|
+
case "project-template-description-input":
|
|
326
|
+
return { kind: "template" };
|
|
327
|
+
case "project-template-task-description-input":
|
|
328
|
+
return { kind: "task", id: selectedTaskId };
|
|
329
|
+
case "project-template-goal-description-input":
|
|
330
|
+
return { kind: "goal", id: selectedGoalId };
|
|
331
|
+
default:
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function preserveActiveDescriptionDraft(template, draft, activeField) {
|
|
336
|
+
if (!draft || template.id !== draft.id || !activeField) {
|
|
337
|
+
return template;
|
|
338
|
+
}
|
|
339
|
+
if (activeField.kind === "template") {
|
|
340
|
+
return {
|
|
341
|
+
...template,
|
|
342
|
+
description: draft.description,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (activeField.kind === "task" && activeField.id) {
|
|
346
|
+
const draftTask = draft.taskTemplates.find((task) => task.id === activeField.id);
|
|
347
|
+
if (!draftTask) {
|
|
348
|
+
return template;
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
...template,
|
|
352
|
+
taskTemplates: template.taskTemplates.map((task) => task.id === activeField.id
|
|
353
|
+
? { ...task, description: draftTask.description }
|
|
354
|
+
: task),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
if (activeField.kind === "goal" && activeField.id) {
|
|
358
|
+
const draftGoal = (draft.goalTemplates ?? []).find((goal) => goal.id === activeField.id);
|
|
359
|
+
if (!draftGoal) {
|
|
360
|
+
return template;
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
...template,
|
|
364
|
+
goalTemplates: (template.goalTemplates ?? []).map((goal) => goal.id === activeField.id
|
|
365
|
+
? { ...goal, description: draftGoal.description }
|
|
366
|
+
: goal),
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
return template;
|
|
370
|
+
}
|
|
268
371
|
function isValidGuid(value) {
|
|
269
372
|
return (!!value &&
|
|
270
373
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value));
|
|
@@ -361,12 +464,28 @@ function canAddTemplateDependency(template, taskId, dependencyId) {
|
|
|
361
464
|
}
|
|
362
465
|
return task.parentTaskId !== dependencyId;
|
|
363
466
|
}
|
|
364
|
-
function buildProjectTemplateAgentContext(template, selectedTaskTemplateId) {
|
|
467
|
+
function buildProjectTemplateAgentContext(template, selectedTaskTemplateId, selectedGoalTemplateId = null) {
|
|
365
468
|
const dependencyCount = template.taskTemplates.reduce((count, task) => count + (task.dependencyIds?.length ?? 0), 0);
|
|
366
469
|
const agentAssignedTaskCount = template.taskTemplates.filter((task) => task.agentProfileId || (task.assigneeType === "Agent" && task.assigneeId)).length;
|
|
367
470
|
const selectedTask = selectedTaskTemplateId
|
|
368
471
|
? (template.taskTemplates.find((task) => task.id === selectedTaskTemplateId) ?? null)
|
|
369
472
|
: null;
|
|
473
|
+
const goalDefinitions = [...(template.goalTemplates ?? [])]
|
|
474
|
+
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
|
475
|
+
.map((goal) => ({
|
|
476
|
+
id: goal.id,
|
|
477
|
+
title: goal.title?.trim() || "Untitled goal",
|
|
478
|
+
description: goal.description?.trim() || null,
|
|
479
|
+
disabled: goal.disabled === true,
|
|
480
|
+
sortOrder: goal.sortOrder ?? 0,
|
|
481
|
+
defaultScopeJson: goal.defaultScopeJson?.trim() || null,
|
|
482
|
+
dataShape: goal.dataShape?.trim() || null,
|
|
483
|
+
}));
|
|
484
|
+
const selectedGoal = selectedGoalTemplateId
|
|
485
|
+
? (goalDefinitions.find((goal) => goal.id === selectedGoalTemplateId) ??
|
|
486
|
+
null)
|
|
487
|
+
: null;
|
|
488
|
+
const enabledGoalCount = goalDefinitions.filter((goal) => goal.disabled !== true).length;
|
|
370
489
|
return {
|
|
371
490
|
activeWorkspace: "settings",
|
|
372
491
|
additionalData: {
|
|
@@ -382,10 +501,22 @@ function buildProjectTemplateAgentContext(template, selectedTaskTemplateId) {
|
|
|
382
501
|
selectedTaskTemplate: selectedTask
|
|
383
502
|
? normalizeTaskTemplate(selectedTask)
|
|
384
503
|
: null,
|
|
504
|
+
selectedGoalTemplateId: selectedGoal ? selectedGoal.id : null,
|
|
505
|
+
selectedGoalTemplateTitle: selectedGoal?.title ?? null,
|
|
506
|
+
selectedGoalTemplate: selectedGoal,
|
|
507
|
+
projectTemplateGoalDefinitions: goalDefinitions,
|
|
508
|
+
projectTemplateGoalSummary: {
|
|
509
|
+
goalCount: goalDefinitions.length,
|
|
510
|
+
enabledGoalCount,
|
|
511
|
+
disabledGoalCount: goalDefinitions.length - enabledGoalCount,
|
|
512
|
+
},
|
|
385
513
|
projectTemplateSummary: {
|
|
386
514
|
taskCount: template.taskTemplates.length,
|
|
387
515
|
dependencyCount,
|
|
388
516
|
agentAssignedTaskCount,
|
|
517
|
+
goalCount: goalDefinitions.length,
|
|
518
|
+
enabledGoalCount,
|
|
519
|
+
disabledGoalCount: goalDefinitions.length - enabledGoalCount,
|
|
389
520
|
defaultCostLimit: template.defaultCostLimit ?? null,
|
|
390
521
|
disabled: template.disabled === true,
|
|
391
522
|
},
|
|
@@ -414,6 +545,10 @@ export function ProjectTemplatesPanel() {
|
|
|
414
545
|
const [newTaskTitle, setNewTaskTitle] = useState("");
|
|
415
546
|
const [newTaskDependencySourceId, setNewTaskDependencySourceId] = useState(null);
|
|
416
547
|
const [creatingTask, setCreatingTask] = useState(false);
|
|
548
|
+
const [selectedGoalId, setSelectedGoalId] = useState(null);
|
|
549
|
+
const [isCreateGoalDialogOpen, setIsCreateGoalDialogOpen] = useState(false);
|
|
550
|
+
const [newGoalTitle, setNewGoalTitle] = useState("");
|
|
551
|
+
const [creatingGoal, setCreatingGoal] = useState(false);
|
|
417
552
|
const [isAddChildTaskDialogOpen, setIsAddChildTaskDialogOpen] = useState(false);
|
|
418
553
|
const [newChildTaskTitle, setNewChildTaskTitle] = useState("");
|
|
419
554
|
const [creatingChildTask, setCreatingChildTask] = useState(false);
|
|
@@ -429,6 +564,12 @@ export function ProjectTemplatesPanel() {
|
|
|
429
564
|
const [editingAgentProfile, setEditingAgentProfile] = useState(null);
|
|
430
565
|
const [isTaskEditorMaximized, setIsTaskEditorMaximized] = useState(false);
|
|
431
566
|
const [taskEditorOverlayBounds, setTaskEditorOverlayBounds] = useState(null);
|
|
567
|
+
const [settingsMainContentBounds, setSettingsMainContentBounds] = useState(null);
|
|
568
|
+
const [agentPanelBounds, setAgentPanelBounds] = useState(null);
|
|
569
|
+
const [isAgentPanelCollapsed, setIsAgentPanelCollapsed] = useState(() => {
|
|
570
|
+
const stored = localStorageService.getItem(PROJECT_TEMPLATE_SPLITTER_STORAGE_KEY);
|
|
571
|
+
return stored?.lastCollapsed ?? true;
|
|
572
|
+
});
|
|
432
573
|
const [forceCollapseAgentPanelKey, setForceCollapseAgentPanelKey] = useState(0);
|
|
433
574
|
const [forceExpandAgentPanelKey, setForceExpandAgentPanelKey] = useState(0);
|
|
434
575
|
const settingsMainContentRef = useRequiredSettingsMainContentRef();
|
|
@@ -441,6 +582,7 @@ export function ProjectTemplatesPanel() {
|
|
|
441
582
|
const draftTemplateRef = useRef(null);
|
|
442
583
|
const selectedTemplateIdRef = useRef(selectedTemplateId);
|
|
443
584
|
const selectedTaskIdRef = useRef(selectedTaskId);
|
|
585
|
+
const selectedGoalIdRef = useRef(selectedGoalId);
|
|
444
586
|
const selectedDependencyIdRef = useRef(selectedDependencyId);
|
|
445
587
|
const isDirtyRef = useRef(isDirty);
|
|
446
588
|
const savingRef = useRef(saving);
|
|
@@ -455,6 +597,7 @@ export function ProjectTemplatesPanel() {
|
|
|
455
597
|
};
|
|
456
598
|
const restoreAgentPanelAfterMaximize = () => {
|
|
457
599
|
if (agentPanelWasExpandedBeforeMaximizeRef.current === true) {
|
|
600
|
+
setIsAgentPanelCollapsed(false);
|
|
458
601
|
setForceExpandAgentPanelKey((value) => value + 1);
|
|
459
602
|
}
|
|
460
603
|
agentPanelWasExpandedBeforeMaximizeRef.current = null;
|
|
@@ -477,11 +620,114 @@ export function ProjectTemplatesPanel() {
|
|
|
477
620
|
const agentPanelCollapsed = wasAgentPanelCollapsed();
|
|
478
621
|
agentPanelWasExpandedBeforeMaximizeRef.current = !agentPanelCollapsed;
|
|
479
622
|
if (!agentPanelCollapsed) {
|
|
623
|
+
setIsAgentPanelCollapsed(true);
|
|
480
624
|
setForceCollapseAgentPanelKey((value) => value + 1);
|
|
481
625
|
}
|
|
482
626
|
setTaskEditorOverlayBounds(nextBounds);
|
|
483
627
|
setIsTaskEditorMaximized(true);
|
|
484
628
|
};
|
|
629
|
+
useEffect(() => {
|
|
630
|
+
const settingsMainContent = settingsMainContentRef.current;
|
|
631
|
+
const updateBounds = () => {
|
|
632
|
+
const nextBounds = measureOverlayBounds(settingsMainContentRef.current);
|
|
633
|
+
if (nextBounds) {
|
|
634
|
+
setSettingsMainContentBounds(nextBounds);
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
updateBounds();
|
|
638
|
+
if (typeof window === "undefined") {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
let frameId = null;
|
|
642
|
+
const scheduleUpdate = () => {
|
|
643
|
+
if (frameId != null) {
|
|
644
|
+
window.cancelAnimationFrame(frameId);
|
|
645
|
+
}
|
|
646
|
+
frameId = window.requestAnimationFrame(() => {
|
|
647
|
+
frameId = null;
|
|
648
|
+
updateBounds();
|
|
649
|
+
});
|
|
650
|
+
};
|
|
651
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" && settingsMainContent
|
|
652
|
+
? new ResizeObserver(scheduleUpdate)
|
|
653
|
+
: null;
|
|
654
|
+
if (resizeObserver && settingsMainContent) {
|
|
655
|
+
resizeObserver.observe(settingsMainContent);
|
|
656
|
+
}
|
|
657
|
+
window.addEventListener("resize", scheduleUpdate);
|
|
658
|
+
window.addEventListener("scroll", scheduleUpdate, true);
|
|
659
|
+
return () => {
|
|
660
|
+
if (frameId != null) {
|
|
661
|
+
window.cancelAnimationFrame(frameId);
|
|
662
|
+
}
|
|
663
|
+
resizeObserver?.disconnect();
|
|
664
|
+
window.removeEventListener("resize", scheduleUpdate);
|
|
665
|
+
window.removeEventListener("scroll", scheduleUpdate, true);
|
|
666
|
+
};
|
|
667
|
+
}, [settingsMainContentRef]);
|
|
668
|
+
useEffect(() => {
|
|
669
|
+
if (isMobile) {
|
|
670
|
+
setAgentPanelBounds(null);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
const updateBounds = () => {
|
|
674
|
+
const element = document.querySelector('[data-testid="splitter-panel-project-template-agent"]');
|
|
675
|
+
const nextBounds = measureOverlayBounds(element);
|
|
676
|
+
setAgentPanelBounds((currentBounds) => {
|
|
677
|
+
if (!nextBounds) {
|
|
678
|
+
return currentBounds === null ? currentBounds : null;
|
|
679
|
+
}
|
|
680
|
+
if (currentBounds &&
|
|
681
|
+
Math.abs(currentBounds.top - nextBounds.top) < 0.5 &&
|
|
682
|
+
Math.abs(currentBounds.left - nextBounds.left) < 0.5 &&
|
|
683
|
+
Math.abs(currentBounds.width - nextBounds.width) < 0.5 &&
|
|
684
|
+
Math.abs(currentBounds.height - nextBounds.height) < 0.5) {
|
|
685
|
+
return currentBounds;
|
|
686
|
+
}
|
|
687
|
+
return nextBounds;
|
|
688
|
+
});
|
|
689
|
+
};
|
|
690
|
+
updateBounds();
|
|
691
|
+
if (typeof window === "undefined") {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
let frameId = null;
|
|
695
|
+
const scheduleUpdate = () => {
|
|
696
|
+
if (frameId != null) {
|
|
697
|
+
window.cancelAnimationFrame(frameId);
|
|
698
|
+
}
|
|
699
|
+
frameId = window.requestAnimationFrame(() => {
|
|
700
|
+
frameId = null;
|
|
701
|
+
updateBounds();
|
|
702
|
+
});
|
|
703
|
+
};
|
|
704
|
+
const settingsMainContent = settingsMainContentRef.current;
|
|
705
|
+
const agentPanelElement = document.querySelector('[data-testid="splitter-panel-project-template-agent"]');
|
|
706
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" && settingsMainContent
|
|
707
|
+
? new ResizeObserver(scheduleUpdate)
|
|
708
|
+
: null;
|
|
709
|
+
if (resizeObserver && settingsMainContent) {
|
|
710
|
+
resizeObserver.observe(settingsMainContent);
|
|
711
|
+
}
|
|
712
|
+
if (resizeObserver && agentPanelElement) {
|
|
713
|
+
resizeObserver.observe(agentPanelElement);
|
|
714
|
+
}
|
|
715
|
+
window.addEventListener("resize", scheduleUpdate);
|
|
716
|
+
window.addEventListener("scroll", scheduleUpdate, true);
|
|
717
|
+
return () => {
|
|
718
|
+
if (frameId != null) {
|
|
719
|
+
window.cancelAnimationFrame(frameId);
|
|
720
|
+
}
|
|
721
|
+
resizeObserver?.disconnect();
|
|
722
|
+
window.removeEventListener("resize", scheduleUpdate);
|
|
723
|
+
window.removeEventListener("scroll", scheduleUpdate, true);
|
|
724
|
+
};
|
|
725
|
+
}, [
|
|
726
|
+
isAgentPanelCollapsed,
|
|
727
|
+
isMobile,
|
|
728
|
+
selectedTemplateId,
|
|
729
|
+
settingsMainContentRef,
|
|
730
|
+
]);
|
|
485
731
|
useEffect(() => {
|
|
486
732
|
if (!isTaskEditorMaximized) {
|
|
487
733
|
setTaskEditorOverlayBounds(null);
|
|
@@ -622,8 +868,14 @@ export function ProjectTemplatesPanel() {
|
|
|
622
868
|
setMobileView("detail");
|
|
623
869
|
return;
|
|
624
870
|
}
|
|
871
|
+
setIsAgentPanelCollapsed(true);
|
|
625
872
|
setForceCollapseAgentPanelKey((value) => value + 1);
|
|
626
873
|
}, [isMobile]);
|
|
874
|
+
const handleShowTemplateAssistant = useCallback(() => {
|
|
875
|
+
setEditingAgentProfile(null);
|
|
876
|
+
setIsAgentPanelCollapsed(false);
|
|
877
|
+
setForceExpandAgentPanelKey((value) => value + 1);
|
|
878
|
+
}, []);
|
|
627
879
|
useEffect(() => {
|
|
628
880
|
if (!isMobile) {
|
|
629
881
|
setMobileView("detail");
|
|
@@ -642,7 +894,8 @@ export function ProjectTemplatesPanel() {
|
|
|
642
894
|
if (result.type !== "success") {
|
|
643
895
|
throw new Error(result.summary || "Failed to load project templates");
|
|
644
896
|
}
|
|
645
|
-
const
|
|
897
|
+
const activeDescriptionDraftField = getActiveDescriptionDraftField(selectedTaskIdRef.current, selectedGoalIdRef.current);
|
|
898
|
+
const loadedTemplates = (result.data ?? []).map((template) => preserveActiveDescriptionDraft(template, draftTemplateRef.current, activeDescriptionDraftField));
|
|
646
899
|
setTemplates(loadedTemplates);
|
|
647
900
|
setState("success");
|
|
648
901
|
const preferredTemplateExists = !!preferredTemplateId &&
|
|
@@ -712,6 +965,9 @@ export function ProjectTemplatesPanel() {
|
|
|
712
965
|
}, [aiProfiles]);
|
|
713
966
|
const selectedTask = useMemo(() => draftTemplate?.taskTemplates.find((task) => task.id === selectedTaskId) ??
|
|
714
967
|
null, [draftTemplate, selectedTaskId]);
|
|
968
|
+
const templateAgentInitialMetadata = useMemo(() => draftTemplate
|
|
969
|
+
? buildProjectTemplateAgentContext(draftTemplate, selectedTaskId, selectedGoalId)
|
|
970
|
+
: undefined, [draftTemplate, selectedGoalId, selectedTaskId]);
|
|
715
971
|
const dependencyTasks = useMemo(() => {
|
|
716
972
|
if (!draftTemplate || !selectedTask)
|
|
717
973
|
return [];
|
|
@@ -781,9 +1037,9 @@ export function ProjectTemplatesPanel() {
|
|
|
781
1037
|
setMobileView("detail");
|
|
782
1038
|
}
|
|
783
1039
|
}, [isMobile]);
|
|
784
|
-
const syncProjectTemplateAgentContext = useCallback(async (agentId, template, selectedTaskTemplateId) => {
|
|
1040
|
+
const syncProjectTemplateAgentContext = useCallback(async (agentId, template, selectedTaskTemplateId, selectedGoalTemplateId) => {
|
|
785
1041
|
try {
|
|
786
|
-
await updateAgentContext(agentId, buildProjectTemplateAgentContext(template, selectedTaskTemplateId));
|
|
1042
|
+
await updateAgentContext(agentId, buildProjectTemplateAgentContext(template, selectedTaskTemplateId, selectedGoalTemplateId));
|
|
787
1043
|
}
|
|
788
1044
|
catch (error) {
|
|
789
1045
|
setTemplateAgentError(error instanceof Error
|
|
@@ -836,8 +1092,9 @@ export function ProjectTemplatesPanel() {
|
|
|
836
1092
|
const currentTemplate = draftTemplateRef.current;
|
|
837
1093
|
if (!currentTemplate || currentTemplate.id !== selectedTemplateId)
|
|
838
1094
|
return;
|
|
839
|
-
void syncProjectTemplateAgentContext(templateAgentId, currentTemplate, selectedTaskId);
|
|
1095
|
+
void syncProjectTemplateAgentContext(templateAgentId, currentTemplate, selectedTaskId, selectedGoalId);
|
|
840
1096
|
}, [
|
|
1097
|
+
selectedGoalId,
|
|
841
1098
|
selectedTaskId,
|
|
842
1099
|
templateAgentId,
|
|
843
1100
|
templateAgentLoading,
|
|
@@ -868,6 +1125,14 @@ export function ProjectTemplatesPanel() {
|
|
|
868
1125
|
taskTemplates: currentTemplate.taskTemplates.map((task) => task.id === selectedTaskId ? updater({ ...task }) : task),
|
|
869
1126
|
}));
|
|
870
1127
|
}, [applyDraftChange, selectedTaskId]);
|
|
1128
|
+
const updateSelectedGoal = useCallback((updater) => {
|
|
1129
|
+
if (!selectedGoalId)
|
|
1130
|
+
return;
|
|
1131
|
+
applyDraftChange((currentTemplate) => ({
|
|
1132
|
+
...currentTemplate,
|
|
1133
|
+
goalTemplates: (currentTemplate.goalTemplates ?? []).map((goal) => goal.id === selectedGoalId ? updater({ ...goal }) : goal),
|
|
1134
|
+
}));
|
|
1135
|
+
}, [applyDraftChange, selectedGoalId]);
|
|
871
1136
|
const handleDuplicateAssignedAgentProfile = useCallback(async () => {
|
|
872
1137
|
if (!editContext || !selectedAgentProfileId)
|
|
873
1138
|
return;
|
|
@@ -999,7 +1264,10 @@ export function ProjectTemplatesPanel() {
|
|
|
999
1264
|
}
|
|
1000
1265
|
if (templateAgentId && savedTemplate.id === selectedTemplateId) {
|
|
1001
1266
|
const nextSelectedTaskId = getSelectedTaskIdForTemplate(savedTemplate, selectedTaskIdRef.current);
|
|
1002
|
-
|
|
1267
|
+
const nextSelectedGoalId = savedTemplate.goalTemplates?.some((goal) => goal.id === selectedGoalId) === true
|
|
1268
|
+
? selectedGoalId
|
|
1269
|
+
: null;
|
|
1270
|
+
void syncProjectTemplateAgentContext(templateAgentId, savedTemplate, nextSelectedTaskId, nextSelectedGoalId);
|
|
1003
1271
|
}
|
|
1004
1272
|
return true;
|
|
1005
1273
|
}
|
|
@@ -1008,7 +1276,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1008
1276
|
setSaving(false);
|
|
1009
1277
|
}
|
|
1010
1278
|
}
|
|
1011
|
-
}, [
|
|
1279
|
+
}, [
|
|
1280
|
+
selectedGoalId,
|
|
1281
|
+
selectedTemplateId,
|
|
1282
|
+
syncProjectTemplateAgentContext,
|
|
1283
|
+
templateAgentId,
|
|
1284
|
+
]);
|
|
1012
1285
|
const applyDraftChangeAndPersist = useCallback((updater) => {
|
|
1013
1286
|
let nextTemplate = null;
|
|
1014
1287
|
let nextSignature = null;
|
|
@@ -1133,6 +1406,9 @@ export function ProjectTemplatesPanel() {
|
|
|
1133
1406
|
useEffect(() => {
|
|
1134
1407
|
selectedTaskIdRef.current = selectedTaskId;
|
|
1135
1408
|
}, [selectedTaskId]);
|
|
1409
|
+
useEffect(() => {
|
|
1410
|
+
selectedGoalIdRef.current = selectedGoalId;
|
|
1411
|
+
}, [selectedGoalId]);
|
|
1136
1412
|
useEffect(() => {
|
|
1137
1413
|
selectedDependencyIdRef.current = selectedDependencyId;
|
|
1138
1414
|
}, [selectedDependencyId]);
|
|
@@ -1243,6 +1519,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1243
1519
|
setSelectedTemplateId(nextTemplate.id);
|
|
1244
1520
|
setDraftTemplate(cloneTemplate(nextTemplate));
|
|
1245
1521
|
setSelectedTaskId(null);
|
|
1522
|
+
setSelectedGoalId(null);
|
|
1246
1523
|
setIsDirty(true);
|
|
1247
1524
|
setSaveError(null);
|
|
1248
1525
|
lastPersistedSignatureRef.current = null;
|
|
@@ -1348,7 +1625,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1348
1625
|
setTemplateAgentId(result.data.agentId);
|
|
1349
1626
|
const currentTemplate = draftTemplateRef.current;
|
|
1350
1627
|
if (currentTemplate?.id === selectedTemplateId) {
|
|
1351
|
-
await syncProjectTemplateAgentContext(result.data.agentId, currentTemplate, selectedTaskIdRef.current);
|
|
1628
|
+
await syncProjectTemplateAgentContext(result.data.agentId, currentTemplate, selectedTaskIdRef.current, selectedGoalId);
|
|
1352
1629
|
}
|
|
1353
1630
|
}
|
|
1354
1631
|
catch (error) {
|
|
@@ -1361,7 +1638,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1361
1638
|
finally {
|
|
1362
1639
|
setTemplateAgentResetting(false);
|
|
1363
1640
|
}
|
|
1364
|
-
}, [
|
|
1641
|
+
}, [
|
|
1642
|
+
flushPendingSave,
|
|
1643
|
+
selectedGoalId,
|
|
1644
|
+
selectedTemplateId,
|
|
1645
|
+
syncProjectTemplateAgentContext,
|
|
1646
|
+
]);
|
|
1365
1647
|
const handleOpenCreateTaskDialog = useCallback(async () => {
|
|
1366
1648
|
if (!draftTemplate)
|
|
1367
1649
|
return;
|
|
@@ -1449,6 +1731,56 @@ export function ProjectTemplatesPanel() {
|
|
|
1449
1731
|
setCreatingTask(false);
|
|
1450
1732
|
}
|
|
1451
1733
|
}, [draftTemplate, newTaskDependencySourceId, newTaskTitle, persistTemplate]);
|
|
1734
|
+
const handleConfirmCreateGoal = useCallback(async () => {
|
|
1735
|
+
if (!draftTemplate)
|
|
1736
|
+
return;
|
|
1737
|
+
const trimmedTitle = newGoalTitle.trim();
|
|
1738
|
+
if (!trimmedTitle) {
|
|
1739
|
+
toast.error("Goal title is required");
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
if (!draftTemplate.name.trim()) {
|
|
1743
|
+
const message = "Project template name is required before it can be saved";
|
|
1744
|
+
setSaveError(message);
|
|
1745
|
+
toast.error(message);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
if (autosaveTimeoutRef.current !== null) {
|
|
1749
|
+
window.clearTimeout(autosaveTimeoutRef.current);
|
|
1750
|
+
autosaveTimeoutRef.current = null;
|
|
1751
|
+
}
|
|
1752
|
+
const nextGoal = createEmptyGoalDefinition((draftTemplate.goalTemplates ?? []).length, trimmedTitle);
|
|
1753
|
+
const nextTemplate = cloneTemplate(draftTemplate);
|
|
1754
|
+
nextTemplate.goalTemplates = [
|
|
1755
|
+
...(nextTemplate.goalTemplates ?? []),
|
|
1756
|
+
nextGoal,
|
|
1757
|
+
];
|
|
1758
|
+
const request = buildUpsertTemplateRequest(nextTemplate);
|
|
1759
|
+
const signature = JSON.stringify(request);
|
|
1760
|
+
latestDraftSignatureRef.current = signature;
|
|
1761
|
+
setDraftTemplate(cloneTemplate(nextTemplate));
|
|
1762
|
+
setTemplates((existingTemplates) => sortTemplates([
|
|
1763
|
+
...existingTemplates.filter((template) => template.id !== nextTemplate.id),
|
|
1764
|
+
cloneTemplate(nextTemplate),
|
|
1765
|
+
]));
|
|
1766
|
+
setSelectedGoalId(nextGoal.id);
|
|
1767
|
+
setIsDirty(true);
|
|
1768
|
+
setSaveError(null);
|
|
1769
|
+
setCreatingGoal(true);
|
|
1770
|
+
try {
|
|
1771
|
+
const saved = await persistTemplate(request, signature, {
|
|
1772
|
+
showErrorToast: true,
|
|
1773
|
+
});
|
|
1774
|
+
if (saved) {
|
|
1775
|
+
setIsCreateGoalDialogOpen(false);
|
|
1776
|
+
setNewGoalTitle("");
|
|
1777
|
+
toast.success("Goal definition created");
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
finally {
|
|
1781
|
+
setCreatingGoal(false);
|
|
1782
|
+
}
|
|
1783
|
+
}, [draftTemplate, newGoalTitle, persistTemplate]);
|
|
1452
1784
|
const handleOpenAddChildTaskDialog = useCallback(async () => {
|
|
1453
1785
|
if (!draftTemplate || !selectedTaskId)
|
|
1454
1786
|
return;
|
|
@@ -1485,7 +1817,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1485
1817
|
...existingTemplates.filter((template) => template.id !== nextTemplate.id),
|
|
1486
1818
|
cloneTemplate(nextTemplate),
|
|
1487
1819
|
]));
|
|
1488
|
-
// Keep the parent task selected so the new
|
|
1820
|
+
// Keep the parent task selected so the new subtask appears immediately.
|
|
1489
1821
|
setIsDirty(true);
|
|
1490
1822
|
setSaveError(null);
|
|
1491
1823
|
setCreatingChildTask(true);
|
|
@@ -1496,7 +1828,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1496
1828
|
if (saved) {
|
|
1497
1829
|
setIsAddChildTaskDialogOpen(false);
|
|
1498
1830
|
setNewChildTaskTitle("");
|
|
1499
|
-
toast.success("
|
|
1831
|
+
toast.success("Subtask template created");
|
|
1500
1832
|
}
|
|
1501
1833
|
}
|
|
1502
1834
|
finally {
|
|
@@ -1531,6 +1863,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1531
1863
|
setSelectedDependencyId(null);
|
|
1532
1864
|
setSelectedTaskId(taskId);
|
|
1533
1865
|
}, []);
|
|
1866
|
+
const handleCloseTaskDetailsPane = useCallback(() => {
|
|
1867
|
+
selectedTaskIdRef.current = null;
|
|
1868
|
+
selectedDependencyIdRef.current = null;
|
|
1869
|
+
setSelectedTaskId(null);
|
|
1870
|
+
setSelectedDependencyId(null);
|
|
1871
|
+
}, []);
|
|
1534
1872
|
const handleSelectDependencyFromGraph = useCallback((taskId, dependencyId) => {
|
|
1535
1873
|
selectedDependencyIdRef.current = dependencyId;
|
|
1536
1874
|
setSelectedTaskId(taskId);
|
|
@@ -1661,6 +1999,43 @@ export function ProjectTemplatesPanel() {
|
|
|
1661
1999
|
}
|
|
1662
2000
|
runDelete();
|
|
1663
2001
|
}, [applyDraftChange, editContext]);
|
|
2002
|
+
const removeGoalDefinitionById = useCallback((goalId) => {
|
|
2003
|
+
const template = draftTemplateRef.current;
|
|
2004
|
+
const goals = template?.goalTemplates ?? [];
|
|
2005
|
+
if (!goals.some((goal) => goal.id === goalId))
|
|
2006
|
+
return;
|
|
2007
|
+
const goalTitle = goals.find((goal) => goal.id === goalId)?.title ?? "Untitled goal";
|
|
2008
|
+
const runDelete = () => {
|
|
2009
|
+
const current = draftTemplateRef.current;
|
|
2010
|
+
const currentGoals = current?.goalTemplates ?? [];
|
|
2011
|
+
if (!currentGoals.some((goal) => goal.id === goalId))
|
|
2012
|
+
return;
|
|
2013
|
+
const remainingGoals = currentGoals.filter((goal) => goal.id !== goalId);
|
|
2014
|
+
applyDraftChange((currentTemplate) => ({
|
|
2015
|
+
...currentTemplate,
|
|
2016
|
+
goalTemplates: (currentTemplate.goalTemplates ?? []).filter((goal) => goal.id !== goalId),
|
|
2017
|
+
}));
|
|
2018
|
+
setSelectedGoalId((prev) => {
|
|
2019
|
+
if (prev === goalId) {
|
|
2020
|
+
return remainingGoals[0]?.id ?? null;
|
|
2021
|
+
}
|
|
2022
|
+
return remainingGoals.some((goal) => goal.id === prev)
|
|
2023
|
+
? prev
|
|
2024
|
+
: (remainingGoals[0]?.id ?? null);
|
|
2025
|
+
});
|
|
2026
|
+
};
|
|
2027
|
+
if (editContext?.confirm) {
|
|
2028
|
+
editContext.confirm({
|
|
2029
|
+
header: "Remove goal definition",
|
|
2030
|
+
message: `Are you sure you want to remove "${goalTitle}"?`,
|
|
2031
|
+
acceptLabel: "Remove",
|
|
2032
|
+
showCancel: true,
|
|
2033
|
+
accept: runDelete,
|
|
2034
|
+
});
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
runDelete();
|
|
2038
|
+
}, [applyDraftChange, editContext]);
|
|
1664
2039
|
const handleDeleteSelectedTask = useCallback(() => {
|
|
1665
2040
|
if (!selectedTaskId)
|
|
1666
2041
|
return;
|
|
@@ -1712,30 +2087,41 @@ export function ProjectTemplatesPanel() {
|
|
|
1712
2087
|
const breadcrumbTaskCount = draftTemplate?.taskTemplates.length ?? 0;
|
|
1713
2088
|
const breadcrumbItems = useMemo(() => breadcrumbDraftName
|
|
1714
2089
|
? [
|
|
1715
|
-
{
|
|
1716
|
-
title: "Workflow Project Templates",
|
|
1717
|
-
subtitle: "Create project templates",
|
|
1718
|
-
onClick: () => {
|
|
1719
|
-
void handleNavigateToOverview();
|
|
1720
|
-
},
|
|
1721
|
-
},
|
|
1722
2090
|
{
|
|
1723
2091
|
title: breadcrumbDraftName,
|
|
1724
2092
|
subtitle: `${breadcrumbTaskCount} task templates`,
|
|
2093
|
+
backLink: {
|
|
2094
|
+
label: "Back to project templates overview",
|
|
2095
|
+
onClick: () => {
|
|
2096
|
+
void handleNavigateToOverview();
|
|
2097
|
+
},
|
|
2098
|
+
},
|
|
1725
2099
|
},
|
|
1726
2100
|
]
|
|
1727
2101
|
: null, [breadcrumbDraftName, breadcrumbTaskCount, handleNavigateToOverview]);
|
|
1728
2102
|
const desktopHeaderActions = useMemo(() => {
|
|
1729
2103
|
if (isMobile)
|
|
1730
2104
|
return null;
|
|
2105
|
+
const showCreate = !draftTemplate;
|
|
1731
2106
|
const showDelete = draftTemplate && !draftTemplate.isSystem;
|
|
1732
|
-
|
|
2107
|
+
const agentPanelHeaderOffset = draftTemplate &&
|
|
2108
|
+
!isTaskEditorMaximized &&
|
|
2109
|
+
!isAgentPanelCollapsed &&
|
|
2110
|
+
agentPanelBounds
|
|
2111
|
+
? Math.round(agentPanelBounds.width + 8)
|
|
2112
|
+
: 0;
|
|
2113
|
+
return (_jsxs("div", { className: "mt-2 flex items-center gap-2", style: agentPanelHeaderOffset > 0
|
|
2114
|
+
? { marginRight: agentPanelHeaderOffset }
|
|
2115
|
+
: undefined, children: [headerStatusBadge, showCreate ? (_jsxs(Button, { size: "sm", onClick: () => void handleCreateTemplate(), "data-testid": "project-template-create-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Create template"] })) : null, showDelete ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(DeleteIcon, { size: "lg" }), deleting ? "Deleting..." : "Delete"] })) : null] }));
|
|
1733
2116
|
}, [
|
|
2117
|
+
agentPanelBounds,
|
|
1734
2118
|
deleting,
|
|
1735
2119
|
draftTemplate,
|
|
1736
2120
|
handleCreateTemplate,
|
|
1737
2121
|
handleDeleteTemplate,
|
|
1738
2122
|
headerStatusBadge,
|
|
2123
|
+
isAgentPanelCollapsed,
|
|
2124
|
+
isTaskEditorMaximized,
|
|
1739
2125
|
isMobile,
|
|
1740
2126
|
]);
|
|
1741
2127
|
useEffect(() => {
|
|
@@ -1773,7 +2159,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1773
2159
|
}));
|
|
1774
2160
|
return nextLayout;
|
|
1775
2161
|
} }) }) }));
|
|
1776
|
-
const taskPane = (_jsx("div", { className: "flex h-full min-h-0 flex-col overflow-hidden", "data-testid": "project-template-task-detail-pane", children: !selectedTask ? (_jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children: _jsx("div", { className: "border-border-default bg-neutral-grey-5 text-neutral-grey-50 rounded-lg border border-dashed p-6 text-center text-xs", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-border-default shrink-0 border-b bg-white px-4 pt-4 pb-3", children: _jsxs("div", { className: "flex items-
|
|
2162
|
+
const taskPane = (_jsx("div", { className: "flex h-full min-h-0 flex-col overflow-hidden", "data-testid": "project-template-task-detail-pane", children: !selectedTask ? (_jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children: _jsx("div", { className: "border-border-default bg-neutral-grey-5 text-neutral-grey-50 rounded-lg border border-dashed p-6 text-center text-xs", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-border-default shrink-0 border-b bg-white px-4 pt-4 pb-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), selectedTask.taskType === "DecisionPoint" ? (_jsx(Badge, { variant: "outline", className: "border-highlight-100 bg-highlight-10 text-2xs text-highlight-100", children: "Decision Point" })) : null, selectedTask.disabled ? (_jsx(Badge, { variant: "outline", className: "text-2xs", children: "Disabled" })) : null] }), _jsx("div", { className: "text-neutral-grey-50 text-xs", children: "Configure task details, assignment, and dependencies." })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: handleDeleteSelectedTask, "data-testid": "project-template-remove-task-button", children: [_jsx(DeleteIcon, { size: "lg" }), "Remove Task"] }), _jsx(CloseButton, { onClick: handleCloseTaskDetailsPane, label: "Close task details", "data-testid": "project-template-close-task-details-button" })] })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-4 pt-3 pb-4", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-task-title-input", children: "Task title" }), _jsx(Input, { id: "project-template-task-title-input", value: selectedTask.title, onChange: (event) => updateSelectedTask((currentTask) => ({
|
|
1777
2163
|
...currentTask,
|
|
1778
2164
|
title: event.target.value,
|
|
1779
2165
|
})), placeholder: "Task title", className: "text-xs md:text-xs", "data-testid": "project-template-task-title-input" })] }), _jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Description" }), _jsx(Textarea, { className: "text-xs", value: selectedTask.description ?? "", onChange: (event) => updateSelectedTask((currentTask) => ({
|
|
@@ -1802,7 +2188,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1802
2188
|
agentProfileId: next?.assigneeType === "Agent"
|
|
1803
2189
|
? next.assigneeId
|
|
1804
2190
|
: null,
|
|
1805
|
-
})), placeholder: "Assign user or agent", buttonClassName: "h-
|
|
2191
|
+
})), placeholder: "Assign user or agent", buttonClassName: "h-8 min-h-0 w-full justify-between rounded-md bg-white text-xs", buttonTestId: "project-template-task-assignee-picker" }) }), selectedTask.assigneeType === "Agent" ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-8 shrink-0 gap-1 px-2 text-xs", onClick: () => void handleEditAssignedAgentProfile(), disabled: !selectedAgentProfileId, "data-testid": "project-template-task-edit-agent-profile-button", children: [_jsx(Settings2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), "Edit Profile"] })) : null] }), profilesError ? (_jsx("div", { className: "text-feedback-orange text-xs", children: profilesError })) : null] })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border p-3", "data-testid": "project-template-dependencies-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "text-neutral-grey-100 flex items-center gap-2 text-xs font-medium", children: [_jsx(Shield, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1.5 }), "Dependencies"] }), _jsxs(Popover, { open: dependencyPickerOpen, onOpenChange: setDependencyPickerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", disabled: dependencyAddCandidates.length === 0, "aria-label": "Add dependency", "data-testid": "project-template-add-dependency-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }) }), _jsxs(PopoverContent, { align: "end", className: "w-72 p-0", sideOffset: 6, "data-testid": "project-template-dependency-popover", children: [_jsx("div", { className: "border-border-default text-neutral-grey-100 border-b px-3 py-2 text-xs font-medium", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 px-2 py-3 text-center text-xs", children: "All other tasks are already linked." })) : (dependencyAddCandidates.map((task) => (_jsxs("button", { type: "button", className: "hover:bg-neutral-grey-5 flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-xs", onClick: () => handleAddDependency(task.id), "data-testid": `project-template-dependency-option-${task.id}`, children: [_jsx(Link2, { className: "text-neutral-grey-50 h-3.5 w-3.5 shrink-0", strokeWidth: 1.5 }), _jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" })] }, task.id)))) })] })] })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "This task must wait for these tasks to finish first." }), dependencyTasks.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: draftTemplate.taskTemplates.filter((t) => t.id !== selectedTask.id).length === 0
|
|
1806
2192
|
? "Add more task templates to create dependencies."
|
|
1807
2193
|
: "No dependencies yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: dependencyTasks.map((task) => (_jsxs("li", { tabIndex: 0, className: cn("flex items-center justify-between gap-2 rounded-md border bg-white px-3 py-2 text-xs transition-colors outline-none", selectedDependencyId === task.id
|
|
1808
2194
|
? "border-feedback-orange bg-feedback-orange-light ring-feedback-orange ring-1"
|
|
@@ -1818,23 +2204,28 @@ export function ProjectTemplatesPanel() {
|
|
|
1818
2204
|
event.preventDefault();
|
|
1819
2205
|
event.stopPropagation();
|
|
1820
2206
|
handleRemoveDependency(task.id);
|
|
1821
|
-
}, "data-testid": `project-template-dependency-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Remove dependency on ${task.title}`, onClick: () => handleRemoveDependency(task.id), "data-testid": `project-template-remove-dependency-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] }), _jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border p-3", "data-testid": "project-template-child-tasks-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "text-neutral-grey-100 flex items-center gap-2 text-xs font-medium", children: [_jsx(CornerDownRight, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1.5 }), "
|
|
2207
|
+
}, "data-testid": `project-template-dependency-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Remove dependency on ${task.title}`, onClick: () => handleRemoveDependency(task.id), "data-testid": `project-template-remove-dependency-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] }), _jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border p-3", "data-testid": "project-template-child-tasks-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "text-neutral-grey-100 flex items-center gap-2 text-xs font-medium", children: [_jsx(CornerDownRight, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1.5 }), "Subtasks"] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: () => void handleOpenAddChildTaskDialog(), disabled: creatingChildTask, "aria-label": "Add subtask", "data-testid": "project-template-add-child-task-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "Subtasks must be completed before this task is done." }), childTaskTemplates.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "No subtasks yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: childTaskTemplates.map((task) => (_jsxs("li", { className: "border-border-default flex items-center justify-between gap-2 rounded-md border bg-white px-3 py-2 text-xs", "data-testid": `project-template-child-task-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Unlink subtask ${task.title}`, onClick: () => handleUnlinkChildTask(task.id), "data-testid": `project-template-unlink-child-task-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] })] })] }) })] })) }));
|
|
1822
2208
|
if (isMobile) {
|
|
1823
2209
|
return (_jsxs("div", { className: "border-border-default flex shrink-0 flex-col border-b", children: [_jsx("div", { className: "border-border-default h-[300px] shrink-0 overflow-hidden border-b", children: graphView }), taskPane] }));
|
|
1824
2210
|
}
|
|
1825
|
-
return (_jsx("div", { className: "border-border-default min-h-[360px] flex-1 overflow-hidden border-b", children: _jsx(Splitter, { direction: "
|
|
2211
|
+
return (_jsx("div", { className: "border-border-default min-h-[360px] flex-1 overflow-hidden border-b", children: _jsx(Splitter, { direction: "horizontal", localStorageKey: "settings-project-template-graph-task-splitter-v2", className: "h-full", panels: [
|
|
1826
2212
|
{
|
|
1827
2213
|
name: "project-template-graph",
|
|
1828
|
-
defaultSize: 400,
|
|
1829
|
-
className: "min-h-0",
|
|
1830
|
-
content: graphView,
|
|
1831
|
-
},
|
|
1832
|
-
{
|
|
1833
|
-
name: "project-template-task-details",
|
|
1834
2214
|
defaultSize: "auto",
|
|
1835
2215
|
className: "min-h-0",
|
|
1836
|
-
content:
|
|
2216
|
+
content: graphView,
|
|
1837
2217
|
},
|
|
2218
|
+
...(selectedTask
|
|
2219
|
+
? [
|
|
2220
|
+
{
|
|
2221
|
+
name: "project-template-task-details",
|
|
2222
|
+
defaultSize: 560,
|
|
2223
|
+
minSize: 360,
|
|
2224
|
+
className: "min-h-0",
|
|
2225
|
+
content: taskPane,
|
|
2226
|
+
},
|
|
2227
|
+
]
|
|
2228
|
+
: []),
|
|
1838
2229
|
] }) }));
|
|
1839
2230
|
};
|
|
1840
2231
|
const detailContent = (_jsxs("div", { className: "bg-neutral-grey-5/40 flex h-full flex-col", "data-testid": "project-template-detail-pane", children: [isMobile && draftTemplate && !draftTemplate.isSystem ? (_jsxs("div", { className: "border-border-default flex min-w-0 items-center gap-3 border-b bg-white px-5 py-2", "data-testid": "project-template-detail-pane-header", children: [_jsx("div", { className: "min-w-0 flex-1", children: templateSelector }), _jsx("div", { className: "flex shrink-0 items-center gap-1.5 self-center", children: _jsx(Button, { variant: "outline", size: "icon", className: "h-9 w-9 shrink-0", onClick: () => handleDeleteTemplate(), disabled: deleting, "aria-label": deleting ? "Deleting template" : "Delete template", title: deleting ? "Deleting…" : "Delete template", "data-testid": "project-template-delete-button", children: deleting ? (_jsx(RefreshCw, { className: "h-4 w-4 animate-spin", strokeWidth: 1.5 })) : (_jsx(DeleteIcon, { size: "lg" })) }) })] })) : null, draftTemplate ? ((() => {
|
|
@@ -1851,6 +2242,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1851
2242
|
content: null,
|
|
1852
2243
|
testId: "project-template-tab-task-editor",
|
|
1853
2244
|
},
|
|
2245
|
+
{
|
|
2246
|
+
id: "project-template-tab-goals",
|
|
2247
|
+
label: "Goals",
|
|
2248
|
+
content: null,
|
|
2249
|
+
testId: "project-template-tab-goals",
|
|
2250
|
+
},
|
|
1854
2251
|
];
|
|
1855
2252
|
const basicSettingsContent = (_jsxs("div", { className: "grid gap-4 overflow-y-auto p-4 md:grid-cols-2", "data-testid": "project-template-basic-settings-panel", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-name-input", children: "Template name" }), _jsx(Input, { id: "project-template-name-input", value: draftTemplate.name, onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1856
2253
|
...currentTemplate,
|
|
@@ -1869,20 +2266,81 @@ export function ProjectTemplatesPanel() {
|
|
|
1869
2266
|
})), className: "data-[state=checked]:bg-feedback-orange data-[state=checked]:shadow-inner", "aria-label": "Disable this project template", "data-testid": "project-template-disabled-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", children: "Hide from create dialog" }), _jsx("div", { className: "text-neutral-grey-50 mt-0.5 text-xs", children: "Keeps the template active, but removes it from the create project dialog." })] }), _jsx(Switch, { checked: draftTemplate.hideFromCreateDialog === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1870
2267
|
...currentTemplate,
|
|
1871
2268
|
hideFromCreateDialog: checked,
|
|
1872
|
-
})), "aria-label": "Hide this project template from the create dialog", "data-testid": "project-template-hide-from-create-dialog-switch" })] })
|
|
1873
|
-
...currentTemplate,
|
|
1874
|
-
openInWizardMode: checked,
|
|
1875
|
-
})), "aria-label": "Open new projects from this template in wizard mode", "data-testid": "project-template-open-in-wizard-mode-switch" })] })] }));
|
|
2269
|
+
})), "aria-label": "Hide this project template from the create dialog", "data-testid": "project-template-hide-from-create-dialog-switch" })] })] }));
|
|
1876
2270
|
const taskEditorContent = (_jsx("div", { className: "flex h-full min-h-0 flex-1 flex-col overflow-hidden", children: renderTemplateTaskEditorMain() }));
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
2271
|
+
const goalDefinitions = draftTemplate.goalTemplates ?? [];
|
|
2272
|
+
const selectedGoal = goalDefinitions.find((goal) => goal.id === selectedGoalId) ?? null;
|
|
2273
|
+
const goalsContent = (_jsx("div", { className: "flex h-full min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4", "data-testid": "project-template-goals-section", children: goalDefinitions.length === 0 ? (_jsx("div", { className: "border-border-default text-neutral-grey-50 rounded-md border border-dashed p-6 text-center text-xs", children: "No goal definitions yet. Use \u201CAdd Goal\u201D to create one \u2014 projects created from this template can pick from these goals." })) : (_jsxs("div", { className: "grid gap-3 md:grid-cols-[220px_1fr]", children: [_jsx("div", { className: "flex flex-col gap-1", children: [...goalDefinitions]
|
|
2274
|
+
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
|
|
2275
|
+
.map((goal) => (_jsxs("div", { "data-testid": `project-template-goal-row-${goal.id}`, className: cn("flex items-center justify-between gap-2 rounded-md px-3 py-2 text-xs", goal.id === selectedGoalId
|
|
2276
|
+
? "bg-neutral-grey-5"
|
|
2277
|
+
: "hover:bg-neutral-grey-5 bg-transparent"), children: [_jsxs("button", { type: "button", className: "min-w-0 flex-1 truncate text-left", onClick: () => setSelectedGoalId(goal.id), children: [goal.title || "Untitled goal", goal.disabled ? " (disabled)" : ""] }), _jsx("button", { type: "button", "aria-label": `Remove ${goal.title || "goal"}`, "data-testid": `project-template-remove-goal-${goal.id}`, className: "text-neutral-grey-50 hover:text-feedback-red shrink-0", onClick: () => removeGoalDefinitionById(goal.id), children: _jsx(Trash2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }, goal.id))) }), selectedGoal ? (_jsxs("div", { className: "border-border-default flex flex-col gap-3 rounded-md border bg-white p-4", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-title-input", children: "Title" }), _jsx(Input, { id: "project-template-goal-title-input", "data-testid": "project-template-goal-title-input", className: "text-xs md:text-xs", value: selectedGoal.title, onChange: (event) => updateSelectedGoal((goal) => ({
|
|
2278
|
+
...goal,
|
|
2279
|
+
title: event.target.value,
|
|
2280
|
+
})), placeholder: "Goal title" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-description-input", children: "Description" }), _jsx(Textarea, { id: "project-template-goal-description-input", "data-testid": "project-template-goal-description-input", className: "text-xs", rows: 3, value: selectedGoal.description ?? "", onChange: (event) => updateSelectedGoal((goal) => ({
|
|
2281
|
+
...goal,
|
|
2282
|
+
description: event.target.value,
|
|
2283
|
+
})), placeholder: "What this goal covers" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-sort-order-input", children: "Sort order" }), _jsx(Input, { id: "project-template-goal-sort-order-input", type: "number", className: "text-xs md:text-xs", value: selectedGoal.sortOrder ?? 0, onChange: (event) => updateSelectedGoal((goal) => ({
|
|
2284
|
+
...goal,
|
|
2285
|
+
sortOrder: event.target.value.trim() === ""
|
|
2286
|
+
? 0
|
|
2287
|
+
: Number(event.target.value),
|
|
2288
|
+
})) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-default-scope-input", children: "Default scope (JSON, optional)" }), _jsx(Textarea, { id: "project-template-goal-default-scope-input", className: "font-mono text-xs", rows: 2, value: selectedGoal.defaultScopeJson ?? "", onChange: (event) => updateSelectedGoal((goal) => ({
|
|
2289
|
+
...goal,
|
|
2290
|
+
defaultScopeJson: event.target.value,
|
|
2291
|
+
})), placeholder: '{"rootItemId":"...","pagesOnly":true}' })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-data-shape-input", children: "Data shape hint (optional)" }), _jsx(Input, { id: "project-template-goal-data-shape-input", className: "text-xs md:text-xs", value: selectedGoal.dataShape ?? "", onChange: (event) => updateSelectedGoal((goal) => ({
|
|
2292
|
+
...goal,
|
|
2293
|
+
dataShape: event.target.value,
|
|
2294
|
+
})), placeholder: "e.g. { recommendations: string[] }" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", children: "Disabled" }), _jsx("div", { className: "text-neutral-grey-50 mt-0.5 text-xs", children: "Keeps the definition but hides it from the runtime goal catalog." })] }), _jsx(Switch, { checked: selectedGoal.disabled === true, onCheckedChange: (checked) => updateSelectedGoal((goal) => ({
|
|
2295
|
+
...goal,
|
|
2296
|
+
disabled: checked,
|
|
2297
|
+
})), "aria-label": "Disable this goal definition", "data-testid": "project-template-goal-disabled-switch" })] })] })) : (_jsx("div", { className: "border-border-default text-neutral-grey-50 flex items-center justify-center rounded-md border border-dashed p-6 text-center text-xs", children: "Select a goal to edit its details." }))] })) }));
|
|
2298
|
+
const detailAction = activeDetailTab === "tasks" ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => void handleOpenCreateTaskDialog(), disabled: creatingTask, "data-testid": "project-template-add-task-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Add Task"] })) : activeDetailTab === "goals" ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
2299
|
+
setNewGoalTitle("");
|
|
2300
|
+
setIsCreateGoalDialogOpen(true);
|
|
2301
|
+
}, disabled: creatingGoal, "data-testid": "project-template-add-goal-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Add Goal"] })) : null;
|
|
2302
|
+
return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain md:overflow-hidden", isTaskEditorMaximized && "overflow-hidden"), children: [saveError ? (_jsx("div", { className: "flex shrink-0 flex-col pb-3 md:max-h-[50vh] md:min-h-0 md:overflow-y-auto md:overscroll-y-contain", children: _jsx("div", { className: "border-feedback-red bg-feedback-red-light text-feedback-red rounded border px-4 py-3 text-xs", children: saveError }) })) : null, _jsxs("section", { className: cn("border-border-default flex min-h-0 flex-1 flex-col rounded-lg border bg-white md:overflow-hidden", isTaskEditorMaximized &&
|
|
2303
|
+
"overflow-hidden rounded-none shadow-xl"), "data-testid": "project-template-task-editor-shell", children: [_jsxs("div", { className: "border-border-default flex h-[53px] shrink-0 items-center justify-between gap-3 border-b px-4 pt-3", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsx(SimpleTabs, { tabs: detailTabs, activeTab: activeDetailTab === "basic"
|
|
2304
|
+
? 0
|
|
2305
|
+
: activeDetailTab === "tasks"
|
|
2306
|
+
? 1
|
|
2307
|
+
: 2, setActiveTab: (index) => setActiveDetailTab(index === 0
|
|
2308
|
+
? "basic"
|
|
2309
|
+
: index === 1
|
|
2310
|
+
? "tasks"
|
|
2311
|
+
: "goals"), hideContent: true, className: "w-full translate-y-0.5 justify-start gap-6" }) }), detailAction ? (_jsx("div", { className: "mb-2 flex shrink-0 items-center", children: detailAction })) : null] }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: activeDetailTab === "basic"
|
|
1881
2312
|
? basicSettingsContent
|
|
1882
|
-
:
|
|
2313
|
+
: activeDetailTab === "tasks"
|
|
2314
|
+
? taskEditorContent
|
|
2315
|
+
: goalsContent })] })] }));
|
|
1883
2316
|
})()) : (_jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-5", children: _jsxs("div", { className: "border-border-default max-w-sm rounded-lg border border-dashed bg-white p-8 text-center", children: [_jsx(GitBranch, { className: "text-neutral-grey-50 mx-auto mb-3 h-10 w-10", strokeWidth: 1.2 }), _jsx("h3", { className: "text-neutral-grey-100 text-xs font-medium", children: "Select a project template" }), _jsx("p", { className: "text-neutral-grey-50 mt-1 text-xs", children: "Choose a template from the dropdown or create a new one to start editing." })] }) }))] }));
|
|
1884
2317
|
const overviewContent = (_jsx("div", { className: "flex h-full min-h-0 flex-col px-10 pt-0 pb-10", "data-testid": "project-template-overview", children: _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden rounded-lg bg-white", children: _jsx(ProjectTemplateSelectorList, { rootTestId: "project-template-overview-list", templates: templates, selectedTemplateId: selectedTemplateId, error: error, deleting: deleting, loading: state === "loading", onSelectTemplate: handleSelectTemplate, onDeleteTemplate: handleDeleteTemplate }) }) }));
|
|
1885
|
-
const
|
|
2318
|
+
const agentFullHeightBounds = useMemo(() => !isMobile && !isTaskEditorMaximized && settingsMainContentBounds
|
|
2319
|
+
? {
|
|
2320
|
+
top: settingsMainContentBounds.top,
|
|
2321
|
+
right: settingsMainContentBounds.left + settingsMainContentBounds.width,
|
|
2322
|
+
height: settingsMainContentBounds.height,
|
|
2323
|
+
}
|
|
2324
|
+
: undefined, [isMobile, isTaskEditorMaximized, settingsMainContentBounds]);
|
|
2325
|
+
const assistantTopToggleStyle = useMemo(() => !isMobile &&
|
|
2326
|
+
!isTaskEditorMaximized &&
|
|
2327
|
+
isAgentPanelCollapsed &&
|
|
2328
|
+
settingsMainContentBounds
|
|
2329
|
+
? {
|
|
2330
|
+
position: "fixed",
|
|
2331
|
+
top: settingsMainContentBounds.top + 8,
|
|
2332
|
+
left: settingsMainContentBounds.left +
|
|
2333
|
+
settingsMainContentBounds.width -
|
|
2334
|
+
88,
|
|
2335
|
+
zIndex: 45,
|
|
2336
|
+
}
|
|
2337
|
+
: undefined, [
|
|
2338
|
+
isAgentPanelCollapsed,
|
|
2339
|
+
isMobile,
|
|
2340
|
+
isTaskEditorMaximized,
|
|
2341
|
+
settingsMainContentBounds,
|
|
2342
|
+
]);
|
|
2343
|
+
const agentPanelContent = (_jsx(ProjectTemplateAgentPanel, { templateName: draftTemplate?.name ?? null, agentId: templateAgentId, loading: templateAgentLoading, resetting: templateAgentResetting, error: templateAgentError, initialMetadata: templateAgentInitialMetadata, fullHeightBounds: agentFullHeightBounds, onStartOver: () => void handleResetTemplateAgent(), onClose: handleHideTemplateAssistant, headerStart: isMobile ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "gap-1 px-2", onClick: handleMobileBackFromAgent, "data-testid": "project-template-mobile-back-from-agent", children: _jsx(ChevronLeft, { className: "h-5 w-5", strokeWidth: 1.5 }) })) : undefined }));
|
|
1886
2344
|
const rightPanelContent = editingAgentProfile ? (_jsx(AgentProfileEditorPanel, { agent: editingAgentProfile, onClose: handleCloseEditingAgentProfile, actions: _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void handleDuplicateAssignedAgentProfile(), disabled: !selectedAgentProfileId ||
|
|
1887
2345
|
!editContext ||
|
|
1888
2346
|
duplicatingAgentProfile ||
|
|
@@ -1899,7 +2357,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1899
2357
|
name: "project-template-agent",
|
|
1900
2358
|
defaultSize: 460,
|
|
1901
2359
|
content: rightPanelContent,
|
|
1902
|
-
className: "overflow-hidden",
|
|
2360
|
+
className: "overflow-hidden bg-white",
|
|
1903
2361
|
collapsible: true,
|
|
1904
2362
|
hidden: isMobile && mobileView !== "agent",
|
|
1905
2363
|
},
|
|
@@ -1910,7 +2368,9 @@ export function ProjectTemplatesPanel() {
|
|
|
1910
2368
|
if (!draftTemplate) {
|
|
1911
2369
|
return overviewContent;
|
|
1912
2370
|
}
|
|
1913
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn("h-full", !isTaskEditorMaximized && "px-10 pt-0 pb-
|
|
2371
|
+
return (_jsxs(_Fragment, { children: [assistantTopToggleStyle ? (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-8 w-8 rounded-md bg-white shadow-sm hover:bg-white", style: assistantTopToggleStyle, onClick: handleShowTemplateAssistant, "aria-label": "Show template assistant", title: "Show template assistant", "data-testid": "project-template-assistant-expand-button", children: _jsx(PanelRightOpen, { className: "h-5 w-5", strokeWidth: 1 }) })) : null, _jsx("div", { className: cn("h-full", !isTaskEditorMaximized && "px-10 pt-0 pb-5"), children: _jsx("div", { className: cn("h-full", isTaskEditorMaximized && "fixed overflow-hidden bg-white shadow-xl"), style: projectTemplateEditorStyle, "data-testid": "project-template-editor", onKeyDownCapture: handleProjectTemplateEditorKeyDownCapture, children: _jsx(Splitter, { panels: panels, localStorageKey: PROJECT_TEMPLATE_SPLITTER_STORAGE_KEY, direction: "horizontal", className: "h-full !overflow-visible", expandLabel: _jsx(PanelRightOpen, { className: "h-5 w-5", strokeWidth: 1 }), expandButtonLabel: "Show template assistant", expandButtonTestId: isTaskEditorMaximized
|
|
2372
|
+
? "project-template-assistant-expand-button"
|
|
2373
|
+
: undefined, expandButtonClassName: cn("border-border-default absolute right-4 z-50 h-8 w-8 rounded-md bg-white p-0 text-neutral-grey-100 shadow-sm backdrop-blur-sm hover:bg-white hover:text-neutral-grey-100 md:p-0", isTaskEditorMaximized ? "top-4" : "hidden"), forceCollapseLastPanelKey: forceCollapseLastPanelKey, forceExpandLastPanelKey: forceExpandLastPanelKey, onLastPanelCollapsedChange: setIsAgentPanelCollapsed }) }) }), _jsx(Dialog, { open: isCreateTaskDialogOpen, onOpenChange: (open) => {
|
|
1914
2374
|
setIsCreateTaskDialogOpen(open);
|
|
1915
2375
|
if (!open) {
|
|
1916
2376
|
setNewTaskDependencySourceId(null);
|
|
@@ -1928,7 +2388,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1928
2388
|
? "Creating..."
|
|
1929
2389
|
: newTaskDependencySourceId
|
|
1930
2390
|
? "Create Dependent Task"
|
|
1931
|
-
: "Create Task" })] })] }) }), _jsx(Dialog, { open:
|
|
2391
|
+
: "Create Task" })] })] }) }), _jsx(Dialog, { open: isCreateGoalDialogOpen, onOpenChange: setIsCreateGoalDialogOpen, children: _jsxs(DialogContent, { className: "max-w-md", "data-testid": "project-template-create-goal-dialog", children: [_jsx(StyledDialogTitle, { icon: _jsx(Plus, { strokeWidth: 1.5 }), title: "Add Goal Definition", subtitle: "Create the goal and save it immediately." }), _jsxs("div", { className: "grid gap-2 p-6", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-new-goal-title", children: "Goal title" }), _jsx(Input, { id: "project-template-new-goal-title", value: newGoalTitle, onChange: (event) => setNewGoalTitle(event.target.value), placeholder: "e.g. Review all pages", className: "text-xs md:text-xs", autoFocus: true, onKeyDown: (event) => {
|
|
2392
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
2393
|
+
event.preventDefault();
|
|
2394
|
+
void handleConfirmCreateGoal();
|
|
2395
|
+
}
|
|
2396
|
+
} })] }), _jsxs(DialogFooter, { className: "px-6 pt-0 pb-6", children: [_jsx(Button, { variant: "outline", onClick: () => setIsCreateGoalDialogOpen(false), disabled: creatingGoal, "data-testid": "project-template-create-goal-cancel-button", children: "Cancel" }), _jsx(Button, { onClick: () => void handleConfirmCreateGoal(), disabled: creatingGoal || !newGoalTitle.trim(), "data-testid": "project-template-create-goal-submit-button", children: creatingGoal ? "Creating..." : "Create Goal" })] })] }) }), _jsx(Dialog, { open: isAddChildTaskDialogOpen, onOpenChange: setIsAddChildTaskDialogOpen, children: _jsxs(DialogContent, { className: "max-w-md", "data-testid": "project-template-create-child-task-dialog", children: [_jsx(StyledDialogTitle, { icon: _jsx(Plus, { strokeWidth: 1.5 }), title: "Add Child Task", subtitle: "Creates a new task that depends on the current task." }), _jsxs("div", { className: "grid gap-2 p-6", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-new-child-task-title", children: "Task title" }), _jsx(Input, { id: "project-template-new-child-task-title", value: newChildTaskTitle, onChange: (event) => setNewChildTaskTitle(event.target.value), placeholder: "e.g. Review content", className: "text-xs md:text-xs", autoFocus: true, onKeyDown: (event) => {
|
|
1932
2397
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
1933
2398
|
event.preventDefault();
|
|
1934
2399
|
void handleConfirmCreateChildTask();
|