fix(sidebar): sleeping sessions obey the group filter - #142
Merged
Merged
Conversation
Dormant rows were appended unconditionally at the very bottom of the sidebar, whatever the display mode or active group tab. The comment called that "kept reachable", but on a filtered tab it read as a leak: every sleeping session from every group, under a tab that was supposed to show one. Placement now follows the display mode: - FilterStrip: dormant rows still trail the live ones, but only those matching ActiveGroupId. "All" still lists every one, so a sleeping session is never more than a click away. - InlineHeaders: each dormant row sits at the end of its own group section and counts toward that header's badge, so it collapses with the group. Ungrouped now also appears when its only members are asleep. - None: unchanged. Rows are resolved by walking SessionManager.Sessions rather than the _dormantSidebarItems dictionary, so sleeping rows follow drag-reorder the same way live ones do instead of insertion order. AddDormantSidebarItem now only registers the row; RebuildSidebarOrder is the single placer, because where a row goes is a filter/mode decision. SleepSession and the wake-failure path call it (in place of a bare RefreshTerminalLayout); the other callers already did. Two further holes, found in review: - Deleting a dormant row removed its Border in place and never rebuilt. Harmless while dormant rows sat outside the sections, but inline headers now count them, so it left "Work (3)" over two rows, or an empty header when it was the section's last occupant. It rebuilds now. - In InlineHeaders mode a dormant session whose GroupId names a group that no longer exists rendered nowhere, while still suppressing EmptyState. That cannot arise in-app (RemoveGroup clears GroupId), but ImportExportService deserializes an arbitrary AppState and nothing reconciles orphan ids, so it now buckets as ungrouped. Live sessions have the same gap; closing it properly means normalizing on load, and is left for a separate change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX
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.
Note
@AThraen: I have not tested this manually in the running app. Build is clean and the unit tests pass, but nothing covers sidebar rendering, so the manual checks under Test plan are all still open. Could you run through them, or tell me if you'd rather I do it before review?
Summary
Sleeping (dormant) sessions now respect the group filter in the sidebar. They used to be appended unconditionally at the very bottom, whatever the display mode or the active group tab.
Why
The old comment called that "kept reachable", but on a filtered tab it reads as a leak: every sleeping session from every group, listed under a tab that is supposed to show one. A sleeping session stays reachable anyway, one click away on All.
Implementation notes
Placement now follows
GroupDisplayMode:ActiveGroupId. All lists every one.AddDormantSidebarItemonly registers the row now; it doesn't add it to the sidebar.RebuildSidebarOrderis the only thing that places rows, because where a row goes depends on the display mode and the filter. Every caller must rebuild afterwards.SleepSessionand the wake-failure path now do (replacing a bareRefreshTerminalLayout), and the other callers already did. I checked this against main after feat(sessions): restart a session without losing it #140, and all five callers rebuild, the restart fallback included.SessionManager.Sessions, not the_dormantSidebarItemsdictionary, so they follow drag-reorder like live rows instead of insertion order.Borderin place and never rebuilt. Now that inline headers count dormant rows, that left "Work (3)" over two rows, or an empty header. It rebuilds now.GroupIdrendered nowhere in InlineHeaders mode, and still kept the empty-state placeholder hidden.RemoveGroupclearsGroupId, so this can't happen from inside the app, butImportExportServiceloads an arbitraryAppState. Such rows are now shown as ungrouped. Live sessions have the same gap and I left it alone: the proper fix is to normalize orphaned ids on load, which is a separate change.Test plan
dotnet buildpasses with 0 warningsdotnet test tests/CodeShellManager.Tests/passes 597/597 (none of these cover sidebar rendering)--cleanrun: no regressions in the empty-state placeholder.🤖 Generated with Claude Code
https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX