From 0ba026092d83e3979de59b282565e120ca64578a Mon Sep 17 00:00:00 2001 From: JGerla Date: Mon, 19 Jan 2026 17:13:46 +0100 Subject: [PATCH] fix: fixed reconnect being able to circumvent connection rules the fix fixes the behavior, however user feedback does not reflect the fix as it driven by events that aren't triggered by onReconnect connection, and thus it would take a lot of time to fix the user feedback for onReconnect --- .../visualProgrammingUI/HandleRuleLogic.ts | 12 ++++++ .../visualProgrammingUI/VisProgStores.tsx | 39 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/pages/VisProgPage/visualProgrammingUI/HandleRuleLogic.ts b/src/pages/VisProgPage/visualProgrammingUI/HandleRuleLogic.ts index 427542a..e212ed2 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/HandleRuleLogic.ts +++ b/src/pages/VisProgPage/visualProgrammingUI/HandleRuleLogic.ts @@ -107,4 +107,16 @@ export function useHandleRules( // finally we return a function that evaluates all rules using the created context return evaluateRules(targetRules, connection, context); }; +} + +export function validateConnectionWithRules( + connection: Connection, + context: ConnectionContext +): RuleResult { + const rules = useFlowStore.getState().getTargetRules( + connection.target!, + connection.targetHandle! + ); + + return evaluateRules(rules,connection, context); } \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx b/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx index defa934..2831748 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx @@ -9,6 +9,7 @@ import { type XYPosition, } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; +import {type ConnectionContext, validateConnectionWithRules} from "./HandleRuleLogic.ts"; import type { FlowState } from './VisProgTypes'; import { NodeDefaults, @@ -129,7 +130,41 @@ const useFlowStore = create(UndoRedo((set, get) => ({ * Handles reconnecting an edge between nodes. */ onReconnect: (oldEdge, newConnection) => { - get().edgeReconnectSuccessful = true; + + function createContext( + source: {id: string, handleId: string}, + target: {id: string, handleId: string} + ) : ConnectionContext { + const edges = get().edges; + const targetConnections = edges.filter(edge => edge.target === target.id && edge.targetHandle === target.handleId).length + return { + connectionCount: targetConnections, + source: source, + target: target + } + } + + // connection validation + const context: ConnectionContext = oldEdge.source === newConnection.source + ? createContext({id: newConnection.source, handleId: newConnection.sourceHandle!}, {id: newConnection.target, handleId: newConnection.targetHandle!}) + : createContext({id: newConnection.target, handleId: newConnection.targetHandle!}, {id: newConnection.source, handleId: newConnection.sourceHandle!}); + + const result = validateConnectionWithRules( + newConnection, + context + ); + + if (!result.isSatisfied) { + set({ + edges: get().edges.map(e => + e.id === oldEdge.id ? oldEdge : e + ), + }); + return; + } + + // further reconnect logic + set({ edgeReconnectSuccessful: true }); set({ edges: reconnectEdge(oldEdge, newConnection, get().edges) }); // We make sure to perform any required data updates on the newly reconnected nodes @@ -188,7 +223,7 @@ const useFlowStore = create(UndoRedo((set, get) => ({ // Let's find our node to check if they have a special deletion function const ourNode = get().nodes.find((n)=>n.id==nodeId); const ourFunction = Object.entries(NodeDeletes).find(([t])=>t==ourNode?.type)?.[1] - + // If there's no function, OR, our function tells us we can delete it, let's do so... if (ourFunction == undefined || ourFunction()) { set({