fix: fixed deleting behaviour

ref: N25B-450
This commit is contained in:
JGerla
2026-01-22 10:26:21 +01:00
parent 363054afda
commit e86c06c3e5
4 changed files with 38 additions and 19 deletions

View File

@@ -44,6 +44,7 @@ const selector = (state: FlowState) => ({
nodes: state.nodes, nodes: state.nodes,
edges: state.edges, edges: state.edges,
onNodesChange: state.onNodesChange, onNodesChange: state.onNodesChange,
onNodesDelete: state.onNodesDelete,
onEdgesDelete: state.onEdgesDelete, onEdgesDelete: state.onEdgesDelete,
onEdgesChange: state.onEdgesChange, onEdgesChange: state.onEdgesChange,
onConnect: state.onConnect, onConnect: state.onConnect,
@@ -69,6 +70,7 @@ const VisProgUI = () => {
const { const {
nodes, edges, nodes, edges,
onNodesChange, onNodesChange,
onNodesDelete,
onEdgesDelete, onEdgesDelete,
onEdgesChange, onEdgesChange,
onConnect, onConnect,
@@ -122,6 +124,7 @@ const VisProgUI = () => {
defaultEdgeOptions={DEFAULT_EDGE_OPTIONS} defaultEdgeOptions={DEFAULT_EDGE_OPTIONS}
nodeTypes={NodeTypes} nodeTypes={NodeTypes}
onNodesChange={onNodesChange} onNodesChange={onNodesChange}
onNodesDelete={onNodesDelete}
onEdgesDelete={onEdgesDelete} onEdgesDelete={onEdgesDelete}
onEdgesChange={onEdgesChange} onEdgesChange={onEdgesChange}
onReconnect={onReconnect} onReconnect={onReconnect}

View File

@@ -56,7 +56,6 @@ function createNode(id: string, type: string, position: XYPosition, data: Record
// ...breaks logic that is dependent on connection events // ...breaks logic that is dependent on connection events
const initialEdges: Edge[] = []; const initialEdges: Edge[] = [];
/** /**
* useFlowStore contains the implementation for all editor functionality * useFlowStore contains the implementation for all editor functionality
* and stores the current state of the visual programming editor * and stores the current state of the visual programming editor
@@ -87,7 +86,9 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
*/ */
onNodesChange: (changes) => set({nodes: applyNodeChanges(changes, get().nodes)}), 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) => { onEdgesDelete: (edges) => {
// we make sure any affected nodes get updated to reflect removal of edges // we make sure any affected nodes get updated to reflect removal of edges
@@ -183,19 +184,30 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
* Deletes a node by ID, respecting NodeDeletes rules. * Deletes a node by ID, respecting NodeDeletes rules.
* Also removes all edges connected to that node. * Also removes all edges connected to that node.
*/ */
deleteNode: (nodeId) => { deleteNode: (nodeId, deleteElements) => {
get().pushSnapshot(); get().pushSnapshot();
// Let's find our node to check if they have a special deletion function // Let's find our node to check if they have a special deletion function
const ourNode = get().nodes.find((n)=>n.id==nodeId); const ourNode = get().nodes.find((n)=>n.id==nodeId);
const ourFunction = Object.entries(NodeDeletes).find(([t])=>t==ourNode?.type)?.[1] 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 there's no function, OR, our function tells us we can delete it, let's do so...
if (ourFunction == undefined || ourFunction()) { if (ourFunction == undefined || ourFunction()) {
set({ deleteElements({
nodes: get().nodes.filter((n) => n.id !== nodeId), nodes: get().nodes.filter((n) => n.id === nodeId),
edges: get().edges.filter((e) => e.source !== nodeId && e.target !== 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),
// })
}
}, },
/** /**

View File

@@ -7,7 +7,7 @@ import type {
OnReconnect, OnReconnect,
Node, Node,
OnEdgesDelete, OnEdgesDelete,
OnNodesDelete OnNodesDelete, DeleteElementsOptions
} from '@xyflow/react'; } from '@xyflow/react';
import type {EditorWarningRegistry} from "./components/EditorWarnings.tsx"; import type {EditorWarningRegistry} from "./components/EditorWarnings.tsx";
import type {HandleRule} from "./HandleRuleLogic.ts"; import type {HandleRule} from "./HandleRuleLogic.ts";
@@ -69,7 +69,10 @@ export type FlowState = {
* Deletes a node and any connected edges. * Deletes a node and any connected edges.
* @param nodeId - the ID of the node to delete * @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. * Replaces the current nodes array in the store.

View File

@@ -1,4 +1,4 @@
import {NodeToolbar} from '@xyflow/react'; import {NodeToolbar, useReactFlow} from '@xyflow/react';
import '@xyflow/react/dist/style.css'; import '@xyflow/react/dist/style.css';
import {type JSX, useState} from "react"; import {type JSX, useState} from "react";
import {createPortal} from "react-dom"; import {createPortal} from "react-dom";
@@ -30,10 +30,11 @@ type ToolbarProps = {
*/ */
export function Toolbar({nodeId, allowDelete}: ToolbarProps) { export function Toolbar({nodeId, allowDelete}: ToolbarProps) {
const {nodes, deleteNode} = useFlowStore(); const {nodes, deleteNode} = useFlowStore();
const { deleteElements } = useReactFlow();
const deleteParentNode = () => { const deleteParentNode = () => {
deleteNode(nodeId);
deleteNode(nodeId, deleteElements);
}; };
const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips; const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips;