Altinity / Altinity/altinity-sql-browser

Schema graph: multi-select + group-move of nodes (marquee, Shift-click, ⌘A) with single-step undo

Offen
#66 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

enhancement
Vorherrschende Sprache
TypeScript
Sterne
8
Forks
2
Ø Merge
1 Std. 34 Min.
Gemergte PRs (30 T.)
6

Beschreibung

⚠️ Reconciled 2026-06-30 (#88). Settled approach: imperative + pure-core, no framework (CLAUDE.md rule 5). Before implementing, extract the interaction surface so this doesn't grow inside explain-graph.js: src/core/graph-selection.js (pure — selection set, nodesInRect marquee hit-test, select-all/connected, batch move + align/distribute, batch undo op) and src/ui/graph-surface.js (pan/zoom, pointer capture, marquee rect, keybindings, selection CSS, toolbar — shared with the EXPLAIN pipeline graph where possible). The Implementation notes below still apply, but land in those extracted modules rather than directly in attachSchemaInteractions. See #68 Phase 5.


Problem

In the full-screen schema/data-flow view, layout is hand-tunable by ⌘/Ctrl-dragging a card — but one node at a time. Re-arranging a group of related tables means dragging each individually, which is slow and tedious. There's no way to select several nodes and move them together.

Proposal

Add a selection set of nodes and let the whole set be dragged as one unit, with light group-layout actions. Build entirely on the existing single-node move machinery (no new runtime deps).

Selecting nodes (all additive to today's bindings):

  • Marquee: Shift-drag on empty canvas draws a selection rectangle; cards it touches join the selection. (Plain drag and ⌘/Ctrl-drag stay pan, so Shift-drag is the free gesture for marquee.)
  • Shift-click a card: toggle it in/out of the selection (doesn't open the detail pane).
  • ⌘A: select every node (when the view has focus).
  • Select a whole database / connected lineage component: a one-shot action — e.g. Alt/double-click a card, or a small "select DB / select connected" control — so a related cluster can be grabbed at once.
  • Deselect: plain-click empty canvas, or Esc.

Moving the group: with ≥1 node selected, ⌘/Ctrl-drag any selected card moves the entire selection by the same delta; edges within and touching the set re-route live. ⌘/Ctrl-drag on an unselected card keeps today's single-node behavior.

Group layout actions (shown only when ≥2 are selected): align (left/right/top/bottom), distribute evenly, and optionally re-tidy (re-run dagre on just the selected subgraph). Layout math stays pure in src/core/.

Persistence & undo: the group move persists per-node like single moves (savedPositions) and is undone/redone as one step (a single ⌘Z reverts the whole drag / align).

Current implementation (reuse what exists)

The single-node move path is fully built and is the template — multi-node is additive on top of it.

  • Interaction wiring: attachSchemaInteractions(...)src/ui/explain-graph.js:423. onDown (:478) gates plain-press (pan / open detail pane) vs ⌘/Ctrl-drag (move one node); onMove (:496) → placeAt (:443); onUp (:502) records one undo op.
  • Pure helpers, src/core/graph-layout.js (all reusable for a group): dragDeltaToSvg (:47, viewBox-aware — the same delta applies to every selected node), straightEdgePoints (:31), incidentEdges (:36), applyPositions (:55, already loops), recordPosition (:65), createMoveHistory (:77, op shape {id,from,to}).
  • Persistence: positions map { "db.table": {x,y} } is savedPositions on the result (app.js:586), reloaded via applyPositions (explain-graph.js:257).
  • Existing single "selected" ring (markSelected/clearSchemaSelection, .eg-card--selected + .eg-card-ring) in src/ui/schema-detail.js + styles.css:703 is coupled to the detail pane and mutually-exclusive. A multi-select set is a distinct concept and must be reconciled with it.
  • No marquee / multi-select infrastructure exists yet. Modifier conventions today: plain-click node → detail pane; ⌘/Ctrl-drag node → move; plain/⌘ drag empty canvas → pan; ⌘/Ctrl+wheel → zoom; ⌘Z/⌘⇧Z/⌘Y → undo/redo.
Implementation notes
  • src/core/graph-layout.js (pure, 100% covered): extend createMoveHistory to a batch op { moves: [{id,from,to}] } so undo/redo applies to the whole set in one step; add nodesInRect(nodes, rect) for marquee hit-testing and pure align/distribute helpers. Reuse dragDeltaToSvg, straightEdgePoints, incidentEdges, recordPosition, applyPositions as-is.
  • src/ui/explain-graph.js attachSchemaInteractions: hold a Set of selected ids; add Shift-click toggle, the Shift-drag marquee (draw an SVG rect, hit-test on mouseup), ⌘A, and select-DB/component; in onDown/onMove loop placeAt over the selection and straighten the union of incident edges once per frame; record one batch undo op in onUp.
  • src/ui/schema-detail.js + styles.css: reconcile the existing detail-pane ring with the new multi-select highlight — either unify into one selection set (pane shows the most-recently-clicked) or give the move-selection its own class. Add a marquee-rectangle style.
  • No new runtime deps (DOM/SVG only); tests in the same change (pure helpers to 100%, integration for the wiring) per the CLAUDE.md coverage gate.
Acceptance criteria
  • Shift-drag marquee, Shift-click toggle, ⌘A, and select-DB/connected all build a multi-node selection with a clear highlight.
  • ⌘/Ctrl-dragging a selected card moves the whole selection; all incident edges re-route live; single-node drag of an unselected card is unchanged.
  • Align + distribute (and/or re-tidy) act on the selection.
  • The group move/align persists in savedPositions and is undone/redone as a single step.
  • Plain-click empty canvas / Esc clears the selection; detail-pane ring behavior reconciled.
  • npm test green at the per-file coverage gate; no new runtime dependency.
Open design questions
  • Exact bindings (Shift-drag marquee vs a toggled "select mode"; how "select DB/component" is triggered).
  • Marquee hit policy: intersect vs full-containment.
  • Unify the detail-pane ring with the move-selection, or keep them visually distinct?
  • Scope of "auto-layout": just align/distribute, or also re-dagre the selected subset?

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit dem in #88 abgestimmten Ansatz und lies Regel 5 in CLAUDE.md; untersuche anschließend src/core/graph-selection.js, src/ui/graph-surface.js und den bestehenden Interaktionspfad in src/ui/explain-graph.js. Vergleiche die relevanten Einstiegspunkte für graph-layout, schema-detail, styles.css und Tests, bevor du entscheidest, wie Auswahl- und Interaktionsoberflächen zusammenspielen. Als abgeschlossen gilt die Aufgabe, wenn die aufgeführten Akzeptanzkriterien für Auswahl, Gruppenbewegung, Layout, Persistenz, Undo/Redo und das coverage-gate ohne eine neue Laufzeitabhängigkeit erfüllt sind.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
frontend
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.