@parhelia/core 0.1.12439 → 0.1.12451
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/types.d.ts +4 -0
- package/dist/config/types.js.map +1 -1
- package/dist/editor/ConfirmationDialog.js +20 -4
- package/dist/editor/ConfirmationDialog.js.map +1 -1
- package/dist/editor/ContentTree.js +7 -2
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +65 -3
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +5 -0
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +2 -0
- package/dist/editor/ai/ToolCallDisplay.js +54 -11
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/types.d.ts +2 -0
- package/dist/editor/services/serviceHelper.js +5 -2
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplateAgentPanel.d.ts +7 -1
- 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 +143 -84
- package/dist/editor/settings/panels/ProjectTemplatesPanel.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/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/TaskBoardWorkspace.js +1 -1
- package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
- package/dist/task-board/components/CreateProjectDialog.js +2 -1
- package/dist/task-board/components/CreateProjectDialog.js.map +1 -1
- package/dist/task-board/types.d.ts +3 -0
- package/dist/task-board/utils/taskDependencyOrdering.d.ts +6 -0
- package/dist/task-board/utils/taskDependencyOrdering.js +138 -1
- package/dist/task-board/utils/taskDependencyOrdering.js.map +1 -1
- package/dist/task-board/views/DependencyGraphView.d.ts +5 -2
- package/dist/task-board/views/DependencyGraphView.js +174 -52
- package/dist/task-board/views/DependencyGraphView.js.map +1 -1
- package/dist/task-board/views/WizardView.js +26 -24
- package/dist/task-board/views/WizardView.js.map +1 -1
- package/dist/tour/Tour.js +63 -0
- package/dist/tour/Tour.js.map +1 -1
- package/dist/tour/default-tour.js +7 -0
- package/dist/tour/default-tour.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "@xyflow/react/dist/style.css";
|
|
2
|
-
import type { GraphLayoutSnapshot, TaskDependency, TaskItem, ProjectPermission } from "../types";
|
|
2
|
+
import type { GraphOrientation, GraphLayoutSnapshot, TaskDependency, TaskItem, ProjectPermission } from "../types";
|
|
3
3
|
export declare function DependencyGraphView(props: {
|
|
4
4
|
projectId?: string;
|
|
5
5
|
layoutKey?: string;
|
|
@@ -19,8 +19,9 @@ export declare function DependencyGraphView(props: {
|
|
|
19
19
|
showExecutionStateBadges?: boolean;
|
|
20
20
|
emptyStateTitle?: string;
|
|
21
21
|
emptyStateDescription?: string;
|
|
22
|
-
orientation?:
|
|
22
|
+
orientation?: GraphOrientation;
|
|
23
23
|
autoLayoutStrategy?: "allEdges" | "hierarchy";
|
|
24
|
+
showOrientationToggle?: boolean;
|
|
24
25
|
/** Debounce before persisting layout (API or parent callback). Use 0 for immediate sync (e.g. project template draft). */
|
|
25
26
|
layoutSaveDebounceMs?: number;
|
|
26
27
|
/** When set, shows a create-dependent-task action near the right handle of each node. */
|
|
@@ -39,4 +40,6 @@ export declare function DependencyGraphView(props: {
|
|
|
39
40
|
miniMapWidth?: number;
|
|
40
41
|
/** MiniMap (overview) height in px. */
|
|
41
42
|
miniMapHeight?: number;
|
|
43
|
+
/** When false, the overview minimap is not rendered (e.g. narrow mobile layouts). */
|
|
44
|
+
showMiniMap?: boolean;
|
|
42
45
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { ReactFlow, Controls, MiniMap, useNodesState, useEdgesState, Handle, Position, MarkerType, } from "@xyflow/react";
|
|
4
4
|
import Dagre from "@dagrejs/dagre";
|
|
5
5
|
import "@xyflow/react/dist/style.css";
|
|
@@ -46,6 +46,14 @@ function TaskGraphNode({ data }) {
|
|
|
46
46
|
const priorityCfg = data.priority ? PRIORITY_CONFIG[data.priority] : null;
|
|
47
47
|
const PriorityIcon = priorityCfg?.icon;
|
|
48
48
|
const actionButtonClass = "nodrag nopan absolute z-20 flex h-5 w-5 items-center justify-center rounded-full border border-slate-200 bg-white text-slate-500 shadow-sm transition-colors hover:border-blue-200 hover:bg-blue-50 hover:text-blue-600";
|
|
49
|
+
const dependentButtonClass = data.dependencySourceHandle === "right"
|
|
50
|
+
? "top-1/2 right-0 translate-x-[calc(100%+6px)] -translate-y-1/2"
|
|
51
|
+
: "bottom-0 left-1/2 -translate-x-1/2 translate-y-[calc(100%+6px)]";
|
|
52
|
+
const dependentTooltipSide = data.dependencySourceHandle === "right" ? "right" : "bottom";
|
|
53
|
+
const subtaskButtonClass = data.hierarchySourceHandle === "right"
|
|
54
|
+
? "top-1/2 right-0 translate-x-[calc(100%+6px)] -translate-y-1/2"
|
|
55
|
+
: "bottom-0 left-1/2 -translate-x-1/2 translate-y-[calc(100%+6px)]";
|
|
56
|
+
const subtaskTooltipSide = data.hierarchySourceHandle === "right" ? "right" : "bottom";
|
|
49
57
|
const nodeSurfaceClass = data.isSelected
|
|
50
58
|
? "ring-primary border-primary/50 ring-2 bg-white"
|
|
51
59
|
: data.isBlocked
|
|
@@ -56,19 +64,19 @@ function TaskGraphNode({ data }) {
|
|
|
56
64
|
return (_jsxs("div", { className: cn("relative cursor-pointer rounded-lg border px-3 py-2 shadow-sm transition-all", nodeSurfaceClass), style: { width: NODE_WIDTH }, "data-testid": `dependency-graph-node-${data.taskId}`, children: [_jsx(Handle, { type: "target", position: Position.Left, id: "left", className: HANDLE_CLASS, "data-testid": `dependency-graph-target-left-${data.taskId}` }), _jsx(Handle, { type: "target", position: Position.Top, id: "top", className: HANDLE_CLASS, "data-testid": `dependency-graph-target-top-${data.taskId}` }), _jsxs("div", { className: "flex items-start justify-between gap-1", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center justify-between gap-1", children: [_jsx("span", { className: "truncate text-[10px] font-medium text-slate-400", children: data.taskKey || data.taskId.slice(0, 8).toUpperCase() }), PriorityIcon && (_jsx(PriorityIcon, { className: cn("h-3 w-3 shrink-0", priorityCfg.color) }))] }), data.onRemoveTask && (_jsx("button", { type: "button", className: "-mt-px -mr-0.5 shrink-0 rounded p-0.5 text-slate-400 transition-colors hover:bg-red-50 hover:text-red-600", "aria-label": "Remove task", "data-testid": `dependency-graph-remove-task-${data.taskId}`, onClick: (event) => {
|
|
57
65
|
event.stopPropagation();
|
|
58
66
|
data.onRemoveTask?.(data.taskId);
|
|
59
|
-
}, children: _jsx(Trash2, { className: "h-2.5 w-2.5", strokeWidth: 1.5 }) }))] }), _jsx("div", { className: "mt-0.5 truncate text-xs font-medium text-slate-800", children: data.title }), _jsxs("div", { className: "mt-1 flex items-center gap-1.5", children: [executionDisplay ? (_jsxs(Badge, { variant: executionDisplay.variant, className: cn("h-5 max-w-full px-1.5 text-[10px] font-bold tracking-wider uppercase", executionDisplay.className), children: [executionDisplay.showSpinner && (_jsx(Loader2, { className: "mr-1 h-2.5 w-2.5 animate-spin" })), executionDisplay.label] })) : (_jsxs("span", { className: cn("inline-flex items-center gap-0.5 rounded-full px-1.5 py-0 text-[10px] font-medium", statusStyle.bg, statusStyle.text), children: [_jsx(StatusIcon, { className: "h-2.5 w-2.5" }), getTaskStatusLabel(status)] })), data.assigneeDisplayName && (_jsxs("span", { className: "truncate text-[10px] text-slate-400", children: ["@", data.assigneeDisplayName] }))] }), data.onAddDependentTaskFromNode && (_jsxs(Tooltip, { delayDuration: 250, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", className: cn(actionButtonClass,
|
|
67
|
+
}, children: _jsx(Trash2, { className: "h-2.5 w-2.5", strokeWidth: 1.5 }) }))] }), _jsx("div", { className: "mt-0.5 truncate text-xs font-medium text-slate-800", children: data.title }), _jsxs("div", { className: "mt-1 flex items-center gap-1.5", children: [executionDisplay ? (_jsxs(Badge, { variant: executionDisplay.variant, className: cn("h-5 max-w-full px-1.5 text-[10px] font-bold tracking-wider uppercase", executionDisplay.className), children: [executionDisplay.showSpinner && (_jsx(Loader2, { className: "mr-1 h-2.5 w-2.5 animate-spin" })), executionDisplay.label] })) : (_jsxs("span", { className: cn("inline-flex items-center gap-0.5 rounded-full px-1.5 py-0 text-[10px] font-medium", statusStyle.bg, statusStyle.text), children: [_jsx(StatusIcon, { className: "h-2.5 w-2.5" }), getTaskStatusLabel(status)] })), data.assigneeDisplayName && (_jsxs("span", { className: "truncate text-[10px] text-slate-400", children: ["@", data.assigneeDisplayName] }))] }), data.onAddDependentTaskFromNode && (_jsxs(Tooltip, { delayDuration: 250, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", className: cn(actionButtonClass, dependentButtonClass), "aria-label": "Add dependent task", "data-testid": `dependency-graph-add-dependent-task-${data.taskId}`, onClick: (event) => {
|
|
60
68
|
event.stopPropagation();
|
|
61
69
|
data.onSelect(data.taskId);
|
|
62
70
|
data.onAddDependentTaskFromNode?.(data.taskId);
|
|
63
71
|
}, onMouseDown: (event) => {
|
|
64
72
|
event.stopPropagation();
|
|
65
|
-
}, children: _jsx(Plus, { className: "h-3 w-3", strokeWidth: 1.75 }) }) }), _jsx(TooltipContent, { side:
|
|
73
|
+
}, children: _jsx(Plus, { className: "h-3 w-3", strokeWidth: 1.75 }) }) }), _jsx(TooltipContent, { side: dependentTooltipSide, sideOffset: 8, children: "Add dependent task" })] })), data.onAddChildTaskFromNode && (_jsxs(Tooltip, { delayDuration: 250, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", className: cn(actionButtonClass, subtaskButtonClass), "aria-label": "Add subtask", "data-testid": `dependency-graph-add-subtask-${data.taskId}`, onClick: (event) => {
|
|
66
74
|
event.stopPropagation();
|
|
67
75
|
data.onSelect(data.taskId);
|
|
68
76
|
data.onAddChildTaskFromNode?.(data.taskId);
|
|
69
77
|
}, onMouseDown: (event) => {
|
|
70
78
|
event.stopPropagation();
|
|
71
|
-
}, children: _jsx(Plus, { className: "h-3 w-3", strokeWidth: 1.75 }) }) }), _jsx(TooltipContent, { side:
|
|
79
|
+
}, children: _jsx(Plus, { className: "h-3 w-3", strokeWidth: 1.75 }) }) }), _jsx(TooltipContent, { side: subtaskTooltipSide, sideOffset: 8, children: "Add subtask" })] })), _jsx(Handle, { type: "source", position: Position.Right, id: "right", className: HANDLE_CLASS, "data-testid": `dependency-graph-source-right-${data.taskId}` }), _jsx(Handle, { type: "source", position: Position.Bottom, id: "bottom", className: HANDLE_CLASS, "data-testid": `dependency-graph-source-bottom-${data.taskId}` })] }));
|
|
72
80
|
}
|
|
73
81
|
const nodeTypes = {
|
|
74
82
|
taskNode: TaskGraphNode,
|
|
@@ -76,13 +84,30 @@ const nodeTypes = {
|
|
|
76
84
|
const HIERARCHY_CHILD_INDENT = 24;
|
|
77
85
|
const HIERARCHY_CHILD_GAP = 32;
|
|
78
86
|
const HIERARCHY_SUBTREE_GAP = 80;
|
|
87
|
+
function normalizeGraphOrientation(orientation) {
|
|
88
|
+
return orientation === "vertical" ? "vertical" : "horizontal";
|
|
89
|
+
}
|
|
90
|
+
function getDependencyHandles(orientation) {
|
|
91
|
+
return orientation === "horizontal"
|
|
92
|
+
? { source: "right", target: "left" }
|
|
93
|
+
: { source: "bottom", target: "top" };
|
|
94
|
+
}
|
|
95
|
+
function getHierarchyHandles(orientation, autoLayoutStrategy) {
|
|
96
|
+
if (autoLayoutStrategy !== "hierarchy") {
|
|
97
|
+
return getDependencyHandles(orientation);
|
|
98
|
+
}
|
|
99
|
+
return orientation === "horizontal"
|
|
100
|
+
? { source: "bottom", target: "left" }
|
|
101
|
+
: { source: "right", target: "left" };
|
|
102
|
+
}
|
|
79
103
|
/**
|
|
80
104
|
* Compound layout for the hierarchy strategy: each parent–children group is
|
|
81
105
|
* laid out vertically (parent on top, children stacked below with a slight
|
|
82
106
|
* indent), and then the resulting subtree "super-nodes" are arranged
|
|
83
|
-
*
|
|
107
|
+
* in the selected orientation via Dagre using the dependency edges between
|
|
108
|
+
* them.
|
|
84
109
|
*/
|
|
85
|
-
function layoutGraphHierarchy(nodes, edges) {
|
|
110
|
+
function layoutGraphHierarchy(nodes, edges, orientation) {
|
|
86
111
|
if (nodes.length === 0)
|
|
87
112
|
return { nodes, edges };
|
|
88
113
|
const childrenOf = new Map();
|
|
@@ -127,7 +152,11 @@ function layoutGraphHierarchy(nodes, edges) {
|
|
|
127
152
|
}
|
|
128
153
|
}
|
|
129
154
|
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
|
130
|
-
g.setGraph({
|
|
155
|
+
g.setGraph({
|
|
156
|
+
rankdir: orientation === "horizontal" ? "LR" : "TB",
|
|
157
|
+
nodesep: 40,
|
|
158
|
+
ranksep: HIERARCHY_SUBTREE_GAP,
|
|
159
|
+
});
|
|
131
160
|
for (const [rootId, data] of subtrees) {
|
|
132
161
|
g.setNode(rootId, { width: data.width, height: data.height });
|
|
133
162
|
}
|
|
@@ -169,7 +198,7 @@ function layoutGraphHierarchy(nodes, edges) {
|
|
|
169
198
|
function layoutGraph(nodes, edges, orientation, autoLayoutStrategy) {
|
|
170
199
|
if (autoLayoutStrategy === "hierarchy" &&
|
|
171
200
|
edges.some((e) => e.data?.relationship === "hierarchy")) {
|
|
172
|
-
return layoutGraphHierarchy(nodes, edges);
|
|
201
|
+
return layoutGraphHierarchy(nodes, edges, orientation);
|
|
173
202
|
}
|
|
174
203
|
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
|
175
204
|
g.setGraph({
|
|
@@ -204,6 +233,8 @@ function buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, b
|
|
|
204
233
|
const childRelationshipKeys = new Set(visibleTasks
|
|
205
234
|
.filter((task) => !!task.parentTaskId)
|
|
206
235
|
.map((task) => `${task.parentTaskId}->${task.taskId}`));
|
|
236
|
+
const dependencyHandles = getDependencyHandles(orientation);
|
|
237
|
+
const hierarchyHandles = getHierarchyHandles(orientation, autoLayoutStrategy);
|
|
207
238
|
const nodes = visibleTasks.map((task) => ({
|
|
208
239
|
id: task.taskId,
|
|
209
240
|
type: "taskNode",
|
|
@@ -220,16 +251,18 @@ function buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, b
|
|
|
220
251
|
isSelected: task.taskId === selectedTaskId,
|
|
221
252
|
isBlocked: blockedTaskIds.has(task.taskId),
|
|
222
253
|
orientation,
|
|
254
|
+
dependencySourceHandle: dependencyHandles.source,
|
|
255
|
+
hierarchySourceHandle: hierarchyHandles.source,
|
|
223
256
|
onSelect,
|
|
224
257
|
onAddDependentTaskFromNode,
|
|
225
258
|
onAddChildTaskFromNode,
|
|
226
259
|
onRemoveTask,
|
|
227
260
|
},
|
|
228
261
|
}));
|
|
229
|
-
const depSourceHandle =
|
|
230
|
-
const depTargetHandle =
|
|
231
|
-
const hierSourceHandle =
|
|
232
|
-
const hierTargetHandle =
|
|
262
|
+
const depSourceHandle = dependencyHandles.source;
|
|
263
|
+
const depTargetHandle = dependencyHandles.target;
|
|
264
|
+
const hierSourceHandle = hierarchyHandles.source;
|
|
265
|
+
const hierTargetHandle = hierarchyHandles.target;
|
|
233
266
|
const dependencyEdges = dependencies
|
|
234
267
|
.filter((dep) => taskMap.has(dep.taskId) &&
|
|
235
268
|
taskMap.has(dep.dependsOnTaskId) &&
|
|
@@ -323,12 +356,15 @@ function buildChildRelationshipKeys(tasks) {
|
|
|
323
356
|
.filter((task) => !!task.parentTaskId)
|
|
324
357
|
.map((task) => `${task.parentTaskId}->${task.taskId}`));
|
|
325
358
|
}
|
|
326
|
-
function isHierarchyConnectionValid(connection, tasks) {
|
|
359
|
+
function isHierarchyConnectionValid(connection, tasks, orientation, autoLayoutStrategy) {
|
|
360
|
+
if (autoLayoutStrategy !== "hierarchy") {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
327
363
|
const { source, sourceHandle, target, targetHandle } = connection;
|
|
328
364
|
if (!source || !target || source === target) {
|
|
329
365
|
return false;
|
|
330
366
|
}
|
|
331
|
-
if (sourceHandle !==
|
|
367
|
+
if (sourceHandle !== getHierarchyHandles(orientation, autoLayoutStrategy).source) {
|
|
332
368
|
return false;
|
|
333
369
|
}
|
|
334
370
|
if (targetHandle && targetHandle !== "left" && targetHandle !== "top") {
|
|
@@ -348,12 +384,12 @@ function isHierarchyConnectionValid(connection, tasks) {
|
|
|
348
384
|
}
|
|
349
385
|
return !buildChildRelationshipKeys(tasks).has(`${source}->${target}`);
|
|
350
386
|
}
|
|
351
|
-
function isDependencyConnectionValid(connection, tasks, dependencies) {
|
|
387
|
+
function isDependencyConnectionValid(connection, tasks, dependencies, orientation) {
|
|
352
388
|
const { source, sourceHandle, target, targetHandle } = connection;
|
|
353
389
|
if (!source || !target || source === target) {
|
|
354
390
|
return false;
|
|
355
391
|
}
|
|
356
|
-
if (sourceHandle !==
|
|
392
|
+
if (sourceHandle !== getDependencyHandles(orientation).source) {
|
|
357
393
|
return false;
|
|
358
394
|
}
|
|
359
395
|
if (targetHandle && targetHandle !== "left" && targetHandle !== "top") {
|
|
@@ -368,15 +404,18 @@ function isDependencyConnectionValid(connection, tasks, dependencies) {
|
|
|
368
404
|
}
|
|
369
405
|
return !buildChildRelationshipKeys(tasks).has(`${source}->${target}`);
|
|
370
406
|
}
|
|
371
|
-
function isGraphConnectionValid(connection, tasks, dependencies) {
|
|
372
|
-
|
|
373
|
-
|
|
407
|
+
function isGraphConnectionValid(connection, tasks, dependencies, orientation, autoLayoutStrategy) {
|
|
408
|
+
const hierarchySourceHandle = getHierarchyHandles(orientation, "hierarchy").source;
|
|
409
|
+
if (autoLayoutStrategy === "hierarchy" &&
|
|
410
|
+
connection.sourceHandle === hierarchySourceHandle) {
|
|
411
|
+
return isHierarchyConnectionValid(connection, tasks, orientation, autoLayoutStrategy);
|
|
374
412
|
}
|
|
375
|
-
return isDependencyConnectionValid(connection, tasks, dependencies);
|
|
413
|
+
return isDependencyConnectionValid(connection, tasks, dependencies, orientation);
|
|
376
414
|
}
|
|
377
|
-
function createLayoutSignature(layoutKey, nodes, viewport) {
|
|
415
|
+
function createLayoutSignature(layoutKey, nodes, viewport, orientation) {
|
|
378
416
|
return JSON.stringify({
|
|
379
417
|
layoutKey,
|
|
418
|
+
orientation,
|
|
380
419
|
nodes: nodes
|
|
381
420
|
.map((node) => ({
|
|
382
421
|
taskId: node.id,
|
|
@@ -394,11 +433,17 @@ function createLayoutSignature(layoutKey, nodes, viewport) {
|
|
|
394
433
|
});
|
|
395
434
|
}
|
|
396
435
|
export function DependencyGraphView(props) {
|
|
397
|
-
const { projectId, layoutKey, tasks, dependencies, savedLayout, selectedTaskId, selectedDependencyId = null, onSelectTask, onSelectDependency, onClearDependencySelection, permission, canPersistLayout: canPersistLayoutOverride, onPersistLayout, onLayoutSaved, highlightBlockedTasks = true, showExecutionStateBadges = true, emptyStateTitle = "No tasks to visualize", emptyStateDescription = "Create tasks in this project to see them in the dependency graph.", orientation = "vertical", autoLayoutStrategy = "allEdges", layoutSaveDebounceMs = SAVE_DEBOUNCE_MS, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask, allowDependencyConnect = false, onCreateDependency, onCreateChildRelationship, miniMapWidth, miniMapHeight, } = props;
|
|
436
|
+
const { projectId, layoutKey, tasks, dependencies, savedLayout, selectedTaskId, selectedDependencyId = null, onSelectTask, onSelectDependency, onClearDependencySelection, permission, canPersistLayout: canPersistLayoutOverride, onPersistLayout, onLayoutSaved, highlightBlockedTasks = true, showExecutionStateBadges = true, emptyStateTitle = "No tasks to visualize", emptyStateDescription = "Create tasks in this project to see them in the dependency graph.", orientation = "vertical", autoLayoutStrategy = "allEdges", showOrientationToggle = false, layoutSaveDebounceMs = SAVE_DEBOUNCE_MS, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask, allowDependencyConnect = false, onCreateDependency, onCreateChildRelationship, miniMapWidth, miniMapHeight, showMiniMap = true, } = props;
|
|
398
437
|
const canPersistLayout = typeof canPersistLayoutOverride === "boolean"
|
|
399
438
|
? canPersistLayoutOverride
|
|
400
439
|
: permission === "Owner" || permission === "Editor";
|
|
401
440
|
const effectiveLayoutKey = layoutKey ?? projectId ?? "graph";
|
|
441
|
+
const fallbackOrientation = normalizeGraphOrientation(orientation);
|
|
442
|
+
const savedLayoutOrientation = savedLayout
|
|
443
|
+
? normalizeGraphOrientation(savedLayout.orientation ?? fallbackOrientation)
|
|
444
|
+
: null;
|
|
445
|
+
const [transientOrientation, setTransientOrientation] = useState(null);
|
|
446
|
+
const effectiveOrientation = transientOrientation ?? savedLayoutOrientation ?? fallbackOrientation;
|
|
402
447
|
const taskMap = useMemo(() => {
|
|
403
448
|
const m = new Map();
|
|
404
449
|
for (const t of tasks)
|
|
@@ -427,13 +472,13 @@ export function DependencyGraphView(props) {
|
|
|
427
472
|
return blocked;
|
|
428
473
|
}, [dependencies, highlightBlockedTasks, taskMap]);
|
|
429
474
|
const onSelect = useCallback((taskId) => onSelectTask(taskId), [onSelectTask]);
|
|
430
|
-
const { nodes: initialNodes, edges: initialEdges } = useMemo(() => buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds,
|
|
475
|
+
const { nodes: initialNodes, edges: initialEdges } = useMemo(() => buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, effectiveOrientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask), [
|
|
431
476
|
tasks,
|
|
432
477
|
dependencies,
|
|
433
478
|
selectedTaskId,
|
|
434
479
|
selectedDependencyId,
|
|
435
480
|
blockedTaskIds,
|
|
436
|
-
|
|
481
|
+
effectiveOrientation,
|
|
437
482
|
showExecutionStateBadges,
|
|
438
483
|
autoLayoutStrategy,
|
|
439
484
|
onSelect,
|
|
@@ -444,6 +489,7 @@ export function DependencyGraphView(props) {
|
|
|
444
489
|
const [nodes, setNodes, onNodesChangeBase] = useNodesState(initialNodes);
|
|
445
490
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
|
446
491
|
const nodesRef = useRef(nodes);
|
|
492
|
+
const suppressNodeSelectionUntilRef = useRef(0);
|
|
447
493
|
const onNodesChange = useCallback((changes) => {
|
|
448
494
|
onNodesChangeBase(changes);
|
|
449
495
|
const hasPositionChange = changes.some((c) => c.type === "position" && c.position);
|
|
@@ -461,22 +507,34 @@ export function DependencyGraphView(props) {
|
|
|
461
507
|
const pendingViewportRef = useRef(null);
|
|
462
508
|
const fitViewOnNextSyncRef = useRef(false);
|
|
463
509
|
const skipNextMoveEndSaveRef = useRef(false);
|
|
464
|
-
const
|
|
510
|
+
const pendingSaveOrientationRef = useRef(null);
|
|
465
511
|
const lastSavedSignatureRef = useRef(null);
|
|
466
512
|
const lastAppliedLayoutKeyRef = useRef(null);
|
|
467
513
|
const lastAppliedLayoutSignatureRef = useRef(null);
|
|
468
514
|
const savedLayoutSignature = useMemo(() => savedLayout
|
|
469
515
|
? JSON.stringify({
|
|
516
|
+
orientation: savedLayoutOrientation,
|
|
470
517
|
updatedAt: savedLayout.updatedAt ?? null,
|
|
471
518
|
nodes: savedLayout.nodes ?? [],
|
|
472
519
|
viewport: savedLayout.viewport ?? null,
|
|
473
520
|
})
|
|
474
|
-
: "null", [savedLayout]);
|
|
475
|
-
|
|
521
|
+
: "null", [savedLayout, savedLayoutOrientation]);
|
|
522
|
+
useEffect(() => {
|
|
523
|
+
setTransientOrientation(null);
|
|
524
|
+
pendingSaveOrientationRef.current = null;
|
|
525
|
+
}, [effectiveLayoutKey]);
|
|
526
|
+
useEffect(() => {
|
|
527
|
+
if (transientOrientation &&
|
|
528
|
+
savedLayoutOrientation &&
|
|
529
|
+
transientOrientation === savedLayoutOrientation) {
|
|
530
|
+
setTransientOrientation(null);
|
|
531
|
+
}
|
|
532
|
+
}, [savedLayoutOrientation, transientOrientation]);
|
|
533
|
+
const persistLayout = useCallback(async (nextNodes, viewport, nextOrientation) => {
|
|
476
534
|
if (!canPersistLayout) {
|
|
477
535
|
return;
|
|
478
536
|
}
|
|
479
|
-
const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport);
|
|
537
|
+
const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport, nextOrientation);
|
|
480
538
|
if (signature === lastSavedSignatureRef.current) {
|
|
481
539
|
return;
|
|
482
540
|
}
|
|
@@ -487,6 +545,7 @@ export function DependencyGraphView(props) {
|
|
|
487
545
|
x: node.position.x,
|
|
488
546
|
y: node.position.y,
|
|
489
547
|
})),
|
|
548
|
+
orientation: nextOrientation,
|
|
490
549
|
viewport: viewport == null
|
|
491
550
|
? null
|
|
492
551
|
: {
|
|
@@ -503,6 +562,7 @@ export function DependencyGraphView(props) {
|
|
|
503
562
|
projectId,
|
|
504
563
|
nodes: layoutPayload.nodes,
|
|
505
564
|
viewport: layoutPayload.viewport,
|
|
565
|
+
orientation: layoutPayload.orientation,
|
|
506
566
|
});
|
|
507
567
|
if (result.type !== "success") {
|
|
508
568
|
toast.error(result.summary || "Failed to save graph layout");
|
|
@@ -514,6 +574,7 @@ export function DependencyGraphView(props) {
|
|
|
514
574
|
lastSavedSignatureRef.current = signature;
|
|
515
575
|
if (nextLayout) {
|
|
516
576
|
const incomingSignature = JSON.stringify({
|
|
577
|
+
orientation: normalizeGraphOrientation(nextLayout.orientation ?? nextOrientation),
|
|
517
578
|
updatedAt: nextLayout.updatedAt ?? null,
|
|
518
579
|
nodes: nextLayout.nodes ?? [],
|
|
519
580
|
viewport: nextLayout.viewport ?? null,
|
|
@@ -530,15 +591,16 @@ export function DependencyGraphView(props) {
|
|
|
530
591
|
}, [
|
|
531
592
|
canPersistLayout,
|
|
532
593
|
effectiveLayoutKey,
|
|
594
|
+
effectiveOrientation,
|
|
533
595
|
onLayoutSaved,
|
|
534
596
|
onPersistLayout,
|
|
535
597
|
projectId,
|
|
536
598
|
]);
|
|
537
|
-
const queueLayoutSave = useCallback((nextNodes, viewport) => {
|
|
599
|
+
const queueLayoutSave = useCallback((nextNodes, viewport, nextOrientation = effectiveOrientation) => {
|
|
538
600
|
if (!canPersistLayout) {
|
|
539
601
|
return;
|
|
540
602
|
}
|
|
541
|
-
const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport);
|
|
603
|
+
const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport, nextOrientation);
|
|
542
604
|
if (signature === lastSavedSignatureRef.current) {
|
|
543
605
|
return;
|
|
544
606
|
}
|
|
@@ -547,14 +609,20 @@ export function DependencyGraphView(props) {
|
|
|
547
609
|
saveTimeoutRef.current = null;
|
|
548
610
|
}
|
|
549
611
|
if (layoutSaveDebounceMs === 0) {
|
|
550
|
-
void persistLayout(nextNodes, viewport);
|
|
612
|
+
void persistLayout(nextNodes, viewport, nextOrientation);
|
|
551
613
|
return;
|
|
552
614
|
}
|
|
553
615
|
saveTimeoutRef.current = window.setTimeout(() => {
|
|
554
616
|
saveTimeoutRef.current = null;
|
|
555
|
-
void persistLayout(nextNodes, viewport);
|
|
617
|
+
void persistLayout(nextNodes, viewport, nextOrientation);
|
|
556
618
|
}, layoutSaveDebounceMs);
|
|
557
|
-
}, [
|
|
619
|
+
}, [
|
|
620
|
+
canPersistLayout,
|
|
621
|
+
effectiveLayoutKey,
|
|
622
|
+
effectiveOrientation,
|
|
623
|
+
layoutSaveDebounceMs,
|
|
624
|
+
persistLayout,
|
|
625
|
+
]);
|
|
558
626
|
const restoreViewport = useCallback(() => {
|
|
559
627
|
const instance = reactFlowRef.current;
|
|
560
628
|
if (!instance || nodesRef.current.length === 0) {
|
|
@@ -566,7 +634,7 @@ export function DependencyGraphView(props) {
|
|
|
566
634
|
skipNextMoveEndSaveRef.current = true;
|
|
567
635
|
window.requestAnimationFrame(() => {
|
|
568
636
|
reactFlowRef.current?.setViewport(viewport, { duration: 0 });
|
|
569
|
-
lastSavedSignatureRef.current = createLayoutSignature(effectiveLayoutKey, nodesRef.current, viewport);
|
|
637
|
+
lastSavedSignatureRef.current = createLayoutSignature(effectiveLayoutKey, nodesRef.current, viewport, effectiveOrientation);
|
|
570
638
|
});
|
|
571
639
|
return;
|
|
572
640
|
}
|
|
@@ -577,14 +645,15 @@ export function DependencyGraphView(props) {
|
|
|
577
645
|
skipNextMoveEndSaveRef.current = true;
|
|
578
646
|
window.requestAnimationFrame(() => {
|
|
579
647
|
reactFlowRef.current?.fitView({ padding: 0.2 });
|
|
580
|
-
if (!
|
|
648
|
+
if (!pendingSaveOrientationRef.current) {
|
|
581
649
|
return;
|
|
582
650
|
}
|
|
583
|
-
|
|
651
|
+
const nextOrientation = pendingSaveOrientationRef.current;
|
|
652
|
+
pendingSaveOrientationRef.current = null;
|
|
584
653
|
const viewport = reactFlowRef.current?.getViewport() ?? null;
|
|
585
|
-
queueLayoutSave(nodesRef.current, viewport);
|
|
654
|
+
queueLayoutSave(nodesRef.current, viewport, nextOrientation);
|
|
586
655
|
});
|
|
587
|
-
}, [effectiveLayoutKey, queueLayoutSave]);
|
|
656
|
+
}, [effectiveLayoutKey, effectiveOrientation, queueLayoutSave]);
|
|
588
657
|
useEffect(() => {
|
|
589
658
|
const shouldApplySavedLayout = lastAppliedLayoutKeyRef.current !== effectiveLayoutKey ||
|
|
590
659
|
lastAppliedLayoutSignatureRef.current !== savedLayoutSignature;
|
|
@@ -601,7 +670,7 @@ export function DependencyGraphView(props) {
|
|
|
601
670
|
fitViewOnNextSyncRef.current = !savedLayout?.viewport;
|
|
602
671
|
if (!savedLayout?.viewport) {
|
|
603
672
|
lastSavedSignatureRef.current = savedLayout?.nodes?.length
|
|
604
|
-
? createLayoutSignature(effectiveLayoutKey, nextNodes, null)
|
|
673
|
+
? createLayoutSignature(effectiveLayoutKey, nextNodes, null, effectiveOrientation)
|
|
605
674
|
: null;
|
|
606
675
|
}
|
|
607
676
|
restoreViewport();
|
|
@@ -610,6 +679,7 @@ export function DependencyGraphView(props) {
|
|
|
610
679
|
initialEdges,
|
|
611
680
|
initialNodes,
|
|
612
681
|
effectiveLayoutKey,
|
|
682
|
+
effectiveOrientation,
|
|
613
683
|
restoreViewport,
|
|
614
684
|
savedLayout,
|
|
615
685
|
savedLayoutSignature,
|
|
@@ -626,18 +696,18 @@ export function DependencyGraphView(props) {
|
|
|
626
696
|
}, []);
|
|
627
697
|
const hasVisibleNodes = initialNodes.length > 0;
|
|
628
698
|
const handleAutoLayout = useCallback(() => {
|
|
629
|
-
const autoLayout = buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds,
|
|
699
|
+
const autoLayout = buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, effectiveOrientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask);
|
|
630
700
|
setNodes(autoLayout.nodes);
|
|
631
701
|
setEdges(autoLayout.edges);
|
|
632
702
|
nodesRef.current = autoLayout.nodes;
|
|
633
703
|
fitViewOnNextSyncRef.current = true;
|
|
634
|
-
|
|
704
|
+
pendingSaveOrientationRef.current = effectiveOrientation;
|
|
635
705
|
restoreViewport();
|
|
636
706
|
}, [
|
|
637
707
|
blockedTaskIds,
|
|
638
708
|
dependencies,
|
|
709
|
+
effectiveOrientation,
|
|
639
710
|
onSelect,
|
|
640
|
-
orientation,
|
|
641
711
|
showExecutionStateBadges,
|
|
642
712
|
autoLayoutStrategy,
|
|
643
713
|
onRemoveTask,
|
|
@@ -651,8 +721,14 @@ export function DependencyGraphView(props) {
|
|
|
651
721
|
tasks,
|
|
652
722
|
]);
|
|
653
723
|
const isValidConnection = useCallback((connection) => allowDependencyConnect
|
|
654
|
-
? isGraphConnectionValid(connection, tasks, dependencies)
|
|
655
|
-
: false, [
|
|
724
|
+
? isGraphConnectionValid(connection, tasks, dependencies, effectiveOrientation, autoLayoutStrategy)
|
|
725
|
+
: false, [
|
|
726
|
+
allowDependencyConnect,
|
|
727
|
+
autoLayoutStrategy,
|
|
728
|
+
dependencies,
|
|
729
|
+
effectiveOrientation,
|
|
730
|
+
tasks,
|
|
731
|
+
]);
|
|
656
732
|
const handleConnect = useCallback((connection) => {
|
|
657
733
|
if (!allowDependencyConnect) {
|
|
658
734
|
return;
|
|
@@ -661,24 +737,64 @@ export function DependencyGraphView(props) {
|
|
|
661
737
|
if (!source || !target) {
|
|
662
738
|
return;
|
|
663
739
|
}
|
|
664
|
-
if (!isGraphConnectionValid(connection, tasks, dependencies)) {
|
|
740
|
+
if (!isGraphConnectionValid(connection, tasks, dependencies, effectiveOrientation, autoLayoutStrategy)) {
|
|
665
741
|
return;
|
|
666
742
|
}
|
|
667
|
-
|
|
668
|
-
if (
|
|
743
|
+
suppressNodeSelectionUntilRef.current = performance.now() + 150;
|
|
744
|
+
if (autoLayoutStrategy === "hierarchy" &&
|
|
745
|
+
sourceHandle === getHierarchyHandles(effectiveOrientation, "hierarchy").source) {
|
|
669
746
|
onCreateChildRelationship?.(source, target);
|
|
670
|
-
return;
|
|
671
747
|
}
|
|
672
|
-
|
|
748
|
+
else {
|
|
749
|
+
onCreateDependency?.(source, target);
|
|
750
|
+
}
|
|
751
|
+
window.requestAnimationFrame(() => {
|
|
752
|
+
onSelectTask(target);
|
|
753
|
+
});
|
|
673
754
|
}, [
|
|
674
755
|
allowDependencyConnect,
|
|
756
|
+
autoLayoutStrategy,
|
|
675
757
|
dependencies,
|
|
758
|
+
effectiveOrientation,
|
|
676
759
|
onCreateChildRelationship,
|
|
677
760
|
onCreateDependency,
|
|
678
761
|
onSelectTask,
|
|
679
762
|
tasks,
|
|
680
763
|
]);
|
|
681
|
-
|
|
764
|
+
const handleOrientationChange = useCallback((nextOrientation) => {
|
|
765
|
+
if (nextOrientation === effectiveOrientation) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
setTransientOrientation(nextOrientation);
|
|
769
|
+
const autoLayout = buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, nextOrientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask);
|
|
770
|
+
setNodes(autoLayout.nodes);
|
|
771
|
+
setEdges(autoLayout.edges);
|
|
772
|
+
nodesRef.current = autoLayout.nodes;
|
|
773
|
+
fitViewOnNextSyncRef.current = true;
|
|
774
|
+
pendingSaveOrientationRef.current = nextOrientation;
|
|
775
|
+
restoreViewport();
|
|
776
|
+
}, [
|
|
777
|
+
autoLayoutStrategy,
|
|
778
|
+
blockedTaskIds,
|
|
779
|
+
dependencies,
|
|
780
|
+
effectiveOrientation,
|
|
781
|
+
onAddChildTaskFromNode,
|
|
782
|
+
onAddDependentTaskFromNode,
|
|
783
|
+
onRemoveTask,
|
|
784
|
+
onSelect,
|
|
785
|
+
restoreViewport,
|
|
786
|
+
selectedDependencyId,
|
|
787
|
+
selectedTaskId,
|
|
788
|
+
setEdges,
|
|
789
|
+
setNodes,
|
|
790
|
+
showExecutionStateBadges,
|
|
791
|
+
tasks,
|
|
792
|
+
]);
|
|
793
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 px-3 pt-2", children: [hasVisibleNodes && highlightBlockedTasks ? (_jsxs("div", { className: "flex items-center gap-2 text-[11px] text-slate-400", children: [_jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { className: "inline-block h-0.5 w-4 rounded-sm bg-orange-400" }), "Blocked by"] }), _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { className: "inline-block h-0.5 w-4 rounded-sm bg-slate-400" }), "Related"] }), _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx("span", { className: "inline-block h-0.5 w-4 rounded-sm bg-blue-500" }), "Child task"] })] })) : (_jsx("div", {})), hasVisibleNodes && (_jsxs("div", { className: "flex items-center gap-2", children: [showOrientationToggle && (_jsxs("div", { className: "inline-flex rounded-md border border-slate-200 bg-white p-0.5", "data-testid": "dependency-graph-orientation-toggle", children: [_jsx("button", { type: "button", className: cn("rounded px-2.5 py-1 text-xs font-medium transition-colors", effectiveOrientation === "horizontal"
|
|
794
|
+
? "bg-slate-900 text-white"
|
|
795
|
+
: "text-slate-500 hover:bg-slate-100 hover:text-slate-700"), "data-testid": "dependency-graph-orientation-horizontal", onClick: () => handleOrientationChange("horizontal"), children: "Horizontal" }), _jsx("button", { type: "button", className: cn("rounded px-2.5 py-1 text-xs font-medium transition-colors", effectiveOrientation === "vertical"
|
|
796
|
+
? "bg-slate-900 text-white"
|
|
797
|
+
: "text-slate-500 hover:bg-slate-100 hover:text-slate-700"), "data-testid": "dependency-graph-orientation-vertical", onClick: () => handleOrientationChange("vertical"), children: "Vertical" })] })), canPersistLayout && (_jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "h-8 px-3", onClick: handleAutoLayout, children: [_jsx(RotateCcw, { className: "mr-1.5 h-4 w-4" }), "Auto layout"] }))] }))] }), _jsx("div", { className: "min-h-0 flex-1", children: !hasVisibleNodes ? (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsxs("div", { className: "flex max-w-sm flex-col items-center gap-3 text-center", children: [_jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-slate-100", children: _jsx(GitBranch, { className: "h-6 w-6 text-slate-400" }) }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-slate-600", children: emptyStateTitle }), _jsx("p", { className: "mt-1 text-xs text-slate-400", children: emptyStateDescription })] })] }) })) : (_jsxs(ReactFlow, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, onConnect: handleConnect, onPaneClick: () => {
|
|
682
798
|
onClearDependencySelection?.();
|
|
683
799
|
}, onEdgeClick: (_event, edge) => {
|
|
684
800
|
if (edge.data?.relationship === "dependency" &&
|
|
@@ -687,9 +803,15 @@ export function DependencyGraphView(props) {
|
|
|
687
803
|
onSelectDependency?.(edge.data.taskId, edge.data.dependsOnTaskId);
|
|
688
804
|
}
|
|
689
805
|
}, onNodeClick: (_event, node) => {
|
|
806
|
+
if (performance.now() < suppressNodeSelectionUntilRef.current) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
690
809
|
onClearDependencySelection?.();
|
|
691
810
|
onSelectTask(node.id);
|
|
692
811
|
}, onNodeDragStart: (_event, node) => {
|
|
812
|
+
if (performance.now() < suppressNodeSelectionUntilRef.current) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
693
815
|
onClearDependencySelection?.();
|
|
694
816
|
onSelectTask(node.id);
|
|
695
817
|
}, onInit: (instance) => {
|
|
@@ -705,7 +827,7 @@ export function DependencyGraphView(props) {
|
|
|
705
827
|
return;
|
|
706
828
|
}
|
|
707
829
|
queueLayoutSave(nodesRef.current, viewport);
|
|
708
|
-
}, nodeTypes: nodeTypes, minZoom: 0.2, maxZoom: 2, proOptions: { hideAttribution: true }, nodesDraggable: canPersistLayout, nodesConnectable: allowDependencyConnect, isValidConnection: isValidConnection, elementsSelectable: true, children: [_jsx(Controls, { showInteractive: false, className: "rounded-lg! border-slate-200! shadow-md!" }), _jsx(MiniMap, { ...(miniMapWidth != null && miniMapHeight != null
|
|
830
|
+
}, nodeTypes: nodeTypes, minZoom: 0.2, maxZoom: 2, proOptions: { hideAttribution: true }, nodesDraggable: canPersistLayout, nodesConnectable: allowDependencyConnect, isValidConnection: isValidConnection, elementsSelectable: true, children: [_jsx(Controls, { showInteractive: false, className: "rounded-lg! border-slate-200! shadow-md!" }), showMiniMap ? (_jsx(MiniMap, { ...(miniMapWidth != null && miniMapHeight != null
|
|
709
831
|
? { width: miniMapWidth, height: miniMapHeight }
|
|
710
832
|
: {}), nodeColor: (node) => {
|
|
711
833
|
const d = node.data;
|
|
@@ -724,6 +846,6 @@ export function DependencyGraphView(props) {
|
|
|
724
846
|
default:
|
|
725
847
|
return "#cbd5e1";
|
|
726
848
|
}
|
|
727
|
-
}, maskColor: "rgba(0, 0, 0, 0.08)", className: "rounded-lg! border-slate-200! shadow-md!" })] })) })] }));
|
|
849
|
+
}, maskColor: "rgba(0, 0, 0, 0.08)", className: "rounded-lg! border-slate-200! shadow-md!" })) : null] })) })] }));
|
|
728
850
|
}
|
|
729
851
|
//# sourceMappingURL=DependencyGraphView.js.map
|