Skip to content

refactor(desktop): cleaner, compact inline agent/port sections in v2 sidebar - #5426

Merged
Kitenite merged 4 commits into
mainfrom
agent-port-ui-cleanup
Jul 3, 2026
Merged

Kitenite merged 4 commits into
mainfrom
agent-port-ui-cleanup

Conversation

@Kitenite

@Kitenite Kitenite commented Jul 3, 2026 •

Copy link
Copy Markdown
Member

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-primary chips.
  • 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/60 neutral tags at text-[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; useWorkspaceDetailsStore now 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 a grid-rows-2 column-flow grid, wrapped in OverflowFadeContainer for 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 typecheck
  • bunx biome check . (root bun run lint additionally 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 DashboardSidebarChipStrip compares 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 WorkspaceSidebar ports UI intentionally untouched (v1 is sunset).

Open in Stage

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 DashboardSidebarChipStrip to 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 v0 collapsedWorkspaceIds to 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.

Written for commit 2fc582f. Summary will update on new commits.

Review in cubic

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.

Kitenite added 2 commits July 2, 2026 17:13
- Restyle port and agent chips as neutral Linear/Notion-style tags
  (bg-muted, 11px text, mono tabular port numbers)
- Split ports and agents into separate collapsible sections with
  per-section persisted collapse state (workspaceId:sectionKey)
- Hide section chevron until hover; align chips with the summary label
- New DashboardSidebarChipStrip: one row while chips fit, two-row grid
  on overflow, then horizontal scroll two rows deep
- Move per-port actions (open in browser, close) from hover icons into
  a right-click context menu so pills never resize on hover
…ver ⋮ menu

Primary click on a port pill now opens the port (per the Settings → Links
→ Ports preference); remote ports fall back to opening the workspace. A
vertical ellipsis fades in on hover (opacity only, so the pill never
resizes) with Open in Browser / Go to Workspace / Close Port.
@ghost

ghost commented Jul 3, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 5 individual chapters for you:

Title
1 Track workspace section collapse state independently
2 Create adaptive chip strip layout component
3 Restyle agent and port badges
4 Split workspace details into independent sections
5 Integrate adaptive layout into sidebar rows
Open in Stage

Chapters generated by Stage for commit 2fc582f on Jul 3, 2026 12:35am UTC.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds an adaptive sidebar chip strip, uses it in port and agent rows, refactors port badge actions into a dropdown, and changes workspace details collapse state from workspace-level to section-level keys.

Changes

Sidebar chip strip and port actions

Layer / File(s) Summary
Chip strip implementation and export
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx, .../DashboardSidebarChipStrip/index.ts
Measures available width versus child widths to switch between two-row grid and single-row flex layouts, and re-exports the component.
Chip strip adoption in sidebar rows
.../DashboardSidebarPortGroup.tsx, .../DashboardSidebarWorkspaceAgentsRow.tsx, .../DashboardSidebarWorkspacePortsRow.tsx, .../DashboardSidebarWorkspaceAgentBadge.tsx
Replaces previous wrappers with DashboardSidebarChipStrip and updates agent badge styling and icon sizing.
Port badge primary action and dropdown
.../DashboardSidebarPortBadge.tsx
Consolidates port interactions into one primary click target plus a dropdown for browser, workspace, and close actions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Workspace details per-section collapse

Layer / File(s) Summary
Collapse state store rename
apps/desktop/src/renderer/stores/workspace-details/store.ts
Renames collapsed workspace tracking to collapsed section tracking and updates the store API and persistence field.
Per-section details rendering
.../DashboardSidebarWorkspaceDetails.tsx, .../DashboardSidebarWorkspaceDetailsToggle.tsx
Renders independent toggles and content per section key and changes chevron visibility behavior on hover and focus.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main sidebar refactor.
Description check ✅ Passed The description includes summary, context, implementation, testing, QA, and follow-ups; only some template sections are left blank.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent-port-ui-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 3, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR refactors the v2 dashboard sidebar's inline port and agent UI — replacing tinted bg-primary chips with compact neutral tags, splitting the single combined toggle into independently collapsible per-section rows, and introducing a new DashboardSidebarChipStrip component that adaptively switches between a single flex row and a two-row CSS grid based on measured chip widths.

  • DashboardSidebarChipStrip: measures chips' natural widths against the container on every render and on resize to choose between 1-row flex and 2-row grid-flow-col layout, wrapped in OverflowFadeContainer for the horizontal scroll fade.
  • DashboardSidebarPortBadge: reworked interactions — primary click opens the port or workspace; a hover-revealed ⋮ dropdown holds Open in Browser / Go to Workspace / Close Port with a kill-pending spinner, eliminating phantom hover-reserved space that shifted pill geometry.
  • store.ts: collapse state key changed from per-workspace collapsedWorkspaceIds to composite ${workspaceId}:${sectionKey} collapsedSectionKeys; no Zustand migrate added so old persisted entries linger silently.

Confidence Score: 4/5

Safe to merge for the visual and interaction improvements; the chip layout revert from two-row back to one-row may get stuck once chips are removed, which is worth fixing before shipping to users with many ports.

The new DashboardSidebarChipStrip has a measurement flaw: CSS Grid stretches narrower chips to their column max-content width in two-row mode, inflating offsetWidth values. The summed needed width stays above available even after enough chips are removed, so the layout never reverts to a single row once the threshold is crossed. The remaining concerns are non-blocking quality issues.

DashboardSidebarChipStrip.tsx — the measurement loop and the grid class applied when isTwoRows is true.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx New component for adaptive 1-row/2-row chip layout; grid mode inflates offsetWidth for narrower chips sharing a column, preventing revert to single-row when chips are removed
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx Reworked port pill: primary click opens port/workspace, hover-revealed ⋮ dropdown for Open in Browser / Go to Workspace / Close Port with kill-pending spinner
apps/desktop/src/renderer/stores/workspace-details/store.ts Changed persist key to composite workspace:section keys; no migration added so old collapsedWorkspaceIds data lingers in localStorage
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx Splits combined toggle into per-section toggles; subscribes to full collapsedSectionKeys object causing all workspace panels to re-render on any toggle
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/components/DashboardSidebarWorkspaceDetailsToggle/DashboardSidebarWorkspaceDetailsToggle.tsx Section chevron hidden until hover via opacity transition; straightforward visibility tweak
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx Swaps flex-wrap div for DashboardSidebarChipStrip with updated alignment padding
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx Swaps flex-wrap div for DashboardSidebarChipStrip with matching padding adjustment
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/components/DashboardSidebarWorkspaceAgentBadge/DashboardSidebarWorkspaceAgentBadge.tsx Restyled to neutral muted tag from primary tinted chip; smaller icon sizes match new design language
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortGroup/DashboardSidebarPortGroup.tsx Replaced hardcoded 2-row OverflowFadeContainer with DashboardSidebarChipStrip for adaptive layout

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[DashboardSidebarWorkspaceDetails] -->|per section| B[DashboardSidebarWorkspaceDetailsToggle]
    A -->|ports section| C[DashboardSidebarWorkspacePortsRow]
    A -->|agents section| D[DashboardSidebarWorkspaceAgentsRow]
    C --> E[DashboardSidebarChipStrip]
    D --> E
    E -->|measure on render + resize| F{chips fit in 1 row?}
    F -->|yes| G[flex row]
    F -->|no| H[grid-rows-2 grid-flow-col]
    G --> I[OverflowFadeContainer horizontal scroll]
    H --> I
    C --> J[DashboardSidebarPortBadge]
    J --> K[Primary button: open port / workspace]
    J --> L[Dropdown: Open in Browser / Go to Workspace / Close Port]
    A -->|collapse state| M[useWorkspaceDetailsStore collapsedSectionKeys]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[DashboardSidebarWorkspaceDetails] -->|per section| B[DashboardSidebarWorkspaceDetailsToggle]
    A -->|ports section| C[DashboardSidebarWorkspacePortsRow]
    A -->|agents section| D[DashboardSidebarWorkspaceAgentsRow]
    C --> E[DashboardSidebarChipStrip]
    D --> E
    E -->|measure on render + resize| F{chips fit in 1 row?}
    F -->|yes| G[flex row]
    F -->|no| H[grid-rows-2 grid-flow-col]
    G --> I[OverflowFadeContainer horizontal scroll]
    H --> I
    C --> J[DashboardSidebarPortBadge]
    J --> K[Primary button: open port / workspace]
    J --> L[Dropdown: Open in Browser / Go to Workspace / Close Port]
    A -->|collapse state| M[useWorkspaceDetailsStore collapsedSectionKeys]
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/stores/workspace-details/store.ts, line 36-44 (link)

    P2 Stale collapsedWorkspaceIds key accumulates in localStorage without cleanup

    The store is persisted under the same "workspace-details-store" name, but the top-level key changed from collapsedWorkspaceIds to collapsedSectionKeys. Without a Zustand migrate function and a bumped version, the old key is silently ignored but remains in localStorage indefinitely. Adding a migration that drops the old key would keep storage clean.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/stores/workspace-details/store.ts
    Line: 36-44
    
    Comment:
    **Stale `collapsedWorkspaceIds` key accumulates in `localStorage` without cleanup**
    
    The store is persisted under the same `"workspace-details-store"` name, but the top-level key changed from `collapsedWorkspaceIds` to `collapsedSectionKeys`. Without a Zustand `migrate` function and a bumped `version`, the old key is silently ignored but remains in `localStorage` indefinitely. Adding a migration that drops the old key would keep storage clean.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx:44-48
**Grid mode inflates chip widths, blocking revert to single row**

When `isTwoRows` is `true`, the container renders as a CSS Grid with `auto-cols-max grid-flow-col`. Grid items stretch to fill their column area by default (`justify-self: stretch`), so a narrow chip sharing a column with a wider chip will report `offsetWidth` equal to the wider chip's width. The `measure` function then sums these inflated values and consistently decides `needed > available`, keeping the layout in two-row mode even after enough chips are removed to fit in a single row.

The fix is to add `justify-items-start` to the grid variant so chips only occupy their natural content width, keeping `offsetWidth` accurate in both layout modes. For example, `isTwoRows ? "grid auto-cols-max grid-flow-col grid-rows-2 justify-items-start" : "flex"`.

### Issue 2 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx:46-48
**All workspace detail panels re-render on any section toggle**

The selector returns the entire `collapsedSectionKeys` object, which is replaced with a new object reference on every `setExpanded` call. Every mounted `DashboardSidebarWorkspaceDetails` instance (one per visible workspace) will re-render whenever any workspace's section is toggled. Narrowing the selector to only the keys this workspace actually needs — `${workspaceId}:ports` and `${workspaceId}:agents` — would scope the subscription correctly.

### Issue 3 of 3
apps/desktop/src/renderer/stores/workspace-details/store.ts:36-44
**Stale `collapsedWorkspaceIds` key accumulates in `localStorage` without cleanup**

The store is persisted under the same `"workspace-details-store"` name, but the top-level key changed from `collapsedWorkspaceIds` to `collapsedSectionKeys`. Without a Zustand `migrate` function and a bumped `version`, the old key is silently ignored but remains in `localStorage` indefinitely. Adding a migration that drops the old key would keep storage clean.

Reviews (1): Last reviewed commit: "feat(desktop): split port menu open acti..." | Re-trigger Greptile

Comment on lines +44 to +48
let needed = -CHIP_GAP_PX;
for (const child of Array.from(node.children)) {
needed += (child as HTMLElement).offsetWidth + CHIP_GAP_PX;
}
setIsTwoRows(needed > available);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Grid mode inflates chip widths, blocking revert to single row

When isTwoRows is true, the container renders as a CSS Grid with auto-cols-max grid-flow-col. Grid items stretch to fill their column area by default (justify-self: stretch), so a narrow chip sharing a column with a wider chip will report offsetWidth equal to the wider chip's width. The measure function then sums these inflated values and consistently decides needed > available, keeping the layout in two-row mode even after enough chips are removed to fit in a single row.

The fix is to add justify-items-start to the grid variant so chips only occupy their natural content width, keeping offsetWidth accurate in both layout modes. For example, isTwoRows ? "grid auto-cols-max grid-flow-col grid-rows-2 justify-items-start" : "flex".

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx
Line: 44-48

Comment:
**Grid mode inflates chip widths, blocking revert to single row**

When `isTwoRows` is `true`, the container renders as a CSS Grid with `auto-cols-max grid-flow-col`. Grid items stretch to fill their column area by default (`justify-self: stretch`), so a narrow chip sharing a column with a wider chip will report `offsetWidth` equal to the wider chip's width. The `measure` function then sums these inflated values and consistently decides `needed > available`, keeping the layout in two-row mode even after enough chips are removed to fit in a single row.

The fix is to add `justify-items-start` to the grid variant so chips only occupy their natural content width, keeping `offsetWidth` accurate in both layout modes. For example, `isTwoRows ? "grid auto-cols-max grid-flow-col grid-rows-2 justify-items-start" : "flex"`.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +46 to 48
const collapsedSectionKeys = useWorkspaceDetailsStore(
(state) => state.collapsedSectionKeys,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 All workspace detail panels re-render on any section toggle

The selector returns the entire collapsedSectionKeys object, which is replaced with a new object reference on every setExpanded call. Every mounted DashboardSidebarWorkspaceDetails instance (one per visible workspace) will re-render whenever any workspace's section is toggled. Narrowing the selector to only the keys this workspace actually needs — ${workspaceId}:ports and ${workspaceId}:agents — would scope the subscription correctly.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx
Line: 46-48

Comment:
**All workspace detail panels re-render on any section toggle**

The selector returns the entire `collapsedSectionKeys` object, which is replaced with a new object reference on every `setExpanded` call. Every mounted `DashboardSidebarWorkspaceDetails` instance (one per visible workspace) will re-render whenever any workspace's section is toggled. Narrowing the selector to only the keys this workspace actually needs — `${workspaceId}:ports` and `${workspaceId}:agents` — would scope the subscription correctly.

How can I resolve this? If you propose a fix, please make it concise.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Relative import instead of path alias.

This imports DashboardSidebarChipStrip via a relative path (../../../../components/DashboardSidebarChipStrip) rather than the configured tsconfig.json path alias. As per path instructions, apps/desktop/src/**/*.{ts,tsx}: "When possible, use the path aliases defined in tsconfig.json instead of relative imports."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx`
at line 2, The import in DashboardSidebarWorkspaceAgentsRow is using a deep
relative path instead of the configured tsconfig alias. Update the
DashboardSidebarChipStrip import to use the appropriate path alias used
throughout apps/desktop/src/**/*.{ts,tsx} rather than
"../../../../components/DashboardSidebarChipStrip", keeping the rest of
DashboardSidebarWorkspaceAgentsRow unchanged.

Source: Path instructions

apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx (2)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Relative import instead of path alias.

Same as in DashboardSidebarWorkspaceAgentsRow.tsx — relative import used instead of the tsconfig.json path alias. As per path instructions, apps/desktop/src/**/*.{ts,tsx}: "When possible, use the path aliases defined in tsconfig.json instead of relative imports."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx`
at line 2, The import in DashboardSidebarWorkspacePortsRow should use the
tsconfig path alias instead of a deep relative path, matching the import style
used in DashboardSidebarWorkspaceAgentsRow. Update the DashboardSidebarChipStrip
import to reference the alias-based path so the component location is resolved
consistently across apps/desktop/src/**/*.{ts,tsx} and avoid relative traversal
from DashboardSidebarWorkspacePortsRow.

Source: Path instructions


22-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Same padding-drop and duplicate pr-2/pl-11/pl-9 logic as the agents row.

This mirrors DashboardSidebarWorkspaceAgentsRow.tsx's cn("pr-2", isInSection ? "pl-11" : "pl-9") verbatim. Consider extracting this into a shared constant/helper (e.g. a getChipRowClassName(isInSection) util) co-located near DashboardSidebarChipStrip, since both rows share the identical alignment comment and logic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx`
around lines 22 - 32, The padding/alignment logic in
DashboardSidebarWorkspacePortsRow duplicates the same
`DashboardSidebarChipStrip` class setup used by the agents row, so extract the
shared `cn("pr-2", isInSection ? "pl-11" : "pl-9")` behavior into a reusable
helper or constant near `DashboardSidebarChipStrip` (for example a
`getChipRowClassName(isInSection)` utility). Update both
DashboardSidebarWorkspacePortsRow and DashboardSidebarWorkspaceAgentsRow to call
the shared symbol so the padding-drop behavior stays consistent in one place.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx (1)

89-132: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Primary button isn't disabled during openUrl mutation, only the dropdown item is.

The dropdown's "Open in Browser" item is disabled via disabled={openUrl.isPending} (line 161), but the primary button (which invokes the same handleOpenInBrowser when canOpenInBrowser) is only guarded by disabled={isPending} (kill-pending), not openUrl.isPending. The early return inside handleOpenInBrowser prevents a duplicate mutation, but the button remains visually clickable/enabled while the external URL request is in flight.

💡 Optional fix for visual consistency
 					<button
 						type="button"
 						onClick={handlePrimaryClick}
-						disabled={isPending}
-						aria-busy={isPending}
+						disabled={isPending || (canOpenInBrowser && openUrl.isPending)}
+						aria-busy={isPending || (canOpenInBrowser && openUrl.isPending)}
 						className="flex min-w-0 items-center gap-1 rounded-l py-0.5 pl-1.5 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
 					>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx`
around lines 89 - 132, The primary port badge button in
DashboardSidebarPortBadge should also reflect the openUrl mutation state, not
just the kill-pending state. Update the button’s disabled/aria-busy logic and
any related styling in DashboardSidebarPortBadge so it uses openUrl.isPending
alongside isPending, matching the existing dropdown item behavior and preventing
the button from appearing interactive while handleOpenInBrowser is already
running.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/renderer/stores/workspace-details/store.ts`:
- Around line 5-39: Persisted workspace-details state was renamed from
collapsedWorkspaceIds to collapsedSectionKeys, so existing
workspace-details-store data will not load correctly. In
useWorkspaceDetailsStore’s persist config, either add version: 1 to
intentionally reset stored state, or add a migrate handler that converts old
collapsedWorkspaceIds entries into the new per-section collapsedSectionKeys
shape before hydration.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx`:
- Around line 89-132: The primary port badge button in DashboardSidebarPortBadge
should also reflect the openUrl mutation state, not just the kill-pending state.
Update the button’s disabled/aria-busy logic and any related styling in
DashboardSidebarPortBadge so it uses openUrl.isPending alongside isPending,
matching the existing dropdown item behavior and preventing the button from
appearing interactive while handleOpenInBrowser is already running.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx`:
- Line 2: The import in DashboardSidebarWorkspaceAgentsRow is using a deep
relative path instead of the configured tsconfig alias. Update the
DashboardSidebarChipStrip import to use the appropriate path alias used
throughout apps/desktop/src/**/*.{ts,tsx} rather than
"../../../../components/DashboardSidebarChipStrip", keeping the rest of
DashboardSidebarWorkspaceAgentsRow unchanged.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx`:
- Line 2: The import in DashboardSidebarWorkspacePortsRow should use the
tsconfig path alias instead of a deep relative path, matching the import style
used in DashboardSidebarWorkspaceAgentsRow. Update the DashboardSidebarChipStrip
import to reference the alias-based path so the component location is resolved
consistently across apps/desktop/src/**/*.{ts,tsx} and avoid relative traversal
from DashboardSidebarWorkspacePortsRow.
- Around line 22-32: The padding/alignment logic in
DashboardSidebarWorkspacePortsRow duplicates the same
`DashboardSidebarChipStrip` class setup used by the agents row, so extract the
shared `cn("pr-2", isInSection ? "pl-11" : "pl-9")` behavior into a reusable
helper or constant near `DashboardSidebarChipStrip` (for example a
`getChipRowClassName(isInSection)` utility). Update both
DashboardSidebarWorkspacePortsRow and DashboardSidebarWorkspaceAgentsRow to call
the shared symbol so the padding-drop behavior stays consistent in one place.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36f4984a-9805-4b23-b479-739fb74ff0c5

📥 Commits

Reviewing files that changed from the base of the PR and between 329e1fc and 3e5fb83.

📒 Files selected for processing (10)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortGroup/DashboardSidebarPortGroup.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/components/DashboardSidebarWorkspaceAgentBadge/DashboardSidebarWorkspaceAgentBadge.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/components/DashboardSidebarWorkspaceDetailsToggle/DashboardSidebarWorkspaceDetailsToggle.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx
  • apps/desktop/src/renderer/stores/workspace-details/store.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found and verified against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

- justify-items-start in 2-row grid so stretched chips don't inflate
  measured widths and lock the strip in two-row mode (greptile P1)
- narrow the collapsed-sections selector to this workspace's keys so
  toggling one workspace doesn't re-render all panels (greptile P2)
- migrate persisted v0 collapsedWorkspaceIds into per-section keys
  instead of dropping users' collapse state (coderabbit)
@Kitenite
Kitenite merged commit 4b2bd29 into main Jul 3, 2026
9 of 10 checks passed
@Kitenite
Kitenite deleted the agent-port-ui-cleanup branch July 3, 2026 00:37
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant