@parhelia/core 0.3.12791 → 0.3.12806
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/PlaceholderInput.js +16 -2
- package/dist/components/ui/PlaceholderInput.js.map +1 -1
- package/dist/editor/FieldHistory.js +12 -2
- package/dist/editor/FieldHistory.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/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/useAgentPromptQueueSocketHandler.d.ts +0 -2
- package/dist/editor/ai/terminal/useAgentPromptQueueSocketHandler.js +6 -5
- package/dist/editor/ai/terminal/useAgentPromptQueueSocketHandler.js.map +1 -1
- 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/useAgentRunStatusSocketHandler.js +3 -3
- package/dist/editor/ai/terminal/useAgentRunStatusSocketHandler.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentStopCommand.d.ts +0 -1
- package/dist/editor/ai/terminal/useAgentStopCommand.js +3 -5
- package/dist/editor/ai/terminal/useAgentStopCommand.js.map +1 -1
- package/dist/editor/ai/terminal/useAgentStreamPipeline.js +1 -1
- package/dist/editor/ai/terminal/useAgentStreamPipeline.js.map +1 -1
- package/dist/editor/ai/types.d.ts +1 -0
- package/dist/editor/bridge/protocol.d.ts +7 -0
- package/dist/editor/bridge/protocol.js.map +1 -1
- package/dist/editor/client/EditorShell.js +29 -5
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +14 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +14 -1
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +6 -1
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.js +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.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/page-editor-chrome/DragInsertionOverlay.js +94 -38
- package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
- package/dist/editor/page-editor-chrome/bridgeLinkValue.d.ts +10 -0
- package/dist/editor/page-editor-chrome/bridgeLinkValue.js +55 -0
- package/dist/editor/page-editor-chrome/bridgeLinkValue.js.map +1 -0
- 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-viewer/PageViewerFrame.js +29 -2
- 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/reviews/ReviewDetail.d.ts +1 -0
- package/dist/editor/reviews/ReviewDetail.js +18 -8
- package/dist/editor/reviews/ReviewDetail.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/settings/panels/ProjectTemplatesPanel.d.ts +4 -0
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +148 -6
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/settings/panels/projectTemplateDuplication.js +5 -0
- package/dist/editor/settings/panels/projectTemplateDuplication.js.map +1 -1
- 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/CopyMoveTargetSelectorDialog.js +26 -10
- package/dist/editor/ui/CopyMoveTargetSelectorDialog.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +5 -9
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/taskExecutionRecords.d.ts +1 -0
- package/dist/task-board/taskExecutionRecords.js +22 -0
- package/dist/task-board/taskExecutionRecords.js.map +1 -1
- package/dist/task-board/types.d.ts +9 -0
- 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";
|
|
@@ -91,7 +91,17 @@ function isProjectTemplateItemChange(changes, selectedTemplateId) {
|
|
|
91
91
|
function cloneTemplate(template) {
|
|
92
92
|
return normalizeProjectTemplate(JSON.parse(JSON.stringify(template)));
|
|
93
93
|
}
|
|
94
|
-
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) {
|
|
95
105
|
const rawAssigneeId = task.assigneeId?.trim() || null;
|
|
96
106
|
const rawAgentProfileId = task.agentProfileId?.trim() || null;
|
|
97
107
|
const rawParentTaskId = task.parentTaskId?.trim() || null;
|
|
@@ -108,6 +118,8 @@ function normalizeTaskTemplate(task) {
|
|
|
108
118
|
: "MultiSelect"
|
|
109
119
|
: null;
|
|
110
120
|
const assigneeType = task.assigneeType ?? (rawAgentProfileId ? "Agent" : null);
|
|
121
|
+
const todos = (task.todos ?? []).map(normalizeTaskTemplateTodo);
|
|
122
|
+
const todosManaged = task.todosManaged === true && todos.length > 0;
|
|
111
123
|
if (assigneeType === "Agent") {
|
|
112
124
|
const canonicalAgentId = rawAgentProfileId || (isValidGuid(rawAssigneeId) ? rawAssigneeId : null);
|
|
113
125
|
return {
|
|
@@ -120,6 +132,8 @@ function normalizeTaskTemplate(task) {
|
|
|
120
132
|
agentProfileId: canonicalAgentId,
|
|
121
133
|
parentTaskId: rawParentTaskId,
|
|
122
134
|
dependencyIds,
|
|
135
|
+
todos,
|
|
136
|
+
todosManaged,
|
|
123
137
|
};
|
|
124
138
|
}
|
|
125
139
|
if (assigneeType === "user" || assigneeType === "Role") {
|
|
@@ -133,6 +147,8 @@ function normalizeTaskTemplate(task) {
|
|
|
133
147
|
agentProfileId: null,
|
|
134
148
|
parentTaskId: rawParentTaskId,
|
|
135
149
|
dependencyIds,
|
|
150
|
+
todos,
|
|
151
|
+
todosManaged,
|
|
136
152
|
};
|
|
137
153
|
}
|
|
138
154
|
return {
|
|
@@ -145,6 +161,8 @@ function normalizeTaskTemplate(task) {
|
|
|
145
161
|
agentProfileId: null,
|
|
146
162
|
parentTaskId: rawParentTaskId,
|
|
147
163
|
dependencyIds,
|
|
164
|
+
todos,
|
|
165
|
+
todosManaged,
|
|
148
166
|
};
|
|
149
167
|
}
|
|
150
168
|
function normalizeGraphOrientation(orientation) {
|
|
@@ -196,6 +214,17 @@ function createEmptyTaskTemplate(taskCount, title) {
|
|
|
196
214
|
sortOrder: taskCount * 100,
|
|
197
215
|
parentTaskId: null,
|
|
198
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,
|
|
199
228
|
};
|
|
200
229
|
}
|
|
201
230
|
function createEmptyGoalDefinition(goalCount, title) {
|
|
@@ -212,7 +241,7 @@ function createEmptyGoalDefinition(goalCount, title) {
|
|
|
212
241
|
function sortTemplates(templates) {
|
|
213
242
|
return [...templates].sort((left, right) => left.name.localeCompare(right.name, undefined, { sensitivity: "base" }));
|
|
214
243
|
}
|
|
215
|
-
function buildUpsertTemplateRequest(template) {
|
|
244
|
+
export function buildUpsertTemplateRequest(template) {
|
|
216
245
|
return {
|
|
217
246
|
projectTemplateId: template.id,
|
|
218
247
|
name: template.name.trim(),
|
|
@@ -249,6 +278,15 @@ function buildUpsertTemplateRequest(template) {
|
|
|
249
278
|
assigneeType: normalizedTask.assigneeType || null,
|
|
250
279
|
assigneeId: normalizedTask.assigneeId || null,
|
|
251
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
|
+
})),
|
|
252
290
|
};
|
|
253
291
|
}),
|
|
254
292
|
goalTemplates: (template.goalTemplates ?? []).map((goal, index) => ({
|
|
@@ -262,7 +300,7 @@ function buildUpsertTemplateRequest(template) {
|
|
|
262
300
|
})),
|
|
263
301
|
};
|
|
264
302
|
}
|
|
265
|
-
function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
303
|
+
export function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
266
304
|
const requestedTaskById = new Map((request.taskTemplates ?? []).map((task) => [task.id, task]));
|
|
267
305
|
const requestedGoalById = new Map((request.goalTemplates ?? []).map((goal) => [goal.id, goal]));
|
|
268
306
|
// Server re-reads goals after BeginEdit/EndEdit; if a just-written goal is
|
|
@@ -310,6 +348,9 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
|
310
348
|
dependencyIds: serverDeps.length === 0 && requestedDeps.length > 0
|
|
311
349
|
? Array.from(new Set(requestedDeps))
|
|
312
350
|
: serverDeps,
|
|
351
|
+
todos: requested?.todos ?? task.todos ?? [],
|
|
352
|
+
todosManaged: (requested?.todos?.length ?? task.todos?.length ?? 0) > 0 &&
|
|
353
|
+
(requested?.todosManaged ?? task.todosManaged) === true,
|
|
313
354
|
};
|
|
314
355
|
}),
|
|
315
356
|
});
|
|
@@ -530,6 +571,7 @@ export function ProjectTemplatesPanel() {
|
|
|
530
571
|
const [templates, setTemplates] = useState([]);
|
|
531
572
|
const [error, setError] = useState(null);
|
|
532
573
|
const [selectedTemplateId, setSelectedTemplateId] = useState(null);
|
|
574
|
+
const [persistedTemplateId, setPersistedTemplateId] = useState(null);
|
|
533
575
|
const [draftTemplate, setDraftTemplate] = useState(null);
|
|
534
576
|
const [selectedTaskId, setSelectedTaskId] = useState(null);
|
|
535
577
|
const [saving, setSaving] = useState(false);
|
|
@@ -834,6 +876,7 @@ export function ProjectTemplatesPanel() {
|
|
|
834
876
|
selectedTemplateIdRef.current = template?.id ?? null;
|
|
835
877
|
draftTemplateRef.current = clonedTemplate;
|
|
836
878
|
setSelectedTemplateId(template?.id ?? null);
|
|
879
|
+
setPersistedTemplateId(template?.id ?? null);
|
|
837
880
|
setDraftTemplate(clonedTemplate);
|
|
838
881
|
setEditingAgentProfile(null);
|
|
839
882
|
setSelectedTaskId(getSelectedTaskIdForTemplate(clonedTemplate, preferredTaskId));
|
|
@@ -960,6 +1003,16 @@ export function ProjectTemplatesPanel() {
|
|
|
960
1003
|
}
|
|
961
1004
|
return byId;
|
|
962
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]);
|
|
963
1016
|
const selectedTask = useMemo(() => draftTemplate?.taskTemplates.find((task) => task.id === selectedTaskId) ??
|
|
964
1017
|
null, [draftTemplate, selectedTaskId]);
|
|
965
1018
|
const templateAgentInitialMetadata = useMemo(() => draftTemplate
|
|
@@ -1059,6 +1112,16 @@ export function ProjectTemplatesPanel() {
|
|
|
1059
1112
|
setTemplateAgentError(null);
|
|
1060
1113
|
return;
|
|
1061
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
|
+
}
|
|
1062
1125
|
setTemplateAgentId(null);
|
|
1063
1126
|
setTemplateAgentLoading(true);
|
|
1064
1127
|
setTemplateAgentError(null);
|
|
@@ -1082,7 +1145,12 @@ export function ProjectTemplatesPanel() {
|
|
|
1082
1145
|
? loadError.message
|
|
1083
1146
|
: "Failed to load project template assistant");
|
|
1084
1147
|
});
|
|
1085
|
-
}, [
|
|
1148
|
+
}, [
|
|
1149
|
+
draftTemplate?.id,
|
|
1150
|
+
persistedTemplateId,
|
|
1151
|
+
selectedTemplateId,
|
|
1152
|
+
syncProjectTemplateAgentContext,
|
|
1153
|
+
]);
|
|
1086
1154
|
useEffect(() => {
|
|
1087
1155
|
if (!templateAgentId || templateAgentLoading)
|
|
1088
1156
|
return;
|
|
@@ -1122,6 +1190,59 @@ export function ProjectTemplatesPanel() {
|
|
|
1122
1190
|
taskTemplates: currentTemplate.taskTemplates.map((task) => task.id === selectedTaskId ? updater({ ...task }) : task),
|
|
1123
1191
|
}));
|
|
1124
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]);
|
|
1125
1246
|
const updateSelectedGoal = useCallback((updater) => {
|
|
1126
1247
|
if (!selectedGoalId)
|
|
1127
1248
|
return;
|
|
@@ -1245,6 +1366,9 @@ export function ProjectTemplatesPanel() {
|
|
|
1245
1366
|
}
|
|
1246
1367
|
const savedTemplate = mergeTemplateResponseWithRequest(result.data, request);
|
|
1247
1368
|
lastPersistedSignatureRef.current = signature;
|
|
1369
|
+
if (selectedTemplateIdRef.current === savedTemplate.id) {
|
|
1370
|
+
setPersistedTemplateId(savedTemplate.id);
|
|
1371
|
+
}
|
|
1248
1372
|
setTemplates((existingTemplates) => sortTemplates([
|
|
1249
1373
|
...existingTemplates.filter((template) => template.id !== savedTemplate.id),
|
|
1250
1374
|
savedTemplate,
|
|
@@ -1511,6 +1635,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1511
1635
|
latestDraftSignatureRef.current = signature;
|
|
1512
1636
|
setTemplates((current) => sortTemplates([nextTemplate, ...current]));
|
|
1513
1637
|
setSelectedTemplateId(nextTemplate.id);
|
|
1638
|
+
setPersistedTemplateId(null);
|
|
1514
1639
|
setDraftTemplate(cloneTemplate(nextTemplate));
|
|
1515
1640
|
setSelectedTaskId(null);
|
|
1516
1641
|
setSelectedGoalId(null);
|
|
@@ -1572,6 +1697,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1572
1697
|
latestDraftSignatureRef.current = signature;
|
|
1573
1698
|
setTemplates((current) => sortTemplates([nextTemplate, ...current]));
|
|
1574
1699
|
setSelectedTemplateId(nextTemplate.id);
|
|
1700
|
+
setPersistedTemplateId(null);
|
|
1575
1701
|
setDraftTemplate(cloneTemplate(nextTemplate));
|
|
1576
1702
|
setSelectedTaskId(getSelectedTaskIdForTemplate(nextTemplate, null));
|
|
1577
1703
|
setSelectedGoalId(null);
|
|
@@ -2257,7 +2383,23 @@ export function ProjectTemplatesPanel() {
|
|
|
2257
2383
|
agentProfileId: next?.assigneeType === "Agent"
|
|
2258
2384
|
? next.assigneeId
|
|
2259
2385
|
: null,
|
|
2260
|
-
})), 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
|
|
2261
2403
|
? "Add more task templates to create dependencies."
|
|
2262
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
|
|
2263
2405
|
? "border-feedback-orange bg-feedback-orange-light ring-feedback-orange ring-1"
|