mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-11 16:09:39 +00:00
fix(frontend): clear the flow graph selection through xyflow's store (#11056)
Selecting a step in the flow editor sometimes opened the Settings panel instead of the step that was clicked. SelectionManager.selectId() clears xyflow's own selection before setting ours, and that clear was wired to clearFlowSelection(), which resets offsetNodeCache and reassigns nodes. That hands xyflow node objects it does not recognise, which is what makes it drop the flag — but it also makes it re-create every node's DOM: 126 elements on a 25-node flow, on every selection. Graph nodes select on pointerdown. A click is dispatched on the closest common ancestor of its pointerdown and pointerup targets, so when the release lands in that teardown gap the browser hit-tests to the pane, the click addresses the pane, and onpaneclick clears the selection back to the settings sentinel. Clear through store.unselectNodesAndEdges() instead, so no node object changes identity and there is no gap to fall into. clearFlowSelection keeps its two group-creation callers, which rebuild the graph anyway. Claude-Session: https://claude.ai/code/session_01R7caEKonPr2DmvsWRR6bCK Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -734,11 +734,9 @@
|
||||
return false
|
||||
}
|
||||
|
||||
// Clear SvelteFlow's internal selection by creating new nodes array
|
||||
function clearFlowSelection() {
|
||||
// xyflow owns `selected` on the objects it was handed, and drops it only when it sees a
|
||||
// node it does not recognise. Serving the cached mapping back would hand it the very
|
||||
// object it marked selected, so the clear has to go through fresh objects.
|
||||
// Resetting the cache and reassigning `nodes` hands xyflow objects it has not seen, the
|
||||
// only lever on its selection available from our own array.
|
||||
offsetNodeCache = new WeakMap<Node, Node>()
|
||||
nodes = nodes.map((node) => {
|
||||
if (node.selected) {
|
||||
@@ -1411,7 +1409,7 @@
|
||||
/>
|
||||
|
||||
<!-- SelectionTool for handling selection changes and filtering -->
|
||||
<SelectionTool {selectionManager} clearGraphSelection={clearFlowSelection} />
|
||||
<SelectionTool {selectionManager} />
|
||||
|
||||
{#if leftHeader}
|
||||
<div class="absolute top-2 left-2 z-10">
|
||||
|
||||
@@ -4,16 +4,18 @@
|
||||
import type { SelectionManager } from './selectionUtils.svelte'
|
||||
interface Props {
|
||||
selectionManager: SelectionManager
|
||||
clearGraphSelection: () => void
|
||||
}
|
||||
|
||||
let { selectionManager, clearGraphSelection }: Props = $props()
|
||||
let { selectionManager }: Props = $props()
|
||||
|
||||
untrack(() => selectionManager).setClearGraphSelection(untrack(() => clearGraphSelection))
|
||||
|
||||
// Get store to access selectionRect
|
||||
const store = useStore()
|
||||
|
||||
// Clear through xyflow's store, never by handing it fresh node objects: replacing them
|
||||
// re-creates every node's DOM, and a click whose node is rebuilt between pointerdown and
|
||||
// release retargets to the pane, which clears the selection that same gesture just made.
|
||||
// While xyflow holds a selection, useOnSelectionChange below re-broadcasts it over ours.
|
||||
untrack(() => selectionManager).setClearGraphSelection(() => store.unselectNodesAndEdges())
|
||||
|
||||
// Handle selection changes from SvelteFlow
|
||||
useOnSelectionChange(({ nodes: selectedNodes, edges: _selectedEdges }) => {
|
||||
// Notes are already non-selectable, so no filtering needed
|
||||
|
||||
@@ -12,6 +12,8 @@ export type GraphContext = {
|
||||
showAssets: Writable<boolean | undefined>
|
||||
noteManager?: NoteManager
|
||||
moveManager?: MoveManager
|
||||
/** Clears xyflow's selection by replacing every node object, so only for callers that rebuild
|
||||
* the graph anyway. A selection change must use `selectionManager` instead. */
|
||||
clearFlowSelection?: () => void
|
||||
yOffset?: number
|
||||
diffManager: FlowDiffManager
|
||||
|
||||
Reference in New Issue
Block a user