fix(desktop): solve #6009 — expanded sidebar Projects section silently collapsed with no visible chevron
What the bug is
The expanded sidebar renders the PROJECTS header and the add-project (+) button with no project rows underneath, while the collapsed icon rail shows every project. Cmd+R doesn't clear it, and the only way to see the projects again is to collapse the sidebar back down.
Root cause
DashboardSidebar gates both the pinned section and every project group on one flag:
// DashboardSidebar.tsx:213,220
{(isCollapsed || !workspacesListCollapsed) && ( ... )}
workspacesListCollapsed comes from renderer/stores/sidebar-workspaces-collapse, which is used in exactly two places: this gate and DashboardSidebarWorkspacesHeader. Both the rail and the expanded list render the same orderedGroups, so this gate is the only difference between the two views — a blank expanded Projects section means the flag is true, and nothing else in the codebase can set it.
Three things turn that state into a sidebar that reads as broken:
- The whole header row is the toggle.
DashboardSidebarWorkspacesHeaderis a full-widthrole="button"(including the flex spacer next to the+button) with anonClickand an Enter/SpaceonKeyDown, so one stray click or a Space press while the row has focus empties the list. - The state was invisible. The chevron was
opacity-0untilgroup-hover/group-focus-visible, so a collapsed section looked identical to an empty one — no cue, and no hint that clicking the header restores it. - It's persisted (zustand
persist), so a reload can't clear it, and the rail ignores the flag entirely, so collapse → expand round-trips right back to the empty view.
The macOS App Management grant is coincidental — nothing in apps/desktop or packages/host-service reads that permission, and no code path other than the header toggle writes this store.
The fix
DashboardSidebarWorkspacesHeader now keeps the chevron at opacity-100 while the list is collapsed (hover-fade is retained only in the expanded state, where the rows already show the state) and exposes aria-expanded. The collapsed section is now self-explanatory and one click from restored.
Tests
New DashboardSidebarWorkspacesHeader.test.tsx (bun test, renderToStaticMarkup — matching the existing StepProgress.test.tsx pattern):
- reproduction: with the list collapsed, the chevron class list must not be
opacity-0/hover-gated — failed before the fix, passes now - reproduction: the header must report
aria-expanded="false"when collapsed — the attribute was absent before - guard: the expanded state still fades the chevron in on hover and rotates it
bun test in apps/desktop: 2282 pass, 0 fail. Zustand feeds getInitialState() to useSyncExternalStore during SSR, so the test stands the store in with a plain selector to render both disclosure states — noted in a comment.
Not fixed here (deliberately out of scope)
The accidental-toggle surface itself: the full-width row hit area (spacer included) and the Space-key handler are the likely trigger, and narrowing the toggle to the label + chevron is a UX call I'd rather leave to a maintainer. Left as-is too: the collapsed rail ignores the flag, which is what makes the reporter's collapse/expand workaround only temporary — but making the rail honor it would hide the project icons entirely, the very symptom they reported on v2.
Refs #6009
Summary by cubic
Fixes the empty Projects section in the expanded sidebar by keeping the chevron visible when collapsed and exposing the state via aria attributes. Fixes #6009.
- Bug Fixes
- Keep the Projects chevron
opacity-100while collapsed; retain hover fade only when expanded; rotation unchanged. - Add
aria-expandedto the header for clear state and accessibility. - Add tests to verify chevron visibility when collapsed and
aria-expandedbehavior; ensure expanded hover/rotation still works.
- Keep the Projects chevron