From 8c2d630af500287072ecb78cc16118f4addc4f0d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 19:51:37 +0000 Subject: [PATCH] fix(editor): Delete/Backspace key removes selected node + orphan edges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit React Flow's built-in keyboard handling was silently no-op'd because deleteKeyCode wasn't set (v12 defaults it to null when the prop is absent in the strict TS types we consume). Set it to ['Delete', 'Backspace'] and add an onNodesDelete handler that filters edges whose endpoints just vanished — applyNodeChanges only touches nodes, so without this the graph kept dangling edges. Also fixes a tsc regression the same touch caught in ConnectionsPage.test where a request.json() cast leaked 'never' back into a later access. --- frontend/src/editor/Canvas.tsx | 10 ++++++++++ frontend/src/pages/ConnectionsPage.test.tsx | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/editor/Canvas.tsx b/frontend/src/editor/Canvas.tsx index 7b69bc0..366cbd4 100644 --- a/frontend/src/editor/Canvas.tsx +++ b/frontend/src/editor/Canvas.tsx @@ -4,6 +4,8 @@ import { useReactFlow, type Connection, type Edge, type Node, type NodeChange, type EdgeChange, applyNodeChanges, applyEdgeChanges, } from "@xyflow/react"; + +const DELETE_KEYS = ["Delete", "Backspace"]; import { nodeTypes as vcNodeTypes } from "./customNode"; import type { VcNodeData } from "./graphAdapter"; @@ -51,6 +53,14 @@ function Inner({ onEdgesChange={handleEdges} onConnect={onConnect} onSelectionChange={({ nodes: sel }) => onSelectNode(sel[0]?.id ?? null)} + onNodesDelete={(deleted) => { + // React Flow removes the nodes via applyNodeChanges above; it does + // NOT auto-remove edges whose endpoints just vanished. Filter here + // so the graph stays valid. + const gone = new Set(deleted.map((n) => n.id)); + onEdgesChange(edges.filter((e) => !gone.has(e.source) && !gone.has(e.target))); + }} + deleteKeyCode={DELETE_KEYS} nodeTypes={vcNodeTypes} fitView > diff --git a/frontend/src/pages/ConnectionsPage.test.tsx b/frontend/src/pages/ConnectionsPage.test.tsx index e5fc655..f6f3d6f 100644 --- a/frontend/src/pages/ConnectionsPage.test.tsx +++ b/frontend/src/pages/ConnectionsPage.test.tsx @@ -38,9 +38,10 @@ describe("ConnectionsPage", () => { { id: "c1", providerId: "nats", name: "local", config: { url: "nats://old" } }, ] as never)), http.put("/api/connections/c1", async ({ request }) => { - latestPut = await request.json() as never; + const body = await request.json() as { name?: string; config?: { url?: string; pass?: string } }; + latestPut = body; return HttpResponse.json({ - id: "c1", providerId: "nats", name: latestPut!.name, config: { url: latestPut!.config?.url }, + id: "c1", providerId: "nats", name: body.name, config: { url: body.config?.url }, } as never); }), );