@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.
Files changed (134) hide show
  1. package/dist/config/config.js +2 -21
  2. package/dist/config/config.js.map +1 -1
  3. package/dist/config/types.d.ts +0 -2
  4. package/dist/config/types.js.map +1 -1
  5. package/dist/editor/ConfirmationDialog.js +4 -20
  6. package/dist/editor/ConfirmationDialog.js.map +1 -1
  7. package/dist/editor/ContentTree.js +7 -19
  8. package/dist/editor/ContentTree.js.map +1 -1
  9. package/dist/editor/Editor.js.map +1 -1
  10. package/dist/editor/PictureCropper.js +41 -45
  11. package/dist/editor/PictureCropper.js.map +1 -1
  12. package/dist/editor/ai/AgentTerminal.js +8 -97
  13. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  14. package/dist/editor/ai/AgentTerminalStatusBar.js +0 -65
  15. package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
  16. package/dist/editor/ai/Agents.js +0 -19
  17. package/dist/editor/ai/Agents.js.map +1 -1
  18. package/dist/editor/ai/AiResponseMessage.js +0 -5
  19. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  20. package/dist/editor/ai/ContentInspectorPopover.d.ts +0 -1
  21. package/dist/editor/ai/ContentInspectorPopover.js +8 -22
  22. package/dist/editor/ai/ContentInspectorPopover.js.map +1 -1
  23. package/dist/editor/ai/ToolCallDisplay.d.ts +0 -2
  24. package/dist/editor/ai/ToolCallDisplay.js +11 -54
  25. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  26. package/dist/editor/ai/dialogs/AgentDialogHandler.js +3 -32
  27. package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
  28. package/dist/editor/ai/dialogs/QuestionnaireInline.js +20 -55
  29. package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
  30. package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +4 -7
  31. package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
  32. package/dist/editor/ai/types.d.ts +0 -2
  33. package/dist/editor/services/agentService.d.ts +0 -27
  34. package/dist/editor/services/agentService.js +2 -11
  35. package/dist/editor/services/agentService.js.map +1 -1
  36. package/dist/editor/services/aiService.js +3 -54
  37. package/dist/editor/services/aiService.js.map +1 -1
  38. package/dist/editor/services/serviceHelper.js +2 -5
  39. package/dist/editor/services/serviceHelper.js.map +1 -1
  40. package/dist/editor/settings/About.js +4 -40
  41. package/dist/editor/settings/About.js.map +1 -1
  42. package/dist/editor/settings/panels/ProjectTemplateAgentPanel.d.ts +1 -7
  43. package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js +3 -3
  44. package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js.map +1 -1
  45. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +84 -165
  46. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  47. package/dist/editor/settings/panels/index.d.ts +0 -1
  48. package/dist/editor/settings/panels/index.js +0 -1
  49. package/dist/editor/settings/panels/index.js.map +1 -1
  50. package/dist/editor/sidebar/NavigationPanelItem.js +1 -1
  51. package/dist/editor/sidebar/NavigationPanelItem.js.map +1 -1
  52. package/dist/editor/sidebar/WorkspaceButton.js +1 -1
  53. package/dist/editor/sidebar/WorkspaceButton.js.map +1 -1
  54. package/dist/editor/tree-indicators/GutterColumns.js +4 -24
  55. package/dist/editor/tree-indicators/GutterColumns.js.map +1 -1
  56. package/dist/editor/tree-indicators/types.d.ts +0 -10
  57. package/dist/editor/ui/Splitter.d.ts +0 -1
  58. package/dist/editor/ui/Splitter.js +1 -7
  59. package/dist/editor/ui/Splitter.js.map +1 -1
  60. package/dist/licensing/LicenseContext.js +4 -40
  61. package/dist/licensing/LicenseContext.js.map +1 -1
  62. package/dist/licensing/LicenseOverlay.js +1 -1
  63. package/dist/licensing/LicenseOverlay.js.map +1 -1
  64. package/dist/licensing/types.d.ts +1 -3
  65. package/dist/licensing/types.js.map +1 -1
  66. package/dist/revision.d.ts +2 -2
  67. package/dist/revision.js +2 -2
  68. package/dist/task-board/TaskBoardWorkspace.js +354 -165
  69. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  70. package/dist/task-board/assigneeDisplay.js +3 -1
  71. package/dist/task-board/assigneeDisplay.js.map +1 -1
  72. package/dist/task-board/components/CreateProjectDialog.js +1 -2
  73. package/dist/task-board/components/CreateProjectDialog.js.map +1 -1
  74. package/dist/task-board/components/ProjectDashboard.js +1 -2
  75. package/dist/task-board/components/ProjectDashboard.js.map +1 -1
  76. package/dist/task-board/components/ProjectSettingsDialog.d.ts +0 -1
  77. package/dist/task-board/components/ProjectSettingsDialog.js +12 -146
  78. package/dist/task-board/components/ProjectSettingsDialog.js.map +1 -1
  79. package/dist/task-board/components/TaskAgentPanel.d.ts +0 -1
  80. package/dist/task-board/components/TaskAgentPanel.js +2 -2
  81. package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
  82. package/dist/task-board/components/TaskAssigneePicker.js +2 -2
  83. package/dist/task-board/components/TaskAssigneePicker.js.map +1 -1
  84. package/dist/task-board/components/TaskBoardMyTasksSidebar.js +1 -1
  85. package/dist/task-board/components/TaskBoardMyTasksSidebar.js.map +1 -1
  86. package/dist/task-board/components/TaskDetailDialog.d.ts +0 -1
  87. package/dist/task-board/components/TaskDetailDialog.js +2 -2
  88. package/dist/task-board/components/TaskDetailDialog.js.map +1 -1
  89. package/dist/task-board/components/TaskDetailPanel.d.ts +0 -1
  90. package/dist/task-board/components/TaskDetailPanel.js +8 -23
  91. package/dist/task-board/components/TaskDetailPanel.js.map +1 -1
  92. package/dist/task-board/components/TaskRow.js +2 -3
  93. package/dist/task-board/components/TaskRow.js.map +1 -1
  94. package/dist/task-board/components/WizardTaskDetailsPanel.js +1 -2
  95. package/dist/task-board/components/WizardTaskDetailsPanel.js.map +1 -1
  96. package/dist/task-board/services/taskService.d.ts +1 -17
  97. package/dist/task-board/services/taskService.js +0 -56
  98. package/dist/task-board/services/taskService.js.map +1 -1
  99. package/dist/task-board/taskExecutionRecords.js +0 -2
  100. package/dist/task-board/taskExecutionRecords.js.map +1 -1
  101. package/dist/task-board/types.d.ts +1 -78
  102. package/dist/task-board/utils/taskDependencyOrdering.d.ts +0 -6
  103. package/dist/task-board/utils/taskDependencyOrdering.js +1 -138
  104. package/dist/task-board/utils/taskDependencyOrdering.js.map +1 -1
  105. package/dist/task-board/views/DependencyGraphView.d.ts +2 -5
  106. package/dist/task-board/views/DependencyGraphView.js +69 -261
  107. package/dist/task-board/views/DependencyGraphView.js.map +1 -1
  108. package/dist/task-board/views/KanbanView.js +1 -8
  109. package/dist/task-board/views/KanbanView.js.map +1 -1
  110. package/dist/task-board/views/ListView.js +1 -1
  111. package/dist/task-board/views/ListView.js.map +1 -1
  112. package/dist/task-board/views/WizardView.js +24 -30
  113. package/dist/task-board/views/WizardView.js.map +1 -1
  114. package/dist/tour/Tour.js +32 -0
  115. package/dist/tour/Tour.js.map +1 -1
  116. package/package.json +1 -1
  117. package/dist/editor/settings/panels/PersistentLogsPanel.d.ts +0 -2
  118. package/dist/editor/settings/panels/PersistentLogsPanel.js +0 -244
  119. package/dist/editor/settings/panels/PersistentLogsPanel.js.map +0 -1
  120. package/dist/task-board/components/ProjectExecutionUserPicker.d.ts +0 -14
  121. package/dist/task-board/components/ProjectExecutionUserPicker.js +0 -65
  122. package/dist/task-board/components/ProjectExecutionUserPicker.js.map +0 -1
  123. package/dist/task-board/components/TaskboardPersistentLogPanel.d.ts +0 -11
  124. package/dist/task-board/components/TaskboardPersistentLogPanel.js +0 -141
  125. package/dist/task-board/components/TaskboardPersistentLogPanel.js.map +0 -1
  126. package/dist/task-board/persistentLogCopy.d.ts +0 -7
  127. package/dist/task-board/persistentLogCopy.js +0 -80
  128. package/dist/task-board/persistentLogCopy.js.map +0 -1
  129. package/dist/task-board/persistentLogLabels.d.ts +0 -38
  130. package/dist/task-board/persistentLogLabels.js +0 -189
  131. package/dist/task-board/persistentLogLabels.js.map +0 -1
  132. package/dist/task-board/useTaskBoardAgentPanelState.d.ts +0 -34
  133. package/dist/task-board/useTaskBoardAgentPanelState.js +0 -283
  134. package/dist/task-board/useTaskBoardAgentPanelState.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import { useCallback, useEffect, useMemo, useRef } 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";
@@ -10,7 +10,7 @@ import { cn } from "../../lib/utils";
10
10
  import { saveGraphLayout } from "../services/taskService";
11
11
  import { Button } from "../../components/ui/button";
12
12
  import { Badge } from "../../components/ui/badge";
13
- import { Tooltip, TooltipContent, TooltipTrigger, } from "../../components/ui/tooltip";
13
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../../components/ui/tooltip";
14
14
  import { Circle, PlayCircle, Clock3, Eye, CheckCircle2, ArrowUp, ArrowDown, Minus, Flame, GitBranch, RotateCcw, Loader2, Plus, Trash2, } from "lucide-react";
15
15
  const NODE_WIDTH = 220;
16
16
  const NODE_HEIGHT = 80;
@@ -46,37 +46,24 @@ 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";
57
- const nodeSurfaceClass = data.isSelected
58
- ? "ring-primary border-primary/50 ring-2 bg-white"
59
- : data.isBlocked
60
- ? "border-red-200 bg-red-50/70"
61
- : data.status === "Done"
62
- ? "border-emerald-200 bg-emerald-50/80"
63
- : "border-slate-200 bg-white hover:border-slate-300 hover:shadow-md";
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) => {
49
+ return (_jsxs("div", { className: cn("relative cursor-pointer rounded-lg border bg-white px-3 py-2 shadow-sm transition-all", data.isSelected
50
+ ? "ring-primary border-primary/50 ring-2"
51
+ : "border-slate-200 hover:border-slate-300 hover:shadow-md", data.isBlocked && !data.isSelected && "border-red-200 bg-red-50/40"), 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: "text-slate-400 hover:bg-red-50 hover:text-red-600 -mr-0.5 -mt-px shrink-0 rounded p-0.5 transition-colors", "aria-label": "Remove task", "data-testid": `dependency-graph-remove-task-${data.taskId}`, onClick: (event) => {
65
52
  event.stopPropagation();
66
53
  data.onRemoveTask?.(data.taskId);
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) => {
54
+ }, 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 uppercase tracking-wider", 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, "top-1/2 right-0 translate-x-[calc(100%+6px)] -translate-y-1/2"), "aria-label": "Add dependent task", "data-testid": `dependency-graph-add-dependent-task-${data.taskId}`, onClick: (event) => {
68
55
  event.stopPropagation();
69
56
  data.onSelect(data.taskId);
70
57
  data.onAddDependentTaskFromNode?.(data.taskId);
71
58
  }, onMouseDown: (event) => {
72
59
  event.stopPropagation();
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) => {
60
+ }, children: _jsx(Plus, { className: "h-3 w-3", strokeWidth: 1.75 }) }) }), _jsx(TooltipContent, { side: "right", 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, "bottom-0 left-1/2 -translate-x-1/2 translate-y-[calc(100%+6px)]"), "aria-label": "Add subtask", "data-testid": `dependency-graph-add-subtask-${data.taskId}`, onClick: (event) => {
74
61
  event.stopPropagation();
75
62
  data.onSelect(data.taskId);
76
63
  data.onAddChildTaskFromNode?.(data.taskId);
77
64
  }, onMouseDown: (event) => {
78
65
  event.stopPropagation();
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}` })] }));
66
+ }, children: _jsx(Plus, { className: "h-3 w-3", strokeWidth: 1.75 }) }) }), _jsx(TooltipContent, { side: "bottom", 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}` })] }));
80
67
  }
81
68
  const nodeTypes = {
82
69
  taskNode: TaskGraphNode,
@@ -84,30 +71,13 @@ const nodeTypes = {
84
71
  const HIERARCHY_CHILD_INDENT = 24;
85
72
  const HIERARCHY_CHILD_GAP = 32;
86
73
  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
- }
103
74
  /**
104
75
  * Compound layout for the hierarchy strategy: each parent–children group is
105
76
  * laid out vertically (parent on top, children stacked below with a slight
106
77
  * indent), and then the resulting subtree "super-nodes" are arranged
107
- * in the selected orientation via Dagre using the dependency edges between
108
- * them.
78
+ * left-to-right via Dagre using the dependency edges between them.
109
79
  */
110
- function layoutGraphHierarchy(nodes, edges, orientation) {
80
+ function layoutGraphHierarchy(nodes, edges) {
111
81
  if (nodes.length === 0)
112
82
  return { nodes, edges };
113
83
  const childrenOf = new Map();
@@ -152,11 +122,7 @@ function layoutGraphHierarchy(nodes, edges, orientation) {
152
122
  }
153
123
  }
154
124
  const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
155
- g.setGraph({
156
- rankdir: orientation === "horizontal" ? "LR" : "TB",
157
- nodesep: 40,
158
- ranksep: HIERARCHY_SUBTREE_GAP,
159
- });
125
+ g.setGraph({ rankdir: "LR", nodesep: 40, ranksep: HIERARCHY_SUBTREE_GAP });
160
126
  for (const [rootId, data] of subtrees) {
161
127
  g.setNode(rootId, { width: data.width, height: data.height });
162
128
  }
@@ -198,7 +164,7 @@ function layoutGraphHierarchy(nodes, edges, orientation) {
198
164
  function layoutGraph(nodes, edges, orientation, autoLayoutStrategy) {
199
165
  if (autoLayoutStrategy === "hierarchy" &&
200
166
  edges.some((e) => e.data?.relationship === "hierarchy")) {
201
- return layoutGraphHierarchy(nodes, edges, orientation);
167
+ return layoutGraphHierarchy(nodes, edges);
202
168
  }
203
169
  const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
204
170
  g.setGraph({
@@ -233,8 +199,6 @@ function buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, b
233
199
  const childRelationshipKeys = new Set(visibleTasks
234
200
  .filter((task) => !!task.parentTaskId)
235
201
  .map((task) => `${task.parentTaskId}->${task.taskId}`));
236
- const dependencyHandles = getDependencyHandles(orientation);
237
- const hierarchyHandles = getHierarchyHandles(orientation, autoLayoutStrategy);
238
202
  const nodes = visibleTasks.map((task) => ({
239
203
  id: task.taskId,
240
204
  type: "taskNode",
@@ -251,27 +215,26 @@ function buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, b
251
215
  isSelected: task.taskId === selectedTaskId,
252
216
  isBlocked: blockedTaskIds.has(task.taskId),
253
217
  orientation,
254
- dependencySourceHandle: dependencyHandles.source,
255
- hierarchySourceHandle: hierarchyHandles.source,
256
218
  onSelect,
257
219
  onAddDependentTaskFromNode,
258
220
  onAddChildTaskFromNode,
259
221
  onRemoveTask,
260
222
  },
261
223
  }));
262
- const depSourceHandle = dependencyHandles.source;
263
- const depTargetHandle = dependencyHandles.target;
264
- const hierSourceHandle = hierarchyHandles.source;
265
- const hierTargetHandle = hierarchyHandles.target;
224
+ const depSourceHandle = orientation === "horizontal" ? "right" : "bottom";
225
+ const depTargetHandle = orientation === "horizontal" ? "left" : "top";
226
+ const hierSourceHandle = autoLayoutStrategy === "hierarchy" ? "bottom" : depSourceHandle;
227
+ const hierTargetHandle = autoLayoutStrategy === "hierarchy" ? "left" : depTargetHandle;
266
228
  const dependencyEdges = dependencies
267
229
  .filter((dep) => taskMap.has(dep.taskId) &&
268
230
  taskMap.has(dep.dependsOnTaskId) &&
269
231
  !childRelationshipKeys.has(`${dep.dependsOnTaskId}->${dep.taskId}`))
270
232
  .map((dep) => {
271
233
  const isBlockedBy = dep.dependencyType === "BlockedBy";
272
- const strokeColor = isBlockedBy ? EDGE_BLOCKED_BY : EDGE_RELATED;
273
- const isSelected = dep.taskId === selectedTaskId &&
274
- dep.dependsOnTaskId === selectedDependencyId;
234
+ const strokeColor = isBlockedBy
235
+ ? EDGE_BLOCKED_BY
236
+ : EDGE_RELATED;
237
+ const isSelected = dep.taskId === selectedTaskId && dep.dependsOnTaskId === selectedDependencyId;
275
238
  return {
276
239
  id: dep.dependencyId,
277
240
  source: dep.dependsOnTaskId,
@@ -301,7 +264,8 @@ function buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, b
301
264
  };
302
265
  });
303
266
  const hierarchyEdges = visibleTasks
304
- .filter((task) => !!task.parentTaskId && taskMap.has(task.parentTaskId))
267
+ .filter((task) => !!task.parentTaskId &&
268
+ taskMap.has(task.parentTaskId))
305
269
  .map((task) => ({
306
270
  id: `parent:${task.parentTaskId}:${task.taskId}`,
307
271
  source: task.parentTaskId,
@@ -356,15 +320,12 @@ function buildChildRelationshipKeys(tasks) {
356
320
  .filter((task) => !!task.parentTaskId)
357
321
  .map((task) => `${task.parentTaskId}->${task.taskId}`));
358
322
  }
359
- function isHierarchyConnectionValid(connection, tasks, orientation, autoLayoutStrategy) {
360
- if (autoLayoutStrategy !== "hierarchy") {
361
- return false;
362
- }
323
+ function isHierarchyConnectionValid(connection, tasks) {
363
324
  const { source, sourceHandle, target, targetHandle } = connection;
364
325
  if (!source || !target || source === target) {
365
326
  return false;
366
327
  }
367
- if (sourceHandle !== getHierarchyHandles(orientation, autoLayoutStrategy).source) {
328
+ if (sourceHandle !== "bottom") {
368
329
  return false;
369
330
  }
370
331
  if (targetHandle && targetHandle !== "left" && targetHandle !== "top") {
@@ -384,12 +345,12 @@ function isHierarchyConnectionValid(connection, tasks, orientation, autoLayoutSt
384
345
  }
385
346
  return !buildChildRelationshipKeys(tasks).has(`${source}->${target}`);
386
347
  }
387
- function isDependencyConnectionValid(connection, tasks, dependencies, orientation) {
348
+ function isDependencyConnectionValid(connection, tasks, dependencies) {
388
349
  const { source, sourceHandle, target, targetHandle } = connection;
389
350
  if (!source || !target || source === target) {
390
351
  return false;
391
352
  }
392
- if (sourceHandle !== getDependencyHandles(orientation).source) {
353
+ if (sourceHandle !== "right") {
393
354
  return false;
394
355
  }
395
356
  if (targetHandle && targetHandle !== "left" && targetHandle !== "top") {
@@ -404,18 +365,15 @@ function isDependencyConnectionValid(connection, tasks, dependencies, orientatio
404
365
  }
405
366
  return !buildChildRelationshipKeys(tasks).has(`${source}->${target}`);
406
367
  }
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);
368
+ function isGraphConnectionValid(connection, tasks, dependencies) {
369
+ if (connection.sourceHandle === "bottom") {
370
+ return isHierarchyConnectionValid(connection, tasks);
412
371
  }
413
- return isDependencyConnectionValid(connection, tasks, dependencies, orientation);
372
+ return isDependencyConnectionValid(connection, tasks, dependencies);
414
373
  }
415
- function createLayoutSignature(layoutKey, nodes, viewport, orientation) {
374
+ function createLayoutSignature(layoutKey, nodes, viewport) {
416
375
  return JSON.stringify({
417
376
  layoutKey,
418
- orientation,
419
377
  nodes: nodes
420
378
  .map((node) => ({
421
379
  taskId: node.id,
@@ -432,43 +390,12 @@ function createLayoutSignature(layoutKey, nodes, viewport, orientation) {
432
390
  : null,
433
391
  });
434
392
  }
435
- function createGraphSyncSignature(nodes, edges) {
436
- return JSON.stringify({
437
- nodes: nodes
438
- .map((node) => ({
439
- id: node.id,
440
- x: node.position.x,
441
- y: node.position.y,
442
- selected: node.data.isSelected,
443
- status: node.data.status,
444
- executionState: node.data.executionState ?? null,
445
- blocked: node.data.isBlocked,
446
- assignee: node.data.assigneeDisplayName ?? null,
447
- }))
448
- .sort((a, b) => a.id.localeCompare(b.id)),
449
- edges: edges
450
- .map((edge) => ({
451
- id: edge.id,
452
- source: edge.source,
453
- target: edge.target,
454
- sourceHandle: edge.sourceHandle ?? null,
455
- targetHandle: edge.targetHandle ?? null,
456
- }))
457
- .sort((a, b) => a.id.localeCompare(b.id)),
458
- });
459
- }
460
393
  export function DependencyGraphView(props) {
461
- 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;
394
+ 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;
462
395
  const canPersistLayout = typeof canPersistLayoutOverride === "boolean"
463
396
  ? canPersistLayoutOverride
464
397
  : permission === "Owner" || permission === "Editor";
465
398
  const effectiveLayoutKey = layoutKey ?? projectId ?? "graph";
466
- const fallbackOrientation = normalizeGraphOrientation(orientation);
467
- const savedLayoutOrientation = savedLayout
468
- ? normalizeGraphOrientation(savedLayout.orientation ?? fallbackOrientation)
469
- : null;
470
- const [transientOrientation, setTransientOrientation] = useState(null);
471
- const effectiveOrientation = transientOrientation ?? savedLayoutOrientation ?? fallbackOrientation;
472
399
  const taskMap = useMemo(() => {
473
400
  const m = new Map();
474
401
  for (const t of tasks)
@@ -480,11 +407,6 @@ export function DependencyGraphView(props) {
480
407
  return new Set();
481
408
  }
482
409
  const blocked = new Set();
483
- for (const task of tasks) {
484
- if ((task.executionBlockedByProjectIds?.length ?? 0) > 0) {
485
- blocked.add(task.taskId);
486
- }
487
- }
488
410
  for (const dep of dependencies) {
489
411
  if (dep.dependencyType !== "BlockedBy")
490
412
  continue;
@@ -497,13 +419,13 @@ export function DependencyGraphView(props) {
497
419
  return blocked;
498
420
  }, [dependencies, highlightBlockedTasks, taskMap]);
499
421
  const onSelect = useCallback((taskId) => onSelectTask(taskId), [onSelectTask]);
500
- const { nodes: initialNodes, edges: initialEdges } = useMemo(() => buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, effectiveOrientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask), [
422
+ const { nodes: initialNodes, edges: initialEdges } = useMemo(() => buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, orientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask), [
501
423
  tasks,
502
424
  dependencies,
503
425
  selectedTaskId,
504
426
  selectedDependencyId,
505
427
  blockedTaskIds,
506
- effectiveOrientation,
428
+ orientation,
507
429
  showExecutionStateBadges,
508
430
  autoLayoutStrategy,
509
431
  onSelect,
@@ -514,7 +436,6 @@ export function DependencyGraphView(props) {
514
436
  const [nodes, setNodes, onNodesChangeBase] = useNodesState(initialNodes);
515
437
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
516
438
  const nodesRef = useRef(nodes);
517
- const suppressNodeSelectionUntilRef = useRef(0);
518
439
  const onNodesChange = useCallback((changes) => {
519
440
  onNodesChangeBase(changes);
520
441
  const hasPositionChange = changes.some((c) => c.type === "position" && c.position);
@@ -532,36 +453,22 @@ export function DependencyGraphView(props) {
532
453
  const pendingViewportRef = useRef(null);
533
454
  const fitViewOnNextSyncRef = useRef(false);
534
455
  const skipNextMoveEndSaveRef = useRef(false);
535
- const pendingSaveOrientationRef = useRef(null);
456
+ const saveAfterViewportRestoreRef = useRef(false);
536
457
  const lastSavedSignatureRef = useRef(null);
537
458
  const lastAppliedLayoutKeyRef = useRef(null);
538
459
  const lastAppliedLayoutSignatureRef = useRef(null);
539
- const lastAppliedGraphSignatureRef = useRef(null);
540
- const lastAppliedNodeIdSignatureRef = useRef(null);
541
460
  const savedLayoutSignature = useMemo(() => savedLayout
542
461
  ? JSON.stringify({
543
- orientation: savedLayoutOrientation,
544
462
  updatedAt: savedLayout.updatedAt ?? null,
545
463
  nodes: savedLayout.nodes ?? [],
546
464
  viewport: savedLayout.viewport ?? null,
547
465
  })
548
- : "null", [savedLayout, savedLayoutOrientation]);
549
- useEffect(() => {
550
- setTransientOrientation(null);
551
- pendingSaveOrientationRef.current = null;
552
- }, [effectiveLayoutKey]);
553
- useEffect(() => {
554
- if (transientOrientation &&
555
- savedLayoutOrientation &&
556
- transientOrientation === savedLayoutOrientation) {
557
- setTransientOrientation(null);
558
- }
559
- }, [savedLayoutOrientation, transientOrientation]);
560
- const persistLayout = useCallback(async (nextNodes, viewport, nextOrientation) => {
466
+ : "null", [savedLayout]);
467
+ const persistLayout = useCallback(async (nextNodes, viewport) => {
561
468
  if (!canPersistLayout) {
562
469
  return;
563
470
  }
564
- const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport, nextOrientation);
471
+ const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport);
565
472
  if (signature === lastSavedSignatureRef.current) {
566
473
  return;
567
474
  }
@@ -572,7 +479,6 @@ export function DependencyGraphView(props) {
572
479
  x: node.position.x,
573
480
  y: node.position.y,
574
481
  })),
575
- orientation: nextOrientation,
576
482
  viewport: viewport == null
577
483
  ? null
578
484
  : {
@@ -589,7 +495,6 @@ export function DependencyGraphView(props) {
589
495
  projectId,
590
496
  nodes: layoutPayload.nodes,
591
497
  viewport: layoutPayload.viewport,
592
- orientation: layoutPayload.orientation,
593
498
  });
594
499
  if (result.type !== "success") {
595
500
  toast.error(result.summary || "Failed to save graph layout");
@@ -601,7 +506,6 @@ export function DependencyGraphView(props) {
601
506
  lastSavedSignatureRef.current = signature;
602
507
  if (nextLayout) {
603
508
  const incomingSignature = JSON.stringify({
604
- orientation: normalizeGraphOrientation(nextLayout.orientation ?? nextOrientation),
605
509
  updatedAt: nextLayout.updatedAt ?? null,
606
510
  nodes: nextLayout.nodes ?? [],
607
511
  viewport: nextLayout.viewport ?? null,
@@ -618,16 +522,15 @@ export function DependencyGraphView(props) {
618
522
  }, [
619
523
  canPersistLayout,
620
524
  effectiveLayoutKey,
621
- effectiveOrientation,
622
525
  onLayoutSaved,
623
526
  onPersistLayout,
624
527
  projectId,
625
528
  ]);
626
- const queueLayoutSave = useCallback((nextNodes, viewport, nextOrientation = effectiveOrientation) => {
529
+ const queueLayoutSave = useCallback((nextNodes, viewport) => {
627
530
  if (!canPersistLayout) {
628
531
  return;
629
532
  }
630
- const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport, nextOrientation);
533
+ const signature = createLayoutSignature(effectiveLayoutKey, nextNodes, viewport);
631
534
  if (signature === lastSavedSignatureRef.current) {
632
535
  return;
633
536
  }
@@ -636,20 +539,14 @@ export function DependencyGraphView(props) {
636
539
  saveTimeoutRef.current = null;
637
540
  }
638
541
  if (layoutSaveDebounceMs === 0) {
639
- void persistLayout(nextNodes, viewport, nextOrientation);
542
+ void persistLayout(nextNodes, viewport);
640
543
  return;
641
544
  }
642
545
  saveTimeoutRef.current = window.setTimeout(() => {
643
546
  saveTimeoutRef.current = null;
644
- void persistLayout(nextNodes, viewport, nextOrientation);
547
+ void persistLayout(nextNodes, viewport);
645
548
  }, layoutSaveDebounceMs);
646
- }, [
647
- canPersistLayout,
648
- effectiveLayoutKey,
649
- effectiveOrientation,
650
- layoutSaveDebounceMs,
651
- persistLayout,
652
- ]);
549
+ }, [canPersistLayout, effectiveLayoutKey, layoutSaveDebounceMs, persistLayout]);
653
550
  const restoreViewport = useCallback(() => {
654
551
  const instance = reactFlowRef.current;
655
552
  if (!instance || nodesRef.current.length === 0) {
@@ -661,7 +558,7 @@ export function DependencyGraphView(props) {
661
558
  skipNextMoveEndSaveRef.current = true;
662
559
  window.requestAnimationFrame(() => {
663
560
  reactFlowRef.current?.setViewport(viewport, { duration: 0 });
664
- lastSavedSignatureRef.current = createLayoutSignature(effectiveLayoutKey, nodesRef.current, viewport, effectiveOrientation);
561
+ lastSavedSignatureRef.current = createLayoutSignature(effectiveLayoutKey, nodesRef.current, viewport);
665
562
  });
666
563
  return;
667
564
  }
@@ -672,73 +569,39 @@ export function DependencyGraphView(props) {
672
569
  skipNextMoveEndSaveRef.current = true;
673
570
  window.requestAnimationFrame(() => {
674
571
  reactFlowRef.current?.fitView({ padding: 0.2 });
675
- if (!pendingSaveOrientationRef.current) {
572
+ if (!saveAfterViewportRestoreRef.current) {
676
573
  return;
677
574
  }
678
- const nextOrientation = pendingSaveOrientationRef.current;
679
- pendingSaveOrientationRef.current = null;
575
+ saveAfterViewportRestoreRef.current = false;
680
576
  const viewport = reactFlowRef.current?.getViewport() ?? null;
681
- queueLayoutSave(nodesRef.current, viewport, nextOrientation);
577
+ queueLayoutSave(nodesRef.current, viewport);
682
578
  });
683
- }, [effectiveLayoutKey, effectiveOrientation, queueLayoutSave]);
579
+ }, [effectiveLayoutKey, queueLayoutSave]);
684
580
  useEffect(() => {
685
581
  const shouldApplySavedLayout = lastAppliedLayoutKeyRef.current !== effectiveLayoutKey ||
686
582
  lastAppliedLayoutSignatureRef.current !== savedLayoutSignature;
687
- const nextNodeIdSignature = initialNodes.map((node) => node.id).join("|");
688
- const savedLayoutNodeCount = savedLayout?.nodes?.length ?? 0;
689
- const shouldAutoLayoutForHierarchy = autoLayoutStrategy === "hierarchy" &&
690
- (savedLayoutNodeCount < initialNodes.length ||
691
- (lastAppliedNodeIdSignatureRef.current !== null &&
692
- lastAppliedNodeIdSignatureRef.current !== nextNodeIdSignature));
693
583
  const nextNodes = shouldApplySavedLayout
694
- ? shouldAutoLayoutForHierarchy
695
- ? initialNodes
696
- : applySavedLayout(initialNodes, savedLayout)
697
- : shouldAutoLayoutForHierarchy
698
- ? initialNodes
699
- : preserveNodePositions(nodesRef.current, initialNodes);
700
- const nextGraphSignature = createGraphSyncSignature(nextNodes, initialEdges);
701
- if (!shouldApplySavedLayout &&
702
- !shouldAutoLayoutForHierarchy &&
703
- nextGraphSignature === lastAppliedGraphSignatureRef.current) {
704
- return;
705
- }
584
+ ? applySavedLayout(initialNodes, savedLayout)
585
+ : preserveNodePositions(nodesRef.current, initialNodes);
706
586
  setNodes(nextNodes);
707
587
  setEdges(initialEdges);
708
588
  nodesRef.current = nextNodes;
709
- lastAppliedGraphSignatureRef.current = nextGraphSignature;
710
- lastAppliedNodeIdSignatureRef.current = nextNodeIdSignature;
711
589
  if (shouldApplySavedLayout) {
712
590
  lastAppliedLayoutKeyRef.current = effectiveLayoutKey;
713
591
  lastAppliedLayoutSignatureRef.current = savedLayoutSignature;
714
- pendingViewportRef.current =
715
- shouldAutoLayoutForHierarchy ? null : (savedLayout?.viewport ?? null);
716
- fitViewOnNextSyncRef.current =
717
- shouldAutoLayoutForHierarchy || !savedLayout?.viewport;
718
- if (!savedLayout?.viewport || shouldAutoLayoutForHierarchy) {
592
+ pendingViewportRef.current = savedLayout?.viewport ?? null;
593
+ fitViewOnNextSyncRef.current = !savedLayout?.viewport;
594
+ if (!savedLayout?.viewport) {
719
595
  lastSavedSignatureRef.current = savedLayout?.nodes?.length
720
- ? createLayoutSignature(effectiveLayoutKey, nextNodes, null, effectiveOrientation)
596
+ ? createLayoutSignature(effectiveLayoutKey, nextNodes, null)
721
597
  : null;
722
598
  }
723
- if (shouldAutoLayoutForHierarchy) {
724
- pendingSaveOrientationRef.current = effectiveOrientation;
725
- }
726
- restoreViewport();
727
- return;
728
- }
729
- if (shouldAutoLayoutForHierarchy) {
730
- pendingViewportRef.current = null;
731
- fitViewOnNextSyncRef.current = true;
732
- pendingSaveOrientationRef.current = effectiveOrientation;
733
599
  restoreViewport();
734
600
  }
735
601
  }, [
736
- autoLayoutStrategy,
737
602
  initialEdges,
738
603
  initialNodes,
739
604
  effectiveLayoutKey,
740
- effectiveOrientation,
741
- projectId,
742
605
  restoreViewport,
743
606
  savedLayout,
744
607
  savedLayoutSignature,
@@ -755,18 +618,18 @@ export function DependencyGraphView(props) {
755
618
  }, []);
756
619
  const hasVisibleNodes = initialNodes.length > 0;
757
620
  const handleAutoLayout = useCallback(() => {
758
- const autoLayout = buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, effectiveOrientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask);
621
+ const autoLayout = buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, orientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask);
759
622
  setNodes(autoLayout.nodes);
760
623
  setEdges(autoLayout.edges);
761
624
  nodesRef.current = autoLayout.nodes;
762
625
  fitViewOnNextSyncRef.current = true;
763
- pendingSaveOrientationRef.current = effectiveOrientation;
626
+ saveAfterViewportRestoreRef.current = true;
764
627
  restoreViewport();
765
628
  }, [
766
629
  blockedTaskIds,
767
630
  dependencies,
768
- effectiveOrientation,
769
631
  onSelect,
632
+ orientation,
770
633
  showExecutionStateBadges,
771
634
  autoLayoutStrategy,
772
635
  onRemoveTask,
@@ -780,14 +643,8 @@ export function DependencyGraphView(props) {
780
643
  tasks,
781
644
  ]);
782
645
  const isValidConnection = useCallback((connection) => allowDependencyConnect
783
- ? isGraphConnectionValid(connection, tasks, dependencies, effectiveOrientation, autoLayoutStrategy)
784
- : false, [
785
- allowDependencyConnect,
786
- autoLayoutStrategy,
787
- dependencies,
788
- effectiveOrientation,
789
- tasks,
790
- ]);
646
+ ? isGraphConnectionValid(connection, tasks, dependencies)
647
+ : false, [allowDependencyConnect, dependencies, tasks]);
791
648
  const handleConnect = useCallback((connection) => {
792
649
  if (!allowDependencyConnect) {
793
650
  return;
@@ -796,64 +653,24 @@ export function DependencyGraphView(props) {
796
653
  if (!source || !target) {
797
654
  return;
798
655
  }
799
- if (!isGraphConnectionValid(connection, tasks, dependencies, effectiveOrientation, autoLayoutStrategy)) {
656
+ if (!isGraphConnectionValid(connection, tasks, dependencies)) {
800
657
  return;
801
658
  }
802
- suppressNodeSelectionUntilRef.current = performance.now() + 150;
803
- if (autoLayoutStrategy === "hierarchy" &&
804
- sourceHandle === getHierarchyHandles(effectiveOrientation, "hierarchy").source) {
659
+ onSelectTask(target);
660
+ if (sourceHandle === "bottom") {
805
661
  onCreateChildRelationship?.(source, target);
662
+ return;
806
663
  }
807
- else {
808
- onCreateDependency?.(source, target);
809
- }
810
- window.requestAnimationFrame(() => {
811
- onSelectTask(target);
812
- });
664
+ onCreateDependency?.(source, target);
813
665
  }, [
814
666
  allowDependencyConnect,
815
- autoLayoutStrategy,
816
667
  dependencies,
817
- effectiveOrientation,
818
668
  onCreateChildRelationship,
819
669
  onCreateDependency,
820
670
  onSelectTask,
821
671
  tasks,
822
672
  ]);
823
- const handleOrientationChange = useCallback((nextOrientation) => {
824
- if (nextOrientation === effectiveOrientation) {
825
- return;
826
- }
827
- setTransientOrientation(nextOrientation);
828
- const autoLayout = buildGraph(tasks, dependencies, selectedTaskId, selectedDependencyId, blockedTaskIds, nextOrientation, showExecutionStateBadges, autoLayoutStrategy, onSelect, onAddDependentTaskFromNode, onAddChildTaskFromNode, onRemoveTask);
829
- setNodes(autoLayout.nodes);
830
- setEdges(autoLayout.edges);
831
- nodesRef.current = autoLayout.nodes;
832
- fitViewOnNextSyncRef.current = true;
833
- pendingSaveOrientationRef.current = nextOrientation;
834
- restoreViewport();
835
- }, [
836
- autoLayoutStrategy,
837
- blockedTaskIds,
838
- dependencies,
839
- effectiveOrientation,
840
- onAddChildTaskFromNode,
841
- onAddDependentTaskFromNode,
842
- onRemoveTask,
843
- onSelect,
844
- restoreViewport,
845
- selectedDependencyId,
846
- selectedTaskId,
847
- setEdges,
848
- setNodes,
849
- showExecutionStateBadges,
850
- tasks,
851
- ]);
852
- 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"
853
- ? "bg-slate-900 text-white"
854
- : "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"
855
- ? "bg-slate-900 text-white"
856
- : "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: () => {
673
+ 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-2 w-4 rounded-sm border border-orange-300 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 && 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: () => {
857
674
  onClearDependencySelection?.();
858
675
  }, onEdgeClick: (_event, edge) => {
859
676
  if (edge.data?.relationship === "dependency" &&
@@ -862,15 +679,9 @@ export function DependencyGraphView(props) {
862
679
  onSelectDependency?.(edge.data.taskId, edge.data.dependsOnTaskId);
863
680
  }
864
681
  }, onNodeClick: (_event, node) => {
865
- if (performance.now() < suppressNodeSelectionUntilRef.current) {
866
- return;
867
- }
868
682
  onClearDependencySelection?.();
869
683
  onSelectTask(node.id);
870
684
  }, onNodeDragStart: (_event, node) => {
871
- if (performance.now() < suppressNodeSelectionUntilRef.current) {
872
- return;
873
- }
874
685
  onClearDependencySelection?.();
875
686
  onSelectTask(node.id);
876
687
  }, onInit: (instance) => {
@@ -886,16 +697,13 @@ export function DependencyGraphView(props) {
886
697
  return;
887
698
  }
888
699
  queueLayoutSave(nodesRef.current, viewport);
889
- }, 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
700
+ }, 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
890
701
  ? { width: miniMapWidth, height: miniMapHeight }
891
702
  : {}), nodeColor: (node) => {
892
- const d = node.data;
893
- if (d?.isBlocked)
894
- return "#fecaca";
895
- const status = d?.status;
703
+ const status = node.data?.status;
896
704
  switch (status) {
897
705
  case "Done":
898
- return "#bbf7d0";
706
+ return "#86efac";
899
707
  case "InProgress":
900
708
  return "#93c5fd";
901
709
  case "Review":
@@ -905,6 +713,6 @@ export function DependencyGraphView(props) {
905
713
  default:
906
714
  return "#cbd5e1";
907
715
  }
908
- }, maskColor: "rgba(0, 0, 0, 0.08)", className: "rounded-lg! border-slate-200! shadow-md!" })) : null] })) })] }));
716
+ }, maskColor: "rgba(0, 0, 0, 0.08)", className: "rounded-lg! border-slate-200! shadow-md!" })] })) })] }));
909
717
  }
910
718
  //# sourceMappingURL=DependencyGraphView.js.map