fix: reorder worktree groups by dragging their header - #187
Merged
Conversation
Reordering stopped at the group boundary. A card moved freely inside its own group, but the groups themselves sat in whatever order they happened to open in, so a worktree you were done with kept its place at the top and the reorder feature only half worked once a checkout split the list. A group has no row anywhere: groupByWorktree derives it from the flat session list, bucketing by session.path and ordering by first appearance. So moving a group means moving its whole block of ids inside that one list, which is what orderGroups builds. The sidebar wraps the groups in an outer DndContext sorting the group keys, and SessionGroup takes the drag from its header alone, so the card context and the group context never contend for the same pointer. The root group's path is the empty string, which a dnd-kit sortable id cannot be — ROOT_GROUP_KEY stands in for it, replacing the same literal the React key already spelled out. A key naming no group contributes no ids, so a group closed mid-drag makes the order short and reorderSessions drops it whole rather than taking that group's sessions with it. A pinned session still carries its group to the head of the list, which stays the one order a drag cannot beat.
…groups # Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Reordering sessions stopped at the group boundary. A card moved freely inside its own group, but the groups themselves sat in whatever order they happened to open in — so with several worktrees open, the one you were done with kept its place at the top and there was no way to move it. Drag a group by its header (the divider carrying the worktree's name) and the whole block moves with it, cards and pull request card included.
A sidebar with a single group draws no header and is unchanged.
How
A group has no row anywhere:
groupByWorktreederives it from the flat session list, bucketing bysession.pathand ordering by first appearance. Moving a group therefore means moving its whole block of ids inside that one list.orderGroups(groups, keys)builds that flat id order, each group keeping its internal order.SessionSidebarwraps the groups in an outerDndContext+SortableContextover the group keys; the drop commitsreorderSessions(projectId, orderGroups(groups, keys)).SessionGroupbecomes a sortable of that outer context but takes the drag from its header alone, so the per-group card context and the group context never contend for the same pointer. It isdisabledwhen there is no header — a lone group has nothing to reorder.ROOT_GROUP_KEYstands in for the root group's empty path, which a dnd-kit sortable id cannot be. It replaces the same"__root__"literal the React key already spelled out.A key naming no group contributes no ids, so a group closed mid-drag makes the order short and
reorderSessions' id-set check drops it whole rather than taking that group's sessions with it.Known ceiling
A pinned session still carries its group to the head of the list (#180). Dropping another group above a pinned group snaps back — the pin stays the one order a drag cannot beat. Recorded in the CHANGELOG entry rather than worked around.
Test plan
pnpm test— 652 pass, 3 new coveringorderGroups(block move, root key, unknown key)tsc --noEmitclean,biome checkclean (no new warnings)vite buildsucceedsCHANGELOG.md[Unreleased]entry lands heretask dev— the frontend gate is node-only, so a render path is not covered: open two worktrees, drag a group header, confirm the block moves and that clicking a card still selects itFollow-up
Filed as #188: the header runs
baseNameover the checkout path, so a worktree namedfeat/xrenders asxand collides withfix/x.