From e86c06c3e58ba8d079013e4e986d324abc1d42a9 Mon Sep 17 00:00:00 2001 From: JGerla Date: Thu, 22 Jan 2026 10:26:21 +0100 Subject: [PATCH] fix: fixed deleting behaviour ref: N25B-450 --- src/pages/VisProgPage/VisProg.tsx | 3 ++ .../visualProgrammingUI/VisProgStores.tsx | 40 ++++++++++++------- .../visualProgrammingUI/VisProgTypes.tsx | 7 +++- .../components/NodeComponents.tsx | 7 ++-- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/pages/VisProgPage/VisProg.tsx b/src/pages/VisProgPage/VisProg.tsx index a5f7887..95b725d 100644 --- a/src/pages/VisProgPage/VisProg.tsx +++ b/src/pages/VisProgPage/VisProg.tsx @@ -44,6 +44,7 @@ const selector = (state: FlowState) => ({ nodes: state.nodes, edges: state.edges, onNodesChange: state.onNodesChange, + onNodesDelete: state.onNodesDelete, onEdgesDelete: state.onEdgesDelete, onEdgesChange: state.onEdgesChange, onConnect: state.onConnect, @@ -69,6 +70,7 @@ const VisProgUI = () => { const { nodes, edges, onNodesChange, + onNodesDelete, onEdgesDelete, onEdgesChange, onConnect, @@ -122,6 +124,7 @@ const VisProgUI = () => { defaultEdgeOptions={DEFAULT_EDGE_OPTIONS} nodeTypes={NodeTypes} onNodesChange={onNodesChange} + onNodesDelete={onNodesDelete} onEdgesDelete={onEdgesDelete} onEdgesChange={onEdgesChange} onReconnect={onReconnect} diff --git a/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx b/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx index dd754bf..c59fd3c 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx @@ -44,19 +44,18 @@ function createNode(id: string, type: string, position: XYPosition, data: Record } } - //* Initial nodes, created by using createNode. */ - // Start and End don't need to apply the UUID, since they are technically never compiled into a program. - const startNode = createNode('start', 'start', {x: 110, y: 100}, {label: "Start"}, false) - const endNode = createNode('end', 'end', {x: 590, y: 100}, {label: "End"}, false) - const initialPhaseNode = createNode(crypto.randomUUID(), 'phase', {x:235, y:100}, {label: "Phase 1", children : [], isFirstPhase: false, nextPhaseId: null}) +//* Initial nodes, created by using createNode. */ +// Start and End don't need to apply the UUID, since they are technically never compiled into a program. +const startNode = createNode('start', 'start', {x: 110, y: 100}, {label: "Start"}, false) +const endNode = createNode('end', 'end', {x: 590, y: 100}, {label: "End"}, false) +const initialPhaseNode = createNode(crypto.randomUUID(), 'phase', {x:235, y:100}, {label: "Phase 1", children : [], isFirstPhase: false, nextPhaseId: null}) - const initialNodes : Node[] = [startNode, endNode, initialPhaseNode]; +const initialNodes : Node[] = [startNode, endNode, initialPhaseNode]; // Initial edges, leave empty as setting initial edges... // ...breaks logic that is dependent on connection events const initialEdges: Edge[] = []; - /** * useFlowStore contains the implementation for all editor functionality * and stores the current state of the visual programming editor @@ -87,7 +86,9 @@ const useFlowStore = create(UndoRedo((set, get) => ({ */ onNodesChange: (changes) => set({nodes: applyNodeChanges(changes, get().nodes)}), - onNodesDelete: (nodes) => nodes.forEach(node => get().unregisterNodeRules(node.id)), + onNodesDelete: (nodes) => nodes.forEach((_node) => { + return; + }), onEdgesDelete: (edges) => { // we make sure any affected nodes get updated to reflect removal of edges @@ -183,19 +184,30 @@ const useFlowStore = create(UndoRedo((set, get) => ({ * Deletes a node by ID, respecting NodeDeletes rules. * Also removes all edges connected to that node. */ - deleteNode: (nodeId) => { + deleteNode: (nodeId, deleteElements) => { get().pushSnapshot(); // 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({ - nodes: get().nodes.filter((n) => n.id !== nodeId), - edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), - })} + deleteElements({ + nodes: get().nodes.filter((n) => n.id === nodeId), + edges: get().edges.filter((e) => e.source !== nodeId && e.target === nodeId)} + ).then(() => { + get().unregisterNodeRules(nodeId); + get().unregisterWarningsForId(nodeId); + }); + // set({ + // nodes: get().nodes.filter((n) => n.id !== nodeId), + // edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), + // }) + } }, /** diff --git a/src/pages/VisProgPage/visualProgrammingUI/VisProgTypes.tsx b/src/pages/VisProgPage/visualProgrammingUI/VisProgTypes.tsx index afb1024..f65440b 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/VisProgTypes.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/VisProgTypes.tsx @@ -7,7 +7,7 @@ import type { OnReconnect, Node, OnEdgesDelete, - OnNodesDelete + OnNodesDelete, DeleteElementsOptions } from '@xyflow/react'; import type {EditorWarningRegistry} from "./components/EditorWarnings.tsx"; import type {HandleRule} from "./HandleRuleLogic.ts"; @@ -69,7 +69,10 @@ export type FlowState = { * Deletes a node and any connected edges. * @param nodeId - the ID of the node to delete */ - deleteNode: (nodeId: string) => void; + deleteNode: (nodeId: string, deleteElements: (params: DeleteElementsOptions) => Promise<{ + deletedNodes: Node[] + deletedEdges: Edge[] + }>) => void; /** * Replaces the current nodes array in the store. diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/NodeComponents.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/NodeComponents.tsx index 38f03a1..2d9bbd8 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/NodeComponents.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/components/NodeComponents.tsx @@ -1,4 +1,4 @@ -import {NodeToolbar} from '@xyflow/react'; +import {NodeToolbar, useReactFlow} from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import {type JSX, useState} from "react"; import {createPortal} from "react-dom"; @@ -30,10 +30,11 @@ type ToolbarProps = { */ export function Toolbar({nodeId, allowDelete}: ToolbarProps) { const {nodes, deleteNode} = useFlowStore(); - + const { deleteElements } = useReactFlow(); const deleteParentNode = () => { - deleteNode(nodeId); + + deleteNode(nodeId, deleteElements); }; const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips;