@parhelia/core 0.1.12468 → 0.1.12470
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/config/config.js +2 -21
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +0 -2
- package/dist/config/types.js.map +1 -1
- package/dist/editor/ConfirmationDialog.js +4 -20
- package/dist/editor/ConfirmationDialog.js.map +1 -1
- package/dist/editor/ContentTree.js +7 -19
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/PictureCropper.js +41 -45
- package/dist/editor/PictureCropper.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +8 -97
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminalStatusBar.js +0 -65
- package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
- package/dist/editor/ai/Agents.js +0 -19
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +0 -5
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContentInspectorPopover.d.ts +0 -1
- package/dist/editor/ai/ContentInspectorPopover.js +8 -22
- package/dist/editor/ai/ContentInspectorPopover.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +0 -2
- package/dist/editor/ai/ToolCallDisplay.js +11 -54
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/dialogs/AgentDialogHandler.js +3 -32
- package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
- package/dist/editor/ai/dialogs/QuestionnaireInline.js +20 -55
- package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
- package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +4 -7
- package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
- package/dist/editor/ai/types.d.ts +0 -2
- package/dist/editor/services/agentService.d.ts +0 -27
- package/dist/editor/services/agentService.js +2 -11
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.js +3 -54
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/serviceHelper.js +2 -5
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/editor/settings/About.js +4 -40
- package/dist/editor/settings/About.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.d.ts +1 -7
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js +3 -3
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +84 -165
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/settings/panels/index.d.ts +0 -1
- package/dist/editor/settings/panels/index.js +0 -1
- package/dist/editor/settings/panels/index.js.map +1 -1
- package/dist/editor/sidebar/NavigationPanelItem.js +1 -1
- package/dist/editor/sidebar/NavigationPanelItem.js.map +1 -1
- package/dist/editor/sidebar/WorkspaceButton.js +1 -1
- package/dist/editor/sidebar/WorkspaceButton.js.map +1 -1
- package/dist/editor/tree-indicators/GutterColumns.js +4 -24
- package/dist/editor/tree-indicators/GutterColumns.js.map +1 -1
- package/dist/editor/tree-indicators/types.d.ts +0 -10
- package/dist/editor/ui/Splitter.d.ts +0 -1
- package/dist/editor/ui/Splitter.js +1 -7
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/licensing/LicenseContext.js +4 -40
- package/dist/licensing/LicenseContext.js.map +1 -1
- package/dist/licensing/LicenseOverlay.js +1 -1
- package/dist/licensing/LicenseOverlay.js.map +1 -1
- package/dist/licensing/types.d.ts +1 -3
- package/dist/licensing/types.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +354 -165
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/assigneeDisplay.js +3 -1
- package/dist/task-board/assigneeDisplay.js.map +1 -1
- package/dist/task-board/components/CreateProjectDialog.js +1 -2
- package/dist/task-board/components/CreateProjectDialog.js.map +1 -1
- package/dist/task-board/components/ProjectDashboard.js +1 -2
- package/dist/task-board/components/ProjectDashboard.js.map +1 -1
- package/dist/task-board/components/ProjectSettingsDialog.d.ts +0 -1
- package/dist/task-board/components/ProjectSettingsDialog.js +12 -146
- package/dist/task-board/components/ProjectSettingsDialog.js.map +1 -1
- package/dist/task-board/components/TaskAgentPanel.d.ts +0 -1
- package/dist/task-board/components/TaskAgentPanel.js +2 -2
- package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
- package/dist/task-board/components/TaskAssigneePicker.js +2 -2
- package/dist/task-board/components/TaskAssigneePicker.js.map +1 -1
- package/dist/task-board/components/TaskBoardMyTasksSidebar.js +1 -1
- package/dist/task-board/components/TaskBoardMyTasksSidebar.js.map +1 -1
- package/dist/task-board/components/TaskDetailDialog.d.ts +0 -1
- package/dist/task-board/components/TaskDetailDialog.js +2 -2
- package/dist/task-board/components/TaskDetailDialog.js.map +1 -1
- package/dist/task-board/components/TaskDetailPanel.d.ts +0 -1
- package/dist/task-board/components/TaskDetailPanel.js +8 -23
- package/dist/task-board/components/TaskDetailPanel.js.map +1 -1
- package/dist/task-board/components/TaskRow.js +2 -3
- package/dist/task-board/components/TaskRow.js.map +1 -1
- package/dist/task-board/components/WizardTaskDetailsPanel.js +1 -2
- package/dist/task-board/components/WizardTaskDetailsPanel.js.map +1 -1
- package/dist/task-board/services/taskService.d.ts +1 -17
- package/dist/task-board/services/taskService.js +0 -56
- package/dist/task-board/services/taskService.js.map +1 -1
- package/dist/task-board/taskExecutionRecords.js +0 -2
- package/dist/task-board/taskExecutionRecords.js.map +1 -1
- package/dist/task-board/types.d.ts +1 -78
- package/dist/task-board/utils/taskDependencyOrdering.d.ts +0 -6
- package/dist/task-board/utils/taskDependencyOrdering.js +1 -138
- package/dist/task-board/utils/taskDependencyOrdering.js.map +1 -1
- package/dist/task-board/views/DependencyGraphView.d.ts +2 -5
- package/dist/task-board/views/DependencyGraphView.js +69 -261
- package/dist/task-board/views/DependencyGraphView.js.map +1 -1
- package/dist/task-board/views/KanbanView.js +1 -8
- package/dist/task-board/views/KanbanView.js.map +1 -1
- package/dist/task-board/views/ListView.js +1 -1
- package/dist/task-board/views/ListView.js.map +1 -1
- package/dist/task-board/views/WizardView.js +24 -30
- package/dist/task-board/views/WizardView.js.map +1 -1
- package/dist/tour/Tour.js +32 -0
- package/dist/tour/Tour.js.map +1 -1
- package/package.json +1 -1
- package/dist/editor/settings/panels/PersistentLogsPanel.d.ts +0 -2
- package/dist/editor/settings/panels/PersistentLogsPanel.js +0 -244
- package/dist/editor/settings/panels/PersistentLogsPanel.js.map +0 -1
- package/dist/task-board/components/ProjectExecutionUserPicker.d.ts +0 -14
- package/dist/task-board/components/ProjectExecutionUserPicker.js +0 -65
- package/dist/task-board/components/ProjectExecutionUserPicker.js.map +0 -1
- package/dist/task-board/components/TaskboardPersistentLogPanel.d.ts +0 -11
- package/dist/task-board/components/TaskboardPersistentLogPanel.js +0 -141
- package/dist/task-board/components/TaskboardPersistentLogPanel.js.map +0 -1
- package/dist/task-board/persistentLogCopy.d.ts +0 -7
- package/dist/task-board/persistentLogCopy.js +0 -80
- package/dist/task-board/persistentLogCopy.js.map +0 -1
- package/dist/task-board/persistentLogLabels.d.ts +0 -38
- package/dist/task-board/persistentLogLabels.js +0 -189
- package/dist/task-board/persistentLogLabels.js.map +0 -1
- package/dist/task-board/useTaskBoardAgentPanelState.d.ts +0 -34
- package/dist/task-board/useTaskBoardAgentPanelState.js +0 -283
- package/dist/task-board/useTaskBoardAgentPanelState.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useState } from "react";
|
|
3
|
-
import { Bot,
|
|
3
|
+
import { Bot, RefreshCw, RotateCcw } from "lucide-react";
|
|
4
4
|
import { Button } from "../../../components/ui/button";
|
|
5
5
|
import { AgentTerminal } from "../../ai/AgentTerminal";
|
|
6
6
|
import { getAiProfilesErrorMessage, loadAiProfiles, } from "../../services/aiService";
|
|
7
|
-
export function ProjectTemplateAgentPanel({ templateName, agentId, loading, resetting, error, onStartOver,
|
|
7
|
+
export function ProjectTemplateAgentPanel({ templateName, agentId, loading, resetting, error, onStartOver, }) {
|
|
8
8
|
const [profiles, setProfiles] = useState([]);
|
|
9
9
|
const [profilesError, setProfilesError] = useState(null);
|
|
10
10
|
useEffect(() => {
|
|
@@ -40,7 +40,7 @@ export function ProjectTemplateAgentPanel({ templateName, agentId, loading, rese
|
|
|
40
40
|
const headerTitle = templateName?.trim()
|
|
41
41
|
? `${templateName} Assistant`
|
|
42
42
|
: "Template Assistant";
|
|
43
|
-
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-white", "data-testid": "project-template-agent-panel", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 border-b px-4 py-3", children: [_jsxs("div", { className: "flex min-w-0
|
|
43
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-white", "data-testid": "project-template-agent-panel", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 border-b px-4 py-3", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Bot, { className: "h-5 w-5 text-muted-foreground" }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-semibold", children: headerTitle }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Ask about task-project structure, dependencies, and template design." })] })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: onStartOver, disabled: !templateName || loading || resetting, title: "Create a fresh assistant conversation for this template", "data-testid": "project-template-agent-reset-button", children: [resetting ? (_jsx(RefreshCw, { className: "h-4 w-4 animate-spin", strokeWidth: 1.5 })) : (_jsx(RotateCcw, { className: "h-4 w-4", strokeWidth: 1.5 })), "Start Over"] })] }), profilesError ? (_jsx("div", { className: "border-b border-amber-200 bg-amber-50 px-4 py-2 text-xs text-amber-700", children: profilesError })) : null, error ? (_jsx("div", { className: "border-b border-red-200 bg-red-50 px-4 py-2 text-xs text-red-700", children: error })) : null, _jsx("div", { className: "min-h-0 flex-1", children: loading ? (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx(RefreshCw, { className: "h-8 w-8 animate-spin text-muted-foreground/60" }), _jsx("div", { className: "text-sm text-muted-foreground", children: "Loading template assistant..." })] })) : !templateName ? (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx(Bot, { className: "h-10 w-10 text-muted-foreground/40" }), _jsxs("div", { className: "grid gap-1", children: [_jsx("div", { className: "text-sm font-medium text-muted-foreground", children: "No template selected" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Select a project template to open its dedicated assistant." })] })] })) : !agentStub ? (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx(Bot, { className: "h-10 w-10 text-muted-foreground/40" }), _jsxs("div", { className: "grid gap-1", children: [_jsx("div", { className: "text-sm font-medium text-muted-foreground", children: "Assistant unavailable" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Try selecting the template again or use Start Over to create a fresh session." })] })] })) : (_jsx(AgentTerminal, { agentStub: agentStub, profiles: profiles, isActive: true, compact: true, hideGreeting: true, displayMode: "full", showSummaryInput: false, className: "h-full" })) })] }));
|
|
44
44
|
}
|
|
45
45
|
export default ProjectTemplateAgentPanel;
|
|
46
46
|
//# sourceMappingURL=ProjectTemplateAgentPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectTemplateAgentPanel.js","sourceRoot":"","sources":["../../../../src/editor/settings/panels/ProjectTemplateAgentPanel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"ProjectTemplateAgentPanel.js","sourceRoot":"","sources":["../../../../src/editor/settings/panels/ProjectTemplateAgentPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -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,
|
|
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";
|
|
@@ -26,7 +26,7 @@ import { AgentProfileEditorPanel, } from "./AgentProfileEditorPanel";
|
|
|
26
26
|
import { ProjectTemplateAgentPanel } from "./ProjectTemplateAgentPanel";
|
|
27
27
|
import { useSearchParams } from "next/navigation";
|
|
28
28
|
import { ParheliaIconWhite } from "../../ui/ParheliaIconWhite";
|
|
29
|
-
|
|
29
|
+
/** Query param for deep-linking the selected project template (settings reload). */
|
|
30
30
|
const SELECTED_PROJECT_TEMPLATE_QUERY_PARAM = "projectTemplateId";
|
|
31
31
|
const PRIORITY_OPTIONS = [
|
|
32
32
|
{ value: "", label: "No priority" },
|
|
@@ -45,8 +45,7 @@ function isProjectTemplateItemChange(changes, selectedTemplateId) {
|
|
|
45
45
|
const normalizedSelectedTemplateId = selectedTemplateId?.toLowerCase() ?? null;
|
|
46
46
|
return changes.some((change) => {
|
|
47
47
|
const path = change.item?.path?.trim().toLowerCase();
|
|
48
|
-
if (path &&
|
|
49
|
-
PROJECT_TEMPLATE_ROOT_PATHS.some((root) => path.startsWith(root))) {
|
|
48
|
+
if (path && PROJECT_TEMPLATE_ROOT_PATHS.some((root) => path.startsWith(root))) {
|
|
50
49
|
return true;
|
|
51
50
|
}
|
|
52
51
|
const itemId = change.item?.id?.trim().toLowerCase();
|
|
@@ -75,7 +74,7 @@ function normalizeTaskTemplate(task) {
|
|
|
75
74
|
parentTaskId: rawParentTaskId,
|
|
76
75
|
};
|
|
77
76
|
}
|
|
78
|
-
if (assigneeType === "
|
|
77
|
+
if (assigneeType === "Human" || assigneeType === "Role") {
|
|
79
78
|
return {
|
|
80
79
|
...task,
|
|
81
80
|
disabled,
|
|
@@ -94,20 +93,11 @@ function normalizeTaskTemplate(task) {
|
|
|
94
93
|
parentTaskId: rawParentTaskId,
|
|
95
94
|
};
|
|
96
95
|
}
|
|
97
|
-
function normalizeGraphOrientation(orientation) {
|
|
98
|
-
return orientation === "vertical" ? "vertical" : "horizontal";
|
|
99
|
-
}
|
|
100
96
|
function normalizeProjectTemplate(template) {
|
|
101
97
|
return {
|
|
102
98
|
...template,
|
|
103
99
|
hideFromCreateDialog: template.hideFromCreateDialog === true,
|
|
104
100
|
openInWizardMode: template.openInWizardMode === true,
|
|
105
|
-
graphLayout: template.graphLayout
|
|
106
|
-
? {
|
|
107
|
-
...template.graphLayout,
|
|
108
|
-
orientation: normalizeGraphOrientation(template.graphLayout.orientation),
|
|
109
|
-
}
|
|
110
|
-
: null,
|
|
111
101
|
taskTemplates: (template.taskTemplates ?? []).map(normalizeTaskTemplate),
|
|
112
102
|
};
|
|
113
103
|
}
|
|
@@ -160,7 +150,6 @@ function buildUpsertTemplateRequest(template) {
|
|
|
160
150
|
projectTemplateId: template.id,
|
|
161
151
|
nodes: template.graphLayout.nodes ?? [],
|
|
162
152
|
viewport: template.graphLayout.viewport ?? null,
|
|
163
|
-
orientation: normalizeGraphOrientation(template.graphLayout.orientation),
|
|
164
153
|
}
|
|
165
154
|
: null,
|
|
166
155
|
taskTemplates: template.taskTemplates.map((task, index) => {
|
|
@@ -194,7 +183,6 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
|
|
|
194
183
|
projectTemplateId: serverTemplate.id,
|
|
195
184
|
nodes: request.graphLayout.nodes ?? [],
|
|
196
185
|
viewport: request.graphLayout.viewport ?? null,
|
|
197
|
-
orientation: normalizeGraphOrientation(request.graphLayout.orientation),
|
|
198
186
|
};
|
|
199
187
|
return normalizeProjectTemplate({
|
|
200
188
|
...serverTemplate,
|
|
@@ -336,7 +324,6 @@ function buildProjectTemplateAgentContext(template, selectedTaskTemplateId) {
|
|
|
336
324
|
}
|
|
337
325
|
export function ProjectTemplatesPanel() {
|
|
338
326
|
const editContext = useEditContext();
|
|
339
|
-
const isMobile = editContext?.isMobile ?? false;
|
|
340
327
|
const searchParams = useSearchParams();
|
|
341
328
|
const [state, setState] = useState("loading");
|
|
342
329
|
const [templates, setTemplates] = useState([]);
|
|
@@ -366,9 +353,6 @@ export function ProjectTemplatesPanel() {
|
|
|
366
353
|
const [templateAgentResetting, setTemplateAgentResetting] = useState(false);
|
|
367
354
|
const [templateAgentError, setTemplateAgentError] = useState(null);
|
|
368
355
|
const [duplicatingAgentProfile, setDuplicatingAgentProfile] = useState(false);
|
|
369
|
-
const [mobileView, setMobileView] = useState("list");
|
|
370
|
-
// Desktop: hide splitter list + detail; show only the assistant column (full width).
|
|
371
|
-
const [desktopAssistantOnly, setDesktopAssistantOnly] = useState(false);
|
|
372
356
|
const [editingAgentProfile, setEditingAgentProfile] = useState(null);
|
|
373
357
|
const autosaveTimeoutRef = useRef(null);
|
|
374
358
|
const lastPersistedSignatureRef = useRef(null);
|
|
@@ -377,8 +361,6 @@ export function ProjectTemplatesPanel() {
|
|
|
377
361
|
const draftTemplateRef = useRef(null);
|
|
378
362
|
const selectedTemplateIdRef = useRef(selectedTemplateId);
|
|
379
363
|
const selectedTaskIdRef = useRef(selectedTaskId);
|
|
380
|
-
const isDirtyRef = useRef(isDirty);
|
|
381
|
-
const savingRef = useRef(saving);
|
|
382
364
|
const templateAgentLoadRunIdRef = useRef(0);
|
|
383
365
|
const externalRefreshTimeoutRef = useRef(null);
|
|
384
366
|
const pendingExternalRefreshRef = useRef(false);
|
|
@@ -423,7 +405,6 @@ export function ProjectTemplatesPanel() {
|
|
|
423
405
|
setSelectedTemplateId(template?.id ?? null);
|
|
424
406
|
setDraftTemplate(clonedTemplate);
|
|
425
407
|
setEditingAgentProfile(null);
|
|
426
|
-
setDesktopAssistantOnly(false);
|
|
427
408
|
setSelectedTaskId(getSelectedTaskIdForTemplate(clonedTemplate, preferredTaskId));
|
|
428
409
|
setIsDirty(false);
|
|
429
410
|
setSaveError(null);
|
|
@@ -437,27 +418,6 @@ export function ProjectTemplatesPanel() {
|
|
|
437
418
|
});
|
|
438
419
|
}
|
|
439
420
|
}, [editContext, searchParams]);
|
|
440
|
-
const handleMobileBackToList = useCallback(() => {
|
|
441
|
-
setMobileView("list");
|
|
442
|
-
selectTemplate(null);
|
|
443
|
-
}, [selectTemplate]);
|
|
444
|
-
const handleMobileBackFromAgent = useCallback(() => {
|
|
445
|
-
setEditingAgentProfile(null);
|
|
446
|
-
setMobileView("detail");
|
|
447
|
-
}, []);
|
|
448
|
-
useEffect(() => {
|
|
449
|
-
if (!isMobile) {
|
|
450
|
-
setMobileView("list");
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
setDesktopAssistantOnly(false);
|
|
454
|
-
}
|
|
455
|
-
}, [isMobile]);
|
|
456
|
-
useEffect(() => {
|
|
457
|
-
if (!isMobile || !editingAgentProfile)
|
|
458
|
-
return;
|
|
459
|
-
setMobileView("agent");
|
|
460
|
-
}, [isMobile, editingAgentProfile]);
|
|
461
421
|
const loadTemplates = useCallback(async (preferredTemplateId) => {
|
|
462
422
|
try {
|
|
463
423
|
setState("loading");
|
|
@@ -589,7 +549,7 @@ export function ProjectTemplatesPanel() {
|
|
|
589
549
|
if (isDirty || saving) {
|
|
590
550
|
return (_jsx("span", { "data-testid": "project-template-save-status", "data-state": "saving", className: "inline-flex min-w-[84px] justify-center rounded bg-amber-100 px-1.5 py-0.5 whitespace-nowrap text-amber-700", children: "Saving..." }));
|
|
591
551
|
}
|
|
592
|
-
return (_jsx("span", { "aria-hidden": "true", "data-testid": "project-template-save-status", "data-state": "saved", className: "
|
|
552
|
+
return (_jsx("span", { "aria-hidden": "true", "data-testid": "project-template-save-status", "data-state": "saved", className: "inline-flex min-w-[84px] justify-center rounded px-1.5 py-0.5 whitespace-nowrap opacity-0", children: "Saving..." }));
|
|
593
553
|
}, [isDirty, saveError, saving]);
|
|
594
554
|
const graphTasks = useMemo(() => buildTemplateTaskItems(draftTemplate, aiProfilesById), [aiProfilesById, draftTemplate]);
|
|
595
555
|
const graphDependencies = useMemo(() => buildTemplateDependencies(draftTemplate), [draftTemplate]);
|
|
@@ -619,10 +579,7 @@ export function ProjectTemplatesPanel() {
|
|
|
619
579
|
}, [selectedAgentProfile, selectedAgentProfileId, selectedTask?.title]);
|
|
620
580
|
const handleCloseEditingAgentProfile = useCallback(() => {
|
|
621
581
|
setEditingAgentProfile(null);
|
|
622
|
-
|
|
623
|
-
setMobileView("detail");
|
|
624
|
-
}
|
|
625
|
-
}, [isMobile]);
|
|
582
|
+
}, []);
|
|
626
583
|
const syncProjectTemplateAgentContext = useCallback(async (agentId, template, selectedTaskTemplateId) => {
|
|
627
584
|
try {
|
|
628
585
|
await updateAgentContext(agentId, buildProjectTemplateAgentContext(template, selectedTaskTemplateId));
|
|
@@ -929,12 +886,6 @@ export function ProjectTemplatesPanel() {
|
|
|
929
886
|
useEffect(() => {
|
|
930
887
|
selectedTaskIdRef.current = selectedTaskId;
|
|
931
888
|
}, [selectedTaskId]);
|
|
932
|
-
useEffect(() => {
|
|
933
|
-
isDirtyRef.current = isDirty;
|
|
934
|
-
}, [isDirty]);
|
|
935
|
-
useEffect(() => {
|
|
936
|
-
savingRef.current = saving;
|
|
937
|
-
}, [saving]);
|
|
938
889
|
const queueExternalTemplateRefresh = useCallback(() => {
|
|
939
890
|
if (saving || isDirty) {
|
|
940
891
|
pendingExternalRefreshRef.current = true;
|
|
@@ -946,23 +897,9 @@ export function ProjectTemplatesPanel() {
|
|
|
946
897
|
}
|
|
947
898
|
externalRefreshTimeoutRef.current = window.setTimeout(() => {
|
|
948
899
|
externalRefreshTimeoutRef.current = null;
|
|
949
|
-
if (savingRef.current || isDirtyRef.current) {
|
|
950
|
-
pendingExternalRefreshRef.current = true;
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
900
|
void loadTemplatesRef.current(selectedTemplateIdRef.current);
|
|
954
901
|
}, PROJECT_TEMPLATE_EXTERNAL_REFRESH_DEBOUNCE_MS);
|
|
955
902
|
}, [isDirty, saving]);
|
|
956
|
-
useEffect(() => {
|
|
957
|
-
if (!saving && !isDirty) {
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
if (externalRefreshTimeoutRef.current !== null) {
|
|
961
|
-
window.clearTimeout(externalRefreshTimeoutRef.current);
|
|
962
|
-
externalRefreshTimeoutRef.current = null;
|
|
963
|
-
pendingExternalRefreshRef.current = true;
|
|
964
|
-
}
|
|
965
|
-
}, [isDirty, saving]);
|
|
966
903
|
useEffect(() => {
|
|
967
904
|
if (!editContext?.itemsRepository) {
|
|
968
905
|
return;
|
|
@@ -1040,11 +977,8 @@ export function ProjectTemplatesPanel() {
|
|
|
1040
977
|
editContext?.updateUrl({
|
|
1041
978
|
[SELECTED_PROJECT_TEMPLATE_QUERY_PARAM]: nextTemplate.id,
|
|
1042
979
|
});
|
|
1043
|
-
if (isMobile) {
|
|
1044
|
-
setMobileView("detail");
|
|
1045
|
-
}
|
|
1046
980
|
await persistTemplate(request, signature, { showErrorToast: true });
|
|
1047
|
-
}, [editContext, flushPendingSave,
|
|
981
|
+
}, [editContext, flushPendingSave, persistTemplate, templates]);
|
|
1048
982
|
const handleDeleteTemplate = useCallback((templateToDelete) => {
|
|
1049
983
|
const template = templateToDelete ?? draftTemplate;
|
|
1050
984
|
if (!template || template.isSystem)
|
|
@@ -1075,7 +1009,8 @@ export function ProjectTemplatesPanel() {
|
|
|
1075
1009
|
}
|
|
1076
1010
|
toast.success("Project template deleted");
|
|
1077
1011
|
const fallbackId = isDeletingSelectedTemplate
|
|
1078
|
-
?
|
|
1012
|
+
? templates.find((currentTemplate) => currentTemplate.id !== templateId)
|
|
1013
|
+
?.id ?? null
|
|
1079
1014
|
: selectedTemplateIdRef.current;
|
|
1080
1015
|
await loadTemplates(fallbackId);
|
|
1081
1016
|
}
|
|
@@ -1106,10 +1041,7 @@ export function ProjectTemplatesPanel() {
|
|
|
1106
1041
|
return;
|
|
1107
1042
|
}
|
|
1108
1043
|
selectTemplate(template);
|
|
1109
|
-
|
|
1110
|
-
setMobileView("detail");
|
|
1111
|
-
}
|
|
1112
|
-
}, [flushPendingSave, selectTemplate, isMobile]);
|
|
1044
|
+
}, [flushPendingSave, selectTemplate]);
|
|
1113
1045
|
const handleRefreshTemplates = useCallback(async () => {
|
|
1114
1046
|
const canContinue = await flushPendingSave({ showErrorToast: true });
|
|
1115
1047
|
if (!canContinue) {
|
|
@@ -1477,116 +1409,103 @@ export function ProjectTemplatesPanel() {
|
|
|
1477
1409
|
handleDeleteTemplate(template);
|
|
1478
1410
|
}, children: _jsx(Trash2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }))] }, template.id));
|
|
1479
1411
|
}) })) })] }) }));
|
|
1480
|
-
const
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
})), 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 === 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 || "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
|
|
1516
|
-
? "Add more task templates to create dependencies."
|
|
1517
|
-
: "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
|
|
1518
|
-
? "border-amber-300 bg-amber-50 ring-1 ring-amber-200"
|
|
1519
|
-
: "border-gray-200"), "aria-selected": selectedDependencyId === task.id, onClick: () => setSelectedDependencyId(task.id), onFocus: () => setSelectedDependencyId(task.id), "data-testid": `project-template-dependency-row-${task.id}`, children: [_jsx("span", { className: "min-w-0 truncate font-medium text-gray-800", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "shrink-0 rounded p-0.5 text-gray-400 hover:bg-gray-100 hover:text-gray-700", "aria-label": `Remove dependency on ${task.title}`, onClick: () => handleRemoveDependency(task.id), "data-testid": `project-template-remove-dependency-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3", "data-testid": "project-template-child-tasks-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800", children: [_jsx(CornerDownRight, { className: "h-4 w-4 text-gray-500", strokeWidth: 1.5 }), "Child tasks"] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: () => void handleOpenAddChildTaskDialog(), disabled: creatingChildTask, "aria-label": "Add child task", "data-testid": "project-template-add-child-task-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }), _jsx("p", { className: "mb-2 text-[11px] leading-snug text-gray-500", children: "Tasks that run after this one (they depend on this task)." }), childTaskTemplates.length === 0 ? (_jsx("div", { className: "text-xs text-gray-500", children: "No child tasks yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: childTaskTemplates.map((task) => (_jsxs("li", { className: "flex items-center justify-between gap-2 rounded-md border border-gray-200 bg-white px-3 py-2 text-xs", "data-testid": `project-template-child-task-row-${task.id}`, children: [_jsx("span", { className: "min-w-0 truncate font-medium text-gray-800", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "shrink-0 rounded p-0.5 text-gray-400 hover:bg-gray-100 hover:text-gray-700", "aria-label": `Unlink child task ${task.title}`, onClick: () => handleUnlinkChildTask(task.id), "data-testid": `project-template-unlink-child-task-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] })] })] }) })] })) }));
|
|
1520
|
-
if (isMobile) {
|
|
1521
|
-
return (_jsxs("div", { className: "flex shrink-0 flex-col border-b border-gray-100", children: [_jsx("div", { className: "h-[300px] shrink-0 overflow-hidden border-b border-gray-100", children: graphView }), taskPane] }));
|
|
1522
|
-
}
|
|
1523
|
-
return (_jsx("div", { className: "min-h-[360px] flex-1 overflow-hidden border-b border-gray-100", children: _jsx(Splitter, { direction: "vertical", localStorageKey: "settings-project-template-graph-task-splitter-v1", className: "h-full", panels: [
|
|
1524
|
-
{
|
|
1525
|
-
name: "project-template-graph",
|
|
1526
|
-
defaultSize: 400,
|
|
1527
|
-
className: "min-h-0",
|
|
1528
|
-
content: graphView,
|
|
1529
|
-
},
|
|
1530
|
-
{
|
|
1531
|
-
name: "project-template-task-details",
|
|
1532
|
-
defaultSize: "auto",
|
|
1533
|
-
className: "min-h-0",
|
|
1534
|
-
content: taskPane,
|
|
1535
|
-
},
|
|
1536
|
-
] }) }));
|
|
1537
|
-
};
|
|
1538
|
-
const detailContent = draftTemplate ? (_jsxs("div", { className: "flex h-full flex-col bg-gray-50/40", "data-testid": "project-template-detail-pane", children: [_jsxs("div", { className: cn("gap-3 border-b border-gray-200 bg-white px-5 py-3.5", isMobile
|
|
1539
|
-
? "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-x-3"
|
|
1540
|
-
: "flex items-center justify-between"), children: [_jsx("div", { className: "min-w-0", children: _jsxs("div", { className: "flex items-center gap-2", children: [isMobile ? (_jsx("button", { type: "button", className: "shrink-0 rounded-md p-1.5 text-gray-700 hover:bg-gray-100 md:hidden", onClick: handleMobileBackToList, "aria-label": "Back to template list", "data-testid": "project-template-mobile-back-to-list", children: _jsx(ChevronLeft, { className: "h-5 w-5", strokeWidth: 1.5 }) })) : null, _jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-900 text-white", children: _jsx(GitBranch, { className: "h-4 w-4", strokeWidth: 1.5 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "truncate text-xs font-semibold text-gray-900", children: draftTemplate.name || "Project Template" }), _jsxs("div", { className: "mt-0.5 flex min-h-[20px] items-center gap-2 text-[11px] text-gray-500", children: [_jsxs("span", { children: [draftTemplate.taskTemplates.length, " task templates"] }), headerStatusBadge] })] })] }) }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5 self-center bg-white pl-1", children: [isMobile ? (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-9 w-9 shrink-0 md:hidden", onClick: () => setMobileView("agent"), "aria-label": "Open template assistant", title: "Open template assistant", "data-testid": "project-template-mobile-open-assistant", children: _jsx(Bot, { className: "h-4 w-4", strokeWidth: 1.5 }) })) : null, !draftTemplate.isSystem &&
|
|
1541
|
-
(isMobile ? (_jsx(Button, { variant: "outline", size: "icon", className: "h-9 w-9 shrink-0", onClick: () => handleDeleteTemplate(), disabled: deleting, "aria-label": deleting ? "Deleting template" : "Delete template", title: deleting ? "Deleting…" : "Delete template", "data-testid": "project-template-delete-button", children: deleting ? (_jsx(RefreshCw, { className: "h-4 w-4 animate-spin", strokeWidth: 1.5 })) : (_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 })) })) : (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), deleting ? "Deleting..." : "Delete"] })))] })] }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto overscroll-y-contain p-5 md:overflow-hidden", children: [_jsxs("div", { className: "flex shrink-0 flex-col gap-5 md:max-h-[50vh] md:min-h-0 md:overflow-y-auto md:overscroll-y-contain", children: [saveError && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 px-4 py-3 text-xs text-red-700", children: saveError })), _jsxs("section", { className: "shrink-0 rounded-lg border border-gray-200 bg-white shadow-sm md:overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex w-full items-center justify-between gap-3 px-4 py-3 text-left", onClick: () => setIsBasicSettingsExpanded((currentValue) => !currentValue), "aria-expanded": isBasicSettingsExpanded, "aria-controls": "project-template-basic-settings", "data-testid": "project-template-basic-settings-toggle", children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [_jsx("span", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-gray-100 text-gray-500", children: _jsx(Settings2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }), _jsxs("div", { children: [_jsx("h3", { className: "text-xs font-semibold tracking-wide text-gray-800", children: "Basic Settings" }), _jsx("p", { className: "text-[11px] leading-tight text-gray-400", children: "Configure the shared defaults for this project template." })] })] }), _jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-gray-400 transition-transform", isBasicSettingsExpanded ? "rotate-180" : "rotate-0"), strokeWidth: 1.5 })] }), isBasicSettingsExpanded && (_jsxs("div", { id: "project-template-basic-settings", className: "grid gap-4 border-t border-gray-100 p-4 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Template name" }), _jsx(Input, { value: draftTemplate.name, onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1542
|
-
...currentTemplate,
|
|
1543
|
-
name: event.target.value,
|
|
1544
|
-
})), placeholder: "Project template name", className: "text-xs md:text-xs", "data-testid": "project-template-name-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: draftTemplate.description ?? "", onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1545
|
-
...currentTemplate,
|
|
1546
|
-
description: event.target.value,
|
|
1547
|
-
})), rows: 4, placeholder: "Describe when to use this template", "data-testid": "project-template-description-input" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Default cost limit" }), _jsx(Input, { type: "number", value: draftTemplate.defaultCostLimit ?? "", onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1548
|
-
...currentTemplate,
|
|
1549
|
-
defaultCostLimit: event.target.value.trim() === ""
|
|
1550
|
-
? null
|
|
1551
|
-
: Number(event.target.value),
|
|
1552
|
-
})), placeholder: "0", className: "text-xs md:text-xs", "data-testid": "project-template-default-cost-limit-input" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-zinc-900", children: "Disabled" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "Makes the template unavailable for project creation and template resolution." })] }), _jsx(Switch, { checked: draftTemplate.disabled === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1553
|
-
...currentTemplate,
|
|
1554
|
-
disabled: checked,
|
|
1555
|
-
})), className: "data-[state=checked]:bg-amber-600 data-[state=checked]:shadow-inner dark:data-[state=checked]:bg-amber-600", "aria-label": "Disable this project template", "data-testid": "project-template-disabled-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-zinc-900", children: "Hide from create dialog" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "Keeps the template active, but removes it from the create project dialog." })] }), _jsx(Switch, { checked: draftTemplate.hideFromCreateDialog === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1556
|
-
...currentTemplate,
|
|
1557
|
-
hideFromCreateDialog: checked,
|
|
1558
|
-
})), "aria-label": "Hide this project template from the create dialog", "data-testid": "project-template-hide-from-create-dialog-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-zinc-900", children: "Open in wizard mode" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "New projects created from this template start in taskboard wizard mode." })] }), _jsx(Switch, { checked: draftTemplate.openInWizardMode === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1412
|
+
const detailContent = draftTemplate ? (_jsxs("div", { className: "flex h-full flex-col bg-gray-50/40", "data-testid": "project-template-detail-pane", children: [_jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-gray-200 bg-white px-5 py-3.5", children: [_jsx("div", { className: "min-w-0", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gray-900 text-white", children: _jsx(GitBranch, { className: "h-4 w-4", strokeWidth: 1.5 }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "truncate text-xs font-semibold text-gray-900", children: draftTemplate.name || "Project Template" }), _jsxs("div", { className: "mt-0.5 flex min-h-[20px] items-center gap-2 text-[11px] text-gray-500", children: [_jsxs("span", { children: [draftTemplate.taskTemplates.length, " task templates"] }), headerStatusBadge] })] })] }) }), _jsx("div", { className: "flex shrink-0 items-center gap-2", children: !draftTemplate.isSystem && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), deleting ? "Deleting..." : "Delete"] })) })] }), _jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-5 overflow-hidden p-5", children: [saveError && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 px-4 py-3 text-xs text-red-700", children: saveError })), _jsxs("section", { className: "shrink-0 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm", children: [_jsxs("button", { type: "button", className: "flex w-full items-center justify-between gap-3 px-4 py-3 text-left", onClick: () => setIsBasicSettingsExpanded((currentValue) => !currentValue), "aria-expanded": isBasicSettingsExpanded, "aria-controls": "project-template-basic-settings", "data-testid": "project-template-basic-settings-toggle", children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [_jsx("span", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-gray-100 text-gray-500", children: _jsx(Settings2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }), _jsxs("div", { children: [_jsx("h3", { className: "text-xs font-semibold tracking-wide text-gray-800", children: "Basic Settings" }), _jsx("p", { className: "text-[11px] leading-tight text-gray-400", children: "Configure the shared defaults for this project template." })] })] }), _jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-gray-400 transition-transform", isBasicSettingsExpanded ? "rotate-180" : "rotate-0"), strokeWidth: 1.5 })] }), isBasicSettingsExpanded && (_jsxs("div", { id: "project-template-basic-settings", className: "grid gap-4 border-t border-gray-100 p-4 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Template name" }), _jsx(Input, { value: draftTemplate.name, onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1413
|
+
...currentTemplate,
|
|
1414
|
+
name: event.target.value,
|
|
1415
|
+
})), placeholder: "Project template name", className: "text-xs md:text-xs", "data-testid": "project-template-name-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: draftTemplate.description ?? "", onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1416
|
+
...currentTemplate,
|
|
1417
|
+
description: event.target.value,
|
|
1418
|
+
})), rows: 4, placeholder: "Describe when to use this template", "data-testid": "project-template-description-input" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Default cost limit" }), _jsx(Input, { type: "number", value: draftTemplate.defaultCostLimit ?? "", onChange: (event) => applyDraftChange((currentTemplate) => ({
|
|
1419
|
+
...currentTemplate,
|
|
1420
|
+
defaultCostLimit: event.target.value.trim() === ""
|
|
1421
|
+
? null
|
|
1422
|
+
: Number(event.target.value),
|
|
1423
|
+
})), placeholder: "0", className: "text-xs md:text-xs", "data-testid": "project-template-default-cost-limit-input" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-zinc-900", children: "Disabled" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "Makes the template unavailable for project creation and template resolution." })] }), _jsx(Switch, { checked: draftTemplate.disabled === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1424
|
+
...currentTemplate,
|
|
1425
|
+
disabled: checked,
|
|
1426
|
+
})), className: "data-[state=checked]:bg-amber-600 data-[state=checked]:shadow-inner dark:data-[state=checked]:bg-amber-600", "aria-label": "Disable this project template", "data-testid": "project-template-disabled-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-zinc-900", children: "Hide from create dialog" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "Keeps the template active, but removes it from the create project dialog." })] }), _jsx(Switch, { checked: draftTemplate.hideFromCreateDialog === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1427
|
+
...currentTemplate,
|
|
1428
|
+
hideFromCreateDialog: checked,
|
|
1429
|
+
})), "aria-label": "Hide this project template from the create dialog", "data-testid": "project-template-hide-from-create-dialog-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-xs font-medium text-zinc-900", children: "Open in wizard mode" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "New projects created from this template start in taskboard wizard mode." })] }), _jsx(Switch, { checked: draftTemplate.openInWizardMode === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
|
|
1430
|
+
...currentTemplate,
|
|
1431
|
+
openInWizardMode: checked,
|
|
1432
|
+
})), "aria-label": "Open new projects from this template in wizard mode", "data-testid": "project-template-open-in-wizard-mode-switch" })] })] }))] }), _jsxs("section", { className: "flex min-h-0 flex-1 flex-col overflow-hidden rounded-lg border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-gray-100 px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-2.5", children: [_jsx("span", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-gray-100 text-gray-500", children: _jsx(GitBranch, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }), _jsxs("div", { children: [_jsx("h3", { className: "text-xs font-semibold tracking-wide text-gray-800", children: "Template Task Editor" }), _jsx("p", { className: "text-[11px] leading-tight text-gray-400", children: "Add task templates, arrange them in the graph, and define dependencies." })] })] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void handleOpenCreateTaskDialog(), disabled: creatingTask, "data-testid": "project-template-add-task-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Add Task"] })] }), _jsx("div", { className: "min-h-[360px] flex-1 overflow-hidden border-b border-gray-100", children: _jsx(Splitter, { direction: "vertical", localStorageKey: "settings-project-template-graph-task-splitter-v1", className: "h-full", panels: [
|
|
1433
|
+
{
|
|
1434
|
+
name: "project-template-graph",
|
|
1435
|
+
defaultSize: 400,
|
|
1436
|
+
className: "min-h-0",
|
|
1437
|
+
content: (_jsx("div", { className: "h-full min-h-0 overflow-hidden bg-slate-50/40", "data-testid": "project-template-graph", children: _jsx(DependencyGraphView, { projectId: draftTemplate.id, layoutKey: `project-template:${draftTemplate.id}`, tasks: graphTasks, dependencies: graphDependencies, miniMapWidth: 56, miniMapHeight: 42, orientation: "horizontal", autoLayoutStrategy: "hierarchy", savedLayout: draftTemplate.graphLayout, selectedTaskId: selectedTaskId, selectedDependencyId: selectedDependencyId, onSelectTask: handleSelectTask, onSelectDependency: handleSelectDependencyFromGraph, onClearDependencySelection: handleClearDependencySelection, onAddDependentTaskFromNode: (taskId) => {
|
|
1438
|
+
void handleOpenCreateDependentTaskDialogForTask(taskId);
|
|
1439
|
+
}, onAddChildTaskFromNode: (taskId) => {
|
|
1440
|
+
void handleOpenAddChildTaskDialogForTask(taskId);
|
|
1441
|
+
}, onRemoveTask: removeTaskTemplateById, allowDependencyConnect: true, onCreateDependency: handleCreateDependencyFromGraph, onCreateChildRelationship: handleCreateChildRelationshipFromGraph, canPersistLayout: true, layoutSaveDebounceMs: 0, highlightBlockedTasks: false, showExecutionStateBadges: false, emptyStateTitle: "No task templates yet", emptyStateDescription: "Add task templates to start designing the project flow.", onPersistLayout: async (layout) => {
|
|
1442
|
+
const nextLayout = {
|
|
1443
|
+
...layout,
|
|
1444
|
+
projectTemplateId: draftTemplate.id,
|
|
1445
|
+
};
|
|
1446
|
+
applyDraftChange((currentTemplate) => ({
|
|
1559
1447
|
...currentTemplate,
|
|
1560
|
-
|
|
1561
|
-
}))
|
|
1562
|
-
|
|
1448
|
+
graphLayout: nextLayout,
|
|
1449
|
+
}));
|
|
1450
|
+
return nextLayout;
|
|
1451
|
+
} }) })),
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
name: "project-template-task-details",
|
|
1455
|
+
defaultSize: "auto",
|
|
1456
|
+
className: "min-h-0",
|
|
1457
|
+
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 pt-4 pb-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "text-xs font-semibold text-gray-900", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), selectedTask.disabled ? (_jsx(Badge, { variant: "outline", className: "text-[10px] uppercase", children: "Disabled" })) : null] }), _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 pt-3 pb-4", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Task title" }), _jsx(Input, { value: selectedTask.title, onChange: (event) => updateSelectedTask((currentTask) => ({
|
|
1458
|
+
...currentTask,
|
|
1459
|
+
title: event.target.value,
|
|
1460
|
+
})), 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) => ({
|
|
1461
|
+
...currentTask,
|
|
1462
|
+
description: event.target.value,
|
|
1463
|
+
})), 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) => ({
|
|
1464
|
+
...currentTask,
|
|
1465
|
+
priority: value || null,
|
|
1466
|
+
})), options: PRIORITY_OPTIONS, "data-testid": "project-template-task-priority-select" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(Label, { htmlFor: `project-template-task-disabled-${selectedTask.id}`, className: "text-xs font-medium text-zinc-900", children: "Disabled" }), _jsx("div", { className: "mt-0.5 text-xs text-zinc-500", children: "Keep this task in the template, but skip it when projects are created." })] }), _jsx(Switch, { id: `project-template-task-disabled-${selectedTask.id}`, checked: selectedTask.disabled === true, onCheckedChange: (checked) => updateSelectedTask((currentTask) => ({
|
|
1467
|
+
...currentTask,
|
|
1468
|
+
disabled: checked,
|
|
1469
|
+
})), "aria-label": "Disable this task template", "data-testid": "project-template-task-disabled-switch" })] }), _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) => ({
|
|
1470
|
+
...currentTask,
|
|
1471
|
+
assigneeType: next?.assigneeType ?? null,
|
|
1472
|
+
assigneeId: next?.assigneeId ?? null,
|
|
1473
|
+
agentProfileId: next?.assigneeType === "Agent"
|
|
1474
|
+
? next.assigneeId
|
|
1475
|
+
: null,
|
|
1476
|
+
})), 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 ===
|
|
1477
|
+
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 ||
|
|
1478
|
+
"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
|
|
1479
|
+
? "Add more task templates to create dependencies."
|
|
1480
|
+
: "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 outline-none transition-colors", selectedDependencyId === task.id
|
|
1481
|
+
? "border-amber-300 bg-amber-50 ring-1 ring-amber-200"
|
|
1482
|
+
: "border-gray-200"), "aria-selected": selectedDependencyId === task.id, onClick: () => setSelectedDependencyId(task.id), onFocus: () => setSelectedDependencyId(task.id), "data-testid": `project-template-dependency-row-${task.id}`, children: [_jsx("span", { className: "min-w-0 truncate font-medium text-gray-800", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "shrink-0 rounded p-0.5 text-gray-400 hover:bg-gray-100 hover:text-gray-700", "aria-label": `Remove dependency on ${task.title}`, onClick: () => handleRemoveDependency(task.id), "data-testid": `project-template-remove-dependency-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3", "data-testid": "project-template-child-tasks-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800", children: [_jsx(CornerDownRight, { className: "h-4 w-4 text-gray-500", strokeWidth: 1.5 }), "Child tasks"] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: () => void handleOpenAddChildTaskDialog(), disabled: creatingChildTask, "aria-label": "Add child task", "data-testid": "project-template-add-child-task-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }), _jsx("p", { className: "mb-2 text-[11px] leading-snug text-gray-500", children: "Tasks that run after this one (they depend on this task)." }), childTaskTemplates.length === 0 ? (_jsx("div", { className: "text-xs text-gray-500", children: "No child tasks yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: childTaskTemplates.map((task) => (_jsxs("li", { className: "flex items-center justify-between gap-2 rounded-md border border-gray-200 bg-white px-3 py-2 text-xs", "data-testid": `project-template-child-task-row-${task.id}`, children: [_jsx("span", { className: "min-w-0 truncate font-medium text-gray-800", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "shrink-0 rounded p-0.5 text-gray-400 hover:bg-gray-100 hover:text-gray-700", "aria-label": `Unlink child task ${task.title}`, onClick: () => handleUnlinkChildTask(task.id), "data-testid": `project-template-unlink-child-task-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] })] })] }) })] })) })),
|
|
1483
|
+
},
|
|
1484
|
+
] }) })] })] })] })) : (_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." })] }) }));
|
|
1485
|
+
const agentPanelContent = (_jsx(ProjectTemplateAgentPanel, { templateName: draftTemplate?.name ?? null, agentId: templateAgentId, loading: templateAgentLoading, resetting: templateAgentResetting, error: templateAgentError, onStartOver: () => void handleResetTemplateAgent() }));
|
|
1563
1486
|
const rightPanelContent = editingAgentProfile ? (_jsx(AgentProfileEditorPanel, { agent: editingAgentProfile, onClose: handleCloseEditingAgentProfile, actions: _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void handleDuplicateAssignedAgentProfile(), disabled: !selectedAgentProfileId ||
|
|
1564
1487
|
!editContext ||
|
|
1565
1488
|
duplicatingAgentProfile ||
|
|
1566
1489
|
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);
|
|
1567
|
-
const rightPanelForSplitter = !isMobile && desktopAssistantOnly ? (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-white", "data-testid": "project-template-desktop-assistant-only", children: [_jsx("div", { className: "flex shrink-0 items-center gap-2 border-b border-gray-200 bg-white px-2 py-2", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "gap-1 px-2", onClick: () => setDesktopAssistantOnly(false), "data-testid": "project-template-desktop-back-from-assistant-only", children: [_jsx(ChevronLeft, { className: "h-5 w-5", strokeWidth: 1.5 }), "Back to template editor"] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden", children: rightPanelContent })] })) : (rightPanelContent);
|
|
1568
1490
|
const panels = [
|
|
1569
1491
|
{
|
|
1570
1492
|
name: "project-template-list",
|
|
1571
1493
|
defaultSize: 360,
|
|
1572
1494
|
content: listContent,
|
|
1573
1495
|
className: "overflow-hidden",
|
|
1574
|
-
hidden: desktopAssistantOnly || (isMobile && mobileView !== "list"),
|
|
1575
1496
|
},
|
|
1576
1497
|
{
|
|
1577
1498
|
name: "project-template-detail",
|
|
1578
1499
|
defaultSize: "auto",
|
|
1579
1500
|
content: detailContent,
|
|
1580
1501
|
className: "overflow-hidden",
|
|
1581
|
-
hidden: desktopAssistantOnly || (isMobile && mobileView !== "detail"),
|
|
1582
1502
|
},
|
|
1583
1503
|
{
|
|
1584
1504
|
name: "project-template-agent",
|
|
1585
1505
|
defaultSize: 460,
|
|
1586
|
-
content:
|
|
1506
|
+
content: rightPanelContent,
|
|
1587
1507
|
className: "overflow-hidden",
|
|
1588
1508
|
collapsible: true,
|
|
1589
|
-
hidden: isMobile && mobileView !== "agent",
|
|
1590
1509
|
},
|
|
1591
1510
|
];
|
|
1592
1511
|
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-full", "data-testid": "project-template-editor", onKeyDownCapture: handleProjectTemplateEditorKeyDownCapture, children: _jsx(Splitter, { panels: panels, localStorageKey: "settings-project-templates-panel-splitter-v2", direction: "horizontal", className: "h-full" }) }), _jsx(Dialog, { open: isCreateTaskDialogOpen, onOpenChange: (open) => {
|