@@ -124,6 +124,58 @@ const mockBlocksFromDb = [
124124 parentId : 'loop-1' ,
125125 extent : 'parent' ,
126126 } ,
127+ {
128+ id : 'loop-1' ,
129+ workflowId : mockWorkflowId ,
130+ type : 'loop' ,
131+ name : 'Loop Container' ,
132+ positionX : 50 ,
133+ positionY : 50 ,
134+ enabled : true ,
135+ horizontalHandles : true ,
136+ advancedMode : false ,
137+ triggerMode : false ,
138+ height : 250 ,
139+ subBlocks : { } ,
140+ outputs : { } ,
141+ data : { width : 500 , height : 300 , loopType : 'for' , count : 5 } ,
142+ parentId : null ,
143+ extent : null ,
144+ } ,
145+ {
146+ id : 'parallel-1' ,
147+ workflowId : mockWorkflowId ,
148+ type : 'parallel' ,
149+ name : 'Parallel Container' ,
150+ positionX : 600 ,
151+ positionY : 50 ,
152+ enabled : true ,
153+ horizontalHandles : true ,
154+ advancedMode : false ,
155+ triggerMode : false ,
156+ height : 250 ,
157+ subBlocks : { } ,
158+ outputs : { } ,
159+ data : { width : 500 , height : 300 , parallelType : 'count' , count : 3 } ,
160+ parentId : null ,
161+ extent : null ,
162+ } ,
163+ {
164+ id : 'block-3' ,
165+ workflowId : mockWorkflowId ,
166+ type : 'api' ,
167+ name : 'Parallel Child' ,
168+ positionX : 650 ,
169+ positionY : 150 ,
170+ enabled : true ,
171+ horizontalHandles : true ,
172+ height : 200 ,
173+ subBlocks : { } ,
174+ outputs : { } ,
175+ data : { parentId : 'parallel-1' , extent : 'parent' } ,
176+ parentId : 'parallel-1' ,
177+ extent : 'parent' ,
178+ } ,
127179]
128180
129181const mockEdgesFromDb = [
@@ -187,6 +239,42 @@ const mockWorkflowState: WorkflowState = {
187239 height : 200 ,
188240 data : { parentId : 'loop-1' , extent : 'parent' } ,
189241 } ,
242+ 'loop-1' : {
243+ id : 'loop-1' ,
244+ type : 'loop' ,
245+ name : 'Loop Container' ,
246+ position : { x : 200 , y : 50 } ,
247+ subBlocks : { } ,
248+ outputs : { } ,
249+ enabled : true ,
250+ horizontalHandles : true ,
251+ height : 250 ,
252+ data : { width : 500 , height : 300 , count : 5 , loopType : 'for' } ,
253+ } ,
254+ 'parallel-1' : {
255+ id : 'parallel-1' ,
256+ type : 'parallel' ,
257+ name : 'Parallel Container' ,
258+ position : { x : 600 , y : 50 } ,
259+ subBlocks : { } ,
260+ outputs : { } ,
261+ enabled : true ,
262+ horizontalHandles : true ,
263+ height : 250 ,
264+ data : { width : 500 , height : 300 , parallelType : 'count' , count : 3 } ,
265+ } ,
266+ 'block-3' : {
267+ id : 'block-3' ,
268+ type : 'api' ,
269+ name : 'Parallel Child' ,
270+ position : { x : 650 , y : 150 } ,
271+ subBlocks : { } ,
272+ outputs : { } ,
273+ enabled : true ,
274+ horizontalHandles : true ,
275+ height : 180 ,
276+ data : { parentId : 'parallel-1' , extent : 'parent' } ,
277+ } ,
190278 } ,
191279 edges : [
192280 {
@@ -567,20 +655,36 @@ describe('Database Helpers', () => {
567655
568656 await dbHelpers . saveWorkflowToNormalizedTables ( mockWorkflowId , mockWorkflowState )
569657
570- expect ( capturedBlockInserts ) . toHaveLength ( 2 )
571- expect ( capturedBlockInserts [ 0 ] ) . toMatchObject ( {
572- id : 'block-1' ,
573- workflowId : mockWorkflowId ,
574- type : 'starter' ,
575- name : 'Start Block' ,
576- positionX : '100' ,
577- positionY : '100' ,
578- enabled : true ,
579- horizontalHandles : true ,
580- height : '150' ,
581- parentId : null ,
582- extent : null ,
583- } )
658+ expect ( capturedBlockInserts ) . toHaveLength ( 5 )
659+ expect ( capturedBlockInserts ) . toEqual (
660+ expect . arrayContaining ( [
661+ expect . objectContaining ( {
662+ id : 'block-1' ,
663+ workflowId : mockWorkflowId ,
664+ type : 'starter' ,
665+ name : 'Start Block' ,
666+ positionX : '100' ,
667+ positionY : '100' ,
668+ enabled : true ,
669+ horizontalHandles : true ,
670+ height : '150' ,
671+ parentId : null ,
672+ extent : null ,
673+ } ) ,
674+ expect . objectContaining ( {
675+ id : 'loop-1' ,
676+ workflowId : mockWorkflowId ,
677+ type : 'loop' ,
678+ parentId : null ,
679+ } ) ,
680+ expect . objectContaining ( {
681+ id : 'parallel-1' ,
682+ workflowId : mockWorkflowId ,
683+ type : 'parallel' ,
684+ parentId : null ,
685+ } ) ,
686+ ] )
687+ )
584688
585689 expect ( capturedEdgeInserts ) . toHaveLength ( 1 )
586690 expect ( capturedEdgeInserts [ 0 ] ) . toMatchObject ( {
@@ -599,6 +703,48 @@ describe('Database Helpers', () => {
599703 type : 'loop' ,
600704 } )
601705 } )
706+
707+ it ( 'should regenerate missing loop and parallel definitions from block data' , async ( ) => {
708+ let capturedSubflowInserts : any [ ] = [ ]
709+
710+ const mockTransaction = vi . fn ( ) . mockImplementation ( async ( callback ) => {
711+ const tx = {
712+ select : vi . fn ( ) . mockReturnValue ( {
713+ from : vi . fn ( ) . mockReturnValue ( {
714+ where : vi . fn ( ) . mockResolvedValue ( [ ] ) ,
715+ } ) ,
716+ } ) ,
717+ delete : vi . fn ( ) . mockReturnValue ( {
718+ where : vi . fn ( ) . mockResolvedValue ( [ ] ) ,
719+ } ) ,
720+ insert : vi . fn ( ) . mockReturnValue ( {
721+ values : vi . fn ( ) . mockImplementation ( ( data ) => {
722+ if ( data . length > 0 && ( data [ 0 ] . type === 'loop' || data [ 0 ] . type === 'parallel' ) ) {
723+ capturedSubflowInserts = data
724+ }
725+ return Promise . resolve ( [ ] )
726+ } ) ,
727+ } ) ,
728+ }
729+ return await callback ( tx )
730+ } )
731+
732+ mockDb . transaction = mockTransaction
733+
734+ const staleWorkflowState = JSON . parse ( JSON . stringify ( mockWorkflowState ) ) as WorkflowState
735+ staleWorkflowState . loops = { }
736+ staleWorkflowState . parallels = { }
737+
738+ await dbHelpers . saveWorkflowToNormalizedTables ( mockWorkflowId , staleWorkflowState )
739+
740+ expect ( capturedSubflowInserts ) . toHaveLength ( 2 )
741+ expect ( capturedSubflowInserts ) . toEqual (
742+ expect . arrayContaining ( [
743+ expect . objectContaining ( { id : 'loop-1' , type : 'loop' } ) ,
744+ expect . objectContaining ( { id : 'parallel-1' , type : 'parallel' } ) ,
745+ ] )
746+ )
747+ } )
602748 } )
603749
604750 describe ( 'workflowExistsInNormalizedTables' , ( ) => {
0 commit comments