Поправил логику проверки удаления узлов

This commit is contained in:
NikitaKalitov
2026-07-20 13:49:44 +03:00
parent 179be1f63b
commit d823b3df47
+20 -11
View File
@@ -259,17 +259,25 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
setSelectedEdgeId(null); setSelectedEdgeId(null);
}, []); }, []);
const onNodesChange = useCallback( // Runs before React Flow computes any removal changes at all (for both
(changes: NodeChange[]) => { // nodes and their connected edges), so blocking here — unlike filtering
const withChildren = new Set(nodes.filter((n) => n.parentId).map((n) => n.parentId!)); // inside onNodesChange — stops the connected edges from being deleted too.
const filteredChanges = changes.filter((change) => { const onBeforeDelete = useCallback(
if (change.type !== 'remove' || !withChildren.has(change.id)) return true; async ({ nodes: nodesToDelete }: { nodes: Node[]; edges: Edge[] }) => {
const hasContainerNode = nodesToDelete.some((node) => nodes.some((n) => n.parentId === node.id));
if (hasContainerNode) {
window.alert('Сначала удалите вложенные узлы — у этого узла есть под-процесс.'); window.alert('Сначала удалите вложенные узлы — у этого узла есть под-процесс.');
return false; return false;
}); }
return true;
},
[nodes],
);
const positionChanges = filteredChanges.filter((c) => c.type === 'position' && c.position); const onNodesChange = useCallback(
let adjustedChanges = filteredChanges; (changes: NodeChange[]) => {
const positionChanges = changes.filter((c) => c.type === 'position' && c.position);
let adjustedChanges = changes;
if (positionChanges.length === 1) { if (positionChanges.length === 1) {
const change = positionChanges[0]; const change = positionChanges[0];
const draggedNode = change.type === 'position' ? nodes.find((n) => n.id === change.id) : undefined; const draggedNode = change.type === 'position' ? nodes.find((n) => n.id === change.id) : undefined;
@@ -286,7 +294,7 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
}; };
const snapped = computeSnapAndGuides(dragged, others); const snapped = computeSnapAndGuides(dragged, others);
setAlignmentGuides(change.dragging === false ? [] : snapped.guides); setAlignmentGuides(change.dragging === false ? [] : snapped.guides);
adjustedChanges = filteredChanges.map((c) => adjustedChanges = changes.map((c) =>
c === change ? { ...c, position: { x: snapped.x, y: snapped.y } } : c, c === change ? { ...c, position: { x: snapped.x, y: snapped.y } } : c,
); );
} }
@@ -294,7 +302,7 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
setAlignmentGuides([]); setAlignmentGuides([]);
} }
const isHistoryWorthy = filteredChanges.some( const isHistoryWorthy = changes.some(
(change) => (change) =>
change.type === 'remove' || change.type === 'remove' ||
(change.type === 'position' && change.dragging === false) || (change.type === 'position' && change.dragging === false) ||
@@ -308,7 +316,7 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
// emitChange — filtering edges here too (redundantly with onEdgesChange) // emitChange — filtering edges here too (redundantly with onEdgesChange)
// guarantees a removed node never leaves a dangling edge behind. // guarantees a removed node never leaves a dangling edge behind.
const removedIds = new Set( const removedIds = new Set(
filteredChanges.filter((change) => change.type === 'remove').map((change) => change.id), changes.filter((change) => change.type === 'remove').map((change) => change.id),
); );
const nextEdges = removedIds.size const nextEdges = removedIds.size
? edges.filter((edge) => !removedIds.has(edge.source) && !removedIds.has(edge.target)) ? edges.filter((edge) => !removedIds.has(edge.source) && !removedIds.has(edge.target))
@@ -574,6 +582,7 @@ function DiagramCanvas({ initialValue, onChange }: DiagramEditorProps) {
onEdgesChange={onEdgesChange} onEdgesChange={onEdgesChange}
onConnect={onConnect} onConnect={onConnect}
onReconnect={onReconnect} onReconnect={onReconnect}
onBeforeDelete={onBeforeDelete}
edgesReconnectable={mode === 'edit'} edgesReconnectable={mode === 'edit'}
onNodeClick={onNodeClick} onNodeClick={onNodeClick}
onEdgeClick={onEdgeClick} onEdgeClick={onEdgeClick}