Skip to content

Add right panel close controls#4148

Open
caezium wants to merge 2 commits into
pingdotgg:mainfrom
caezium:agent/right-panel-close-button
Open

Add right panel close controls#4148
caezium wants to merge 2 commits into
pingdotgg:mainfrom
caezium:agent/right-panel-close-button

Conversation

@caezium

@caezium caezium commented Jul 19, 2026

Copy link
Copy Markdown

What Changed

  • Add an explicit close button as the right-most control in the inline right-panel title-bar cluster.
  • Add a configurable rightPanel.closeActiveSurface command, bound to Cmd+W/Ctrl+W while focus is inside the right panel.
  • Route the macOS native Close Window accelerator through a stable renderer listener so any active right-panel tab closes before the app window, including terminal and preview cases where DOM focus reports the page root.
  • Preserve browser/editor-style middle-click closing for right-panel surface tabs, with regression coverage proving only button 1 closes the selected tab.
  • Harden focus ownership across preview webviews and pointer-driven focus transitions, and keep the close-surface shortcut disabled while the right panel is closed.
  • Add focused coverage for panel focus detection, shortcut precedence, close-request routing, menu dispatch, title-bar control ordering, and middle-click tab closing.

Why

The right panel has per-tab close actions but no obvious way to hide the whole panel. On macOS, Cmd+W also reaches Electron's native Close Window action instead of closing the active side-panel tab. Right-panel tabs also follow the familiar browser/editor convention: middle-click closes the selected tab without closing the panel or app window.

Closes #4146.
Closes #4147.

UI Changes

Before

Right panel before the whole-panel close control

After

Right panel with the close control at the far-right edge

Interaction

Cmd+W / whole-panel close

Watch the last active tab close and the panel reopen

The Cmd+W clip starts with one Files tab, so closing the last tab hides the panel; the panel toggle then reopens it.

Middle-click tab close

Watch middle-click close Files while Terminal and the app window stay open

This clip uses an isolated Close controls demo fixture and contains no private workspace content.

Validation

  • bun x vp test run apps/web/src/components/RightPanelTabs.test.tsx (5 tests passed)
  • bun x vp test run apps/web/src/lib/rightPanelFocus.test.ts apps/web/src/lib/nativeCloseFocus.test.ts apps/web/src/lib/rightPanelCloseRequest.test.ts apps/web/src/components/RightPanelTabs.test.tsx (4 files, 33 tests passed)
  • Targeted lint for all touched web files (passes)
  • bun run --cwd apps/web typecheck (passes)
  • Real Electron dev app: the far-right X closes the whole right panel and the panel toggle reopens it.
  • Real Electron dev app: invoking the native File → Close Window action with Files open closes the Files surface and leaves the app window open, even when accessibility focus reports only the page root.
  • Real Electron dev app: middle-clicking an inactive Files tab closes only Files while Terminal, the right panel, and the app window stay open.
  • bun x vp check (passes with 10 existing warnings in unrelated files)
  • bun x vp run typecheck (passes across all 15 workspaces)

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Medium Risk
Touches macOS menu accelerators, window-close routing, and keyboard shortcut precedence across desktop and renderer; behavior is heavily tested but regressions could affect Cmd+W or accidental window closes.

Overview
Adds right-panel close affordances and wires macOS Close Window / Cmd+W through the renderer before falling back to native window close.

The web app gains a title-bar Close right panel control, a rightPanel.closeActiveSurface binding (mod+w when rightPanelFocus and not terminalFocus), middle-click-to-close on panel tabs, and focus tracking (nativeCloseFocus, rightPanelFocus) so close targets the drawer terminal, a right-panel terminal pane, an active surface, or the whole panel. On macOS Electron, in-app Cmd+W for those close commands is deferred so the menu path can run; AppSidebarLayout handles close-window-or-right-panel via a cancelable event before window.close().

The desktop app replaces macOS File’s native close role with a custom Close Window item that sends close-window-or-right-panel to the main window through new dispatchMenuActionToMainWindow (no reveal), or performClose: when focus is on system UI or a non-main window. ElectronMenu.sendActionToFirstResponder supports the native fallback.

Reviewed by Cursor Bugbot for commit 137c501. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add right-panel close controls with Cmd+W and title bar button support

  • Adds a RightPanelCloseControl button to the right-panel title bar and wires Cmd+W (as rightPanel.closeActiveSurface) to close the active right-panel pane, surface, or panel when the right panel owns focus.
  • Introduces focus-tracking utilities (nativeCloseFocus.ts, rightPanelFocus.ts) to determine whether native close should target a right-panel entity or fall through to the window.
  • On macOS, replaces the File menu's native role: close with a custom Close Window handler in DesktopApplicationMenu.ts that routes close-window-or-right-panel to the renderer's main window first, falling back to performClose: via ElectronMenu.sendActionToFirstResponder.
  • Adds dispatchMenuActionToMainWindow to DesktopWindow for targeted dispatch that returns whether the action was handled.
  • Behavioral Change: Cmd+W now closes the active right-panel surface when the right panel is focused, deferring to the native window close only when the panel is not focused or does not handle the action.

Macroscope summarized 137c501.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1e3dd204-7acc-40a9-9197-4c928b3eb28b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 19, 2026
@caezium
caezium marked this pull request as ready for review July 19, 2026 14:16
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/components/ChatView.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature (right panel close controls) with significant complexity including cross-platform focus tracking and Electron menu integration. Multiple unresolved review comments identify bugs, including a high-severity deadlock issue with Cmd+W in preview webviews.

You can customize Macroscope's approvability policy. Learn more.

Comment thread apps/web/src/lib/rightPanelCloseRequest.ts
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/lib/rightPanelFocus.ts
Comment thread packages/shared/src/keybindings.ts Outdated
Comment thread apps/web/src/components/RightPanelTabs.tsx
Comment thread apps/desktop/src/window/DesktopApplicationMenu.ts
Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/lib/rightPanelCloseRequest.ts Outdated
Comment thread apps/web/src/lib/terminalFocus.ts Outdated
Comment thread apps/web/src/lib/nativeCloseFocus.ts
Comment thread apps/web/src/lib/nativeCloseFocus.ts
@juliusmarminge

Copy link
Copy Markdown
Member

what is the interaction demo doing? looks like you're just toggling visibility which you can already do with Mod+Shift+B ?

@caezium

caezium commented Jul 19, 2026

Copy link
Copy Markdown
Author

pressing cmd+w to close a single panel, since in the vid there was only one, the whole panel closed, sorry for the bad video, ill record another one

Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/web/src/lib/rightPanelFocus.ts
Comment thread apps/web/src/lib/nativeCloseFocus.ts
Comment thread apps/web/src/components/chat/PanelLayoutControls.tsx
@caezium

caezium commented Jul 19, 2026

Copy link
Copy Markdown
Author

Updated the PR description with a separate real-app middle-click demo. It starts with Files and Terminal open, then middle-click closes only Files while Terminal, the right panel, and the app window stay open. I also added focused regression coverage for button 1 and clarified what the existing Cmd+W clip is showing.

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 19, 2026
Comment thread apps/web/src/lib/rightPanelFocus.ts Outdated
@caezium

caezium commented Jul 19, 2026

Copy link
Copy Markdown
Author

Follow-up review fix in 85e780f: hosted preview focus is now matched by tab ID against the active right-panel preview, so a standalone preview cannot trigger the right-panel close shortcut. The focused tests cover matching and mismatched preview IDs.

Comment thread apps/web/src/components/ChatView.tsx Outdated
@caezium
caezium force-pushed the agent/right-panel-close-button branch from 85e780f to 4935f60 Compare July 19, 2026 20:38
Comment thread apps/web/src/lib/nativeCloseFocus.ts
caezium and others added 2 commits July 20, 2026 16:40
Keep native close focus scoped to the active hosted preview and preserve pointer ownership across webview blur transitions.

Co-authored-by: codex <codex@users.noreply.github.com>
terminalFocus: terminalFocusOwner !== null,
terminalOpen: Boolean(terminalUiState.terminalOpen),
modelPickerOpen: composerRef.current?.isModelPickerOpen() ?? false,
rightPanelFocus: isRightPanelFocused({

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.

🟡 Medium components/ChatView.tsx:3959

The keydown effect computes rightPanelFocus from rightPanelOpen and activeRightPanelPreviewTabId but omits both from its dependency array, so the installed handler retains stale values. If the right panel is closed without another listed dependency changing, the handler still sees rightPanelOpen: true, and Cmd+W resolves rightPanel.closeActiveSurface even though the panel is already closed. Preview-tab changes are similarly affected — focus ownership can be stale. Add rightPanelOpen and activeRightPanelPreviewTabId to the effect's dependency array.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/ChatView.tsx around line 3959:

The keydown effect computes `rightPanelFocus` from `rightPanelOpen` and `activeRightPanelPreviewTabId` but omits both from its dependency array, so the installed handler retains stale values. If the right panel is closed without another listed dependency changing, the handler still sees `rightPanelOpen: true`, and `Cmd+W` resolves `rightPanel.closeActiveSurface` even though the panel is already closed. Preview-tab changes are similarly affected — focus ownership can be stale. Add `rightPanelOpen` and `activeRightPanelPreviewTabId` to the effect's dependency array.

send();
yield* sendMenuAction(targetWindow, action, true);
}),
dispatchMenuActionToMainWindow: Effect.fn("desktop.window.dispatchMenuActionToMainWindow")(

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.

🟡 Medium window/DesktopWindow.ts:799

dispatchMenuActionToMainWindow returns true whenever the window matches the main window, even when sendMenuAction only registers a once("did-finish-load") listener and the IPC message has not actually been sent yet. If a menu action like Close Window is invoked while the main frame is still loading and that load fails or is replaced without emitting did-finish-load, the action is silently never delivered — yet the caller treats true as handled and skips its native fallback (e.g. performClose:). The result is that the Close Window command does nothing in this state. Consider returning true only after the message has actually been sent, or adding a fallback so the action is not lost when did-finish-load never fires.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/desktop/src/window/DesktopWindow.ts around line 799:

`dispatchMenuActionToMainWindow` returns `true` whenever the window matches the main window, even when `sendMenuAction` only registers a `once("did-finish-load")` listener and the IPC message has not actually been sent yet. If a menu action like Close Window is invoked while the main frame is still loading and that load fails or is replaced without emitting `did-finish-load`, the action is silently never delivered — yet the caller treats `true` as handled and skips its native fallback (e.g. `performClose:`). The result is that the Close Window command does nothing in this state. Consider returning `true` only after the message has actually been sent, or adding a fallback so the action is not lost when `did-finish-load` never fires.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 137c501. Configure here.

terminalFocused: terminalFocusOwner !== null,
})
) {
return;

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.

Preview Cmd+W close deadlocks

High Severity

On macOS desktop, Cmd+W from a focused right-panel preview webview is deferred to the application menu, but preview webContents already preventDefaults that accelerator and forwards a synthetic keydown into the main renderer. The deferred handler then ignores that synthetic event, so neither the menu path nor the renderer close path runs and the surface stays open.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 137c501. Configure here.

rightPanelFocus: isRightPanelFocused({
rightPanelOpen,
activePreviewTabId: activeRightPanelPreviewTabId,
}),

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.

Keyboard close ignores retained focus

Medium Severity

rightPanel.closeActiveSurface gates on live isRightPanelFocused only, while pointer/webview ownership lives in nativeCloseFocus and is used solely by the macOS menu path via shouldDeferCloseCommandToDesktopMenu. On Windows/Linux Electron, Ctrl+W after a pointer activation that leaves document.activeElement on body (or other non-panel nodes) never resolves the command, so the active surface does not close.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 137c501. Configure here.

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

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Close the active right-panel tab with Cmd+W [Feature]: Add an explicit close button to the right panel header

2 participants