@@ -110,7 +110,7 @@ const WorkflowContent = React.memo(() => {
110110 // Hooks
111111 const params = useParams ( )
112112 const router = useRouter ( )
113- const { project , getNodes, fitView } = useReactFlow ( )
113+ const { screenToFlowPosition , getNodes, fitView } = useReactFlow ( )
114114 const { emitCursorUpdate } = useSocket ( )
115115
116116 // Get workspace ID from the params
@@ -170,7 +170,7 @@ const WorkflowContent = React.memo(() => {
170170 // Get diff analysis for edge reconstruction
171171 const { diffAnalysis, isShowingDiff, isDiffReady } = useWorkflowDiffStore ( )
172172
173- // Reconstruct deleted edges when viewing original workflow and filter trigger edges
173+ // Reconstruct deleted edges when viewing original workflow and filter out invalid edges
174174 const edgesForDisplay = useMemo ( ( ) => {
175175 let edgesToFilter = edges
176176
@@ -237,7 +237,21 @@ const WorkflowContent = React.memo(() => {
237237 // Combine existing edges with reconstructed deleted edges
238238 edgesToFilter = [ ...edges , ...reconstructedEdges ]
239239 }
240- return edgesToFilter
240+
241+ // Filter out edges that connect to/from annotation-only blocks (note blocks)
242+ // These blocks don't have handles and shouldn't have connections
243+ return edgesToFilter . filter ( ( edge ) => {
244+ const sourceBlock = blocks [ edge . source ]
245+ const targetBlock = blocks [ edge . target ]
246+
247+ // Remove edge if either source or target is an annotation-only block
248+ if ( ! sourceBlock || ! targetBlock ) return false
249+ if ( isAnnotationOnlyBlock ( sourceBlock . type ) || isAnnotationOnlyBlock ( targetBlock . type ) ) {
250+ return false
251+ }
252+
253+ return true
254+ } )
241255 } , [ edges , isShowingDiff , isDiffReady , diffAnalysis , blocks ] )
242256
243257 // User permissions - get current user's specific permissions from context
@@ -680,7 +694,11 @@ const WorkflowContent = React.memo(() => {
680694 // Auto-connect logic for blocks inside containers
681695 const isAutoConnectEnabled = useGeneralStore . getState ( ) . isAutoConnectEnabled
682696 let autoConnectEdge
683- if ( isAutoConnectEnabled && data . type !== 'starter' ) {
697+ if (
698+ isAutoConnectEnabled &&
699+ data . type !== 'starter' &&
700+ ! isAnnotationOnlyBlock ( data . type )
701+ ) {
684702 if ( existingChildBlocks . length > 0 ) {
685703 // Connect to the nearest existing child block within the container
686704 const closestBlock = existingChildBlocks
@@ -694,7 +712,7 @@ const WorkflowContent = React.memo(() => {
694712 . sort ( ( a , b ) => a . distance - b . distance ) [ 0 ] ?. block
695713
696714 if ( closestBlock ) {
697- // Don't create edges into trigger blocks
715+ // Don't create edges into trigger blocks or annotation blocks
698716 const targetBlockConfig = getBlock ( data . type )
699717 const isTargetTrigger =
700718 data . enableTriggerMode === true || targetBlockConfig ?. category === 'triggers'
@@ -769,10 +787,14 @@ const WorkflowContent = React.memo(() => {
769787 // Regular auto-connect logic
770788 const isAutoConnectEnabled = useGeneralStore . getState ( ) . isAutoConnectEnabled
771789 let autoConnectEdge
772- if ( isAutoConnectEnabled && data . type !== 'starter' ) {
790+ if (
791+ isAutoConnectEnabled &&
792+ data . type !== 'starter' &&
793+ ! isAnnotationOnlyBlock ( data . type )
794+ ) {
773795 const closestBlock = findClosestOutput ( position )
774796 if ( closestBlock ) {
775- // Don't create edges into trigger blocks
797+ // Don't create edges into trigger blocks or annotation blocks
776798 const targetBlockConfig = getBlock ( data . type )
777799 const isTargetTrigger =
778800 data . enableTriggerMode === true || targetBlockConfig ?. category === 'triggers'
@@ -842,7 +864,7 @@ const WorkflowContent = React.memo(() => {
842864 const baseName = type === 'loop' ? 'Loop' : 'Parallel'
843865 const name = getUniqueBlockName ( baseName , blocks )
844866
845- const centerPosition = project ( {
867+ const centerPosition = screenToFlowPosition ( {
846868 x : window . innerWidth / 2 ,
847869 y : window . innerHeight / 2 ,
848870 } )
@@ -891,7 +913,7 @@ const WorkflowContent = React.memo(() => {
891913 }
892914
893915 // Calculate the center position of the viewport
894- const centerPosition = project ( {
916+ const centerPosition = screenToFlowPosition ( {
895917 x : window . innerWidth / 2 ,
896918 y : window . innerHeight / 2 ,
897919 } )
@@ -906,11 +928,11 @@ const WorkflowContent = React.memo(() => {
906928 // Auto-connect logic
907929 const isAutoConnectEnabled = useGeneralStore . getState ( ) . isAutoConnectEnabled
908930 let autoConnectEdge
909- if ( isAutoConnectEnabled && type !== 'starter' ) {
931+ if ( isAutoConnectEnabled && type !== 'starter' && ! isAnnotationOnlyBlock ( type ) ) {
910932 const closestBlock = findClosestOutput ( centerPosition )
911933 logger . info ( 'Closest block found:' , closestBlock )
912934 if ( closestBlock ) {
913- // Don't create edges into trigger blocks
935+ // Don't create edges into trigger blocks or annotation blocks
914936 const targetBlockConfig = blockConfig
915937 const isTargetTrigger = enableTriggerMode || targetBlockConfig ?. category === 'triggers'
916938
@@ -977,7 +999,7 @@ const WorkflowContent = React.memo(() => {
977999 )
9781000 }
9791001 } , [
980- project ,
1002+ screenToFlowPosition ,
9811003 blocks ,
9821004 addBlock ,
9831005 addEdge ,
@@ -1014,7 +1036,7 @@ const WorkflowContent = React.memo(() => {
10141036 }
10151037
10161038 const bounds = canvasElement . getBoundingClientRect ( )
1017- const position = project ( {
1039+ const position = screenToFlowPosition ( {
10181040 x : detail . clientX - bounds . left ,
10191041 y : detail . clientY - bounds . top ,
10201042 } )
@@ -1041,7 +1063,7 @@ const WorkflowContent = React.memo(() => {
10411063 'toolbar-drop-on-empty-workflow-overlay' ,
10421064 handleOverlayToolbarDrop as EventListener
10431065 )
1044- } , [ project , handleToolbarDrop ] )
1066+ } , [ screenToFlowPosition , handleToolbarDrop ] )
10451067
10461068 /**
10471069 * Recenter canvas when diff appears
@@ -1090,7 +1112,7 @@ const WorkflowContent = React.memo(() => {
10901112 if ( ! data ?. type ) return
10911113
10921114 const reactFlowBounds = event . currentTarget . getBoundingClientRect ( )
1093- const position = project ( {
1115+ const position = screenToFlowPosition ( {
10941116 x : event . clientX - reactFlowBounds . left ,
10951117 y : event . clientY - reactFlowBounds . top ,
10961118 } )
@@ -1106,22 +1128,22 @@ const WorkflowContent = React.memo(() => {
11061128 logger . error ( 'Error dropping block on ReactFlow canvas:' , { err } )
11071129 }
11081130 } ,
1109- [ project , handleToolbarDrop ]
1131+ [ screenToFlowPosition , handleToolbarDrop ]
11101132 )
11111133
11121134 const handleCanvasPointerMove = useCallback (
11131135 ( event : React . PointerEvent < Element > ) => {
11141136 const target = event . currentTarget as HTMLElement
11151137 const bounds = target . getBoundingClientRect ( )
11161138
1117- const position = project ( {
1139+ const position = screenToFlowPosition ( {
11181140 x : event . clientX - bounds . left ,
11191141 y : event . clientY - bounds . top ,
11201142 } )
11211143
11221144 emitCursorUpdate ( position )
11231145 } ,
1124- [ project , emitCursorUpdate ]
1146+ [ screenToFlowPosition , emitCursorUpdate ]
11251147 )
11261148
11271149 const handleCanvasPointerLeave = useCallback ( ( ) => {
@@ -1144,7 +1166,7 @@ const WorkflowContent = React.memo(() => {
11441166
11451167 try {
11461168 const reactFlowBounds = event . currentTarget . getBoundingClientRect ( )
1147- const position = project ( {
1169+ const position = screenToFlowPosition ( {
11481170 x : event . clientX - reactFlowBounds . left ,
11491171 y : event . clientY - reactFlowBounds . top ,
11501172 } )
@@ -1188,7 +1210,7 @@ const WorkflowContent = React.memo(() => {
11881210 logger . error ( 'Error in onDragOver' , { err } )
11891211 }
11901212 } ,
1191- [ project , isPointInLoopNode , getNodes ]
1213+ [ screenToFlowPosition , isPointInLoopNode , getNodes ]
11921214 )
11931215
11941216 // Initialize workflow when it exists in registry and isn't active
@@ -1584,8 +1606,8 @@ const WorkflowContent = React.memo(() => {
15841606 // Store currently dragged node ID
15851607 setDraggedNodeId ( node . id )
15861608
1587- // Emit collaborative position update during drag for smooth real-time movement
1588- collaborativeUpdateBlockPosition ( node . id , node . position , false )
1609+ // Note: We don't emit position updates during drag to avoid flooding socket events.
1610+ // The final position is sent in onNodeDragStop for collaborative updates.
15891611
15901612 // Get the current parent ID of the node being dragged
15911613 const currentParentId = blocks [ node . id ] ?. data ?. parentId || null
@@ -1721,14 +1743,7 @@ const WorkflowContent = React.memo(() => {
17211743 }
17221744 }
17231745 } ,
1724- [
1725- getNodes ,
1726- potentialParentId ,
1727- blocks ,
1728- getNodeAbsolutePosition ,
1729- getNodeDepth ,
1730- collaborativeUpdateBlockPosition ,
1731- ]
1746+ [ getNodes , potentialParentId , blocks , getNodeAbsolutePosition , getNodeDepth ]
17321747 )
17331748
17341749 // Add in a nodeDrag start event to set the dragStartParentId
@@ -1855,7 +1870,8 @@ const WorkflowContent = React.memo(() => {
18551870
18561871 // Auto-connect when moving an existing block into a container
18571872 const isAutoConnectEnabled = useGeneralStore . getState ( ) . isAutoConnectEnabled
1858- if ( isAutoConnectEnabled ) {
1873+ // Don't auto-connect annotation blocks (like note blocks)
1874+ if ( isAutoConnectEnabled && ! isAnnotationOnlyBlock ( node . data ?. type ) ) {
18591875 // Existing children in the target container (excluding the moved node)
18601876 const existingChildBlocks = Object . values ( blocks ) . filter (
18611877 ( b ) => b . data ?. parentId === potentialParentId && b . id !== node . id
0 commit comments