@@ -71,12 +71,7 @@ export const duplicateNodes = (
7171 const oldNodeId = node . id ;
7272
7373 if ( isTaskNode ( node ) ) {
74- const oldTaskId = nodeManager . getRefId ( oldNodeId ) ;
75- if ( ! oldTaskId ) {
76- console . warn ( "Could not find taskId for node:" , node ) ;
77- return ;
78- }
79-
74+ const oldTaskId = node . data . taskId ;
8075 const newTaskId = getUniqueTaskId ( graphSpec , oldTaskId ) ;
8176 const newNodeId = nodeManager . getNodeId ( newTaskId , "task" ) ;
8277
@@ -101,16 +96,14 @@ export const duplicateNodes = (
10196 } ;
10297 newTasks [ newTaskId ] = newTaskSpec ;
10398 } else if ( isInputNode ( node ) ) {
104- const inputSpec = componentSpec . inputs ?. find (
105- ( input ) => input . name === node . data . label ,
106- ) ;
99+ const inputSpec = node . data . spec ;
107100
108- const newInputName = getUniqueInputName ( componentSpec , inputSpec ? .name ) ;
101+ const newInputName = getUniqueInputName ( componentSpec , inputSpec . name ) ;
109102 const newNodeId = nodeManager . getNodeId ( newInputName , "input" ) ;
110103
111104 nodeIdMap [ oldNodeId ] = newNodeId ;
112105
113- const annotations = inputSpec ? .annotations || { } ;
106+ const annotations = inputSpec . annotations || { } ;
114107
115108 const updatedAnnotations = setPositionInAnnotations ( annotations , {
116109 x : node . position . x + OFFSET ,
@@ -125,19 +118,14 @@ export const duplicateNodes = (
125118
126119 newInputs [ newInputName ] = newInputSpec ;
127120 } else if ( isOutputNode ( node ) ) {
128- const outputSpec = componentSpec . outputs ?. find (
129- ( output ) => output . name === node . data . label ,
130- ) ;
121+ const outputSpec = node . data . spec ;
131122
132- const newOutputName = getUniqueOutputName (
133- componentSpec ,
134- outputSpec ?. name ,
135- ) ;
123+ const newOutputName = getUniqueOutputName ( componentSpec , outputSpec . name ) ;
136124 const newNodeId = nodeManager . getNodeId ( newOutputName , "output" ) ;
137125
138126 nodeIdMap [ oldNodeId ] = newNodeId ;
139127
140- const annotations = outputSpec ? .annotations || { } ;
128+ const annotations = outputSpec . annotations || { } ;
141129
142130 const updatedAnnotations = setPositionInAnnotations ( annotations , {
143131 x : node . position . x + OFFSET ,
@@ -192,10 +180,11 @@ export const duplicateNodes = (
192180 }
193181 } ) ;
194182
195- // Outputs are defined in the graph spec
196183 const updatedGraphOutputs = { ...graphSpec . outputValues } ;
197- if ( connection !== "none" ) {
198- /* Reconfigure Outputs */
184+
185+ // Output Nodes can only have one input, so the "external" connection mode does not apply to them.
186+ if ( connection !== "none" && connection !== "external" ) {
187+ /* Reconfigure Output Nodes */
199188 Object . entries ( newOutputs ) . forEach ( ( output ) => {
200189 const [ outputName ] = output ;
201190 const newNodeId = nodeManager . getNodeId ( outputName , "output" ) ;
@@ -207,57 +196,62 @@ export const duplicateNodes = (
207196 return ;
208197 }
209198
210- const oldOutputName = nodeManager . getRefId ( oldNodeId ) ;
199+ const originalOutputNode = nodesToDuplicate . find (
200+ ( node ) => node . id === oldNodeId && isOutputNode ( node ) ,
201+ ) ;
211202
212- if ( ! graphSpec . outputValues || ! oldOutputName ) {
203+ if ( ! originalOutputNode || ! isOutputNode ( originalOutputNode ) ) {
213204 return ;
214205 }
215206
216- const outputValue = graphSpec . outputValues [ oldOutputName ] ;
207+ const oldOutputName = originalOutputNode . data . spec . name ;
208+
209+ const originalOutputValue = graphSpec . outputValues ?. [ oldOutputName ] ;
217210
218- if ( ! outputValue ) {
211+ if ( ! originalOutputValue ) {
212+ // Todo: Handle cross-instance copy + paste for output nodes (we don't have the original graphSpec available so we can't look up the output value)
213+ console . warn (
214+ `No output value found for output ${ oldOutputName } in graph spec.` ,
215+ ) ;
219216 return ;
220217 }
221218
222- const updatedOutputValue = { ...outputValue } ;
223-
224- // If the outputvalue references a task that was also duplicated (internal connection), we need to update it to refer to the duplicated task id
225- let isInternal = false ;
226- if (
227- typeof updatedOutputValue === "object" &&
228- updatedOutputValue !== null &&
229- connection !== "external"
230- ) {
231- if ( "taskOutput" in updatedOutputValue ) {
232- const oldTaskId = updatedOutputValue . taskOutput . taskId ;
233- const oldTaskNodeId = nodeManager . getNodeId ( oldTaskId , "task" ) ;
234- if ( oldTaskNodeId in nodeIdMap ) {
235- const newTaskId = nodeManager . getRefId ( nodeIdMap [ oldTaskNodeId ] ) ;
236- if ( ! newTaskId ) {
237- return ;
238- }
239-
240- updatedOutputValue . taskOutput = {
241- ...updatedOutputValue . taskOutput ,
242- taskId : newTaskId ,
243- } ;
244-
245- isInternal = true ;
246- }
247- }
219+ if ( ! ( "taskOutput" in originalOutputValue ) ) {
220+ console . warn (
221+ `Output ${ oldOutputName } is not connected to a task output` ,
222+ ) ;
223+ return ;
248224 }
249225
250- if (
251- ( isInternal && connection === "internal" ) ||
252- ( ! isInternal && connection === "external" ) ||
253- connection === "all"
254- ) {
255- updatedGraphOutputs [ outputName ] = updatedOutputValue ;
226+ const connectedTaskId = originalOutputValue . taskOutput . taskId ;
227+ const connectedOutputName = originalOutputValue . taskOutput . outputName ;
228+
229+ const originalNodeId = nodeManager . getNodeId ( connectedTaskId , "task" ) ;
230+
231+ const newTaskNodeId = nodeIdMap [ originalNodeId ] ;
232+ if ( ! newTaskNodeId ) {
233+ console . warn ( `No mapping found for task node ${ originalNodeId } ` ) ;
234+ return ;
256235 }
236+
237+ const newTaskId = nodeManager . getRefId ( newTaskNodeId ) ;
238+ if ( ! newTaskId ) {
239+ console . warn ( `Could not get new task ID for node ${ newTaskNodeId } ` ) ;
240+ return ;
241+ }
242+
243+ const outputValue : TaskOutputArgument = {
244+ taskOutput : {
245+ taskId : newTaskId ,
246+ outputName : connectedOutputName ,
247+ } ,
248+ } ;
249+
250+ updatedGraphOutputs [ outputName ] = outputValue ;
257251 } ) ;
258252 }
259253
260- /* Update the Graph Spec & Inputs */
254+ /* Update the Graph Spec */
261255 const updatedTasks = { ...graphSpec . tasks , ...newTasks } ;
262256 const updatedGraphSpec = {
263257 ...graphSpec ,
@@ -513,43 +507,61 @@ function reconfigureConnections(
513507
514508 if ( "taskOutput" in argument ) {
515509 const oldTaskId = argument . taskOutput . taskId ;
516- oldNodeId = nodeManager . getNodeId ( oldTaskId , "task" ) ;
517510
518- if ( ! isGraphImplementation ( componentSpec . implementation ) ) {
519- throw new Error ( "ComponentSpec does not contain a graph implementation." ) ;
511+ const taskNode = nodes . find (
512+ ( node ) => isTaskNode ( node ) && node . data . taskId === oldTaskId ,
513+ ) ;
514+
515+ if ( taskNode ) {
516+ oldNodeId = taskNode . id ;
517+ isExternal = false ;
518+ } else {
519+ if ( ! isGraphImplementation ( componentSpec . implementation ) ) {
520+ throw new Error (
521+ "ComponentSpec does not contain a graph implementation." ,
522+ ) ;
523+ }
524+
525+ const graphSpec = componentSpec . implementation . graph ;
526+ isExternal = oldTaskId in graphSpec . tasks ;
520527 }
521528
522- const graphSpec = componentSpec . implementation . graph ;
523- isExternal = oldTaskId in graphSpec . tasks ;
529+ if ( ! oldNodeId ) {
530+ return reconfigureExternalConnection ( taskSpec , argKey , mode ) ;
531+ }
524532
525533 const newNodeId = nodeIdMap [ oldNodeId ] ;
526-
527534 if ( ! newNodeId ) {
528535 return reconfigureExternalConnection ( taskSpec , argKey , mode ) ;
529536 }
530537
531538 const newTaskId = nodeManager . getRefId ( newNodeId ) ;
532-
533539 newArgId = newTaskId ;
534540 } else if ( "graphInput" in argument ) {
535541 const oldInputName = argument . graphInput . inputName ;
536- oldNodeId = nodeManager . getNodeId ( oldInputName , "input" ) ;
537542
538- if ( ! ( "inputs" in componentSpec ) ) {
539- throw new Error ( "ComponentSpec does not contain inputs." ) ;
543+ const inputNode = nodes . find (
544+ ( node ) => isInputNode ( node ) && node . data . spec . name === oldInputName ,
545+ ) ;
546+
547+ if ( inputNode ) {
548+ oldNodeId = inputNode . id ;
549+ isExternal = false ;
550+ } else {
551+ const inputs = componentSpec . inputs || [ ] ;
552+ isExternal = inputs . some ( ( input ) => input . name === oldInputName ) ;
540553 }
541554
542- const inputs = componentSpec . inputs || [ ] ;
543- isExternal = inputs . some ( ( input ) => input . name === oldInputName ) ;
555+ if ( ! oldNodeId ) {
556+ return reconfigureExternalConnection ( taskSpec , argKey , mode ) ;
557+ }
544558
545559 const newNodeId = nodeIdMap [ oldNodeId ] ;
546-
547560 if ( ! newNodeId ) {
548561 return reconfigureExternalConnection ( taskSpec , argKey , mode ) ;
549562 }
550563
551564 const newInputName = nodeManager . getRefId ( newNodeId ) ;
552-
553565 newArgId = newInputName ;
554566 }
555567
0 commit comments