@@ -631,6 +631,69 @@ export const FlowCanvas = forwardRef<{
631631 return `import "${ sourceUri } " as ${ sourcePackageName } \nimport "${ targetUri } " as ${ targetPackageName } \n\nreactions: ${ sourcePackageName } To${ targetPackageName } \nin reaction to changes in ${ sourcePackageName } \nexecute actions in ${ targetPackageName } \n\n` ;
632632 } , [ nodes ] ) ;
633633
634+ const resolveReactionFileId = async ( raw : any ) : Promise < number | null > => {
635+ if ( typeof raw === 'number' ) return raw ;
636+ if ( typeof raw === 'string' ) return Number ( raw ) || null ;
637+ if ( typeof raw ?. id === 'number' ) return raw . id ;
638+ return null ;
639+ } ;
640+
641+ const uploadReactionFile = useCallback ( async (
642+ sourceNodeId : string ,
643+ targetNodeId : string ,
644+ edgeId : string
645+ ) : Promise < number | null > => {
646+ const uniquePadding = ' ' . repeat ( Math . floor ( Math . random ( ) * 50 ) + 1 ) ;
647+ const initialContent = buildInitialReactionCode ( sourceNodeId , targetNodeId ) + uniquePadding ;
648+ const fileName = `reaction-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } .reactions` ;
649+ const file = new File ( [ initialContent ] , fileName , { type : 'text/plain;charset=utf-8' } ) ;
650+
651+ try {
652+ const uploadResult = await apiService . uploadFile ( file , 'REACTION' ) ;
653+ const reactionFileId = await resolveReactionFileId ( uploadResult ?. data ) ;
654+ if ( reactionFileId == null ) {
655+ console . error ( '❌ Upload succeeded but no file ID returned' ) ;
656+ } else {
657+ console . log ( '✅ Reaction file created for new edge:' , edgeId , 'fileId:' , reactionFileId ) ;
658+ }
659+ return reactionFileId ;
660+ } catch ( err ) {
661+ console . error ( 'Failed to create reaction file for new edge:' , err ) ;
662+ return null ;
663+ }
664+ } , [ buildInitialReactionCode ] ) ;
665+
666+ const buildNewEdge = useCallback ( (
667+ sourceNodeId : string ,
668+ targetNode : Node ,
669+ sourceHandle : string ,
670+ reactionFileId : number | null ,
671+ color : string
672+ ) : Edge => {
673+ const sourceNodePos = nodes . find ( n => n . id === sourceNodeId ) ?. position ;
674+ const targetHandle = sourceNodePos
675+ ? calculateTargetHandle ( sourceNodePos , targetNode . position )
676+ : 'left' as HandlePosition ;
677+
678+ const edgeId = `edge-${ sourceNodeId } -${ targetNode . id } -${ Date . now ( ) } ` ;
679+ return {
680+ id : edgeId ,
681+ source : sourceNodeId ,
682+ target : targetNode . id ,
683+ sourceHandle,
684+ targetHandle,
685+ type : 'reactions' ,
686+ style : { stroke : color , strokeWidth : 2 } ,
687+ data : {
688+ reactionFileId,
689+ sourceMetaModelId : getBackendMetaModelIdForNode ( sourceNodeId ) ,
690+ targetMetaModelId : getBackendMetaModelIdForNode ( targetNode . id ) ,
691+ sourceMetaModelSourceId : getMetaModelSourceIdForNode ( sourceNodeId ) ,
692+ targetMetaModelSourceId : getMetaModelSourceIdForNode ( targetNode . id ) ,
693+ }
694+ } ;
695+ } , [ nodes , calculateTargetHandle , getBackendMetaModelIdForNode , getMetaModelSourceIdForNode ] ) ;
696+
634697 const handleConnectionEnd = useCallback ( async ( e : MouseEvent ) => {
635698 console . log ( 'handleConnectionEnd CALLED' ) ;
636699
@@ -641,99 +704,42 @@ export const FlowCanvas = forwardRef<{
641704
642705 console . log ( '🔵 Connection drag ended' ) ;
643706
644- const flowPosition = reactFlowInstance . screenToFlowPosition ( {
645- x : e . clientX ,
646- y : e . clientY ,
647- } ) ;
648-
649- const intersectingNodes = nodes . filter ( node => {
650- if ( node . type !== 'ecoreFile' || node . id === connectionDragState . sourceNodeId ) {
651- return false ;
652- }
653- return isPositionInsideNode ( flowPosition , node ) ;
654- } ) ;
707+ const flowPosition = reactFlowInstance . screenToFlowPosition ( { x : e . clientX , y : e . clientY } ) ;
708+ const intersectingNodes = nodes . filter ( node =>
709+ node . type === 'ecoreFile'
710+ && node . id !== connectionDragState . sourceNodeId
711+ && isPositionInsideNode ( flowPosition , node )
712+ ) ;
655713
656714 console . log ( '🔵 Intersecting nodes:' , intersectingNodes ) ;
657715
658716 if ( intersectingNodes . length > 0 ) {
659717 const targetNode = intersectingNodes [ 0 ] ;
660718 console . log ( '✅ Connection ended on node:' , targetNode . id ) ;
661719
662- const existingEdge = edges . find ( edge =>
720+ const alreadyConnected = edges . some ( edge =>
663721 edge . source === connectionDragState . sourceNodeId && edge . target === targetNode . id
664722 ) ;
665723
666- if ( existingEdge ) {
667- console . log ( '⚠️ Connection in this direction already exists' ) ;
668- setConnectionDragState ( null ) ;
669- return ;
670- }
671-
672- const sourceNodePos = nodes . find ( n => n . id === connectionDragState . sourceNodeId ) ?. position ;
673- const targetNodePos = targetNode . position ;
674-
675- let targetHandle : HandlePosition = 'left' ;
676- if ( sourceNodePos && targetNodePos ) {
677- targetHandle = calculateTargetHandle ( sourceNodePos , targetNodePos ) ;
678- }
679-
680- console . log ( '🔵 Calculated handles:' , {
681- source : connectionDragState . sourceHandle ,
682- target : targetHandle
683- } ) ;
684-
685- const color = getColorForPair ( connectionDragState . sourceNodeId , targetNode . id ) ;
724+ if ( ! alreadyConnected ) {
725+ const color = getColorForPair ( connectionDragState . sourceNodeId , targetNode . id ) ;
726+ const edgeId = `edge-${ connectionDragState . sourceNodeId } -${ targetNode . id } -${ Date . now ( ) } ` ;
727+ const reactionFileId = await uploadReactionFile ( connectionDragState . sourceNodeId , targetNode . id , edgeId ) ;
728+ const sourceHandle = connectionDragState ?. sourceHandle ;
729+ if ( ! sourceHandle ) return ;
730+ const newEdge = buildNewEdge ( connectionDragState . sourceNodeId , targetNode , sourceHandle , reactionFileId , color ) ;
686731
687- const edgeId = `edge-${ connectionDragState . sourceNodeId } -${ targetNode . id } -${ Date . now ( ) } ` ;
688- const uniquePadding = ' ' . repeat ( Math . floor ( Math . random ( ) * 50 ) + 1 ) ;
689- const initialContent = buildInitialReactionCode ( connectionDragState . sourceNodeId , targetNode . id ) + uniquePadding ;
690- const fileName = `reaction-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } .reactions` ;
691- const file = new File ( [ initialContent ] , fileName , { type : 'text/plain;charset=utf-8' } ) ;
692-
693- let reactionFileId : number | null = null ;
694- try {
695- const uploadResult = await apiService . uploadFile ( file , 'REACTION' ) ;
696- const raw = uploadResult ?. data as any ;
697- reactionFileId = typeof raw === 'number' ? raw
698- : typeof raw === 'string' ? Number ( raw ) || null
699- : typeof raw ?. id === 'number' ? raw . id
700- : null ;
701-
702- if ( reactionFileId == null ) {
703- console . error ( '❌ Upload succeeded but no file ID returned' ) ;
704- } else {
705- console . log ( '✅ Reaction file created for new edge:' , edgeId , 'fileId:' , reactionFileId ) ;
706- }
707- } catch ( err ) {
708- console . error ( 'Failed to create reaction file for new edge:' , err ) ;
732+ console . log ( '🎯 Creating edge:' , newEdge ) ;
733+ addEdge ( newEdge ) ;
734+ } else {
735+ console . log ( '⚠️ Connection in this direction already exists' ) ;
709736 }
710-
711- const newEdge : Edge = {
712- id : edgeId ,
713- source : connectionDragState . sourceNodeId ,
714- target : targetNode . id ,
715- sourceHandle : connectionDragState . sourceHandle ,
716- targetHandle : targetHandle ,
717- type : 'reactions' ,
718- style : { stroke : color , strokeWidth : 2 } ,
719- data : {
720- reactionFileId,
721- sourceMetaModelId : getBackendMetaModelIdForNode ( connectionDragState . sourceNodeId ) ,
722- targetMetaModelId : getBackendMetaModelIdForNode ( targetNode . id ) ,
723- sourceMetaModelSourceId : getMetaModelSourceIdForNode ( connectionDragState . sourceNodeId ) ,
724- targetMetaModelSourceId : getMetaModelSourceIdForNode ( targetNode . id ) ,
725- }
726- } ;
727-
728- console . log ( '🎯 Creating edge:' , newEdge ) ;
729- addEdge ( newEdge ) ;
730737 } else {
731738 console . log ( '❌ Connection ended in empty space - cancelled' ) ;
732739 }
733740
734741 setConnectionDragState ( null ) ;
735- } , [ reactFlowInstance , nodes , edges , addEdge , connectionDragState , getColorForPair , isPositionInsideNode , calculateTargetHandle , getBackendMetaModelIdForNode , getMetaModelSourceIdForNode , buildInitialReactionCode ] ) ;
736-
742+ } , [ reactFlowInstance , nodes , edges , addEdge , connectionDragState , getColorForPair , isPositionInsideNode , uploadReactionFile , buildNewEdge ] ) ;
737743
738744 const handleConnectionMove = useCallback ( ( e : MouseEvent ) => {
739745 if ( ! reactFlowInstance ) return ;
0 commit comments