77 type GraphInputArgument ,
88 type InputSpec ,
99 isGraphImplementation ,
10+ isGraphInputArgument ,
11+ isTaskOutputArgument ,
1012 type OutputSpec ,
1113 type TaskOutputArgument ,
1214 type TaskSpec ,
@@ -28,6 +30,14 @@ import {
2830 getUniqueTaskName ,
2931} from "@/utils/unique" ;
3032
33+ import {
34+ getFlexNode ,
35+ updateFlexNodeInComponentSpec ,
36+ } from "../FlexNode/interface" ;
37+ import type { FlexNodeData } from "../FlexNode/types" ;
38+ import { createFlexNode } from "../FlexNode/utils" ;
39+ import { isFlexNode } from "../types" ;
40+ import addFlexNode from "./addFlexNode" ;
3141import { getNodesBounds } from "./geometry" ;
3242
3343const OFFSET = 10 ;
@@ -49,6 +59,7 @@ export const duplicateNodes = (
4959 position ?: XYPosition ;
5060 connection ?: ConnectionMode ;
5161 status ?: boolean ;
62+ author ?: string ;
5263 } ,
5364) => {
5465 if ( ! isGraphImplementation ( componentSpec . implementation ) ) {
@@ -62,10 +73,12 @@ export const duplicateNodes = (
6273 const newTasks : Record < string , TaskSpec > = { } ;
6374 const newInputs : Record < string , InputSpec > = { } ;
6475 const newOutputs : Record < string , OutputSpec > = { } ;
76+ const newFlexNodes : Record < string , FlexNodeData > = { } ;
6577
6678 // Default Config
6779 const selected = config ?. selected ?? true ;
6880 const connection = config ?. connection ?? "all" ;
81+ const author = config ?. author ?? "system" ;
6982
7083 /* Create new Nodes and map old Task IDs to new Task IDs */
7184 nodesToDuplicate . forEach ( ( node ) => {
@@ -141,6 +154,27 @@ export const duplicateNodes = (
141154 } ;
142155
143156 newOutputs [ newOutputId ] = newOutputSpec ;
157+ } else if ( isFlexNode ( node ) ) {
158+ const flexNode = getFlexNode ( node . id , componentSpec ) ;
159+ const { spec : updatedComponentSpec , nodeId : newNodeId } = addFlexNode (
160+ {
161+ x : node . position . x + OFFSET ,
162+ y : node . position . y + OFFSET ,
163+ } ,
164+ author ,
165+ componentSpec ,
166+ flexNode ? { ...flexNode , id : undefined } : undefined ,
167+ ) ;
168+
169+ const newNodeData = getFlexNode ( newNodeId , updatedComponentSpec ) ;
170+ if ( ! newNodeData ) {
171+ throw new Error ( "Failed to retrieve newly created Flex Node data." ) ;
172+ }
173+
174+ newFlexNodes [ newNodeId ] = newNodeData ;
175+ nodeIdMap [ oldNodeId ] = newNodeId ;
176+ } else {
177+ throw new Error ( `Unsupported node type: ${ node . type } ` ) ;
144178 }
145179 } ) ;
146180
@@ -153,11 +187,7 @@ export const duplicateNodes = (
153187 const newTaskSpec = newTasks [ taskId ] ;
154188
155189 // Check if the Argument is a connection to another Task or Input Node (i.e. TaskOutput or GraphInput) or a static value
156- if (
157- typeof argument === "object" &&
158- argument !== null &&
159- ( "taskOutput" in argument || "graphInput" in argument )
160- ) {
190+ if ( isTaskOutputArgument ( argument ) || isGraphInputArgument ( argument ) ) {
161191 newTasks [ taskId ] = reconfigureConnections (
162192 newTaskSpec ,
163193 argKey ,
@@ -217,7 +247,7 @@ export const duplicateNodes = (
217247 updatedOutputValue !== null &&
218248 connection !== "external"
219249 ) {
220- if ( "taskOutput" in updatedOutputValue ) {
250+ if ( isTaskOutputArgument ( updatedOutputValue ) ) {
221251 const oldTaskId = updatedOutputValue . taskOutput . taskId ;
222252 const oldTaskNodeId = taskIdToNodeId ( oldTaskId ) ;
223253 if ( oldTaskNodeId in nodeIdMap ) {
@@ -348,6 +378,28 @@ export const duplicateNodes = (
348378
349379 updatedNodes . push ( originalNode ) ;
350380
381+ return newNode ;
382+ } else if ( isFlexNode ( originalNode ) ) {
383+ const newNodeData = newFlexNodes [ newNodeId ] ;
384+
385+ if ( ! newNodeData ) {
386+ return null ;
387+ }
388+
389+ const newNode = createFlexNode ( newNodeData ) ;
390+
391+ newNode . id = newNodeId ;
392+
393+ // Move selection to new node by default
394+ if ( selected ) {
395+ originalNode . selected = false ;
396+ newNode . selected = true ;
397+ }
398+
399+ newNode . measured = originalNode . measured ;
400+
401+ updatedNodes . push ( originalNode ) ;
402+
351403 return newNode ;
352404 }
353405 } )
@@ -447,13 +499,26 @@ export const duplicateNodes = (
447499 if ( updatedOutputIndex !== - 1 ) {
448500 updatedOutputs [ updatedOutputIndex ] = newOutputSpec ;
449501 }
502+ } else if ( isFlexNode ( node ) ) {
503+ const flexNode = getFlexNode ( node . id , componentSpec ) ;
504+
505+ if ( ! flexNode ) {
506+ return ;
507+ }
508+
509+ const newFlexNodeData = {
510+ ...flexNode ,
511+ position : newPosition ,
512+ } ;
513+
514+ newFlexNodes [ node . id ] = newFlexNodeData ;
450515 }
451516
452517 node . position = newPosition ;
453518 } ) ;
454519 }
455520
456- const updatedComponentSpec = {
521+ const updatedComponentSpec : ComponentSpec = {
457522 ...componentSpec ,
458523 inputs : updatedInputs ,
459524 outputs : updatedOutputs ,
@@ -463,7 +528,13 @@ export const duplicateNodes = (
463528 updatedComponentSpec . implementation . graph = updatedGraphSpec ;
464529 }
465530
466- return { updatedComponentSpec, nodeIdMap, newNodes, updatedNodes } ;
531+ /* Handle Flex Nodes */
532+ let spec = updatedComponentSpec ;
533+ Object . values ( newFlexNodes ) . forEach ( ( newNodeData ) => {
534+ spec = updateFlexNodeInComponentSpec ( spec , newNodeData ) ;
535+ } ) ;
536+
537+ return { updatedComponentSpec : spec , nodeIdMap, newNodes, updatedNodes } ;
467538} ;
468539
469540function reconfigureConnections (
@@ -479,7 +550,7 @@ function reconfigureConnections(
479550 let newArgId = undefined ;
480551 let isExternal = false ;
481552
482- if ( "taskOutput" in argument ) {
553+ if ( isTaskOutputArgument ( argument ) ) {
483554 const oldTaskId = argument . taskOutput . taskId ;
484555 oldNodeId = taskIdToNodeId ( oldTaskId ) ;
485556
@@ -499,7 +570,7 @@ function reconfigureConnections(
499570 const newTaskId = nodeIdToTaskId ( newNodeId ) ;
500571
501572 newArgId = newTaskId ;
502- } else if ( "graphInput" in argument ) {
573+ } else if ( isGraphInputArgument ( argument ) ) {
503574 const oldInputId = argument . graphInput . inputName ;
504575 oldNodeId = inputNameToNodeId ( oldInputId ) ;
505576
@@ -596,7 +667,7 @@ function updateTaskArgumentConnection(
596667 argument : TaskOutputArgument | GraphInputArgument ,
597668 newArgId : string ,
598669) : TaskSpec {
599- if ( "taskOutput" in argument ) {
670+ if ( isTaskOutputArgument ( argument ) ) {
600671 return {
601672 ...taskSpec ,
602673 arguments : {
@@ -610,7 +681,7 @@ function updateTaskArgumentConnection(
610681 } ,
611682 } ,
612683 } ;
613- } else if ( "graphInput" in argument ) {
684+ } else if ( isGraphInputArgument ( argument ) ) {
614685 return {
615686 ...taskSpec ,
616687 arguments : {
0 commit comments