Drag if-else condition, the node didn't update the handle, causing inability to add and change the edge. #5050

Closed
opened 2026-02-21 18:09:10 -05:00 by yindo · 1 comment
Owner

Originally created by @aixgeek on GitHub (Aug 15, 2024).

Originally assigned to: @zxhlyh on GitHub.

Self Checks

  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

0.7.0

Cloud or Self Hosted

Cloud, Self Hosted (Docker), Self Hosted (Source)

Steps to reproduce

Reactflow Official Document: When you programmatically add or remove handles to a node or update a node's handle position, you need to let React Flow know about it using this hook. This will update the internal dimensions of the node and properly reposition handles on the canvas if necessary.

Drag if-else condition, the node didn't update the handle, causing inability to add and change the edge.

image

image

✔️ Expected Behavior

No response

Actual Behavior

No response

Originally created by @aixgeek on GitHub (Aug 15, 2024). Originally assigned to: @zxhlyh on GitHub. ### Self Checks - [X] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [X] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [X] I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)). - [X] [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:) - [X] Please do not modify this template :) and fill in all the required fields. ### Dify version 0.7.0 ### Cloud or Self Hosted Cloud, Self Hosted (Docker), Self Hosted (Source) ### Steps to reproduce Reactflow Official Document: When you programmatically add or remove handles to a node or update a node's handle position, you need to let React Flow know about it using this hook. This will update the internal dimensions of the node and properly reposition handles on the canvas if necessary. Drag if-else condition, the node didn't update the handle, causing inability to add and change the edge. ![image](https://github.com/user-attachments/assets/d9b8d70b-cf3c-4649-965b-8632571f678d) ![image](https://github.com/user-attachments/assets/3b60df55-793e-40f9-a87d-93a439c71c40) ### ✔️ Expected Behavior _No response_ ### ❌ Actual Behavior _No response_
yindo added the 🌊 feat:workflow label 2026-02-21 18:09:10 -05:00
yindo closed this issue 2026-02-21 18:09:10 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 15, 2024):

To resolve the issue in Dify version 0.7.0 where dragging an if-else condition in the visual workflow editor does not update the handle, preventing the addition and modification of edges, you need to ensure that the handle updates correctly during the drag operation.

Here is a potential fix:

  1. Ensure that the handleNodeDragStop function correctly updates the node's position and handles.
  2. Make sure the handleNodeConnectEnd function properly sets the connecting node payload and updates the edges.

Here is an example of how you might modify the handleNodeDragStop and handleNodeConnectEnd functions to ensure the handles are updated correctly:

const handleNodeDragStop = useCallback<NodeDragHandler>((_, node) => {
  const {
    setHelpLineHorizontal,
    setHelpLineVertical,
  } = workflowStore.getState();

  if (getNodesReadOnly())
    return;

  const { x, y } = dragNodeStartPosition.current;
  if (!(x === node.position.x && y === node.position.y)) {
    setHelpLineHorizontal();
    setHelpLineVertical();
    handleSyncWorkflowDraft();

    if (x !== 0 && y !== 0) {
      // selecting a note will trigger a drag stop event with x and y as 0
      saveStateToHistory(WorkflowHistoryEvent.NodeDragStop);
    }

    // Update the node's handle positions
    const { getNodes, setNodes } = store.getState();
    const nodes = getNodes();
    const updatedNodes = nodes.map(n => {
      if (n.id === node.id) {
        return {
          ...n,
          position: node.position,
        };
      }
      return n;
    });
    setNodes(updatedNodes);
  }
}, [workflowStore, getNodesReadOnly, saveStateToHistory, handleSyncWorkflowDraft]);

const handleNodeConnectEnd = useCallback<OnConnectEnd>((e: any) => {
  if (getNodesReadOnly())
    return;

  const {
    connectingNodePayload,
    setConnectingNodePayload,
    enteringNodePayload,
    setEnteringNodePayload,
  } = workflowStore.getState();
  if (connectingNodePayload && enteringNodePayload) {
    const {
      setShowAssignVariablePopup,
      hoveringAssignVariableGroupId,
    } = workflowStore.getState();
    const { screenToFlowPosition } = reactflow;
    const {
      getNodes,
      setNodes,
    } = store.getState();
    const nodes = getNodes();
    const fromHandleType = connectingNodePayload.handleType;
    const fromHandleId = connectingNodePayload.handleId;
    const fromNode = nodes.find(n => n.id === connectingNodePayload.nodeId)!;
    const toNode = nodes.find(n => n.id === enteringNodePayload.nodeId)!;
    const toParentNode = nodes.find(n => n.id === toNode.parentId);

    if (fromNode.parentId !== toNode.parentId)
      return;

    const { x, y } = screenToFlowPosition({ x: e.x, y: e.y });

    if (fromHandleType === 'source' && (toNode.data.type === BlockEnum.VariableAssigner || toNode.data.type === BlockEnum.VariableAggregator)) {
      const groupEnabled = toNode.data.advanced_settings?.group_enabled;
      const firstGroupId = toNode.data.advanced_settings?.groups[0].groupId;
      let handleId = 'target';
      if (groupEnabled) {
        if (hoveringAssignVariableGroupId)
          handleId = hoveringAssignVariableGroupId;
        else
          handleId = firstGroupId;
      }
      const newNodes = produce(nodes, (draft) => {
        draft.forEach((node) => {
          if (node.id === toNode.id) {
            node.data._showAddVariablePopup = true;
            node.data._holdAddVariablePopup = true;
          }
        });
      });
      setNodes(newNodes);
      setShowAssignVariablePopup({
        nodeId: fromNode.id,
        nodeData: fromNode.data,
        variableAssignerNodeId: toNode.id,
        variableAssignerNodeData: toNode.data,
        variableAssignerNodeHandleId: handleId,
        parentNode: toParentNode,
        x: x - toNode.positionAbsolute!.x,
        y: y - toNode.positionAbsolute!.y,
      });
      handleNodeConnect({
        source: fromNode.id,
        sourceHandle: fromHandleId,
        target: toNode.id,
        targetHandle: 'target',
      });
    }
  }
  setConnectingNodePayload(undefined);
  setEnteringNodePayload(undefined);
}, [store, handleNodeConnect, getNodesReadOnly, workflowStore, reactflow]);

This code ensures that the node's position and handles are updated correctly when the drag operation stops and when a connection ends. Adjustments may be needed based on the specific implementation details of your application [1].

To continue talking to Dosu, mention @dosu.

@dosubot[bot] commented on GitHub (Aug 15, 2024): <!-- Answer --> To resolve the issue in Dify version 0.7.0 where dragging an if-else condition in the visual workflow editor does not update the handle, preventing the addition and modification of edges, you need to ensure that the handle updates correctly during the drag operation. Here is a potential fix: 1. Ensure that the `handleNodeDragStop` function correctly updates the node's position and handles. 2. Make sure the `handleNodeConnectEnd` function properly sets the connecting node payload and updates the edges. Here is an example of how you might modify the `handleNodeDragStop` and `handleNodeConnectEnd` functions to ensure the handles are updated correctly: ```ts const handleNodeDragStop = useCallback<NodeDragHandler>((_, node) => { const { setHelpLineHorizontal, setHelpLineVertical, } = workflowStore.getState(); if (getNodesReadOnly()) return; const { x, y } = dragNodeStartPosition.current; if (!(x === node.position.x && y === node.position.y)) { setHelpLineHorizontal(); setHelpLineVertical(); handleSyncWorkflowDraft(); if (x !== 0 && y !== 0) { // selecting a note will trigger a drag stop event with x and y as 0 saveStateToHistory(WorkflowHistoryEvent.NodeDragStop); } // Update the node's handle positions const { getNodes, setNodes } = store.getState(); const nodes = getNodes(); const updatedNodes = nodes.map(n => { if (n.id === node.id) { return { ...n, position: node.position, }; } return n; }); setNodes(updatedNodes); } }, [workflowStore, getNodesReadOnly, saveStateToHistory, handleSyncWorkflowDraft]); const handleNodeConnectEnd = useCallback<OnConnectEnd>((e: any) => { if (getNodesReadOnly()) return; const { connectingNodePayload, setConnectingNodePayload, enteringNodePayload, setEnteringNodePayload, } = workflowStore.getState(); if (connectingNodePayload && enteringNodePayload) { const { setShowAssignVariablePopup, hoveringAssignVariableGroupId, } = workflowStore.getState(); const { screenToFlowPosition } = reactflow; const { getNodes, setNodes, } = store.getState(); const nodes = getNodes(); const fromHandleType = connectingNodePayload.handleType; const fromHandleId = connectingNodePayload.handleId; const fromNode = nodes.find(n => n.id === connectingNodePayload.nodeId)!; const toNode = nodes.find(n => n.id === enteringNodePayload.nodeId)!; const toParentNode = nodes.find(n => n.id === toNode.parentId); if (fromNode.parentId !== toNode.parentId) return; const { x, y } = screenToFlowPosition({ x: e.x, y: e.y }); if (fromHandleType === 'source' && (toNode.data.type === BlockEnum.VariableAssigner || toNode.data.type === BlockEnum.VariableAggregator)) { const groupEnabled = toNode.data.advanced_settings?.group_enabled; const firstGroupId = toNode.data.advanced_settings?.groups[0].groupId; let handleId = 'target'; if (groupEnabled) { if (hoveringAssignVariableGroupId) handleId = hoveringAssignVariableGroupId; else handleId = firstGroupId; } const newNodes = produce(nodes, (draft) => { draft.forEach((node) => { if (node.id === toNode.id) { node.data._showAddVariablePopup = true; node.data._holdAddVariablePopup = true; } }); }); setNodes(newNodes); setShowAssignVariablePopup({ nodeId: fromNode.id, nodeData: fromNode.data, variableAssignerNodeId: toNode.id, variableAssignerNodeData: toNode.data, variableAssignerNodeHandleId: handleId, parentNode: toParentNode, x: x - toNode.positionAbsolute!.x, y: y - toNode.positionAbsolute!.y, }); handleNodeConnect({ source: fromNode.id, sourceHandle: fromHandleId, target: toNode.id, targetHandle: 'target', }); } } setConnectingNodePayload(undefined); setEnteringNodePayload(undefined); }, [store, handleNodeConnect, getNodesReadOnly, workflowStore, reactflow]); ``` This code ensures that the node's position and handles are updated correctly when the drag operation stops and when a connection ends. Adjustments may be needed based on the specific implementation details of your application <sup>[[1]](https://github.com/langgenius/dify/blob/main/web/app/components/workflow/hooks/use-nodes-interactions.ts)</sup>. <!-- Dosu Comment Footer --> *To continue talking to [Dosu](https://dosu.dev), mention @dosu.*
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#5050