Merge branch 'demo' into refactor/nodes-match-functionality

This commit is contained in:
Björn Otgaar
2026-01-07 15:15:17 +01:00
20 changed files with 671 additions and 89 deletions

View File

@@ -8,6 +8,7 @@ import {
type Edge,
type XYPosition,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import type { FlowState } from './VisProgTypes';
import {
NodeDefaults,
@@ -50,8 +51,9 @@ function createNode(id: string, type: string, position: XYPosition, data: Record
const initialNodes : Node[] = [startNode, endNode, initialPhaseNode,];
// * Initial edges * /
const initialEdges: Edge[] = []; // no initial edges as edge connect events don't fire when using initial edges
// Initial edges, leave empty as setting initial edges...
// ...breaks logic that is dependent on connection events
const initialEdges: Edge[] = [];
/**
@@ -84,8 +86,9 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
*/
onNodesChange: (changes) => set({nodes: applyNodeChanges(changes, get().nodes)}),
onEdgesDelete: (edges) => {
onNodesDelete: (nodes) => nodes.forEach(node => get().unregisterNodeRules(node.id)),
onEdgesDelete: (edges) => {
// we make sure any affected nodes get updated to reflect removal of edges
edges.forEach((edge) => {
const nodes = get().nodes;
@@ -231,6 +234,79 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
past: [],
future: [],
isBatchAction: false,
// handleRuleRegistry definitions
/**
* stores registered rules for handle connection validation
*/
ruleRegistry: new Map(),
/**
* gets the rules registered by that handle described by the given node and handle ids
*
* @param {string} targetNodeId
* @param {string} targetHandleId
* @returns {HandleRule[]}
*/
getTargetRules: (targetNodeId, targetHandleId) => {
const key = `${targetNodeId}:${targetHandleId}`;
const rules = get().ruleRegistry.get(key);
// helper function that handles a situation where no rules were registered
const missingRulesResponse = () => {
console.warn(
`No rules were registered for the following handle "${key}"!
returning and empty handleRule[] to avoid crashing`);
return []
}
return rules
? rules
: missingRulesResponse()
},
/**
* registers a handle's connection rules
*
* @param {string} nodeId
* @param {string} handleId
* @param {HandleRule[]} rules
*/
registerRules: (nodeId, handleId, rules) => {
const registry = get().ruleRegistry;
registry.set(`${nodeId}:${handleId}`, rules);
set({ ruleRegistry: registry }) ;
},
/**
* unregisters a handles connection rules
*
* @param {string} nodeId
* @param {string} handleId
*/
unregisterHandleRules: (nodeId, handleId) => {
set( () => {
const registry = get().ruleRegistry;
registry.delete(`${nodeId}:${handleId}`);
return { ruleRegistry: registry };
})
},
/**
* unregisters connection rules for all handles on the given node
* used for cleaning up rules on node deletion
*
* @param {string} nodeId
*/
unregisterNodeRules: (nodeId) => {
set(() => {
const registry = get().ruleRegistry;
registry.forEach((_,key) => {
if (key.startsWith(`${nodeId}:`)) registry.delete(key)
})
return { ruleRegistry: registry };
})
}
}))
);