diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx index c1542caabc..110658ffdb 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/Flow.tsx @@ -8,6 +8,7 @@ import { useWorkflowWatcher } from 'features/nodes/hooks/useWorkflowWatcher'; import { $cursorPos, $isAddNodePopoverOpen, + $isUpdatingEdge, $pendingConnection, $viewport, connectionMade, @@ -160,6 +161,7 @@ export const Flow = memo(() => { const onEdgeUpdateStart: NonNullable = useCallback( (e, edge, _handleType) => { + $isUpdatingEdge.set(true); // update mouse event edgeUpdateMouseEvent.current = e; // always delete the edge when starting an updated @@ -170,8 +172,7 @@ export const Flow = memo(() => { const onEdgeUpdate: OnEdgeUpdateFunc = useCallback( (_oldEdge, newConnection) => { - // instead of updating the edge (we deleted it earlier), we instead create - // a new one. + // Because we deleted the edge when the update started, we must create a new edge from the connection dispatch(connectionMade(newConnection)); }, [dispatch] @@ -179,8 +180,10 @@ export const Flow = memo(() => { const onEdgeUpdateEnd: NonNullable = useCallback( (e, edge, _handleType) => { - // Handle the case where user begins a drag but didn't move the cursor - - // bc we deleted the edge, we need to add it back + $isUpdatingEdge.set(false); + $pendingConnection.set(null); + // Handle the case where user begins a drag but didn't move the cursor - we deleted the edge when starting + // the edge update - we need to add it back if ( // ignore touch events !('touches' in e) && diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useConnection.ts b/invokeai/frontend/web/src/features/nodes/hooks/useConnection.ts index 468a0bd645..06471391eb 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useConnection.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useConnection.ts @@ -1,7 +1,13 @@ import { useStore } from '@nanostores/react'; import { useAppStore } from 'app/store/storeHooks'; import { $mouseOverNode } from 'features/nodes/hooks/useMouseOverNode'; -import { $isAddNodePopoverOpen, $pendingConnection, $templates, connectionMade } from 'features/nodes/store/nodesSlice'; +import { + $isAddNodePopoverOpen, + $isUpdatingEdge, + $pendingConnection, + $templates, + connectionMade, +} from 'features/nodes/store/nodesSlice'; import { getFirstValidConnection } from 'features/nodes/store/util/findConnectionToValidHandle'; import { isInvocationNode } from 'features/nodes/types/invocation'; import { useCallback, useMemo } from 'react'; @@ -42,10 +48,19 @@ export const useConnection = () => { const onConnectEnd = useCallback(() => { const { dispatch } = store; const pendingConnection = $pendingConnection.get(); + const isUpdatingEdge = $isUpdatingEdge.get(); + const mouseOverNodeId = $mouseOverNode.get(); + + // If we are in the middle of an edge update, and the mouse isn't over a node, we should just bail so the edge + // update logic can finish up + if (isUpdatingEdge && !mouseOverNodeId) { + $pendingConnection.set(null); + return; + } + if (!pendingConnection) { return; } - const mouseOverNodeId = $mouseOverNode.get(); const { nodes, edges } = store.getState().nodes.present; if (mouseOverNodeId) { const candidateNode = nodes.filter(isInvocationNode).find((n) => n.id === mouseOverNodeId); diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index cc3c9db3e8..cfd9fa8ef8 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -592,7 +592,7 @@ export const $templates = atom({}); export const $copiedNodes = atom([]); export const $copiedEdges = atom([]); export const $pendingConnection = atom(null); -export const $isModifyingEdge = atom(false); +export const $isUpdatingEdge = atom(false); export const $viewport = atom({ x: 0, y: 0, zoom: 1 }); export const $isAddNodePopoverOpen = atom(false); export const closeAddNodePopover = () => {