diff --git a/src/frontend/src/CustomEdges/index.tsx b/src/frontend/src/CustomEdges/index.tsx index 28ae265ce..b7d38b5d9 100644 --- a/src/frontend/src/CustomEdges/index.tsx +++ b/src/frontend/src/CustomEdges/index.tsx @@ -24,10 +24,25 @@ export function DefaultEdge({ (sourceNode?.position.x ?? 0) + (sourceNode?.measured?.width ?? 0); const targetXNew = targetNode?.position.x ?? 0; - const distance = 200 + 0.1 * (Math.abs(sourceXNew - targetXNew) / 2); - const distanceY = 200 + 0.3 * Math.abs(sourceY - targetY); + const distance = 200 + 0.1 * ((sourceXNew - targetXNew) / 2); - const edgePathLoop = `M ${sourceXNew} ${sourceY} C ${sourceXNew + distance} ${sourceY + distanceY}, ${targetXNew - distance} ${targetY + distanceY}, ${targetXNew} ${targetY}`; + const zeroOnNegative = + (1 + + (1 - Math.exp(-0.01 * Math.abs(sourceXNew - targetXNew))) * + (sourceXNew - targetXNew >= 0 ? 1 : -1)) / + 2; + + const distanceY = + 200 - + 200 * (1 - zeroOnNegative) + + 0.3 * Math.abs(targetY - sourceY) * zeroOnNegative; + + const sourceDistanceY = + 200 - + 200 * (1 - zeroOnNegative) + + 0.3 * Math.abs(sourceY - targetY) * zeroOnNegative; + + const edgePathLoop = `M ${sourceXNew} ${sourceY} C ${sourceXNew + distance} ${sourceY + sourceDistanceY}, ${targetXNew - distance} ${targetY + distanceY}, ${targetXNew} ${targetY}`; const [edgePath] = getBezierPath({ sourceX: sourceXNew, diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 6d1442a4b..864b24c8a 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -581,14 +581,29 @@ function hasLoop( // Check if this connection would create a cycle const targetNode = nodes.find((n) => n.id === target); - const hasCycle = (node, visited = new Set()): boolean => { + const hasCycle = ( + node, + visited = new Set(), + firstEdge: EdgeType | null = null, + ): boolean => { if (visited.has(node.id)) return false; visited.add(node.id); for (const outgoer of getOutgoers(node, nodes, edges)) { - if (outgoer.id === source) return true; - if (hasCycle(outgoer, visited)) return true; + const edge = edges.find( + (e) => e.source === node.id && e.target === outgoer.id, + ); + if (outgoer.id === source) { + const sourceHandleObject = scapeJSONParse( + firstEdge?.sourceHandle ?? edge?.sourceHandle ?? "", + ); + const sourceHandleParsed = scapedJSONStringfy(sourceHandleObject); + if (sourceHandleParsed === e.targetHandle) { + return true; + } + } + if (hasCycle(outgoer, visited, firstEdge || edge)) return true; } return false; };