feat(desktop): add top bar ports dropdown as an alternative ports layout
Merged
AV
3mo ago+691+691+012345678901234567890123456789-569-569-012345678901234567890123456789
Summary
Adds a topbar ports-display mode as an A/B-able alternative to the existing inline sidebar chip — both coexist, gated by a new settings toggle so they can be compared side by side.
- Today, detected dev-server ports render as a chip under each workspace item in the sidebar ("inline" mode, unchanged default).
- This adds a compact top-bar pill (radio-tower icon + live count, hidden when the total is 0) that opens a workspace-grouped dropdown: clickable group headers (with a
remotetag for non-local hosts and a hover-revealed close-all), and per-port rows showing a:port+ label/process with hover-revealed open / open-in-external-browser / copy / close actions. The footer shows the live total and a global close-all. - Settings → Experimental gets a
Switchlabeled "Ports in top bar dropdown".
Implementation notes
- Single zustand store (
stores/inline-workspace-ports.ts) is now mode-based ("inline" | "topbar") instead of boolean, with a migration that folds both the old boolean shape and a since-removed"panel"mode into the new shape. - The existing ports-data provider (
DashboardSidebarPortsProvider) is hoisted from the sidebar up to_dashboard/layout.tsxso it's reachable from the top bar and the v2 workspace tab bar too, and survives remounts on workspace navigation instead of blinking the pill to empty state. useDashboardSidebarPortsData/useDashboardSidebarPortKillmoved fromDashboardSidebarPortsList/hooks/toDashboardSidebar/hooks/(pure relocation, all import sites updated) since they're now shared by the inline chip, the topbar dropdown, and the workspace context menu.- The pill mounts in exactly one of three mutually-exclusive chrome locations depending on what's visible: the expanded sidebar header, the
TopBar, or the v2 workspace tab bar's trailing slot (collapsed rail). - Along the way, fixed a pane-store flash on v2 workspace switches (
useV2WorkspacePaneLayoutnow seeds synchronously from the persisted collection row instead of an empty state) and gatedBackgroundTerminalsButtononisLayoutReadyto stop it flashing a bogus count — both needed since the new pill shares the same tab-bar trailing slot.
Supersedes #5998.
Test plan
-
bun run lintclean -
bun run --cwd apps/desktop typecheckclean - Verified live in the running dev app via CDP: settings toggle switches to topbar mode and persists (
localStorageconfirms{"state":{"mode":"topbar"},"version":2}); pill renders in the sidebar header next to the nav controls with the correct live count - Full manual pass of the remaining checklist (dropdown open/copy/close actions, three-way pill placement across chrome states, migration from the old boolean/
"panel"shapes, no tab-bar flash on fast workspace switching) — recommend a manual spot-check before merge
https://claude.ai/code/session_01QMevhGg9VnuZC6SnQbV6qE
Summary by cubic
Adds a top‑bar ports dropdown as an alternative to the inline sidebar chip to consolidate dev‑server ports and reduce sidebar noise. Previously ports only appeared inline; new mode shows a compact pill with a live count that opens a workspace‑grouped dropdown with open, copy URL, close, and close‑all actions.
- Settings: Experimental toggle “Ports in top bar dropdown” switches between “inline” (default) and “topbar”. The
inline-workspace-portsstore now persists amode; prior boolean and removed "panel" values migrate to "inline"/"topbar". - Data flow:
DashboardSidebarPortsProvideris hoisted to_dashboard/layout.tsx; the “enabled” gate moved into the data hook so the provider’s identity is stable and the dashboard does not remount on sidebar collapse/expand. Polling runs only when v2 is on and either topbar mode is active or inline mode with the sidebar open and not collapsed. - Placement: the pill renders in one place based on visible chrome—expanded sidebar header, the
TopBar, or the v2 workspace tab bar trailing slot—and hides when the total count is 0. The top bar suppresses a duplicate when the sidebar hosts chrome. - Actions: per‑port open (primary/external), copy URL (local ports only; via shared clipboard hook), and close; per‑workspace and global close‑all with toasts.
- Cleanup: removed the bottom
DashboardSidebarPortsList; shared hooksuseDashboardSidebarPortsData/useDashboardSidebarPortKillmoved underDashboardSidebar/hooks/; addedTopBarPortsDropdown. - Related fixes: seed
useV2WorkspacePaneLayoutfrom the persisted row and only sync once the live query is ready to prevent a tab‑bar flash; gateBackgroundTerminalsButtononisLayoutReady; bump minimum workspace sidebar width to 225.
Summary by CodeRabbit
- New Features
- Added a top-bar ports dropdown showing live workspace ports.
- Open ports, copy URLs, navigate to workspaces, or close individual, grouped, or all ports.
- Added experimental settings for top-bar or inline port display.
- Improvements
- Port data now refreshes and updates live across the dashboard.
- Preserved workspace pane layout during navigation.
- Slightly increased the minimum workspace sidebar width.