Skip to content

Commit 28dbb2b

Browse files
committed
Fix IO Node Copy + Paste
1 parent c82efe1 commit 28dbb2b

File tree

4 files changed

+170
-114
lines changed

4 files changed

+170
-114
lines changed

src/components/shared/ReactFlow/FlowCanvas/utils/addTask.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ describe("addTask", () => {
123123
? Object.keys(newComponentSpec.implementation.graph.tasks)
124124
: [];
125125
expect(taskIds.length).toBe(2);
126-
expect(taskIds).toContain("TestTask 2");
126+
expect(taskIds).toContain("TestTask (2)");
127127
});
128128

129129
it("should create unique names for inputs when duplicates exist", () => {
@@ -139,7 +139,7 @@ describe("addTask", () => {
139139
};
140140

141141
expect(newComponentSpec.inputs.length).toBe(2);
142-
expect(newComponentSpec.inputs[1].name).toBe("Input 2");
142+
expect(newComponentSpec.inputs[1].name).toBe("Input (2)");
143143
});
144144

145145
it("should create unique names for outputs when duplicates exist", () => {
@@ -155,6 +155,6 @@ describe("addTask", () => {
155155
};
156156

157157
expect(newComponentSpec.outputs.length).toBe(2);
158-
expect(newComponentSpec.outputs[1].name).toBe("Output 2");
158+
expect(newComponentSpec.outputs[1].name).toBe("Output (2)");
159159
});
160160
});

src/components/shared/ReactFlow/FlowCanvas/utils/duplicateNodes.test.ts

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { describe, expect, it, vi } from "vitest";
33

44
import { NodeManager } from "@/nodeManager";
55
import type { TaskNodeData } from "@/types/nodes";
6-
import type {
7-
ComponentSpec,
8-
InputSpec,
9-
OutputSpec,
10-
TaskOutputArgument,
11-
TaskSpec,
6+
import {
7+
type ComponentSpec,
8+
type InputSpec,
9+
isGraphImplementation,
10+
type OutputSpec,
11+
type TaskOutputArgument,
12+
type TaskSpec,
1213
} from "@/utils/componentSpec";
1314

1415
import { duplicateNodes } from "./duplicateNodes";
@@ -63,7 +64,7 @@ const createMockComponentSpecWithOutputs = (
6364
acc[output.name] = {
6465
taskOutput: {
6566
taskId: "task1",
66-
outputName: "result",
67+
outputName: output.name,
6768
},
6869
};
6970
return acc;
@@ -124,7 +125,7 @@ const createMockInputNode = (
124125
position,
125126
data: {
126127
label: inputName,
127-
inputSpec: { ...mockInputSpec, name: inputName },
128+
spec: { ...mockInputSpec, name: inputName },
128129
},
129130
selected: false,
130131
dragging: false,
@@ -145,7 +146,7 @@ const createMockOutputNode = (
145146
position,
146147
data: {
147148
label: outputName,
148-
outputSpec: { ...mockOutputSpec, name: outputName },
149+
spec: { ...mockOutputSpec, name: outputName },
149150
},
150151
selected: false,
151152
dragging: false,
@@ -211,7 +212,7 @@ describe("duplicateNodes", () => {
211212
if ("graph" in result.updatedComponentSpec.implementation!) {
212213
expect(
213214
result.updatedComponentSpec.implementation.graph.tasks,
214-
).toHaveProperty("original-task 2");
215+
).toHaveProperty("original-task (2)");
215216
}
216217
});
217218

@@ -237,14 +238,14 @@ describe("duplicateNodes", () => {
237238
expect(result.newNodes).toHaveLength(1);
238239
expect(result.newNodes[0].type).toBe("input");
239240
expect(result.newNodes[0].id).toBe(
240-
nodeManager.getNodeId("original-input 2", "input"),
241+
nodeManager.getNodeId("original-input (2)", "input"),
241242
);
242243
expect(result.newNodes[0].position).toEqual({ x: 60, y: 60 });
243244

244245
expect(result.updatedComponentSpec.inputs).toHaveLength(2);
245246
expect(
246247
result.updatedComponentSpec.inputs?.some(
247-
(input) => input.name === "original-input 2",
248+
(input) => input.name === "original-input (2)",
248249
),
249250
).toBe(true);
250251
});
@@ -275,14 +276,14 @@ describe("duplicateNodes", () => {
275276
expect(result.newNodes).toHaveLength(1);
276277
expect(result.newNodes[0].type).toBe("output");
277278
expect(result.newNodes[0].id).toBe(
278-
nodeManager.getNodeId("original-output 2", "output"),
279+
nodeManager.getNodeId("original-output (2)", "output"),
279280
);
280281
expect(result.newNodes[0].position).toEqual({ x: 310, y: 310 });
281282

282283
expect(result.updatedComponentSpec.outputs).toHaveLength(2);
283284
expect(
284285
result.updatedComponentSpec.outputs?.some(
285-
(output) => output.name === "original-output 2",
286+
(output) => output.name === "original-output (2)",
286287
),
287288
).toBe(true);
288289
});
@@ -305,13 +306,13 @@ describe("duplicateNodes", () => {
305306
const result = duplicateNodes(componentSpec, nodes, nodeManager);
306307

307308
expect(result.newNodes).toHaveLength(2);
308-
if ("graph" in result.updatedComponentSpec.implementation!) {
309+
if (isGraphImplementation(result.updatedComponentSpec.implementation)) {
309310
expect(
310311
result.updatedComponentSpec.implementation.graph.tasks,
311-
).toHaveProperty("task1 2");
312+
).toHaveProperty("task1 (2)");
312313
expect(
313314
result.updatedComponentSpec.implementation.graph.tasks,
314-
).toHaveProperty("task2 2");
315+
).toHaveProperty("task2 (2)");
315316
}
316317
});
317318
});
@@ -419,7 +420,7 @@ describe("duplicateNodes", () => {
419420

420421
if ("graph" in result.updatedComponentSpec.implementation!) {
421422
const duplicatedTask2 =
422-
result.updatedComponentSpec.implementation.graph.tasks["task2 2"];
423+
result.updatedComponentSpec.implementation.graph.tasks["task2 (2)"];
423424
expect(duplicatedTask2.arguments).toEqual({});
424425
}
425426
});
@@ -443,10 +444,10 @@ describe("duplicateNodes", () => {
443444

444445
if ("graph" in result.updatedComponentSpec.implementation!) {
445446
const duplicatedTask2 =
446-
result.updatedComponentSpec.implementation.graph.tasks["task2 2"];
447+
result.updatedComponentSpec.implementation.graph.tasks["task2 (2)"];
447448
expect(duplicatedTask2.arguments?.input1).toEqual({
448449
taskOutput: {
449-
taskId: "task1 2",
450+
taskId: "task1 (2)",
450451
outputName: "output1",
451452
},
452453
});
@@ -496,7 +497,7 @@ describe("duplicateNodes", () => {
496497

497498
if ("graph" in result.updatedComponentSpec.implementation!) {
498499
const duplicatedTask2 =
499-
result.updatedComponentSpec.implementation.graph.tasks["task2 2"];
500+
result.updatedComponentSpec.implementation.graph.tasks["task2 (2)"];
500501

501502
// Should remove internal connection to task1 (since task1 is being duplicated)
502503
expect(duplicatedTask2.arguments?.input1).toBeUndefined();
@@ -530,10 +531,10 @@ describe("duplicateNodes", () => {
530531

531532
if ("graph" in result.updatedComponentSpec.implementation!) {
532533
const duplicatedTask2 =
533-
result.updatedComponentSpec.implementation.graph.tasks["task2 2"];
534+
result.updatedComponentSpec.implementation.graph.tasks["task2 (2)"];
534535
expect(duplicatedTask2.arguments?.input1).toEqual({
535536
taskOutput: {
536-
taskId: "task1 2",
537+
taskId: "task1 (2)",
537538
outputName: "output1",
538539
},
539540
});
@@ -571,26 +572,45 @@ describe("duplicateNodes", () => {
571572
connection: "all",
572573
});
573574

574-
if ("graph" in result.updatedComponentSpec.implementation!) {
575+
if (isGraphImplementation(result.updatedComponentSpec.implementation)) {
575576
const duplicatedTask =
576-
result.updatedComponentSpec.implementation.graph.tasks["task1 2"];
577+
result.updatedComponentSpec.implementation.graph.tasks["task1 (2)"];
577578
expect(duplicatedTask.arguments?.input1).toEqual({
578579
graphInput: {
579-
inputName: "graph-input 2",
580+
inputName: "graph-input (2)",
580581
},
581582
});
582583
}
583584
});
584585

585586
it("should handle graph output connections", () => {
587+
const outputSpec: OutputSpec = {
588+
...mockOutputSpec,
589+
name: "graph-output-node",
590+
};
591+
592+
const taskComponentSpec: ComponentSpec = {
593+
name: "task-component",
594+
inputs: [],
595+
outputs: [
596+
{
597+
name: "graph-output",
598+
type: "String",
599+
annotations: {},
600+
},
601+
],
602+
implementation: {
603+
container: { image: "task-image" },
604+
},
605+
};
606+
586607
const taskSpec: TaskSpec = {
587608
...mockTaskSpec,
588609
arguments: {},
589-
};
590-
591-
const outputSpec: OutputSpec = {
592-
...mockOutputSpec,
593-
name: "graph-output",
610+
componentRef: {
611+
name: "task-component",
612+
spec: taskComponentSpec,
613+
},
594614
};
595615

596616
const componentSpec = createMockComponentSpecWithOutputs(
@@ -602,23 +622,23 @@ describe("duplicateNodes", () => {
602622
const nodeManager = createMockNodeManager();
603623
const nodes = [
604624
createMockTaskNode("task1", taskSpec, nodeManager),
605-
createMockOutputNode("graph-output", nodeManager),
625+
createMockOutputNode("graph-output-node", nodeManager),
606626
];
607627

608628
const result = duplicateNodes(componentSpec, nodes, nodeManager, {
609629
connection: "all",
610630
});
611631

612632
// Check that outputValues are updated for duplicated outputs
613-
if ("graph" in result.updatedComponentSpec.implementation!) {
633+
if (isGraphImplementation(result.updatedComponentSpec.implementation)) {
614634
const outputValues =
615635
result.updatedComponentSpec.implementation.graph.outputValues;
616636

617637
// Duplicated output should reference duplicated task
618-
expect(outputValues?.["graph-output 2"]).toEqual({
638+
expect(outputValues?.["graph-output-node (2)"]).toEqual({
619639
taskOutput: {
620-
taskId: "task1 2",
621-
outputName: "result",
640+
taskId: "task1 (2)",
641+
outputName: "graph-output-node",
622642
},
623643
});
624644
}
@@ -656,7 +676,7 @@ describe("duplicateNodes", () => {
656676
it("should handle nodes without position annotations", () => {
657677
const taskSpecWithoutPosition = {
658678
...mockTaskSpec,
659-
annotations: {}, // No position annotation
679+
annotations: {},
660680
};
661681

662682
const componentSpec = createMockComponentSpec({

0 commit comments

Comments
 (0)