refactor(desktop): cleaner, compact inline agent/port sections in v2 sidebar
Merged
KI
4mo ago+306+306+012345678901234567890123456789-143-143-012345678901234567890123456789
Summary
- Restyles the inline agent and port pills under workspace rows (and the bottom Ports section) as compact, neutral Linear/Notion-style tags, replacing the tinted
bg-primarychips. - Splits ports and agents into separate collapsible sections with independently persisted collapse state, instead of one merged "2 ports · 1 agent" toggle.
- Adds adaptive chip layout: one row while chips fit, a two-row grid on overflow, then horizontal scroll two rows deep.
- Reworks port pill interactions: click opens the port in the browser; a hover-revealed ⋮ menu holds Open in External Browser / Open in Superset Browser / Go to Workspace / Close Port.
Why / Context
The inline agent/port UI read as loud colored CTAs, pills were oversized with phantom trailing space (invisible hover icons reserved ~28px each), rows misaligned with the section toggle, and hover made pills grow and push their neighbors.
How It Works
- Pills (
DashboardSidebarPortBadge,DashboardSidebarWorkspaceAgentBadge):bg-muted/60neutral tags attext-[11px]with mono tabular port numbers; status color is reserved for the agent status dot. - Sections (
DashboardSidebarWorkspaceDetails): each detail section renders its own toggle row;useWorkspaceDetailsStorenow keys collapse state by${workspaceId}:${sectionKey}(previously per-workspace); a persist migration (v0 → v1) expands each old per-workspace collapsed flag into both section keys. - Layout (new
DashboardSidebarChipStrip): measures chips' natural widths against the container (every render + ResizeObserver) and toggles between a flex row and agrid-rows-2column-flow grid, wrapped inOverflowFadeContainerfor the scroll fade. Pure-CSS child growth intentionally doesn't re-measure, so hover can't flip the layout. - Port actions: the ⋮ trigger is always rendered and hidden via opacity, so pill geometry never changes on hover. Kill-pending swaps ⋮ for a spinner and dims the pill.
- Section chevrons are hidden until hover (opacity, slot reserved); chip rows are left-aligned with the section summary label.
Manual QA Checklist
- Ports and agents show as separate "N ports" / "N agents" sections under a workspace row
- Collapsing one section leaves the other open; state persists after app restart
- Chips: single row when few, two rows when overflowing, horizontal scroll (with right fade) beyond that; resizing the sidebar reflows correctly
- Hovering a port pill reveals ⋮ without any pill/neighbor movement
- Click on a local port opens per Settings → Links → Ports preference; remote port click jumps to the workspace
- ⋮ menu: Open in External Browser + Open in Superset Browser (local only), Go to Workspace, Close Port (destructive); Close shows spinner while pending
- Collapse state from a pre-PR build carries over (v0 → v1 store migration)
- "Close all ports" hover action still works on the ports section header
- Agent pill click focuses the bound terminal; status dot shows working/permission/review
- Bottom "Ports" list groups behave the same (adaptive rows, new pill styling)
Testing
bun run typecheckbunx biome check .(rootbun run lintadditionally shells out to ripgrep, which isn't installed on this machine; Biome itself is clean)- Manual testing in dev mode
Design Decisions
- ⋮ menu instead of inline hover icons: inline icons either reserve phantom width (misaligned idle pills) or expand on hover (layout shift). An opacity-revealed ⋮ keeps geometry constant; destructive close moves behind a menu.
- Measured 1→2-row layout instead of pure CSS: CSS can't express "wrap once, then scroll horizontally", so
DashboardSidebarChipStripcompares natural chip widths to the container width.
Known Limitations
- The ⋮ slot is ~20px of invisible space at the end of each idle port pill (the cost of shift-free hover).
- Menu wording ("External Browser" / "Superset Browser") differs from Settings → Links wording ("default browser" / "in-app browser").
Follow-ups
- v1
WorkspaceSidebarports UI intentionally untouched (v1 is sunset).
Summary by cubic
Refactors the v2 sidebar ports/agents UI with compact neutral tags, per-section collapsible groups, and a measured two-row chip layout. Port pills open per preference on click; the menu separates External vs Superset in‑app open, and existing collapse state is preserved.
-
New Features
- Compact neutral tags for ports and agents; agent status stays a colored dot.
- Separate collapsible “Ports” and “Agents” with per‑section persisted state.
- Port click opens per Settings → Links → Ports; remote ports open the workspace. Menu: Open in External Browser, Open in Superset Browser, Go to Workspace, Close.
- Adaptive chip layout via
DashboardSidebarChipStrip: single row, then two‑row grid on overflow, then horizontal scroll without hover shifts.
-
Refactors
- Added
DashboardSidebarChipStripto measure chip widths and choose 1‑row/2‑row/scroll; bottom “Ports” list uses the same layout. Grid uses justify‑items‑start to avoid stretched chips inflating measurements. - Chevron appears on hover; chips align with the section summary label.
- Persisted state keys are now
${workspaceId}:${sectionKey}with a migration from v0collapsedWorkspaceIdsto per‑section keys (existing collapsed workspaces map to collapsed Ports and Agents). - Narrowed store selector to this workspace’s section keys to avoid sidebar‑wide re‑renders.
- Added
Summary by CodeRabbit
-
New Features
- Sidebar lists now use an adaptive chip strip that automatically switches between multi-row and single-row layouts, scrolling horizontally when space is limited.
- Workspace details are now expandable/collapsible independently per section (instead of one shared state).
-
Bug Fixes / UX Improvements
- Port badge interactions are simplified to a primary click plus a dropdown with “open” options and “Go to Workspace”, with updated tooltip text and a pending-safe “Close Port”.
-
Style
- Improved badge and chevron presentation for a cleaner, more consistent sidebar look.