فهرست منبع

fix: Delete key ignored with the node picker open, or a node selected but not focused

Two separate bugs, both leaving the Delete key doing nothing at all with
no hint as to why.

The node picker is a sidebar, not a modal. It deliberately stays open
after adding a node, and the canvas beside it stays fully usable with the
mouse - but the keyboard handler returned early on it as though it were a
modal, swallowing Delete, Escape, Enter and the arrow keys. Escape in
particular could not close the panel it is the obvious key for. The only
thing that actually needed protecting is the picker's search box, and the
handler already computes `typing` for exactly that.

Separately, one node could be "the node you mean" in two ways: clicked,
which sets the focus, or rubber-banded and shift-clicked, which only sets
`selected`. Multi-delete read `selected` and single delete read the focus,
so Delete on a rubber-band-selected node did nothing. Both are now folded
into one set of targets.

Verified in the browser: Delete works with the picker open and on a
Ctrl+A-selected node, typing in the picker's search box is still plain
typing, Escape closes the picker, several nodes still delete without a
confirmation, and each deletion undoes.
fszontagh 1 ماه پیش
والد
کامیت
a9db45bf87
1فایلهای تغییر یافته به همراه27 افزوده شده و 10 حذف شده
  1. 27 10
      webui/src/pages/WorkflowEditorPage.tsx

+ 27 - 10
webui/src/pages/WorkflowEditorPage.tsx

@@ -1692,21 +1692,31 @@ function WorkflowEditorInner() {
         }
       }
 
-      if (showNodePicker) return
+      // The node picker is a sidebar, not a modal: the canvas stays usable
+      // beside it and it deliberately stays open after adding a node. So the
+      // canvas keys keep working while it is open - the only thing needing
+      // protection is its search box, and that is what `typing` is for.
+      if (typing) return
 
       if (e.key === 'Delete') {
         e.preventDefault()
-        // Check for multiple selected nodes first
-        const selectedNodes = nodes.filter(n => n.selected)
-        if (selectedNodes.length > 1) {
-          // Delete all selected nodes without confirmation for multi-select
-          const selectedIds = new Set(selectedNodes.map(n => n.id))
-          setNodes((nds) => nds.filter((n) => !selectedIds.has(n.id)))
-          setEdges((eds) => eds.filter((e) => !selectedIds.has(e.source) && !selectedIds.has(e.target)))
+
+        // One node can be "the node you mean" in two ways: clicked, which sets
+        // the focus, or rubber-banded and shift-clicked, which only sets
+        // `selected`. Reading just one of them made Delete do nothing at all
+        // for the other, with no hint as to why.
+        const targetIds = new Set(nodes.filter((n) => n.selected).map((n) => n.id))
+        if (focusedNodeId) targetIds.add(focusedNodeId)
+
+        if (targetIds.size > 1) {
+          // Several at once goes through without a confirmation: it was a
+          // deliberate selection, and undo puts it back.
+          setNodes((nds) => nds.filter((n) => !targetIds.has(n.id)))
+          setEdges((eds) => eds.filter((e) => !targetIds.has(e.source) && !targetIds.has(e.target)))
           setHasChanges(true)
           setFocusedNodeId(null)
-        } else if (focusedNodeId) {
-          setShowDeleteConfirm(focusedNodeId)
+        } else if (targetIds.size === 1) {
+          setShowDeleteConfirm([...targetIds][0])
         } else if (selectedEdgeId) {
           deleteEdge(selectedEdgeId)
         }
@@ -1714,6 +1724,13 @@ function WorkflowEditorInner() {
       }
 
       if (e.key === 'Escape') {
+        // Closing the picker comes first, otherwise the one key everybody
+        // presses to dismiss a panel does nothing to it.
+        if (showNodePicker) {
+          setShowNodePicker(false)
+          setConnectDrop(null)
+          return
+        }
         setFocusedNodeId(null)
         setSelectedEdgeId(null)
         setContextMenu(null)