Skip to content

Drag and drop sessions between tag groups in the session list - #83

Merged
karngyan merged 2 commits into
mainfrom
issue-81-session-dnd
Aug 17, 2026
Merged

Drag and drop sessions between tag groups in the session list#83
karngyan merged 2 commits into
mainfrom
issue-81-session-dnd

Conversation

@karngyan

@karngyan karngyan commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Closes #81.

What

Session rows in the sessions list can now be picked up and dropped onto a group heading. Dropping on a tag heading moves the session there: the tag it was dragged out of comes off, the tag it landed on goes on, and the rest of its tags are untouched. Dropping on the "No tag" remainder clears every tag. Machine, state and directory headings reject the drop with a no-drop cursor while the row is in the air and a notice explaining why on release. With no grouping there is nothing to drop onto, so dragging is off.

How

  • Library: @dnd-kit/core (MouseSensor + TouchSensor + DragOverlay). A mouse needs 5px of travel to lift a row, so plain clicks, the checkbox and the row menu keep working. A finger needs a 300ms hold, so scrolling stays scrolling; the rows suppress text selection and the iOS link callout only while a drag contract is present.
  • Semantics: a pure dropOnGroup(grouping, session, fromKey, toKey) verdict in sessions/view.ts, beside spawnFromGroup and unit-tested the same way. The route turns a retag verdict into the same fleet.update the tag editor sends, follows it with a fleet.list() so the row visibly re-groups, and says what happened in the status line.
  • Visuals: valid targets highlight the group band with the row-hover wash plus a ring outline; the dragged row dims in place and a small card naming it rides the pointer.
  • Discoverability: each row wears a small grip ahead of its checkbox — quiet until hover like the checkbox and the ⋯ trigger, full strength on coarse pointers — with a grab cursor and a "Drag to move to another group" tooltip. It is an advertisement rather than the handle it looks like (the whole row lifts), and it only renders while some heading on screen would actually take the drop, so the machine grouping does not promise a move every release would refuse.
  • Accessibility: drag and drop is a shortcut, never the only path — the tag editor stays as the keyboard and screen-reader route, exactly as the issue asks. The refusals are announced through the existing live region.

Multi-select drag is left as the follow-up the issue names.

Tests

  • cd web && pnpm vitest run — 75 files, 1477 tests, green (includes the real vite build in styles.build.test.ts).
  • pnpm run lint (tsc) — clean.
  • New unit tests pin every verdict of dropOnGroup and the drag wiring the DOM can honestly prove; sessions.test.tsx queries the notice line by element now that dnd-kit portals a second role=status live region onto the body.

🤖 Generated with Claude Code

karngyan and others added 2 commits August 17, 2026 22:56
The sessions list grows drag and drop for the one thing a drop can
honestly change: tags. A row picked up under one tag heading and let go
over another swaps the source tag for the target, dropping on the
untagged remainder clears them all, and both travel as the same update
the tag editor sends, so dragging is a shortcut for an existing edit
rather than a new power. Machine, state and directory headings refuse
the drop out loud, with a no-drop cursor in the air and the reason as a
notice on release; the ungrouped view offers no drag at all.

The verdict is a pure function beside spawnFromGroup, pinned by unit
tests; the table wires dnd-kit around it — a mouse pays five pixels to
lift, a finger pays a hold so scrolling stays scrolling, and the ghost
is a card naming the row rather than the row itself. The keyboard path
remains the tag editor, which drag and drop deliberately never replaces.

Closes #81.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drag and drop nobody has tried is drag and drop nobody has: the gesture
needed a face. Each row now wears a small grip ahead of its checkbox,
quiet until hover exactly as the checkbox and the row menu are, and at
full strength for a coarse pointer, which has no hover to learn from.
It is an advertisement rather than a handle — the whole row still
lifts — so it only renders while some heading on screen would take the
drop: a grip under the machine grouping would promise a move that every
release refuses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karngyan
karngyan merged commit 5d85cde into main Aug 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drag and drop sessions between groups in the session list

1 participant