Skip to content

Commit b62b77d

Browse files
committed
Fix inability to delete edges
1 parent 5e3ceff commit b62b77d

File tree

7 files changed

+136
-122
lines changed

7 files changed

+136
-122
lines changed

src/components/shared/ReactFlow/FlowCanvas/IONode/IONode.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ interface IONodeProps {
2828
}
2929

3030
const IONode = ({ type, data, selected = false }: IONodeProps) => {
31-
const { getInputNodeId, getOutputNodeId } = useNodeManager();
31+
const { getNodeId, getHandleNodeId } = useNodeManager();
3232
const { graphSpec, componentSpec } = useComponentSpec();
3333
const { setContent, clearContent } = useContextPanel();
3434

@@ -59,11 +59,13 @@ const IONode = ({ type, data, selected = false }: IONodeProps) => {
5959
[componentSpec.outputs, spec.name],
6060
);
6161

62-
const nodeId = isInput
63-
? getInputNodeId(inputNameToInputId(spec.name))
64-
: getOutputNodeId(outputNameToOutputId(spec.name));
62+
const inputId = inputNameToInputId(spec.name);
63+
const outputId = outputNameToOutputId(spec.name);
64+
const id = isInput ? inputId : outputId;
6565

66-
const nodeHandleId = `${nodeId}_handle`;
66+
const nodeId = getNodeId(id, type);
67+
const handleNodeType = isInput ? "outputHandle" : "inputHandle";
68+
const nodeHandleId = getHandleNodeId(id, "handle", handleNodeType);
6769

6870
const handleHandleClick = useCallback(() => {
6971
if (ENABLE_DEBUG_MODE) {

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskNodeCard/Handles.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const InputHandle = ({
3434
onLabelClick,
3535
onHandleSelectionChange,
3636
}: InputHandleProps) => {
37-
const { getTaskInputNodeId } = useNodeManager();
37+
const { getInputHandleNodeId } = useNodeManager();
3838
const { taskId, nodeId, state, name } = useTaskNode();
3939

4040
const fromHandle = useConnection((connection) => connection.fromHandle?.id);
@@ -47,7 +47,7 @@ export const InputHandle = ({
4747
const [selected, setSelected] = useState(false);
4848
const [active, setActive] = useState(false);
4949

50-
const handleId = getTaskInputNodeId(taskId, input.name);
50+
const handleId = getInputHandleNodeId(taskId, input.name);
5151

5252
const missing = invalid ? "bg-red-700!" : "bg-gray-500!";
5353
const hasValue = value !== undefined && value !== null;
@@ -230,7 +230,7 @@ export const OutputHandle = ({
230230
onLabelClick,
231231
onHandleSelectionChange,
232232
}: OutputHandleProps) => {
233-
const { getTaskOutputNodeId } = useNodeManager();
233+
const { getOutputHandleNodeId } = useNodeManager();
234234
const { taskId, nodeId, state, name } = useTaskNode();
235235

236236
const fromHandle = useConnection((connection) => connection.fromHandle?.id);
@@ -243,7 +243,7 @@ export const OutputHandle = ({
243243
const [selected, setSelected] = useState(false);
244244
const [active, setActive] = useState(false);
245245

246-
const handleId = getTaskOutputNodeId(taskId, output.name);
246+
const handleId = getOutputHandleNodeId(taskId, output.name);
247247
const hasValue = value !== undefined && value !== "" && value !== null;
248248

249249
const handleHandleClick = useCallback(

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskNodeCard/TaskNodeInputs.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function TaskNodeInputs({
2727
expanded,
2828
onBackgroundClick,
2929
}: TaskNodeInputsProps) {
30-
const { getTaskInputNodeId } = useNodeManager();
30+
const { getInputHandleNodeId } = useNodeManager();
3131
const { taskId, inputs, taskSpec, state, select } = useTaskNode();
3232
const { graphSpec } = useComponentSpec();
3333
const {
@@ -146,7 +146,7 @@ export function TaskNodeInputs({
146146
}
147147

148148
const input = inputs.find(
149-
(i) => getTaskInputNodeId(taskId, i.name) === fromHandle?.id,
149+
(i) => getInputHandleNodeId(taskId, i.name) === fromHandle?.id,
150150
);
151151

152152
if (!input) return;

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskNodeCard/TaskNodeOutputs.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function TaskNodeOutputs({
2323
expanded,
2424
onBackgroundClick,
2525
}: TaskNodeOutputsProps) {
26-
const { getTaskOutputNodeId } = useNodeManager();
26+
const { getOutputHandleNodeId } = useNodeManager();
2727
const { taskId, nodeId, outputs, state, select } = useTaskNode();
2828
const {
2929
highlightSearchFilter,
@@ -41,7 +41,7 @@ export function TaskNodeOutputs({
4141
edges.some(
4242
(edge) =>
4343
edge.source === nodeId &&
44-
edge.sourceHandle === getTaskOutputNodeId(taskId, output.name),
44+
edge.sourceHandle === getOutputHandleNodeId(taskId, output.name),
4545
),
4646
);
4747

@@ -139,7 +139,7 @@ export function TaskNodeOutputs({
139139
}
140140

141141
const output = outputs.find(
142-
(o) => getTaskOutputNodeId(taskId, o.name) === fromHandle?.id,
142+
(o) => getOutputHandleNodeId(taskId, o.name) === fromHandle?.id,
143143
);
144144

145145
if (!output) return;

src/components/shared/ReactFlow/FlowCanvas/utils/addAndConnectNode.ts

Lines changed: 55 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Connection, Handle } from "@xyflow/react";
22

3-
import type { NodeManager } from "@/nodeManager";
3+
import type { NodeManager, NodeType } from "@/nodeManager";
44
import {
55
type ComponentReference,
66
type ComponentSpec,
@@ -48,57 +48,44 @@ export function addAndConnectNode({
4848
return componentSpec;
4949
}
5050

51-
const isTaskHandle = nodeManager.isManaged(fromHandle.id);
52-
let fromHandleType: "input" | "output";
53-
let fromHandleName: string | undefined;
54-
let fromTaskId: string | undefined;
51+
const fromNodeId = fromHandle.nodeId;
52+
const fromNodeType = nodeManager.getNodeType(fromNodeId);
53+
const fromTaskId = nodeManager.getTaskId(fromNodeId);
5554

56-
if (isTaskHandle) {
57-
// Handle is managed by NodeManager (task handle)
58-
const fromHandleInfo = nodeManager.getHandleInfo(fromHandle.id);
59-
const fromNodeType = nodeManager.getNodeType(fromHandle.id);
55+
if (!fromTaskId) {
56+
return componentSpec;
57+
}
6058

61-
if (!fromHandleInfo || !fromNodeType) {
62-
return componentSpec;
63-
}
59+
let fromHandleType: NodeType | undefined;
60+
let fromHandleName: string | undefined;
6461

65-
fromHandleType = fromNodeType === "taskInput" ? "input" : "output";
66-
fromHandleName = fromHandleInfo.handleName;
67-
fromTaskId = fromHandleInfo.taskId;
62+
if (fromNodeType === "task") {
63+
const fromHandleInfo = nodeManager.getHandleInfo(fromHandle.id);
64+
fromHandleName = fromHandleInfo?.handleName;
65+
fromHandleType = nodeManager.getNodeType(fromHandle.id);
66+
} else if (fromNodeType === "input") {
67+
fromHandleType = "outputHandle";
68+
fromHandleName = inputIdToInputName(fromTaskId);
69+
} else if (fromNodeType === "output") {
70+
fromHandleType = "inputHandle";
71+
fromHandleName = outputIdToOutputName(fromTaskId);
6872
} else {
69-
// Simple IO node handle - get info from the source node, not the handle
70-
const fromNodeId = fromHandle.nodeId;
71-
const fromNodeType = nodeManager.getNodeType(fromNodeId);
72-
73-
if (!fromNodeType) {
74-
return componentSpec;
75-
}
76-
77-
if (fromNodeType === "input") {
78-
fromHandleType = "output";
79-
const inputId = nodeManager.getTaskId(fromNodeId);
80-
if (inputId) {
81-
fromHandleName = inputIdToInputName(inputId);
82-
fromTaskId = inputId;
83-
}
84-
} else if (fromNodeType === "output") {
85-
fromHandleType = "input";
86-
const outputId = nodeManager.getTaskId(fromNodeId);
87-
if (outputId) {
88-
fromHandleName = outputIdToOutputName(outputId);
89-
fromTaskId = outputId;
90-
}
91-
} else {
92-
return componentSpec;
93-
}
73+
return componentSpec;
74+
}
75+
76+
if (!fromHandleName) {
77+
return componentSpec;
9478
}
9579

96-
if (!fromTaskId || !fromHandleName) {
80+
if (
81+
!fromHandleType ||
82+
(fromHandleType !== "inputHandle" && fromHandleType !== "outputHandle")
83+
) {
9784
return componentSpec;
9885
}
9986

10087
const adjustedPosition =
101-
fromHandleType === "input"
88+
fromHandleType === "inputHandle"
10289
? { ...position, x: position.x - DEFAULT_NODE_DIMENSIONS.w }
10390
: position;
10491

@@ -129,7 +116,7 @@ export function addAndConnectNode({
129116
// 3. Determine the connection data type and find the first matching handle on the new node
130117
let fromComponentSpec: ComponentSpec | undefined;
131118

132-
if (isTaskHandle) {
119+
if (fromNodeType === "task") {
133120
// Get spec from task
134121
const fromTaskSpec = graphSpec.tasks[fromTaskId];
135122
fromComponentSpec = fromTaskSpec?.componentRef.spec;
@@ -139,55 +126,48 @@ export function addAndConnectNode({
139126
}
140127

141128
let connectionType: TypeSpecType | undefined;
142-
if (fromHandleType === "input") {
129+
if (fromHandleType === "inputHandle") {
143130
connectionType = fromComponentSpec?.inputs?.find(
144131
(io) => io.name === fromHandleName,
145132
)?.type;
146-
} else if (fromHandleType === "output") {
133+
} else if (fromHandleType === "outputHandle") {
147134
connectionType = fromComponentSpec?.outputs?.find(
148135
(io) => io.name === fromHandleName,
149136
)?.type;
150137
}
151138

152139
// Find the first matching handle on the new node
153-
const toHandleType = fromHandleType === "input" ? "output" : "input";
154-
let targetHandleId: string | undefined;
155-
156-
if (toHandleType === "input") {
157-
const handleName = componentRef.spec?.inputs?.find(
158-
(io) => io.type === connectionType,
159-
)?.name;
160-
if (!handleName) {
161-
return newComponentSpec;
162-
}
163-
164-
targetHandleId = nodeManager.getTaskHandleNodeId(
165-
newTaskId,
166-
handleName,
167-
"taskInput",
168-
);
169-
} else if (toHandleType === "output") {
170-
const handleName = componentRef.spec?.outputs?.find(
171-
(io) => io.type === connectionType,
172-
)?.name;
173-
if (!handleName) {
174-
return newComponentSpec;
175-
}
176-
177-
targetHandleId = nodeManager.getTaskHandleNodeId(
178-
newTaskId,
179-
handleName,
180-
"taskOutput",
181-
);
140+
const toHandleType =
141+
fromHandleType === "inputHandle" ? "outputHandle" : "inputHandle";
142+
143+
const inputHandleName = componentRef.spec?.inputs?.find(
144+
(io) => io.type === connectionType,
145+
)?.name;
146+
147+
const outputHandleName = componentRef.spec?.outputs?.find(
148+
(io) => io.type === connectionType,
149+
)?.name;
150+
151+
const toHandleName =
152+
toHandleType === "inputHandle" ? inputHandleName : outputHandleName;
153+
154+
if (!toHandleName) {
155+
return newComponentSpec;
182156
}
183157

158+
const targetHandleId = nodeManager.getHandleNodeId(
159+
newTaskId,
160+
toHandleName,
161+
toHandleType,
162+
);
163+
184164
// 4. Build a Connection object and use handleConnection to add the edge
185165
if (targetHandleId) {
186166
const fromNodeId = fromHandle.nodeId;
187167
const fromHandleId = fromHandle.id;
188168

189169
const isReversedConnection =
190-
fromHandleType === "input" && toHandleType === "output";
170+
fromHandleType === "inputHandle" && toHandleType === "outputHandle";
191171

192172
const connection: Connection = isReversedConnection
193173
? // Drawing from an input handle to a new output handle
Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import type { Edge } from "@xyflow/react";
22

33
import type { NodeManager } from "@/nodeManager";
4-
import type { ComponentSpec, GraphImplementation } from "@/utils/componentSpec";
4+
import {
5+
type ComponentSpec,
6+
isGraphImplementation,
7+
} from "@/utils/componentSpec";
58
import { outputIdToOutputName } from "@/utils/nodes/conversions";
69

710
import { setGraphOutputValue } from "./setGraphOutputValue";
@@ -12,38 +15,67 @@ export const removeEdge = (
1215
componentSpec: ComponentSpec,
1316
nodeManager: NodeManager,
1417
) => {
15-
const graphSpec = (componentSpec.implementation as GraphImplementation)
16-
?.graph;
18+
if (!isGraphImplementation(componentSpec.implementation)) {
19+
return componentSpec;
20+
}
21+
22+
const graphSpec = componentSpec.implementation.graph;
23+
const updatedComponentSpec = { ...componentSpec };
1724

18-
if (!edge.targetHandle) {
25+
const targetNodeId = edge.target;
26+
const targetTaskId = nodeManager.getTaskId(targetNodeId);
27+
const targetNodeType = nodeManager.getNodeType(targetNodeId);
28+
29+
if (!targetTaskId || !targetNodeType) {
30+
console.error("Could not resolve target node information:", {
31+
targetNodeId,
32+
targetTaskId,
33+
targetNodeType,
34+
});
1935
return componentSpec;
2036
}
2137

22-
const inputName = nodeManager.getHandleInfo(edge.targetHandle)?.handleName;
38+
switch (targetNodeType) {
39+
case "task": {
40+
if (!edge.targetHandle) {
41+
console.error("No target handle found for task connection");
42+
return componentSpec;
43+
}
44+
45+
const targetHandleInfo = nodeManager.getHandleInfo(edge.targetHandle);
46+
if (!targetHandleInfo) {
47+
console.error("Could not resolve target handle info");
48+
return componentSpec;
49+
}
2350

24-
const updatedComponentSpec = {
25-
...componentSpec,
26-
};
51+
const inputName = targetHandleInfo.handleName;
52+
const newGraphSpec = setTaskArgument(graphSpec, targetTaskId, inputName);
2753

28-
const taskId = nodeManager.getTaskId(edge.target);
29-
if (!taskId) return componentSpec;
54+
updatedComponentSpec.implementation = {
55+
...updatedComponentSpec.implementation,
56+
graph: newGraphSpec,
57+
};
58+
break;
59+
}
3060

31-
if (inputName !== undefined && graphSpec) {
32-
const newGraphSpec = setTaskArgument(graphSpec, taskId, inputName);
33-
updatedComponentSpec.implementation = {
34-
...updatedComponentSpec.implementation,
35-
graph: newGraphSpec,
36-
};
61+
case "output": {
62+
const outputName = outputIdToOutputName(targetTaskId);
63+
const newGraphSpec = setGraphOutputValue(graphSpec, outputName);
3764

38-
return updatedComponentSpec;
39-
} else {
40-
const outputName = outputIdToOutputName(taskId);
41-
const newGraphSpec = setGraphOutputValue(graphSpec, outputName);
42-
updatedComponentSpec.implementation = {
43-
...updatedComponentSpec.implementation,
44-
graph: newGraphSpec,
45-
};
65+
updatedComponentSpec.implementation = {
66+
...updatedComponentSpec.implementation,
67+
graph: newGraphSpec,
68+
};
69+
break;
70+
}
4671

47-
return updatedComponentSpec;
72+
default:
73+
console.error(
74+
"Unsupported target node type for edge removal:",
75+
targetNodeType,
76+
);
77+
return componentSpec;
4878
}
79+
80+
return updatedComponentSpec;
4981
};

0 commit comments

Comments
 (0)