🤖 feat: RightSidebar tiling & terminals - #1340
Conversation
5c7fc7b to
13d2de5
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
ff4881d to
0fd9247
Compare
|
@codex review |
0fd9247 to
bfd6b1f
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
afc69b4 to
0c9258d
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
1 similar comment
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
65f6c0e to
fd4ea21
Compare
0e4391d to
5ea4d1e
Compare
6bed7a8 to
bc1aa89
Compare
Implements an IDE-like dock-lite sidebar with nested split/tabset layout: - Terminal tab embedded in RightSidebar (stable, not destroyed on tab switch) - Tab dragging with @dnd-kit for reliable click vs drag disambiguation - Edge docking to create horizontal/vertical splits - Unified sidebar width across all tabs (resizing affects all equally) - Layout state persisted in localStorage Technical highlights: - Migrated from react-dnd HTML5Backend to @dnd-kit with PointerSensor - 8px distance activation constraint prevents accidental drags - DragOverlay for smooth cursor-following preview - No tooltip interference (not built on HTML5 Drag API) - Proper MUX_ROOT support for e2e tests --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
When switching between workspaces (e.g., SSH → Local), the TerminalTab was passing the old workspace's session ID to TerminalView before the useEffect synced the state. This caused errors like 'trying to open SSH terminal for local project'. Fix: Read sessionId directly from the Map instead of caching in useState. The Map lookup always returns the correct session for the current workspaceId, eliminating the timing bug. --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
Show 'Connecting...' overlay until we receive the initial screenState from the backend. This prevents the flash of stale/empty terminal content that was visible when switching between terminal tabs. - Add isLoading state, reset to true on sessionId change - Set isLoading=false when onScreenState callback fires - Render loading overlay with visibility:hidden on terminal container - Keep terminal mounted but hidden during loading for instant reveal
The attach stream already yields screenState as its first message, making the standalone getScreenState endpoint redundant. The internal terminalService.getScreenState() method is kept since attach uses it. - Remove schema definition from api.ts - Remove router endpoint from router.ts - Remove test for the standalone endpoint - Update stale comment in terminalService.ts
- rightSidebarLayout.test.ts: Update tests to match new default tabs (costs, review) - terminal is no longer in default layout - terminalService.test.ts: Fix openWindow expectation to include undefined sessionId arg, simplify session creation test
Terminal is no longer a default tab - tests must click the '+' button to add one before testing terminal functionality. - terminal.spec.ts: Use ui.metaSidebar.addTerminal() instead of selectTab - sidebarDragDrop.spec.ts: Add terminal before tests that use it - ui.ts: Add addTerminal() helper method
- Terminal tabs now use 'Close terminal' button as selector (name is dynamic)
- Use per-workspace layout key (right-sidebar:layout:{workspaceId})
- Skip drag reorder tests on Linux/Xvfb (flaky with programmatic DnD)
- addTerminal() helper uses robust locator instead of name regex
- Add CLOSE_TAB keybind (Ctrl/Cmd+W) - Only terminal tabs are closeable (other tabs ignore the keybind) - Add to KeybindsSection settings UI
- Move + (New terminal) button to be left-aligned next to tabs - Add keybind help (⌘W on Mac, Ctrl+W elsewhere) to close button tooltip - Set CLOSE_TAB keybind to require Cmd on Mac (matches Ghostty behavior)
Wrap term.write() and term.clear() calls in try-catch to handle intermittent 'memory access out of bounds' errors from xterm's WASM. These errors can occur during normal operation and should not break the terminal or leave it stuck in 'Connecting' state.
The terminal (ghostty-web) captures keyboard events before they reach the window listener. Using capture phase intercepts the event first, allowing Cmd/Ctrl+W to close the active terminal tab even when the terminal has focus.
44580fb to
5573b05
Compare
Replace the popout terminal behavior with integrated terminal: - Ctrl/Cmd+T now adds a new terminal tab to the right sidebar - Terminal button in workspace header also uses integrated terminal - Command palette 'New Terminal Window' still opens popout for flexibility - 'Open Terminal Window for Workspace...' opens popout for other workspaces Implementation: - RightSidebar exposes handleAddTerminal via addTerminalRef prop - AIView passes ref to both RightSidebar and WorkspaceHeader - handleAddTerminal auto-expands sidebar if collapsed
- Use capture phase for useAIViewKeybinds so Ctrl/Cmd+T works when terminal focused - Add tab shrinking (min-w-0, max-w-[120px], truncate) for overflow - Add horizontal scroll to tab strip when tabs exceed container width - Keep + button fixed with shrink-0
f694c81 to
d8fbbe3
Compare
- When closing active tab, focus next tab (or previous if no next) - Persist terminal titles to localStorage for reload survival - Clean up persisted titles when closing/popping-out terminals
d8fbbe3 to
4b0f306
Compare
…orts (coder#4472) ## Summary Deletes browser production code that only tests still called, and moves the tests that guarded live behavior onto the live code path. Part of the test-audit follow-up campaign (frontend area, WS7). ## What was removed | Removed | Why it was dead | What happened to its tests | | --- | --- | --- | | `StatsTab` component + its test-only `_snapshot`/`_clearStats` props and `useStatsData` overrides | No production caller since coder#2729 moved the Stats tab to `StatsContainer` (`TimingPanel` + `ModelBreakdownPanel`) | `StatsTab.clear.test.tsx` replaced by `TimingPanel.clear.test.tsx`, which drives the live path: real `WorkspaceStore` stats subscription + `APIProvider` client whose `workspace.stats.clear` rejects | | `compareRecords`, `compareArrays` (`useStableReference.ts`) | Only `compareMaps` is used (`App.tsx`) | 12 comparator tests deleted; stale "tested manually via useUnreadTracking…" comments fixed | | `closeSplit` (`rightSidebarLayout.ts`) | Never called in production since coder#1340 | Test deleted | | `isActionableTaskExecutionStatus` | Last caller removed in coder#4341 | No tests | | `shouldRefreshInlineSkillSuggestions` | coder#4013 made inline suggestions synchronously derived, so there is no refresh gate | Tests deleted | | `getAnthropicThinkingDisableReason` + `hasAnthropicThinkingSignature` | coder#1450 stopped disabling Anthropic thinking | Tests deleted; the one transform test that used it as an oracle now asserts the preserved signature directly | | `useProjectGitStatuses` (`GitStatusStore.ts`) | No production caller | None in CI | | `buildReviewDiffPathFilter`, `normalizeReviewPanelAssistedHunks` (test-only wrappers in `ReviewPanel.tsx`) | Production calls `buildReviewDiffPathFilterSpecs` / `getReviewPanelPathContext` + `normalizeAssistedReviewHunks` directly | Tests retargeted to those production functions (`getReviewPanelPathContext` is now exported) | | `computeTaskAwaitPollGroupInfos` (test-only wrapper) | ChatPane calls `computeOperationalBundleInfos({ taskAwaitPollsOnly })` | Tests use a local fixture helper around the production function | | 2 `/fork` cases in `parser.test.ts` | Same contract and name as `fork.test.ts` | Deleted | Retained on purpose (test reset seams, not dead code): `__resetForTests` (highlight worker), `resetAiSelectionIntentForTests`, `overlayWorkspaceStoreRaw` (test-support module). ## Validation - Sweep: every `export` under `src/browser` (excluding stories) checked for non-test references across `src/`, `tests/`, `vscode/`, `scripts/`, `.storybook/`; orphan-module sweep found only the two HTML entry points. - `TimingPanel.clear.test.tsx` fails when `handleClearStats` stops setting the error (mutation check). - `bun test` on RightSidebar, hooks/useStableReference, utils/{messages,agentSkills,ui,rightSidebarLayout}, stores/GitStatusStore: 1141 pass. - `make static-check` green. LOC: production +11 / −585; tests +134 / −355. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$4.21`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs=4.21 -->
Summary
Implements IDE-like "dock-lite" functionality for the RightSidebar with persistent nested splits, tabsets, drag-and-drop tab moving (including reordering), and stable embedded Terminal behavior.
Key Changes
Layout & Persistence
getRightSidebarLayoutKey(workspaceId)RIGHT_SIDEBAR_WIDTH_KEY)Drag & Drop
SidebarDragLayercomponent for consistent drag preview across panesDragAwarePanelResizeHandledisables pointer events during tab dragsTerminal Integration
TerminalSessionRoutersingleton centralizes terminal streaming/subscriptionsterminal.listSessionson mountTest Infrastructure
dragElementhelper using programmaticDragEventdispatch (works in Xvfb)Testing
Generated with
mux• Model:anthropic:claude-opus-4-5• Thinking:high