@parhelia/core 0.1.12393 → 0.1.12404
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/input.d.ts +1 -1
- package/dist/components/ui/input.js +5 -3
- package/dist/components/ui/input.js.map +1 -1
- package/dist/editor/FieldHistory.js +47 -17
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/PictureCropper.js +9 -4
- package/dist/editor/PictureCropper.js.map +1 -1
- package/dist/editor/PictureEditor.js +12 -13
- package/dist/editor/PictureEditor.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +136 -23
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminalStatusBar.d.ts +5 -1
- package/dist/editor/ai/AgentTerminalStatusBar.js +182 -22
- package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
- package/dist/editor/ai/ContentInspectorPopover.js +105 -24
- package/dist/editor/ai/ContentInspectorPopover.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.d.ts +2 -1
- package/dist/editor/ai/ContextInfoBar.js +9 -6
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/agentDiagnostics.d.ts +36 -0
- package/dist/editor/ai/agentDiagnostics.js +120 -0
- package/dist/editor/ai/agentDiagnostics.js.map +1 -0
- package/dist/editor/ai/dialogs/QuestionnaireInline.d.ts +2 -1
- package/dist/editor/ai/dialogs/QuestionnaireInline.js +452 -63
- package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
- package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +27 -5
- package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
- package/dist/editor/client/EditorShell.js +8 -0
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +6 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/hooks/useEditorWebSocket.d.ts +3 -0
- package/dist/editor/client/hooks/useEditorWebSocket.js +66 -1
- package/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -1
- package/dist/editor/client/socketDiagnostics.d.ts +19 -0
- package/dist/editor/client/socketDiagnostics.js +32 -0
- package/dist/editor/client/socketDiagnostics.js.map +1 -0
- package/dist/editor/pictureRawValue.d.ts +3 -0
- package/dist/editor/pictureRawValue.js +30 -0
- package/dist/editor/pictureRawValue.js.map +1 -0
- package/dist/editor/reviews/CreateReviewDetailsStep.d.ts +1 -1
- package/dist/editor/reviews/CreateReviewDialog.js +3 -2
- package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +57 -0
- package/dist/editor/services/agentService.js +30 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +5 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/settings/panels/AgentProfileConfigPanel.js +1 -0
- package/dist/editor/settings/panels/AgentProfileConfigPanel.js.map +1 -1
- package/dist/editor/settings/panels/AgentProfileEditorPanel.d.ts +14 -0
- package/dist/editor/settings/panels/AgentProfileEditorPanel.js +7 -0
- package/dist/editor/settings/panels/AgentProfileEditorPanel.js.map +1 -0
- package/dist/editor/settings/panels/AgentsPanel.js +2 -2
- package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +132 -82
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/ui/ItemCollectionEditor.d.ts +2 -1
- package/dist/editor/ui/ItemCollectionEditor.js +70 -27
- package/dist/editor/ui/ItemCollectionEditor.js.map +1 -1
- package/dist/editor/ui/TreeListSelector.d.ts +4 -1
- package/dist/editor/ui/TreeListSelector.js +2 -2
- package/dist/editor/ui/TreeListSelector.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +11 -18
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/components/ItemCollectionEditorDialog.js +28 -17
- package/dist/task-board/components/ItemCollectionEditorDialog.js.map +1 -1
- package/dist/task-board/components/ProjectDashboard.d.ts +4 -0
- package/dist/task-board/components/ProjectDashboard.js +1 -1
- package/dist/task-board/components/ProjectDashboard.js.map +1 -1
- package/dist/task-board/components/ProjectListContent.d.ts +1 -1
- package/dist/task-board/components/ProjectListContent.js +4 -1
- package/dist/task-board/components/ProjectListContent.js.map +1 -1
- package/dist/task-board/components/ProjectOverviewContent.d.ts +17 -0
- package/dist/task-board/components/ProjectOverviewContent.js +134 -0
- package/dist/task-board/components/ProjectOverviewContent.js.map +1 -0
- package/dist/task-board/components/ProjectSelector.d.ts +1 -1
- package/dist/task-board/components/ProjectSelector.js +1 -1
- package/dist/task-board/components/ProjectSelector.js.map +1 -1
- package/dist/task-board/components/TaskAssigneePicker.d.ts +3 -2
- package/dist/task-board/components/TaskAssigneePicker.js +10 -6
- package/dist/task-board/components/TaskAssigneePicker.js.map +1 -1
- package/dist/task-board/components/TaskDetailPanel.js +59 -9
- package/dist/task-board/components/TaskDetailPanel.js.map +1 -1
- package/dist/task-board/services/taskService.d.ts +5 -1
- package/dist/task-board/services/taskService.js +11 -0
- package/dist/task-board/services/taskService.js.map +1 -1
- package/dist/task-board/taskBoardNavStore.d.ts +3 -1
- package/dist/task-board/taskBoardNavStore.js.map +1 -1
- package/dist/task-board/types.d.ts +30 -0
- package/dist/task-board/utils/taskDependencyOrdering.d.ts +3 -0
- package/dist/task-board/utils/taskDependencyOrdering.js +64 -0
- package/dist/task-board/utils/taskDependencyOrdering.js.map +1 -0
- package/dist/task-board/views/WizardView.js +5 -15
- package/dist/task-board/views/WizardView.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
|
-
import { AlertCircle, ChevronDown, CornerDownRight, GitBranch, Link2, Plus, RefreshCw, Search, Settings2, Shield, Trash2, X, } from "lucide-react";
|
|
3
|
+
import { AlertCircle, ChevronDown, CopyPlus, CornerDownRight, GitBranch, Link2, Plus, RefreshCw, Search, Settings2, Shield, Trash2, X, } from "lucide-react";
|
|
4
4
|
import { toast } from "sonner";
|
|
5
5
|
import { Button } from "../../../components/ui/button";
|
|
6
6
|
import { Dialog, DialogContent, DialogFooter, } from "../../../components/ui/dialog";
|
|
@@ -14,12 +14,15 @@ import { Badge } from "../../../components/ui/badge";
|
|
|
14
14
|
import { Popover, PopoverContent, PopoverTrigger, } from "../../../components/ui/popover";
|
|
15
15
|
import { Splitter } from "../../ui/Splitter";
|
|
16
16
|
import { DependencyGraphView } from "../../../task-board/views/DependencyGraphView";
|
|
17
|
+
import { TaskAssigneePicker } from "../../../task-board/components/TaskAssigneePicker";
|
|
17
18
|
import { deleteProjectTemplate, getProjectTemplates, getProjectTemplateAgent, resetProjectTemplateAgent, upsertProjectTemplate, } from "../../../task-board/services/taskService";
|
|
18
19
|
import { getAiProfilesErrorMessage, loadAiProfiles, } from "../../services/aiService";
|
|
19
20
|
import { updateAgentContext } from "../../services/agentService";
|
|
20
21
|
import { useEditContext } from "../../client/editContext";
|
|
22
|
+
import { ItemNameDialog, } from "../../ui/ItemNameDialogNew";
|
|
21
23
|
import { isTypingEventTarget } from "../../utils/keyboardNavigation";
|
|
22
24
|
import { cn } from "../../../lib/utils";
|
|
25
|
+
import { AgentProfileEditorPanel, } from "./AgentProfileEditorPanel";
|
|
23
26
|
import { ProjectTemplateAgentPanel } from "./ProjectTemplateAgentPanel";
|
|
24
27
|
import { useSearchParams } from "next/navigation";
|
|
25
28
|
/** Query param for deep-linking the selected project template (settings reload). */
|
|
@@ -31,12 +34,6 @@ const PRIORITY_OPTIONS = [
|
|
|
31
34
|
{ value: "High", label: "High" },
|
|
32
35
|
{ value: "Critical", label: "Critical" },
|
|
33
36
|
];
|
|
34
|
-
const ASSIGNEE_TYPE_OPTIONS = [
|
|
35
|
-
{ value: "", label: "Unassigned" },
|
|
36
|
-
{ value: "Agent", label: "Agent profile" },
|
|
37
|
-
{ value: "Human", label: "Human user" },
|
|
38
|
-
{ value: "Role", label: "Role" },
|
|
39
|
-
];
|
|
40
37
|
const PROJECT_TEMPLATE_AUTOSAVE_DEBOUNCE_MS = 1200;
|
|
41
38
|
function cloneTemplate(template) {
|
|
42
39
|
return normalizeProjectTemplate(JSON.parse(JSON.stringify(template)));
|
|
@@ -330,6 +327,8 @@ export function ProjectTemplatesPanel() {
|
|
|
330
327
|
const [templateAgentLoading, setTemplateAgentLoading] = useState(false);
|
|
331
328
|
const [templateAgentResetting, setTemplateAgentResetting] = useState(false);
|
|
332
329
|
const [templateAgentError, setTemplateAgentError] = useState(null);
|
|
330
|
+
const [duplicatingAgentProfile, setDuplicatingAgentProfile] = useState(false);
|
|
331
|
+
const [editingAgentProfile, setEditingAgentProfile] = useState(null);
|
|
333
332
|
const autosaveTimeoutRef = useRef(null);
|
|
334
333
|
const lastPersistedSignatureRef = useRef(null);
|
|
335
334
|
const latestDraftSignatureRef = useRef(null);
|
|
@@ -373,6 +372,7 @@ export function ProjectTemplatesPanel() {
|
|
|
373
372
|
draftTemplateRef.current = clonedTemplate;
|
|
374
373
|
setSelectedTemplateId(template?.id ?? null);
|
|
375
374
|
setDraftTemplate(clonedTemplate);
|
|
375
|
+
setEditingAgentProfile(null);
|
|
376
376
|
setSelectedTaskId(getSelectedTaskIdForTemplate(clonedTemplate, preferredTaskId));
|
|
377
377
|
setIsDirty(false);
|
|
378
378
|
setSaveError(null);
|
|
@@ -501,23 +501,6 @@ export function ProjectTemplatesPanel() {
|
|
|
501
501
|
return draftTemplate.taskTemplates.filter((task) => task.id !== selectedTaskId &&
|
|
502
502
|
!selectedTask.dependencyIds.includes(task.id));
|
|
503
503
|
}, [draftTemplate, selectedTaskId, selectedTask]);
|
|
504
|
-
const parentTaskSelectOptions = useMemo(() => {
|
|
505
|
-
if (!draftTemplate || !selectedTaskId) {
|
|
506
|
-
return [{ value: "", label: "None" }];
|
|
507
|
-
}
|
|
508
|
-
const others = draftTemplate.taskTemplates.filter((task) => task.id !== selectedTaskId);
|
|
509
|
-
return [
|
|
510
|
-
{ value: "", label: "None" },
|
|
511
|
-
...[...others]
|
|
512
|
-
.sort((a, b) => (a.title || "").localeCompare(b.title || "", undefined, {
|
|
513
|
-
sensitivity: "base",
|
|
514
|
-
}))
|
|
515
|
-
.map((task) => ({
|
|
516
|
-
value: task.id,
|
|
517
|
-
label: task.title?.trim() || "Untitled Task",
|
|
518
|
-
})),
|
|
519
|
-
];
|
|
520
|
-
}, [draftTemplate, selectedTaskId]);
|
|
521
504
|
const headerStatusBadge = useMemo(() => {
|
|
522
505
|
if (saveError) {
|
|
523
506
|
return (_jsx("span", { "data-testid": "project-template-save-status", "data-state": "error", className: "inline-flex min-w-[84px] justify-center rounded bg-red-100 px-1.5 py-0.5 whitespace-nowrap text-red-700", children: "Save failed" }));
|
|
@@ -529,11 +512,33 @@ export function ProjectTemplatesPanel() {
|
|
|
529
512
|
}, [isDirty, saveError, saving]);
|
|
530
513
|
const graphTasks = useMemo(() => buildTemplateTaskItems(draftTemplate, aiProfilesById), [aiProfilesById, draftTemplate]);
|
|
531
514
|
const graphDependencies = useMemo(() => buildTemplateDependencies(draftTemplate), [draftTemplate]);
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
515
|
+
const selectedAgentProfileId = selectedTask?.assigneeType === "Agent"
|
|
516
|
+
? selectedTask.assigneeId ?? selectedTask.agentProfileId ?? null
|
|
517
|
+
: null;
|
|
518
|
+
const selectedAgentProfile = useMemo(() => selectedAgentProfileId
|
|
519
|
+
? aiProfilesById[selectedAgentProfileId.toLowerCase()] ?? null
|
|
520
|
+
: null, [aiProfilesById, selectedAgentProfileId]);
|
|
521
|
+
const selectedTaskAssigneeDisplayValue = selectedTask?.assigneeType === "Agent"
|
|
522
|
+
? selectedAgentProfile?.displayTitle ||
|
|
523
|
+
selectedAgentProfile?.name ||
|
|
524
|
+
selectedTask.assigneeId ||
|
|
525
|
+
selectedTask.agentProfileId ||
|
|
526
|
+
null
|
|
527
|
+
: selectedTask?.assigneeId ?? null;
|
|
528
|
+
const handleEditAssignedAgentProfile = useCallback(() => {
|
|
529
|
+
if (!selectedAgentProfileId)
|
|
530
|
+
return;
|
|
531
|
+
setEditingAgentProfile({
|
|
532
|
+
id: selectedAgentProfileId,
|
|
533
|
+
name: selectedAgentProfile?.displayTitle ||
|
|
534
|
+
selectedAgentProfile?.name ||
|
|
535
|
+
selectedTask?.title ||
|
|
536
|
+
"Agent Profile",
|
|
537
|
+
});
|
|
538
|
+
}, [selectedAgentProfile, selectedAgentProfileId, selectedTask?.title]);
|
|
539
|
+
const handleCloseEditingAgentProfile = useCallback(() => {
|
|
540
|
+
setEditingAgentProfile(null);
|
|
541
|
+
}, []);
|
|
537
542
|
const syncProjectTemplateAgentContext = useCallback(async (agentId, template, selectedTaskTemplateId) => {
|
|
538
543
|
try {
|
|
539
544
|
await updateAgentContext(agentId, buildProjectTemplateAgentContext(template, selectedTaskTemplateId));
|
|
@@ -621,6 +626,92 @@ export function ProjectTemplatesPanel() {
|
|
|
621
626
|
taskTemplates: currentTemplate.taskTemplates.map((task) => task.id === selectedTaskId ? updater({ ...task }) : task),
|
|
622
627
|
}));
|
|
623
628
|
}, [applyDraftChange, selectedTaskId]);
|
|
629
|
+
const handleDuplicateAssignedAgentProfile = useCallback(async () => {
|
|
630
|
+
if (!editContext || !selectedAgentProfileId)
|
|
631
|
+
return;
|
|
632
|
+
try {
|
|
633
|
+
setDuplicatingAgentProfile(true);
|
|
634
|
+
const sourceDescriptor = {
|
|
635
|
+
id: selectedAgentProfileId,
|
|
636
|
+
language: editContext.item?.language ??
|
|
637
|
+
editContext.currentItemDescriptor?.language ??
|
|
638
|
+
"en",
|
|
639
|
+
version: 0,
|
|
640
|
+
};
|
|
641
|
+
const sourceItem = await editContext.itemsRepository.getItem(sourceDescriptor);
|
|
642
|
+
if (!sourceItem) {
|
|
643
|
+
toast.error("Unable to load the selected agent profile");
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
const newName = await editContext.openDialog(ItemNameDialog, {
|
|
647
|
+
name: `Copy of ${sourceItem.name}`,
|
|
648
|
+
title: "Duplicate Agent Profile",
|
|
649
|
+
message: "Enter a name for the duplicated agent profile:",
|
|
650
|
+
parentItem: { ...sourceItem.descriptor, id: sourceItem.parentId },
|
|
651
|
+
itemId: sourceItem.id,
|
|
652
|
+
});
|
|
653
|
+
if (!newName) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
const duplicatedProfile = await editContext.operations.duplicateItem(sourceItem.descriptor, {
|
|
657
|
+
id: sourceItem.parentId,
|
|
658
|
+
language: sourceItem.language,
|
|
659
|
+
version: 0,
|
|
660
|
+
}, newName);
|
|
661
|
+
if (!duplicatedProfile) {
|
|
662
|
+
toast.error("Unable to duplicate the selected agent profile");
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
try {
|
|
666
|
+
const duplicatedItem = await editContext.itemsRepository.getItem({
|
|
667
|
+
id: duplicatedProfile.id,
|
|
668
|
+
language: duplicatedProfile.language ?? sourceItem.language,
|
|
669
|
+
version: duplicatedProfile.version ?? 0,
|
|
670
|
+
});
|
|
671
|
+
const displayTitleField = duplicatedItem?.fields.find((field) => {
|
|
672
|
+
const fieldName = field.name?.trim().toLowerCase();
|
|
673
|
+
const displayName = field.displayName?.trim().toLowerCase();
|
|
674
|
+
return fieldName === "display title" || displayName === "display title";
|
|
675
|
+
});
|
|
676
|
+
if (displayTitleField) {
|
|
677
|
+
await editContext.operations.editField({
|
|
678
|
+
field: displayTitleField.descriptor,
|
|
679
|
+
rawValue: newName,
|
|
680
|
+
refresh: "immediate",
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
catch {
|
|
685
|
+
// Best-effort only; duplication itself already succeeded.
|
|
686
|
+
}
|
|
687
|
+
updateSelectedTask((currentTask) => ({
|
|
688
|
+
...currentTask,
|
|
689
|
+
assigneeType: "Agent",
|
|
690
|
+
assigneeId: duplicatedProfile.id,
|
|
691
|
+
agentProfileId: duplicatedProfile.id,
|
|
692
|
+
}));
|
|
693
|
+
setEditingAgentProfile({
|
|
694
|
+
id: duplicatedProfile.id,
|
|
695
|
+
name: duplicatedProfile.name || newName,
|
|
696
|
+
});
|
|
697
|
+
try {
|
|
698
|
+
const refreshedProfiles = await loadAiProfiles();
|
|
699
|
+
setAiProfiles(refreshedProfiles || []);
|
|
700
|
+
setProfilesError(null);
|
|
701
|
+
}
|
|
702
|
+
catch (loadError) {
|
|
703
|
+
setProfilesError(getAiProfilesErrorMessage(loadError));
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
catch (duplicateError) {
|
|
707
|
+
toast.error(duplicateError instanceof Error
|
|
708
|
+
? `Failed to duplicate agent profile: ${duplicateError.message}`
|
|
709
|
+
: "Failed to duplicate agent profile");
|
|
710
|
+
}
|
|
711
|
+
finally {
|
|
712
|
+
setDuplicatingAgentProfile(false);
|
|
713
|
+
}
|
|
714
|
+
}, [editContext, selectedAgentProfileId, updateSelectedTask]);
|
|
624
715
|
const currentSaveRequest = useMemo(() => {
|
|
625
716
|
if (!draftTemplate || !draftTemplate.name.trim()) {
|
|
626
717
|
return null;
|
|
@@ -1224,65 +1315,20 @@ export function ProjectTemplatesPanel() {
|
|
|
1224
1315
|
content: (_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: "rounded-lg border border-dashed border-gray-200 bg-gray-50 p-6 text-center text-xs text-gray-500", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "shrink-0 border-b border-gray-100 bg-white px-4 pb-3 pt-4", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xs font-semibold text-gray-900", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), _jsx("div", { className: "text-xs text-gray-500", children: "Configure task details, assignment, and dependencies." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleDeleteSelectedTask, "data-testid": "project-template-remove-task-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), "Remove Task"] })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-4 pb-4 pt-3", 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", children: "Task title" }), _jsx(Input, { value: selectedTask.title, onChange: (event) => updateSelectedTask((currentTask) => ({
|
|
1225
1316
|
...currentTask,
|
|
1226
1317
|
title: event.target.value,
|
|
1227
|
-
})), 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: "
|
|
1228
|
-
const newParentId = value.trim() || null;
|
|
1229
|
-
updateSelectedTask((currentTask) => {
|
|
1230
|
-
const oldParent = currentTask.parentTaskId ?? null;
|
|
1231
|
-
let deps = [
|
|
1232
|
-
...(currentTask.dependencyIds ?? []),
|
|
1233
|
-
];
|
|
1234
|
-
if (oldParent &&
|
|
1235
|
-
oldParent !== newParentId) {
|
|
1236
|
-
deps = deps.filter((id) => id !== oldParent);
|
|
1237
|
-
}
|
|
1238
|
-
if (newParentId) {
|
|
1239
|
-
if (!deps.includes(newParentId)) {
|
|
1240
|
-
deps = [...deps, newParentId];
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
else if (oldParent) {
|
|
1244
|
-
deps = deps.filter((id) => id !== oldParent);
|
|
1245
|
-
}
|
|
1246
|
-
return {
|
|
1247
|
-
...currentTask,
|
|
1248
|
-
parentTaskId: newParentId,
|
|
1249
|
-
dependencyIds: deps,
|
|
1250
|
-
};
|
|
1251
|
-
});
|
|
1252
|
-
}, options: parentTaskSelectOptions, placeholder: "No parent", "data-testid": "project-template-task-parent-select" }), _jsx("p", { className: "text-[11px] leading-snug text-gray-500", children: "Marks this task as a child in the template; the parent is also added as a blocking dependency unless already listed." })] }), _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) => ({
|
|
1318
|
+
})), 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) => ({
|
|
1253
1319
|
...currentTask,
|
|
1254
1320
|
description: event.target.value,
|
|
1255
1321
|
})), rows: 4, placeholder: "Describe what this task should accomplish", "data-testid": "project-template-task-description-input" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Priority" }), _jsx(Select, { className: "text-xs", value: selectedTask.priority ?? "", onValueChange: (value) => updateSelectedTask((currentTask) => ({
|
|
1256
1322
|
...currentTask,
|
|
1257
1323
|
priority: value || null,
|
|
1258
|
-
})), options: PRIORITY_OPTIONS, "data-testid": "project-template-task-priority-select" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Default
|
|
1324
|
+
})), options: PRIORITY_OPTIONS, "data-testid": "project-template-task-priority-select" })] }), _jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx(Label, { className: "text-xs", children: "Default assignee" }), selectedTask.assigneeType === "Agent" ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 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] }), _jsx(TaskAssigneePicker, { projectTemplateId: draftTemplate.id, assigneeType: selectedTask.assigneeType ?? null, value: selectedTask.assigneeId ?? null, displayValue: selectedTaskAssigneeDisplayValue, onChange: (next) => updateSelectedTask((currentTask) => ({
|
|
1259
1325
|
...currentTask,
|
|
1260
|
-
assigneeType:
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
?
|
|
1326
|
+
assigneeType: next?.assigneeType ?? null,
|
|
1327
|
+
assigneeId: next?.assigneeId ?? null,
|
|
1328
|
+
agentProfileId: next?.assigneeType === "Agent"
|
|
1329
|
+
? next.assigneeId
|
|
1264
1330
|
: null,
|
|
1265
|
-
|
|
1266
|
-
? (currentTask.agentProfileId ?? null)
|
|
1267
|
-
: null,
|
|
1268
|
-
})), options: ASSIGNEE_TYPE_OPTIONS, "data-testid": "project-template-task-assignee-type-select" })] }), selectedTask.assigneeType === "Agent" ? (_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Agent profile" }), _jsx(Select, { className: "text-xs", value: selectedTask.assigneeId ??
|
|
1269
|
-
selectedTask.agentProfileId ??
|
|
1270
|
-
"", onValueChange: (value) => updateSelectedTask((currentTask) => ({
|
|
1271
|
-
...currentTask,
|
|
1272
|
-
assigneeType: "Agent",
|
|
1273
|
-
assigneeId: value || null,
|
|
1274
|
-
agentProfileId: value || null,
|
|
1275
|
-
})), options: profileOptions, searchable: true, placeholder: "Select an agent profile", "data-testid": "project-template-task-agent-profile-select" }), profilesError && (_jsx("div", { className: "text-xs text-amber-700", children: profilesError }))] })) : selectedTask.assigneeType === "Human" ? (_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Default user identifier" }), _jsx(Input, { value: selectedTask.assigneeId ?? "", onChange: (event) => updateSelectedTask((currentTask) => ({
|
|
1276
|
-
...currentTask,
|
|
1277
|
-
assigneeType: "Human",
|
|
1278
|
-
assigneeId: event.target.value,
|
|
1279
|
-
agentProfileId: null,
|
|
1280
|
-
})), placeholder: "sitecore\\\\john", className: "text-xs md:text-xs", "data-testid": "project-template-task-user-assignee-input" })] })) : selectedTask.assigneeType === "Role" ? (_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Default role identifier" }), _jsx(Input, { value: selectedTask.assigneeId ?? "", onChange: (event) => updateSelectedTask((currentTask) => ({
|
|
1281
|
-
...currentTask,
|
|
1282
|
-
assigneeType: "Role",
|
|
1283
|
-
assigneeId: event.target.value,
|
|
1284
|
-
agentProfileId: null,
|
|
1285
|
-
})), placeholder: "sitecore\\\\Author", className: "text-xs md:text-xs", "data-testid": "project-template-task-role-assignee-input" })] })) : null] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 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: "flex items-center gap-2 text-xs font-medium text-gray-800", children: [_jsx(Shield, { className: "h-4 w-4 text-gray-500", 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-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-700", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length ===
|
|
1331
|
+
})), placeholder: "Assign user or agent", buttonClassName: "h-8 w-full justify-between rounded-md bg-white text-xs font-medium", buttonTestId: "project-template-task-assignee-picker" }), profilesError ? (_jsx("div", { className: "text-xs text-amber-700", children: profilesError })) : null] })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 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: "flex items-center gap-2 text-xs font-medium text-gray-800", children: [_jsx(Shield, { className: "h-4 w-4 text-gray-500", 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-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-700", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length ===
|
|
1286
1332
|
0 ? (_jsx("div", { className: "px-2 py-3 text-center text-xs text-gray-500", children: "All other tasks are already linked." })) : (dependencyAddCandidates.map((task) => (_jsxs("button", { type: "button", className: "flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-xs hover:bg-gray-100", onClick: () => handleAddDependency(task.id), "data-testid": `project-template-dependency-option-${task.id}`, children: [_jsx(Link2, { className: "h-3.5 w-3.5 shrink-0 text-gray-400", strokeWidth: 1.5 }), _jsx("span", { className: "min-w-0 truncate font-medium text-gray-900", children: task.title ||
|
|
1287
1333
|
"Untitled Task" })] }, task.id)))) })] })] })] }), _jsx("p", { className: "mb-2 text-[11px] leading-snug text-gray-500", children: "This task must wait for these tasks to finish first." }), dependencyTasks.length === 0 ? (_jsx("div", { className: "text-xs text-gray-500", children: draftTemplate.taskTemplates.filter((t) => t.id !== selectedTask.id).length === 0
|
|
1288
1334
|
? "Add more task templates to create dependencies."
|
|
@@ -1290,6 +1336,10 @@ export function ProjectTemplatesPanel() {
|
|
|
1290
1336
|
},
|
|
1291
1337
|
] }) })] })] })] })) : (_jsx("div", { className: "flex h-full items-center justify-center bg-gray-50/40", children: _jsxs("div", { className: "max-w-sm rounded-lg border border-dashed border-gray-300 bg-white p-8 text-center", children: [_jsx(GitBranch, { className: "mx-auto mb-3 h-10 w-10 text-gray-300", strokeWidth: 1.2 }), _jsx("h3", { className: "text-xs font-semibold text-gray-900", children: "Select a project template" }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Choose a template from the list or create a new one to start editing." })] }) }));
|
|
1292
1338
|
const agentPanelContent = (_jsx(ProjectTemplateAgentPanel, { templateName: draftTemplate?.name ?? null, agentId: templateAgentId, loading: templateAgentLoading, resetting: templateAgentResetting, error: templateAgentError, onStartOver: () => void handleResetTemplateAgent() }));
|
|
1339
|
+
const rightPanelContent = editingAgentProfile ? (_jsx(AgentProfileEditorPanel, { agent: editingAgentProfile, onClose: handleCloseEditingAgentProfile, actions: _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void handleDuplicateAssignedAgentProfile(), disabled: !selectedAgentProfileId ||
|
|
1340
|
+
!editContext ||
|
|
1341
|
+
duplicatingAgentProfile ||
|
|
1342
|
+
editingAgentProfile.id !== selectedAgentProfileId, "data-testid": "project-template-task-duplicate-agent-profile-button", children: [_jsx(CopyPlus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), duplicatingAgentProfile ? "Duplicating..." : "Duplicate"] }) })) : (agentPanelContent);
|
|
1293
1343
|
const panels = [
|
|
1294
1344
|
{
|
|
1295
1345
|
name: "project-template-list",
|
|
@@ -1306,7 +1356,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1306
1356
|
{
|
|
1307
1357
|
name: "project-template-agent",
|
|
1308
1358
|
defaultSize: 460,
|
|
1309
|
-
content:
|
|
1359
|
+
content: rightPanelContent,
|
|
1310
1360
|
className: "overflow-hidden",
|
|
1311
1361
|
collapsible: true,
|
|
1312
1362
|
},
|