Skip to content

Commit 3710449

Browse files
committed
POC Unpack Subgraphs onto empty Canvas
1 parent ac41105 commit 3710449

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,17 @@ import { hydrateComponentReference } from "@/services/componentService";
3737
import {
3838
type ComponentSpec,
3939
type InputSpec,
40+
isGraphImplementation,
4041
isNotMaterializedComponentReference,
4142
type TaskSpec,
4243
} from "@/utils/componentSpec";
4344
import { readTextFromFile } from "@/utils/dom";
4445
import { deselectAllNodes } from "@/utils/flowUtils";
4546
import createNodesFromComponentSpec from "@/utils/nodes/createNodesFromComponentSpec";
47+
import { extractPositionFromAnnotations } from "@/utils/nodes/extractPositionFromAnnotations";
4648
import {
4749
getSubgraphComponentSpec,
50+
isSubgraph,
4851
updateSubgraphSpec,
4952
} from "@/utils/subgraphUtils";
5053

@@ -579,6 +582,90 @@ const FlowCanvas = ({
579582
}
580583
}
581584

585+
// Drop a subgraph onto an empty canvas
586+
if (
587+
nodes.length === 0 &&
588+
taskType === "task" &&
589+
droppedTask &&
590+
isSubgraph(droppedTask) &&
591+
droppedTask.componentRef.spec &&
592+
isGraphImplementation(droppedTask.componentRef.spec.implementation)
593+
) {
594+
const dialogDetails = {
595+
title: "Import Subgraph as Pipeline",
596+
description: `Dropping the subgraph "${droppedTask.componentRef.spec.name}" onto an empty canvas will unpack its internal components. Do you want to proceed?`,
597+
};
598+
599+
const confirmed = await triggerConfirmation(dialogDetails);
600+
601+
if (!confirmed) {
602+
return;
603+
}
604+
605+
// Todo: copy over IO values
606+
// Todo: output node connections
607+
// Todo: Move logic into a utility
608+
console.log("Unpacking subgraph onto empty canvas");
609+
console.log("Dropped Task:", droppedTask);
610+
611+
const graphSpec = droppedTask.componentRef.spec?.implementation.graph;
612+
613+
let updatedSubgraphSpec = { ...currentSubgraphSpec };
614+
615+
Object.entries(graphSpec.tasks).forEach(([_, task]) => {
616+
const { spec } = addTask(
617+
"task",
618+
task,
619+
extractPositionFromAnnotations(task.annotations),
620+
updatedSubgraphSpec,
621+
);
622+
623+
updatedSubgraphSpec = spec;
624+
});
625+
626+
droppedTask.componentRef.spec.inputs?.forEach((input) => {
627+
const { spec } = addTask(
628+
"input",
629+
null,
630+
extractPositionFromAnnotations(input.annotations),
631+
updatedSubgraphSpec,
632+
{
633+
name: input.name,
634+
type: input.type,
635+
description: input.description,
636+
},
637+
);
638+
639+
updatedSubgraphSpec = spec;
640+
});
641+
642+
droppedTask.componentRef.spec.outputs?.forEach((output) => {
643+
const { spec } = addTask(
644+
"output",
645+
null,
646+
extractPositionFromAnnotations(output.annotations),
647+
updatedSubgraphSpec,
648+
{
649+
name: output.name,
650+
type: output.type,
651+
description: output.description,
652+
},
653+
);
654+
655+
updatedSubgraphSpec = spec;
656+
});
657+
658+
const newRootSpec = updateSubgraphSpec(
659+
componentSpec,
660+
currentSubgraphPath,
661+
updatedSubgraphSpec,
662+
);
663+
664+
setComponentSpec(newRootSpec);
665+
666+
return;
667+
}
668+
582669
// Replacing an existing node
583670
if (replaceTarget) {
584671
if (!droppedTask) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface AddTaskResult {
2626
* Options for creating input/output nodes.
2727
* Omits position-related fields (annotations) which are automatically set.
2828
*/
29-
type IONodeOptions = Omit<Partial<InputSpec>, "annotations">;
29+
type IONodeOptions = Omit<Partial<InputSpec | OutputSpec>, "annotations">;
3030

3131
/**
3232
* Creates a task, input, or output node and adds it to the component specification.

0 commit comments

Comments
 (0)