@parhelia/core 0.3.12788 → 0.3.12798
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/components/ui/LanguageSelector.js +4 -1
- package/dist/components/ui/LanguageSelector.js.map +1 -1
- package/dist/components/ui/PlaceholderInput.js +16 -2
- package/dist/components/ui/PlaceholderInput.js.map +1 -1
- package/dist/components/ui/select.js +12 -1
- package/dist/components/ui/select.js.map +1 -1
- package/dist/editor/FieldHistory.js +14 -4
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/ai/InlineAiDialog.js +35 -8
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/agentTodoExtraction.d.ts +1 -0
- package/dist/editor/ai/agentTodoExtraction.js +3 -0
- package/dist/editor/ai/agentTodoExtraction.js.map +1 -1
- package/dist/editor/ai/terminal/agentSessionState.js +26 -4
- package/dist/editor/ai/terminal/agentSessionState.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentProjectProgress.d.ts +4 -3
- package/dist/editor/ai/terminal/components/AgentProjectProgress.js +34 -50
- package/dist/editor/ai/terminal/components/AgentProjectProgress.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentTerminalView.d.ts +2 -1
- package/dist/editor/ai/terminal/components/AgentTerminalView.js +2 -2
- package/dist/editor/ai/terminal/components/AgentTerminalView.js.map +1 -1
- package/dist/editor/ai/terminal/components/AgentThinkingIndicator.js +2 -1
- package/dist/editor/ai/terminal/components/AgentThinkingIndicator.js.map +1 -1
- package/dist/editor/ai/terminal/components/AiResponseMessage.js +55 -41
- package/dist/editor/ai/terminal/components/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/terminal/components/ApprovalCard.d.ts +1 -0
- package/dist/editor/ai/terminal/components/ApprovalCard.js +15 -1
- package/dist/editor/ai/terminal/components/ApprovalCard.js.map +1 -1
- package/dist/editor/ai/terminal/components/EditFieldToolCallContent.d.ts +24 -0
- package/dist/editor/ai/terminal/components/EditFieldToolCallContent.js +97 -0
- package/dist/editor/ai/terminal/components/EditFieldToolCallContent.js.map +1 -0
- package/dist/editor/ai/terminal/components/InitialThinkingSplash.js +2 -1
- package/dist/editor/ai/terminal/components/InitialThinkingSplash.js.map +1 -1
- package/dist/editor/ai/terminal/components/TodoListPanel.js +5 -3
- package/dist/editor/ai/terminal/components/TodoListPanel.js.map +1 -1
- package/dist/editor/ai/terminal/components/ToolCallDisplay.d.ts +4 -1
- package/dist/editor/ai/terminal/components/ToolCallDisplay.js +33 -5
- package/dist/editor/ai/terminal/components/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/terminal/components/ValueDiff.d.ts +15 -0
- package/dist/editor/ai/terminal/components/ValueDiff.js +21 -0
- package/dist/editor/ai/terminal/components/ValueDiff.js.map +1 -0
- package/dist/editor/ai/terminal/components/agentThinkingStyles.d.ts +1 -0
- package/dist/editor/ai/terminal/components/agentThinkingStyles.js +2 -0
- package/dist/editor/ai/terminal/components/agentThinkingStyles.js.map +1 -0
- package/dist/editor/ai/terminal/components/toolCallContentRenderers.d.ts +15 -0
- package/dist/editor/ai/terminal/components/toolCallContentRenderers.js +12 -0
- package/dist/editor/ai/terminal/components/toolCallContentRenderers.js.map +1 -0
- package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.js +6 -1
- package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentStreamPipeline.js +1 -0
- package/dist/editor/ai/terminal/useAgentStreamPipeline.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentTerminalController.js +1 -0
- package/dist/editor/ai/terminal/useAgentTerminalController.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentTerminalViewProps.d.ts +1 -0
- package/dist/editor/ai/terminal/useAgentTerminalViewProps.js +2 -1
- package/dist/editor/ai/terminal/useAgentTerminalViewProps.js.map +1 -1
- package/dist/editor/ai/types.d.ts +1 -0
- package/dist/editor/bridge/protocol.d.ts +11 -0
- package/dist/editor/bridge/protocol.js +1 -0
- package/dist/editor/bridge/protocol.js.map +1 -1
- package/dist/editor/client/EditorShell.js +184 -68
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +13 -3
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/hooks/activeSessionSnapshots.d.ts +2 -0
- package/dist/editor/client/hooks/activeSessionSnapshots.js +43 -0
- package/dist/editor/client/hooks/activeSessionSnapshots.js.map +1 -0
- package/dist/editor/client/hooks/feedbackSocketState.js +3 -0
- package/dist/editor/client/hooks/feedbackSocketState.js.map +1 -1
- package/dist/editor/client/hooks/operationRefreshDeduplication.d.ts +22 -0
- package/dist/editor/client/hooks/operationRefreshDeduplication.js +45 -0
- package/dist/editor/client/hooks/operationRefreshDeduplication.js.map +1 -0
- package/dist/editor/client/hooks/socketMessageRetention.d.ts +7 -0
- package/dist/editor/client/hooks/socketMessageRetention.js +11 -0
- package/dist/editor/client/hooks/socketMessageRetention.js.map +1 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js +53 -19
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/hooks/useWorkbox.d.ts +4 -0
- package/dist/editor/client/hooks/useWorkbox.js +132 -2
- package/dist/editor/client/hooks/useWorkbox.js.map +1 -1
- package/dist/editor/client/itemsRepository.d.ts +7 -1
- package/dist/editor/client/itemsRepository.js +55 -19
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/operations.d.ts +7 -3
- package/dist/editor/client/operations.js +216 -150
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +21 -4
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/client/sidebarAvailability.d.ts +4 -0
- package/dist/editor/client/sidebarAvailability.js +15 -0
- package/dist/editor/client/sidebarAvailability.js.map +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.js +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +1 -1
- package/dist/editor/commands/itemCommands.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/field-types/RichTextEditorComponent.js +6 -1
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +2 -3
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.d.ts +6 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +91 -5
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/singleLineTextValue.d.ts +3 -0
- package/dist/editor/field-types/singleLineTextValue.js +9 -0
- package/dist/editor/field-types/singleLineTextValue.js.map +1 -0
- package/dist/editor/menubar/ItemLanguageVersion.js +1 -1
- package/dist/editor/menubar/ItemLanguageVersion.js.map +1 -1
- package/dist/editor/menubar/VersionSelector.js +18 -6
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/menubar/WorkflowButton.js +8 -3
- package/dist/editor/menubar/WorkflowButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/notifications/NotificationCenter.js +26 -7
- package/dist/editor/notifications/NotificationCenter.js.map +1 -1
- package/dist/editor/notifications/useNotifications.d.ts +3 -1
- package/dist/editor/notifications/useNotifications.js +27 -9
- package/dist/editor/notifications/useNotifications.js.map +1 -1
- package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js +18 -0
- package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +54 -19
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineFieldHistoryButton.js +30 -8
- package/dist/editor/page-editor-chrome/InlineFieldHistoryButton.js.map +1 -1
- package/dist/editor/page-editor-chrome/VersionDiffHighlightings.js +30 -8
- package/dist/editor/page-editor-chrome/VersionDiffHighlightings.js.map +1 -1
- package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.d.ts +4 -0
- package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.js.map +1 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +23 -1
- package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.d.ts +5 -3
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js +111 -19
- package/dist/editor/page-editor-chrome/useBridgeInlineEditing.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.d.ts +2 -1
- package/dist/editor/page-viewer/EditorForm.js +41 -12
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.d.ts +2 -0
- package/dist/editor/page-viewer/PageViewer.js +11 -2
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +266 -44
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/bridgeFieldPatch.js +1 -0
- package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
- package/dist/editor/page-viewer/bridgeInlineAiSelection.d.ts +17 -0
- package/dist/editor/page-viewer/bridgeInlineAiSelection.js +80 -0
- package/dist/editor/page-viewer/bridgeInlineAiSelection.js.map +1 -0
- package/dist/editor/page-viewer/bridgeInlineEditCommit.d.ts +18 -0
- package/dist/editor/page-viewer/bridgeInlineEditCommit.js +24 -0
- package/dist/editor/page-viewer/bridgeInlineEditCommit.js.map +1 -0
- package/dist/editor/page-viewer/bridgeInlineEditSession.d.ts +3 -0
- package/dist/editor/page-viewer/bridgeInlineEditSession.js +30 -0
- package/dist/editor/page-viewer/bridgeInlineEditSession.js.map +1 -1
- package/dist/editor/page-viewer/bridgeItemChangeTarget.d.ts +9 -0
- package/dist/editor/page-viewer/bridgeItemChangeTarget.js +38 -0
- package/dist/editor/page-viewer/bridgeItemChangeTarget.js.map +1 -0
- package/dist/editor/page-viewer/bridgePointerDragRelease.d.ts +31 -0
- package/dist/editor/page-viewer/bridgePointerDragRelease.js +32 -0
- package/dist/editor/page-viewer/bridgePointerDragRelease.js.map +1 -0
- package/dist/editor/page-viewer/renderUrl.d.ts +8 -0
- package/dist/editor/page-viewer/renderUrl.js +10 -0
- package/dist/editor/page-viewer/renderUrl.js.map +1 -1
- package/dist/editor/personalization/PersonalizationPanel.js +52 -25
- package/dist/editor/personalization/PersonalizationPanel.js.map +1 -1
- package/dist/editor/reviews/Comment.js +3 -1
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.js +2 -0
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/Comments.js +16 -3
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/SuggestedEdit.js +25 -2
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
- package/dist/editor/reviews/SuggestionCommentThread.js +2 -0
- package/dist/editor/reviews/SuggestionCommentThread.js.map +1 -1
- package/dist/editor/reviews/applySuggestedEditActions.js +105 -25
- package/dist/editor/reviews/applySuggestedEditActions.js.map +1 -1
- package/dist/editor/reviews/commentState.d.ts +4 -0
- package/dist/editor/reviews/commentState.js +15 -0
- package/dist/editor/reviews/commentState.js.map +1 -0
- package/dist/editor/reviews/feedbackOrdering.d.ts +1 -0
- package/dist/editor/reviews/feedbackOrdering.js +6 -0
- package/dist/editor/reviews/feedbackOrdering.js.map +1 -1
- package/dist/editor/reviews/suggestionContentChange.d.ts +7 -0
- package/dist/editor/reviews/suggestionContentChange.js +10 -0
- package/dist/editor/reviews/suggestionContentChange.js.map +1 -1
- package/dist/editor/reviews/suggestionPatch.js +6 -0
- package/dist/editor/reviews/suggestionPatch.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +6 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/personalizationService.js +30 -6
- package/dist/editor/services/personalizationService.js.map +1 -1
- package/dist/editor/services/suggestedEditsService.d.ts +1 -0
- package/dist/editor/services/suggestedEditsService.js +3 -0
- package/dist/editor/services/suggestedEditsService.js.map +1 -1
- package/dist/editor/settings/SettingsView.js +15 -7
- package/dist/editor/settings/SettingsView.js.map +1 -1
- package/dist/editor/settings/panels/MemoriesPanel.js +3 -2
- package/dist/editor/settings/panels/MemoriesPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplatesPanel.d.ts +7 -0
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +232 -21
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/settings/panels/projectTemplateDuplication.d.ts +5 -0
- package/dist/editor/settings/panels/projectTemplateDuplication.js +57 -0
- package/dist/editor/settings/panels/projectTemplateDuplication.js.map +1 -0
- package/dist/editor/setup-wizard/steps/CreateSettingsStep.js +9 -4
- package/dist/editor/setup-wizard/steps/CreateSettingsStep.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +1 -1
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/ui/PerfectTree.js +2 -2
- package/dist/editor/ui/PerfectTree.js.map +1 -1
- package/dist/editor/ui/PublishRestrictionsDialog.js +9 -1
- package/dist/editor/ui/PublishRestrictionsDialog.js.map +1 -1
- package/dist/editor/utils.js +5 -2
- package/dist/editor/utils.js.map +1 -1
- package/dist/editor/views/EditorSlot.js +5 -1
- package/dist/editor/views/EditorSlot.js.map +1 -1
- package/dist/editor/views/SingleEditView.d.ts +4 -1
- package/dist/editor/views/SingleEditView.js +2 -2
- package/dist/editor/views/SingleEditView.js.map +1 -1
- package/dist/licensing/LicenseContext.js +7 -0
- package/dist/licensing/LicenseContext.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +10 -10
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/taskExecutionRecords.d.ts +1 -0
- package/dist/task-board/taskExecutionRecords.js +29 -0
- package/dist/task-board/taskExecutionRecords.js.map +1 -1
- package/dist/task-board/types.d.ts +9 -0
- package/dist/task-board/views/DependencyGraphView.d.ts +1 -0
- package/dist/task-board/views/DependencyGraphView.js +15 -12
- package/dist/task-board/views/DependencyGraphView.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, Link2, PanelRightOpen, Plus, RefreshCw, Settings2, Shield, Trash2, X, } from "lucide-react";
|
|
2
|
+
import { ArrowDown, ArrowUp, ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, ListChecks, 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";
|
|
@@ -32,6 +32,7 @@ import { isTypingEventTarget } from "../../utils/keyboardNavigation";
|
|
|
32
32
|
import { useRequiredSettingsBreadcrumbItems, useRequiredSettingsHeaderActions, useRequiredSettingsMainContentRef, } from "../SettingsHeaderActionsContext";
|
|
33
33
|
import { AgentProfileEditorPanel, } from "./AgentProfileEditorPanel";
|
|
34
34
|
import { ProjectTemplateAgentPanel } from "./ProjectTemplateAgentPanel";
|
|
35
|
+
import { duplicateProjectTemplate, getDuplicateProjectTemplateName, } from "./projectTemplateDuplication";
|
|
35
36
|
import { ProjectTemplateSelector } from "./ProjectTemplateSelector";
|
|
36
37
|
import { ProjectTemplateSelectorList } from "./ProjectTemplateSelectorList";
|
|
37
38
|
// Query param for deep-linking the selected project template (settings reload).
|
|
@@ -90,7 +91,17 @@ function isProjectTemplateItemChange(changes, selectedTemplateId) {
|
|
|
90
91
|
function cloneTemplate(template) {
|
|
91
92
|
return normalizeProjectTemplate(JSON.parse(JSON.stringify(template)));
|
|
92
93
|
}
|
|
93
|
-
function
|
|
94
|
+
function normalizeTaskTemplateTodo(todo, index) {
|
|
95
|
+
return {
|
|
96
|
+
...todo,
|
|
97
|
+
id: todo.id?.trim() || crypto.randomUUID(),
|
|
98
|
+
title: todo.title ?? "",
|
|
99
|
+
instructions: todo.instructions ?? "",
|
|
100
|
+
agentProfileId: todo.agentProfileId?.trim() || null,
|
|
101
|
+
sortOrder: Number.isFinite(todo.sortOrder) ? todo.sortOrder : index * 100,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function normalizeTaskTemplate(task) {
|
|
94
105
|
const rawAssigneeId = task.assigneeId?.trim() || null;
|
|
95
106
|
const rawAgentProfileId = task.agentProfileId?.trim() || null;
|
|
96
107
|
const rawParentTaskId = task.parentTaskId?.trim() || null;
|
|
@@ -107,6 +118,8 @@ function normalizeTaskTemplate(task) {
|
|
|
107
118
|
: "MultiSelect"
|
|
108
119
|
: null;
|
|
109
120
|
const assigneeType = task.assigneeType ?? (rawAgentProfileId ? "Agent" : null);
|
|
121
|
+
const todos = (task.todos ?? []).map(normalizeTaskTemplateTodo);
|
|
122
|
+
const todosManaged = task.todosManaged === true && todos.length > 0;
|
|
110
123
|
if (assigneeType === "Agent") {
|
|
111
124
|
const canonicalAgentId = rawAgentProfileId || (isValidGuid(rawAssigneeId) ? rawAssigneeId : null);
|
|
112
125
|
return {
|
|
@@ -119,6 +132,8 @@ function normalizeTaskTemplate(task) {
|
|
|
119
132
|
agentProfileId: canonicalAgentId,
|
|
120
133
|
parentTaskId: rawParentTaskId,
|
|
121
134
|
dependencyIds,
|
|
135
|
+
todos,
|
|
136
|
+
todosManaged,
|
|
122
137
|
};
|
|
123
138
|
}
|
|
124
139
|
if (assigneeType === "user" || assigneeType === "Role") {
|
|
@@ -132,6 +147,8 @@ function normalizeTaskTemplate(task) {
|
|
|
132
147
|
agentProfileId: null,
|
|
133
148
|
parentTaskId: rawParentTaskId,
|
|
134
149
|
dependencyIds,
|
|
150
|
+
todos,
|
|
151
|
+
todosManaged,
|
|
135
152
|
};
|
|
136
153
|
}
|
|
137
154
|
return {
|
|
@@ -144,6 +161,8 @@ function normalizeTaskTemplate(task) {
|
|
|
144
161
|
agentProfileId: null,
|
|
145
162
|
parentTaskId: rawParentTaskId,
|
|
146
163
|
dependencyIds,
|
|
164
|
+
todos,
|
|
165
|
+
todosManaged,
|
|
147
166
|
};
|
|
148
167
|
}
|
|
149
168
|
function normalizeGraphOrientation(orientation) {
|
|
@@ -195,6 +214,17 @@ function createEmptyTaskTemplate(taskCount, title) {
|
|
|
195
214
|
sortOrder: taskCount * 100,
|
|
196
215
|
parentTaskId: null,
|
|
197
216
|
dependencyIds: [],
|
|
217
|
+
todos: [],
|
|
218
|
+
todosManaged: false,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function createEmptyTaskTemplateTodo(todoCount) {
|
|
222
|
+
return {
|
|
223
|
+
id: crypto.randomUUID(),
|
|
224
|
+
title: `Todo ${todoCount + 1}`,
|
|
225
|
+
instructions: "",
|
|
226
|
+
agentProfileId: null,
|
|
227
|
+
sortOrder: todoCount * 100,
|
|
198
228
|
};
|
|
199
229
|
}
|
|
200
230
|
function createEmptyGoalDefinition(goalCount, title) {
|
|
@@ -211,7 +241,7 @@ function createEmptyGoalDefinition(goalCount, title) {
|
|
|
211
241
|
function sortTemplates(templates) {
|
|
212
242
|
return [...templates].sort((left, right) => left.name.localeCompare(right.name, undefined, { sensitivity: "base" }));
|
|
213
243
|
}
|
|
214
|
-
function buildUpsertTemplateRequest(template) {
|
|
244
|
+
export function buildUpsertTemplateRequest(template) {
|
|
215
245
|
return {
|
|
216
246
|
projectTemplateId: template.id,
|
|
217
247
|
name: template.name.trim(),
|
|
@@ -248,6 +278,15 @@ function buildUpsertTemplateRequest(template) {
|
|
|
248
278
|
assigneeType: normalizedTask.assigneeType || null,
|
|
249
279
|
assigneeId: normalizedTask.assigneeId || null,
|
|
250
280
|
dependencyIds: Array.from(new Set(normalizedTask.dependencyIds || [])),
|
|
281
|
+
todosManaged: normalizedTask.todosManaged === true &&
|
|
282
|
+
(normalizedTask.todos?.length ?? 0) > 0,
|
|
283
|
+
todos: (normalizedTask.todos ?? []).map((todo, todoIndex) => ({
|
|
284
|
+
id: todo.id,
|
|
285
|
+
title: todo.title.trim(),
|
|
286
|
+
instructions: todo.instructions?.trim() || null,
|
|
287
|
+
agentProfileId: todo.agentProfileId || null,
|
|
288
|
+
sortOrder: todoIndex * 100,
|
|
289
|
+
})),
|
|
251
290
|
};
|
|
252
291
|
}),
|
|
253
292
|
goalTemplates: (template.goalTemplates ?? []).map((goal, index) => ({
|
|
@@ -261,7 +300,7 @@ function buildUpsertTemplateRequest(template) {
|
|
|
261
300
|
})),
|
|
262
301
|
};
|
|
263
302
|
}
|
|
264
|
-
function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
303
|
+
export function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
265
304
|
const requestedTaskById = new Map((request.taskTemplates ?? []).map((task) => [task.id, task]));
|
|
266
305
|
const requestedGoalById = new Map((request.goalTemplates ?? []).map((goal) => [goal.id, goal]));
|
|
267
306
|
// Server re-reads goals after BeginEdit/EndEdit; if a just-written goal is
|
|
@@ -309,6 +348,9 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
|
309
348
|
dependencyIds: serverDeps.length === 0 && requestedDeps.length > 0
|
|
310
349
|
? Array.from(new Set(requestedDeps))
|
|
311
350
|
: serverDeps,
|
|
351
|
+
todos: requested?.todos ?? task.todos ?? [],
|
|
352
|
+
todosManaged: (requested?.todos?.length ?? task.todos?.length ?? 0) > 0 &&
|
|
353
|
+
(requested?.todosManaged ?? task.todosManaged) === true,
|
|
312
354
|
};
|
|
313
355
|
}),
|
|
314
356
|
});
|
|
@@ -372,19 +414,15 @@ function isValidGuid(value) {
|
|
|
372
414
|
return (!!value &&
|
|
373
415
|
/^[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));
|
|
374
416
|
}
|
|
375
|
-
function readProjectTemplateIdFromUrl(searchParams) {
|
|
376
|
-
const raw = searchParams.get(SELECTED_PROJECT_TEMPLATE_QUERY_PARAM) ||
|
|
377
|
-
(typeof window !== "undefined"
|
|
378
|
-
? new URLSearchParams(window.location.search).get(SELECTED_PROJECT_TEMPLATE_QUERY_PARAM)
|
|
379
|
-
: null);
|
|
380
|
-
return raw && isValidGuid(raw) ? raw : null;
|
|
381
|
-
}
|
|
382
|
-
function readProjectTemplateIdFromWindow() {
|
|
417
|
+
export function readProjectTemplateIdFromUrl(searchParams) {
|
|
383
418
|
const raw = typeof window !== "undefined"
|
|
384
419
|
? new URLSearchParams(window.location.search).get(SELECTED_PROJECT_TEMPLATE_QUERY_PARAM)
|
|
385
|
-
:
|
|
420
|
+
: searchParams.get(SELECTED_PROJECT_TEMPLATE_QUERY_PARAM);
|
|
386
421
|
return raw && isValidGuid(raw) ? raw : null;
|
|
387
422
|
}
|
|
423
|
+
function readProjectTemplateIdFromWindow() {
|
|
424
|
+
return readProjectTemplateIdFromUrl(new URLSearchParams());
|
|
425
|
+
}
|
|
388
426
|
function getSelectedTaskIdForTemplate(template, preferredTaskId) {
|
|
389
427
|
const taskTemplates = template?.taskTemplates ?? [];
|
|
390
428
|
if (!taskTemplates.length) {
|
|
@@ -533,6 +571,7 @@ export function ProjectTemplatesPanel() {
|
|
|
533
571
|
const [templates, setTemplates] = useState([]);
|
|
534
572
|
const [error, setError] = useState(null);
|
|
535
573
|
const [selectedTemplateId, setSelectedTemplateId] = useState(null);
|
|
574
|
+
const [persistedTemplateId, setPersistedTemplateId] = useState(null);
|
|
536
575
|
const [draftTemplate, setDraftTemplate] = useState(null);
|
|
537
576
|
const [selectedTaskId, setSelectedTaskId] = useState(null);
|
|
538
577
|
const [saving, setSaving] = useState(false);
|
|
@@ -837,6 +876,7 @@ export function ProjectTemplatesPanel() {
|
|
|
837
876
|
selectedTemplateIdRef.current = template?.id ?? null;
|
|
838
877
|
draftTemplateRef.current = clonedTemplate;
|
|
839
878
|
setSelectedTemplateId(template?.id ?? null);
|
|
879
|
+
setPersistedTemplateId(template?.id ?? null);
|
|
840
880
|
setDraftTemplate(clonedTemplate);
|
|
841
881
|
setEditingAgentProfile(null);
|
|
842
882
|
setSelectedTaskId(getSelectedTaskIdForTemplate(clonedTemplate, preferredTaskId));
|
|
@@ -963,6 +1003,16 @@ export function ProjectTemplatesPanel() {
|
|
|
963
1003
|
}
|
|
964
1004
|
return byId;
|
|
965
1005
|
}, [aiProfiles]);
|
|
1006
|
+
const taskTodoProfileOptions = useMemo(() => [
|
|
1007
|
+
{ value: "__task_agent__", label: "Use task agent profile" },
|
|
1008
|
+
...aiProfiles
|
|
1009
|
+
.filter((profile) => !!profile.id)
|
|
1010
|
+
.map((profile) => ({
|
|
1011
|
+
value: profile.id,
|
|
1012
|
+
label: profile.displayTitle || profile.name || profile.id,
|
|
1013
|
+
}))
|
|
1014
|
+
.sort((left, right) => left.label.localeCompare(right.label)),
|
|
1015
|
+
], [aiProfiles]);
|
|
966
1016
|
const selectedTask = useMemo(() => draftTemplate?.taskTemplates.find((task) => task.id === selectedTaskId) ??
|
|
967
1017
|
null, [draftTemplate, selectedTaskId]);
|
|
968
1018
|
const templateAgentInitialMetadata = useMemo(() => draftTemplate
|
|
@@ -1062,6 +1112,16 @@ export function ProjectTemplatesPanel() {
|
|
|
1062
1112
|
setTemplateAgentError(null);
|
|
1063
1113
|
return;
|
|
1064
1114
|
}
|
|
1115
|
+
// New and duplicated templates are shown optimistically before their first
|
|
1116
|
+
// save has reached Sitecore. Resolving the assistant during that window
|
|
1117
|
+
// races the upsert and produces a transient "Project template not found"
|
|
1118
|
+
// response. Wait until persistTemplate confirms this ID exists remotely.
|
|
1119
|
+
if (persistedTemplateId !== selectedTemplateId) {
|
|
1120
|
+
setTemplateAgentId(null);
|
|
1121
|
+
setTemplateAgentLoading(true);
|
|
1122
|
+
setTemplateAgentError(null);
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1065
1125
|
setTemplateAgentId(null);
|
|
1066
1126
|
setTemplateAgentLoading(true);
|
|
1067
1127
|
setTemplateAgentError(null);
|
|
@@ -1085,7 +1145,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1085
1145
|
? loadError.message
|
|
1086
1146
|
: "Failed to load project template assistant");
|
|
1087
1147
|
});
|
|
1088
|
-
}, [
|
|
1148
|
+
}, [
|
|
1149
|
+
draftTemplate?.id,
|
|
1150
|
+
persistedTemplateId,
|
|
1151
|
+
selectedTemplateId,
|
|
1152
|
+
syncProjectTemplateAgentContext,
|
|
1153
|
+
]);
|
|
1089
1154
|
useEffect(() => {
|
|
1090
1155
|
if (!templateAgentId || templateAgentLoading)
|
|
1091
1156
|
return;
|
|
@@ -1125,6 +1190,59 @@ export function ProjectTemplatesPanel() {
|
|
|
1125
1190
|
taskTemplates: currentTemplate.taskTemplates.map((task) => task.id === selectedTaskId ? updater({ ...task }) : task),
|
|
1126
1191
|
}));
|
|
1127
1192
|
}, [applyDraftChange, selectedTaskId]);
|
|
1193
|
+
const handleAddTaskTodo = useCallback(() => {
|
|
1194
|
+
updateSelectedTask((currentTask) => ({
|
|
1195
|
+
...currentTask,
|
|
1196
|
+
todos: [
|
|
1197
|
+
...(currentTask.todos ?? []),
|
|
1198
|
+
createEmptyTaskTemplateTodo(currentTask.todos?.length ?? 0),
|
|
1199
|
+
],
|
|
1200
|
+
}));
|
|
1201
|
+
}, [updateSelectedTask]);
|
|
1202
|
+
const handleUpdateTaskTodo = useCallback((todoId, updater) => {
|
|
1203
|
+
updateSelectedTask((currentTask) => ({
|
|
1204
|
+
...currentTask,
|
|
1205
|
+
todos: (currentTask.todos ?? []).map((todo) => todo.id === todoId ? updater({ ...todo }) : todo),
|
|
1206
|
+
}));
|
|
1207
|
+
}, [updateSelectedTask]);
|
|
1208
|
+
const handleRemoveTaskTodo = useCallback((todoId) => {
|
|
1209
|
+
updateSelectedTask((currentTask) => {
|
|
1210
|
+
const todos = (currentTask.todos ?? [])
|
|
1211
|
+
.filter((todo) => todo.id !== todoId)
|
|
1212
|
+
.map((todo, index) => ({ ...todo, sortOrder: index * 100 }));
|
|
1213
|
+
return {
|
|
1214
|
+
...currentTask,
|
|
1215
|
+
todos,
|
|
1216
|
+
todosManaged: todos.length > 0 && currentTask.todosManaged === true,
|
|
1217
|
+
};
|
|
1218
|
+
});
|
|
1219
|
+
}, [updateSelectedTask]);
|
|
1220
|
+
const handleMoveTaskTodo = useCallback((todoId, direction) => {
|
|
1221
|
+
updateSelectedTask((currentTask) => {
|
|
1222
|
+
const todos = [...(currentTask.todos ?? [])];
|
|
1223
|
+
const currentIndex = todos.findIndex((todo) => todo.id === todoId);
|
|
1224
|
+
const targetIndex = currentIndex + direction;
|
|
1225
|
+
if (currentIndex < 0 ||
|
|
1226
|
+
targetIndex < 0 ||
|
|
1227
|
+
targetIndex >= todos.length) {
|
|
1228
|
+
return currentTask;
|
|
1229
|
+
}
|
|
1230
|
+
const currentTodo = todos[currentIndex];
|
|
1231
|
+
const targetTodo = todos[targetIndex];
|
|
1232
|
+
if (currentTodo === undefined || targetTodo === undefined) {
|
|
1233
|
+
return currentTask;
|
|
1234
|
+
}
|
|
1235
|
+
todos[currentIndex] = targetTodo;
|
|
1236
|
+
todos[targetIndex] = currentTodo;
|
|
1237
|
+
return {
|
|
1238
|
+
...currentTask,
|
|
1239
|
+
todos: todos.map((todo, index) => ({
|
|
1240
|
+
...todo,
|
|
1241
|
+
sortOrder: index * 100,
|
|
1242
|
+
})),
|
|
1243
|
+
};
|
|
1244
|
+
});
|
|
1245
|
+
}, [updateSelectedTask]);
|
|
1128
1246
|
const updateSelectedGoal = useCallback((updater) => {
|
|
1129
1247
|
if (!selectedGoalId)
|
|
1130
1248
|
return;
|
|
@@ -1248,6 +1366,9 @@ export function ProjectTemplatesPanel() {
|
|
|
1248
1366
|
}
|
|
1249
1367
|
const savedTemplate = mergeTemplateResponseWithRequest(result.data, request);
|
|
1250
1368
|
lastPersistedSignatureRef.current = signature;
|
|
1369
|
+
if (selectedTemplateIdRef.current === savedTemplate.id) {
|
|
1370
|
+
setPersistedTemplateId(savedTemplate.id);
|
|
1371
|
+
}
|
|
1251
1372
|
setTemplates((existingTemplates) => sortTemplates([
|
|
1252
1373
|
...existingTemplates.filter((template) => template.id !== savedTemplate.id),
|
|
1253
1374
|
savedTemplate,
|
|
@@ -1341,13 +1462,10 @@ export function ProjectTemplatesPanel() {
|
|
|
1341
1462
|
}
|
|
1342
1463
|
setEditingAgentProfile(null);
|
|
1343
1464
|
selectTemplate(null);
|
|
1344
|
-
editContext?.updateUrl({
|
|
1345
|
-
[SELECTED_PROJECT_TEMPLATE_QUERY_PARAM]: undefined,
|
|
1346
|
-
});
|
|
1347
1465
|
if (isMobile) {
|
|
1348
1466
|
setMobileView("detail");
|
|
1349
1467
|
}
|
|
1350
|
-
}, [
|
|
1468
|
+
}, [flushPendingSave, isMobile, selectTemplate]);
|
|
1351
1469
|
useEffect(() => {
|
|
1352
1470
|
if (autosaveTimeoutRef.current !== null) {
|
|
1353
1471
|
window.clearTimeout(autosaveTimeoutRef.current);
|
|
@@ -1517,6 +1635,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1517
1635
|
latestDraftSignatureRef.current = signature;
|
|
1518
1636
|
setTemplates((current) => sortTemplates([nextTemplate, ...current]));
|
|
1519
1637
|
setSelectedTemplateId(nextTemplate.id);
|
|
1638
|
+
setPersistedTemplateId(null);
|
|
1520
1639
|
setDraftTemplate(cloneTemplate(nextTemplate));
|
|
1521
1640
|
setSelectedTaskId(null);
|
|
1522
1641
|
setSelectedGoalId(null);
|
|
@@ -1532,6 +1651,80 @@ export function ProjectTemplatesPanel() {
|
|
|
1532
1651
|
}
|
|
1533
1652
|
await persistTemplate(request, signature, { showErrorToast: true });
|
|
1534
1653
|
}, [editContext, flushPendingSave, isMobile, persistTemplate, templates]);
|
|
1654
|
+
const handleDuplicateTemplate = useCallback(async () => {
|
|
1655
|
+
const canContinue = await flushPendingSave({ showErrorToast: true });
|
|
1656
|
+
if (!canContinue) {
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
const sourceTemplate = draftTemplateRef.current ?? draftTemplate;
|
|
1660
|
+
if (!sourceTemplate) {
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
const suggestedName = getDuplicateProjectTemplateName(sourceTemplate.name, templates.map((template) => template.name));
|
|
1664
|
+
let templateName = null;
|
|
1665
|
+
if (editContext) {
|
|
1666
|
+
templateName = await editContext.openDialog(ItemNameDialog, {
|
|
1667
|
+
name: suggestedName,
|
|
1668
|
+
title: "Duplicate Project Template",
|
|
1669
|
+
message: "Enter a name for the duplicated template:",
|
|
1670
|
+
headerIcon: _jsx(CopyPlus, { strokeWidth: 1 }),
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
else {
|
|
1674
|
+
templateName = window.prompt("Enter a name for the duplicated template:", suggestedName);
|
|
1675
|
+
}
|
|
1676
|
+
if (templateName == null) {
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
const trimmedName = templateName.trim();
|
|
1680
|
+
if (!trimmedName) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
const nameLower = trimmedName.toLowerCase();
|
|
1684
|
+
if (templates.some((t) => t.name.trim().toLowerCase() === nameLower)) {
|
|
1685
|
+
toast.error("A project template with this name already exists");
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
const nextTemplate = duplicateProjectTemplate(sourceTemplate, trimmedName);
|
|
1689
|
+
const request = buildUpsertTemplateRequest(nextTemplate);
|
|
1690
|
+
const signature = JSON.stringify(request);
|
|
1691
|
+
if (autosaveTimeoutRef.current !== null) {
|
|
1692
|
+
window.clearTimeout(autosaveTimeoutRef.current);
|
|
1693
|
+
autosaveTimeoutRef.current = null;
|
|
1694
|
+
}
|
|
1695
|
+
selectedTemplateIdRef.current = nextTemplate.id;
|
|
1696
|
+
draftTemplateRef.current = nextTemplate;
|
|
1697
|
+
latestDraftSignatureRef.current = signature;
|
|
1698
|
+
setTemplates((current) => sortTemplates([nextTemplate, ...current]));
|
|
1699
|
+
setSelectedTemplateId(nextTemplate.id);
|
|
1700
|
+
setPersistedTemplateId(null);
|
|
1701
|
+
setDraftTemplate(cloneTemplate(nextTemplate));
|
|
1702
|
+
setSelectedTaskId(getSelectedTaskIdForTemplate(nextTemplate, null));
|
|
1703
|
+
setSelectedGoalId(null);
|
|
1704
|
+
setIsDirty(true);
|
|
1705
|
+
setSaveError(null);
|
|
1706
|
+
lastPersistedSignatureRef.current = null;
|
|
1707
|
+
latestDraftSignatureRef.current = null;
|
|
1708
|
+
editContext?.updateUrl({
|
|
1709
|
+
[SELECTED_PROJECT_TEMPLATE_QUERY_PARAM]: nextTemplate.id,
|
|
1710
|
+
});
|
|
1711
|
+
if (isMobile) {
|
|
1712
|
+
setMobileView("detail");
|
|
1713
|
+
}
|
|
1714
|
+
const didPersist = await persistTemplate(request, signature, {
|
|
1715
|
+
showErrorToast: true,
|
|
1716
|
+
});
|
|
1717
|
+
if (didPersist) {
|
|
1718
|
+
toast.success("Project template duplicated");
|
|
1719
|
+
}
|
|
1720
|
+
}, [
|
|
1721
|
+
draftTemplate,
|
|
1722
|
+
editContext,
|
|
1723
|
+
flushPendingSave,
|
|
1724
|
+
isMobile,
|
|
1725
|
+
persistTemplate,
|
|
1726
|
+
templates,
|
|
1727
|
+
]);
|
|
1535
1728
|
const handleDeleteTemplate = useCallback((templateToDelete) => {
|
|
1536
1729
|
const template = templateToDelete ?? draftTemplate;
|
|
1537
1730
|
if (!template || template.isSystem)
|
|
@@ -2112,17 +2305,19 @@ export function ProjectTemplatesPanel() {
|
|
|
2112
2305
|
: 0;
|
|
2113
2306
|
return (_jsxs("div", { className: "mt-2 flex items-center gap-2", style: agentPanelHeaderOffset > 0
|
|
2114
2307
|
? { 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 }), "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] }));
|
|
2308
|
+
: 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 }), "Create template"] })) : null, draftTemplate ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void handleDuplicateTemplate(), disabled: saving || deleting, "data-testid": "project-template-duplicate-button", children: [_jsx(CopyPlus, { className: "h-4 w-4", strokeWidth: 1 }), "Duplicate"] })) : 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] }));
|
|
2116
2309
|
}, [
|
|
2117
2310
|
agentPanelBounds,
|
|
2118
2311
|
deleting,
|
|
2119
2312
|
draftTemplate,
|
|
2120
2313
|
handleCreateTemplate,
|
|
2121
2314
|
handleDeleteTemplate,
|
|
2315
|
+
handleDuplicateTemplate,
|
|
2122
2316
|
headerStatusBadge,
|
|
2123
2317
|
isAgentPanelCollapsed,
|
|
2124
2318
|
isTaskEditorMaximized,
|
|
2125
2319
|
isMobile,
|
|
2320
|
+
saving,
|
|
2126
2321
|
]);
|
|
2127
2322
|
useEffect(() => {
|
|
2128
2323
|
if (!setSettingsBreadcrumbItems)
|
|
@@ -2188,7 +2383,23 @@ export function ProjectTemplatesPanel() {
|
|
|
2188
2383
|
agentProfileId: next?.assigneeType === "Agent"
|
|
2189
2384
|
? next.assigneeId
|
|
2190
2385
|
: null,
|
|
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 }), "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-
|
|
2386
|
+
})), 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 }), "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-todos-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(ListChecks, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1 }), "Todos"] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "flex items-center gap-1.5", title: (selectedTask.todos?.length ?? 0) > 0
|
|
2387
|
+
? "Deliver todo items to the agent one at a time"
|
|
2388
|
+
: "Add at least one todo to enable managed execution", children: [_jsx(Switch, { id: "project-template-todos-managed", checked: selectedTask.todosManaged === true, disabled: (selectedTask.todos?.length ?? 0) === 0, onCheckedChange: (checked) => updateSelectedTask((currentTask) => ({
|
|
2389
|
+
...currentTask,
|
|
2390
|
+
todosManaged: checked &&
|
|
2391
|
+
(currentTask.todos?.length ?? 0) > 0,
|
|
2392
|
+
})), "aria-label": "Managed todo execution", "data-testid": "project-template-todos-managed-toggle" }), _jsx(Label, { htmlFor: "project-template-todos-managed", className: "text-neutral-grey-100 text-xs", children: "Managed" })] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: handleAddTaskTodo, "aria-label": "Add todo", "data-testid": "project-template-add-todo-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1 }) })] })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "These task-specific todos override predefined todos from the assigned agent profile. Managed lists are delivered one item at a time after a brief orientation turn." }), (selectedTask.todos ?? []).length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "No todos yet. The agent profile defaults will be used." })) : (_jsx("div", { className: "space-y-2", children: (selectedTask.todos ?? []).map((todo, todoIndex) => (_jsxs("div", { className: "border-border-default space-y-2 rounded-md border bg-white p-2", "data-testid": `project-template-todo-row-${todo.id}`, children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Input, { className: "h-8 min-w-0 flex-1 text-xs md:text-xs", value: todo.title, onChange: (event) => handleUpdateTaskTodo(todo.id, (current) => ({
|
|
2393
|
+
...current,
|
|
2394
|
+
title: event.target.value,
|
|
2395
|
+
})), placeholder: "Todo title", "aria-label": `Todo ${todoIndex + 1} title`, "data-testid": "project-template-todo-title-input" }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "h-7 w-7 shrink-0", disabled: todoIndex === 0, onClick: () => handleMoveTaskTodo(todo.id, -1), "aria-label": `Move ${todo.title || "todo"} up`, "data-testid": "project-template-move-todo-up", children: _jsx(ArrowUp, { className: "h-3.5 w-3.5", strokeWidth: 1 }) }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "h-7 w-7 shrink-0", disabled: todoIndex ===
|
|
2396
|
+
(selectedTask.todos?.length ?? 0) - 1, onClick: () => handleMoveTaskTodo(todo.id, 1), "aria-label": `Move ${todo.title || "todo"} down`, "data-testid": "project-template-move-todo-down", children: _jsx(ArrowDown, { className: "h-3.5 w-3.5", strokeWidth: 1 }) }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "text-feedback-red h-7 w-7 shrink-0", onClick: () => handleRemoveTaskTodo(todo.id), "aria-label": `Remove ${todo.title || "todo"}`, "data-testid": "project-template-remove-todo-button", children: _jsx(Trash2, { className: "h-3.5 w-3.5", strokeWidth: 1 }) })] }), _jsx(Textarea, { className: "text-xs", rows: 2, value: todo.instructions ?? "", onChange: (event) => handleUpdateTaskTodo(todo.id, (current) => ({
|
|
2397
|
+
...current,
|
|
2398
|
+
instructions: event.target.value,
|
|
2399
|
+
})), placeholder: "Instructions for completing this todo", "aria-label": `Todo ${todoIndex + 1} instructions`, "data-testid": "project-template-todo-instructions-input" }), _jsx(Select, { value: todo.agentProfileId ?? "__task_agent__", onValueChange: (value) => handleUpdateTaskTodo(todo.id, (current) => ({
|
|
2400
|
+
...current,
|
|
2401
|
+
agentProfileId: value === "__task_agent__" ? null : value,
|
|
2402
|
+
})), options: taskTodoProfileOptions, searchable: true, placeholder: "Use task agent profile", "data-testid": "project-template-todo-agent-profile-select" })] }, todo.id))) }))] }), _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 }), "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 }) }) }), _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 }), _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
|
|
2192
2403
|
? "Add more task templates to create dependencies."
|
|
2193
2404
|
: "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
|
|
2194
2405
|
? "border-feedback-orange bg-feedback-orange-light ring-feedback-orange ring-1"
|
|
@@ -2228,7 +2439,7 @@ export function ProjectTemplatesPanel() {
|
|
|
2228
2439
|
: []),
|
|
2229
2440
|
] }) }));
|
|
2230
2441
|
};
|
|
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
|
|
2442
|
+
const detailContent = (_jsxs("div", { className: "bg-neutral-grey-5/40 flex h-full flex-col", "data-testid": "project-template-detail-pane", children: [isMobile && draftTemplate ? (_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 }), _jsxs("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: () => void handleDuplicateTemplate(), disabled: saving || deleting, "aria-label": "Duplicate template", title: "Duplicate template", "data-testid": "project-template-duplicate-button", children: _jsx(CopyPlus, { className: "h-4 w-4", strokeWidth: 1 }) }), !draftTemplate.isSystem ? (_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 })) : (_jsx(DeleteIcon, { size: "lg" })) })) : null] })] })) : null, draftTemplate ? ((() => {
|
|
2232
2443
|
const detailTabs = [
|
|
2233
2444
|
{
|
|
2234
2445
|
id: "project-template-tab-basic-settings",
|