@@ -101,7 +101,6 @@ export function WorkflowCanvas() {
101101 useReactFlow ( ) ;
102102
103103 const connectingNodeId = useRef < string | null > ( null ) ;
104- const connectingHandleType = useRef < "source" | "target" | null > ( null ) ;
105104 const justCreatedNodeFromConnection = useRef ( false ) ;
106105 const viewportInitialized = useRef ( false ) ;
107106 const [ isCanvasReady , setIsCanvasReady ] = useState ( false ) ;
@@ -228,27 +227,6 @@ export function WorkflowCanvas() {
228227 [ ]
229228 ) ;
230229
231- const nodeHasHandle = useCallback (
232- ( nodeId : string , handleType : "source" | "target" ) => {
233- const node = nodes . find ( ( n ) => n . id === nodeId ) ;
234-
235- if ( ! node ) {
236- return false ;
237- }
238-
239- if ( node . type === "add" ) {
240- return false ;
241- }
242-
243- if ( handleType === "target" ) {
244- return node . type !== "trigger" ;
245- }
246-
247- return true ;
248- } ,
249- [ nodes ]
250- ) ;
251-
252230 const isValidConnection = useCallback (
253231 ( connection : XYFlowConnection | XYFlowEdge ) => {
254232 // Ensure we have both source and target
@@ -294,7 +272,6 @@ export function WorkflowCanvas() {
294272 const onConnectStart = useCallback (
295273 ( _event : MouseEvent | TouchEvent , params : OnConnectStartParams ) => {
296274 connectingNodeId . current = params . nodeId ;
297- connectingHandleType . current = params . handleType ;
298275 } ,
299276 [ ]
300277 ) ;
@@ -329,125 +306,6 @@ export function WorkflowCanvas() {
329306 [ ]
330307 ) ;
331308
332- const handleConnectionToExistingNode = useCallback (
333- ( nodeElement : Element ) => {
334- const targetNodeId = nodeElement . getAttribute ( "data-id" ) ;
335- const fromSource = connectingHandleType . current === "source" ;
336- const requiredHandle = fromSource ? "target" : "source" ;
337- const connectingId = connectingNodeId . current ;
338-
339- if (
340- targetNodeId &&
341- connectingId &&
342- targetNodeId !== connectingId &&
343- nodeHasHandle ( targetNodeId , requiredHandle )
344- ) {
345- const sourceId = fromSource ? connectingId : targetNodeId ;
346- const targetId = fromSource ? targetNodeId : connectingId ;
347- onConnect ( {
348- source : sourceId ,
349- target : targetId ,
350- sourceHandle : null ,
351- targetHandle : null ,
352- } ) ;
353- }
354- } ,
355- [ nodeHasHandle , onConnect ]
356- ) ;
357-
358- const handleConnectionToNewNode = useCallback (
359- ( event : MouseEvent | TouchEvent , clientX : number , clientY : number ) => {
360- const sourceNodeId = connectingNodeId . current ;
361- if ( ! sourceNodeId ) {
362- return ;
363- }
364-
365- const { adjustedX, adjustedY } = calculateMenuPosition (
366- event ,
367- clientX ,
368- clientY
369- ) ;
370-
371- // Get the action template
372- const actionTemplate = nodeTemplates . find ( ( t ) => t . type === "action" ) ;
373- if ( ! actionTemplate ) {
374- return ;
375- }
376-
377- // Get the position in the flow coordinate system
378- const position = screenToFlowPosition ( {
379- x : adjustedX ,
380- y : adjustedY ,
381- } ) ;
382-
383- // Center the node vertically at the cursor position
384- // Node height is 192px (h-48 in Tailwind)
385- const nodeHeight = 192 ;
386- position . y -= nodeHeight / 2 ;
387-
388- const newNode : WorkflowNode = {
389- id : nanoid ( ) ,
390- type : actionTemplate . type ,
391- position,
392- data : {
393- label : actionTemplate . label ,
394- description : actionTemplate . description ,
395- type : actionTemplate . type ,
396- config : actionTemplate . defaultConfig ,
397- status : "idle" ,
398- } ,
399- selected : true ,
400- } ;
401-
402- addNode ( newNode ) ;
403- setSelectedNode ( newNode . id ) ;
404- setActiveTab ( "properties" ) ;
405-
406- // Deselect all other nodes and select only the new node
407- // Need to do this after a delay because panOnDrag will clear selection
408- setTimeout ( ( ) => {
409- setNodes ( ( currentNodes ) =>
410- currentNodes . map ( ( n ) => ( {
411- ...n ,
412- selected : n . id === newNode . id ,
413- } ) )
414- ) ;
415- } , 50 ) ;
416-
417- // Create connection from the source node to the new node
418- const fromSource = connectingHandleType . current === "source" ;
419-
420- const newEdge = {
421- id : nanoid ( ) ,
422- source : fromSource ? sourceNodeId : newNode . id ,
423- target : fromSource ? newNode . id : sourceNodeId ,
424- type : "animated" ,
425- } ;
426- setEdges ( [ ...edges , newEdge ] ) ;
427- setHasUnsavedChanges ( true ) ;
428- // Trigger immediate autosave for the new edge
429- triggerAutosave ( { immediate : true } ) ;
430-
431- // Set flag to prevent immediate deselection
432- justCreatedNodeFromConnection . current = true ;
433- setTimeout ( ( ) => {
434- justCreatedNodeFromConnection . current = false ;
435- } , 100 ) ;
436- } ,
437- [
438- calculateMenuPosition ,
439- screenToFlowPosition ,
440- addNode ,
441- edges ,
442- setEdges ,
443- setNodes ,
444- setSelectedNode ,
445- setActiveTab ,
446- setHasUnsavedChanges ,
447- triggerAutosave ,
448- ]
449- ) ;
450-
451309 const onConnectEnd = useCallback (
452310 ( event : MouseEvent | TouchEvent ) => {
453311 if ( ! connectingNodeId . current ) {
@@ -469,28 +327,96 @@ export function WorkflowCanvas() {
469327 return ;
470328 }
471329
472- const nodeElement = target . closest ( ".react-flow__node" ) ;
330+ const isNode = target . closest ( ".react-flow__node" ) ;
473331 const isHandle = target . closest ( ".react-flow__handle" ) ;
474332
475- // Create connection on edge dragged over node release
476- if ( nodeElement && ! isHandle && connectingHandleType . current ) {
477- handleConnectionToExistingNode ( nodeElement ) ;
478- connectingNodeId . current = null ;
479- connectingHandleType . current = null ;
480- return ;
481- }
333+ if ( ! ( isNode || isHandle ) ) {
334+ const { adjustedX, adjustedY } = calculateMenuPosition (
335+ event ,
336+ clientX ,
337+ clientY
338+ ) ;
482339
483- if ( ! ( nodeElement || isHandle ) ) {
484- handleConnectionToNewNode ( event , clientX , clientY ) ;
340+ // Get the action template
341+ const actionTemplate = nodeTemplates . find ( ( t ) => t . type === "action" ) ;
342+ if ( ! actionTemplate ) {
343+ return ;
344+ }
345+
346+ // Get the position in the flow coordinate system
347+ const position = screenToFlowPosition ( {
348+ x : adjustedX ,
349+ y : adjustedY ,
350+ } ) ;
351+
352+ // Center the node vertically at the cursor position
353+ // Node height is 192px (h-48 in Tailwind)
354+ const nodeHeight = 192 ;
355+ position . y -= nodeHeight / 2 ;
356+
357+ // Create new action node
358+ const newNode : WorkflowNode = {
359+ id : nanoid ( ) ,
360+ type : actionTemplate . type ,
361+ position,
362+ data : {
363+ label : actionTemplate . label ,
364+ description : actionTemplate . description ,
365+ type : actionTemplate . type ,
366+ config : actionTemplate . defaultConfig ,
367+ status : "idle" ,
368+ } ,
369+ selected : true ,
370+ } ;
371+
372+ addNode ( newNode ) ;
373+ setSelectedNode ( newNode . id ) ;
374+ setActiveTab ( "properties" ) ;
375+
376+ // Deselect all other nodes and select only the new node
377+ // Need to do this after a delay because panOnDrag will clear selection
378+ setTimeout ( ( ) => {
379+ setNodes ( ( currentNodes ) =>
380+ currentNodes . map ( ( n ) => ( {
381+ ...n ,
382+ selected : n . id === newNode . id ,
383+ } ) )
384+ ) ;
385+ } , 50 ) ;
386+
387+ // Create connection from the source node to the new node
388+ const newEdge = {
389+ id : nanoid ( ) ,
390+ source : connectingNodeId . current ,
391+ target : newNode . id ,
392+ type : "animated" ,
393+ } ;
394+ setEdges ( [ ...edges , newEdge ] ) ;
395+ setHasUnsavedChanges ( true ) ;
396+ // Trigger immediate autosave for the new edge
397+ triggerAutosave ( { immediate : true } ) ;
398+
399+ // Set flag to prevent immediate deselection
400+ justCreatedNodeFromConnection . current = true ;
401+ setTimeout ( ( ) => {
402+ justCreatedNodeFromConnection . current = false ;
403+ } , 100 ) ;
485404 }
486405
487406 connectingNodeId . current = null ;
488- connectingHandleType . current = null ;
489407 } ,
490408 [
491409 getClientPosition ,
492- handleConnectionToExistingNode ,
493- handleConnectionToNewNode ,
410+ calculateMenuPosition ,
411+ screenToFlowPosition ,
412+ addNode ,
413+ edges ,
414+ setEdges ,
415+ setNodes ,
416+ setSelectedNode ,
417+ setActiveTab ,
418+ setHasUnsavedChanges ,
419+ triggerAutosave ,
494420 ]
495421 ) ;
496422
0 commit comments