feat(web): let the sidebar's sections be arranged by hand - #5
Merged
Conversation
Section order was whatever the grouping produced: sections with live work first, then history-only ones, then the quiet seeded projects, first appearance breaking ties inside each rank. That is a reasonable default and a poor permanent arrangement — the one project you check every morning drifts down the list the moment nothing is running in it, and environments had no ordering control at all. Order becomes a second pass over the built tree rather than a variant of the grouping. Which sections exist is one question; where they sit is another, and splitting them is what lets an arrangement survive threads arriving, settling, and being filtered out. Three modes, in the same menu that already sorts threads: Busiest first (the old behavior), Name (A–Z), and Custom. Custom is reachable two ways, because a sidebar is a list you point at and also a list you drive from the keyboard. Drag a header to move it, or right-click and choose Move up / Move down; either switches to Custom and records the whole level, so the result stops depending on activity. Requiring the mode to be picked first would have made the first drag a silent no-op. Sections move only within their own level. A drop is refused outright when it lands outside the dragged section's siblings, and while a drag is in flight every other level disables its droppables, so a project level never animates a swap it would then discard. Reparenting is not a thing sections can express. Header rows now carry their parent, their siblings and their index. The alternative was recovering the level by splitting keys on "/", which happens to work today and would break the first time an id contains one. The manual list is one flat array across levels — child keys are already parent-prefixed, so ranks are unambiguous — and keys of sections that are not currently rendered are kept rather than pruned: grouping axes and the provider filter hide sections temporarily, and dropping their order would quietly throw away an arrangement. Switching to Custom from the menu seeds every unplaced section where it currently sits, so it freezes what you are looking at instead of leaving untouched levels free to reshuffle. A project added later joins the end of its level; Reset section order goes back to Busiest first. Written by Claude Opus 5 in Claude Code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Problem
Section order in the sidebar was whatever the grouping produced: sections with live work first, then history-only ones, then quiet seeded projects, with first-appearance breaking ties. A good default, a poor permanent arrangement — the project you check every morning drifts down the list the moment nothing is running in it, and environments had no ordering control at all.
What changed
Ordering is now a second pass over the built section tree, kept separate from grouping. Three modes, in the menu that already sorts threads:
Custom is reachable two ways: drag a section header, or right-click it and pick Move up / Move down. Either one switches to Custom and records the whole level, so the result stops depending on activity. Reset section order goes back to Busiest first.
Sections move only within their own level. A drop outside the dragged section's siblings is refused, and while a drag is in flight every other level disables its droppables, so a project level never animates a swap it would discard. Sections cannot be reparented, only resequenced.
Notes on the design
/.Verification
vp test run apps/web/src/components/sidebarThreadGrouping.test.ts— 42 passed, including new coverage fororderSidebarThreadGroups,planSidebarSectionOrder,collectSidebarSectionKeysand the level facts on header rows.vp test runonSidebar.logic,Sidebar.snooze,environmentGrouping,CommandPalette.logic,ui/sidebar,SidebarStageBackdrop,threadSidebarWidth,DesktopClientSettings— all passing.tsgo --noEmitclean forapps/web,apps/desktop,packages/contracts;vp lintclean for the touched files.Written by Claude Opus 5 in Claude Code.
🤖 Generated with Claude Code