softflow24 / data-river

https://data-river.dev
MIT License
49 stars 11 forks source link

If & else handles can connect to items in invalid ways. #132

Open itsWindows11 opened 1 month ago

itsWindows11 commented 1 month ago

⚠️ Search for existing issues first ⚠️

Which Operating System are you using?

Windows

Which version of data-river are you using?

0.0.1

Describe your issue.

As shown in the video below, if/else handles can be connected to a block directly despite an indirect connection to that same block existing. Also, if a block is connected to the "if handle", it can get connected to the "else handle", and vice versa.

https://github.com/user-attachments/assets/6ec09adf-d325-46d9-ba92-ea28360972fe

Paste Error from Terminal/Console

No response

c0rtexR commented 1 month ago

Desired Behavior:

Proposed Solution:

Implement connection validation logic to prevent invalid configurations:

  1. Use isValidConnection on Handles:

    Update the SourceHandle component to include an isValidConnection function that checks for invalid connections. This function should:

    • Check if the target node is already connected to the other output (if or else) of the same logic block.
    • Prevent the connection if it would result in both if and else outputs connecting to the same node.
    • Check for potential cycles that could create infinite loops.
  2. Pre-calculate Invalid Connections:

    Perform validation during the connection attempt (onConnect event) rather than during dragging to avoid performance issues with animation frames.

  3. Update Connectable State:

    Dynamically set the connectable prop on the Handle components based on the validation results to prevent users from creating invalid connections.

Action Items:

Example Code Snippet:

// SourceHandle.ts
import React from "react";
import { Handle, Position } from "reactflow";
import { useSelector } from "react-redux";

const SourceHandle = ({ isVisible, nodeId, handleId }) => {
  const edges = useSelector((state) => state.reactFlow.edges);

  const isValidConnection = (connection) => {
    // Prevent connecting both 'if' and 'else' to the same target
    const existingConnections = edges.filter(
      (edge) =>
        edge.source === nodeId &&
        edge.target === connection.target &&
        edge.sourceHandle !== connection.sourceHandle
    );
    return existingConnections.length === 0;
  };

  return (
    <Handle
      type="source"
      position={Position.Right}
      id={handleId} // e.g., 'if' or 'else'
      isValidConnection={isValidConnection}
      style={{ visibility: isVisible ? "visible" : "hidden" }}
    />
  );
};

export default SourceHandle;

Notes: