Skip to content

feat(desktop): New Tab screen for the right pane - #8965

Merged
saddlepaddle merged 12 commits into
mainfrom
saddlepaddle/right-pane-codex-style-new-tab-screen
Oct 28, 2026
Merged

saddlepaddle merged 12 commits into
mainfrom
saddlepaddle/right-pane-codex-style-new-tab-screen

Conversation

@saddlepaddle

@saddlepaddle saddlepaddle commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

The right pane's "+" now opens a full New Tab pane instead of a dropdown, following Satya's right-pane audit (#general, 10-27). It has three sections, titled like the cloud sidebar's hover card (layout "A2" from the mocks):

  • Tools: Terminal, Browser, Changes, Files, Review, Pages (plus Desktop on a sandbox and Mobile behind its flag), with their hotkeys. These are the center empty state's rows (EmptyTabActionButton).
  • Pages: this workspace's 4 newest pages, as the right pane's Pages view shows them (PagesListCard).
  • Pull requests: every PR linked to this workspace, newest first, in any state, as one-line hover-card rows (CloudPullRequestRow), from the host's PR history (pullRequests.historyByWorkspaces), so it works for local and cloud workspaces.

Screenshots: https://app.superset.sh/page/right-pane-new-tab-screen-zupovt

What changed

  • "+" adds a New Tab, and an overflowing tab bar scrolls it into view. Splits in the right pane (header button, Split Horizontally/Vertically) put a New Tab in the new split; the center still splits to a terminal.
  • Opening an empty right pane adds a New Tab. This only reacts to the pane opening or its layout loading, so closing the last tab still closes the pane.
  • Picking anything (tool, page, PR) replaces the New Tab in place and focuses the new pane. If that page, or the workspace's one PR pane, is already open, it is retargeted and focused instead, and the New Tab stays.
  • Hotkeys: when a New Tab is the focused pane, ⌘T, ⌘⇧B and ⌘⇧G replace it with a terminal, browser or Changes pane. Anywhere else they behave as before.
  • No duplicate header: a New Tab alone in its tab hides its pane header, since the tab already says "New Tab". In a split it keeps the header, so each pane can be told apart and closed. Splitting a lone New Tab is from the right-click menu. (@superset/panes gets an optional hideHeader(context) on pane definitions.)
  • Lists stay loaded: useNewTabLists owns the pages and PR queries. The right pane area (mounted while the workspace is open) keeps them cached and refreshes them every minute, so a New Tab renders them on its first frame with no request.
  • One helper, replaceNewTabPane, serves picks, page/PR clicks and hotkeys. It unpins first, because a header click pins a pane and replacePane skips pinned panes.
  • @superset/panes: Workspace takes onAddTab so "+" can be a plain button. New new-tab pane kind. PagesListCard moves up to be shared. EmptyTabActionButton takes a className.
  • Removed RightPaneAddMenu, RightPaneEmptyState and page.tsx's addRightPane.

Choices to check

  • PR +/− counts: the host's PR history doesn't store them, so each row reads them from the PR detail query the pull-request pane uses (local and cloud). The right pane area keeps those queries warm, so counts are there when a New Tab opens. A PR linked twice (for example under the old URL after the repo rename) shows once, keeping the newest link.
  • Which pages: this workspace's pages, newest first. Sections with nothing to show are hidden.
  • Terminal from the New Tab opens a blank terminal and skips "apply on new tab" presets, which build their own tab layout.
  • Files, Review and Pages have no hotkeys. Split hotkeys still act on the center pane only.

Test cases

Case Expected Checked
Open an empty right pane One New Tab App + hook test
Close the only tab / reopen Pane closes, not refilled / fresh New Tab App + hook test
"Move to Right Side" while closed Only the moved pane App
"+" Adds a New Tab App
"+" with the tab bar overflowing (2 → 15 tabs) New tab fully visible every time App + unit test
Split from header or context menu New split is a New Tab App + unit test
Lone New Tab / New Tab in a split No header / header shown App
Pick a tool (Browser, Files, Changes, Terminal) Replaces in place, takes focus App
Pick after a header click (pinned) Still replaces App + unit test
⌘T / ⌘⇧B / ⌘⇧G with a New Tab focused Replaces it in place, no extra tab App
⌘⇧B with another pane focused Adds a browser tab as before App
New Tab after 60 s with none on screen Lists in the first render, 0 requests; background refresh ran once at 60 s App
Click a page card / PR row Page / PR pane in place of the New Tab App
PR pane already open elsewhere Retargets it, New Tab stays Unit test
Desktop/Mobile tiles Only on a sandbox / with mobile-pane Unit test

Known gap, not changed: "Reveal in sidebar" still targets the old sidebar's file tree, which the right pane area doesn't render.

Verification

  • Dev app over CDP with right-pane-area on: every "App" row above, no console.error. A page opened from the New Tab gets the right page pane, but its body is blank locally because bun dev doesn't run the page content server (port 6794). That applies to every page pane in this setup.
  • bun test: new tests for replaceNewTabPane, withNewTabSplits, the open-empty hook and createRightPane pass, plus packages/panes. A full run of the v2-workspace folder shows 1 unrelated failure: a Lexical import-order error in the chat composer's useLinkChips.test.tsx, which passes alone.
  • Biome clean. typecheck has no errors in changed files; the existing better-auth type errors in packages/auth/packages/trpc are unrelated. check:i18n clean, no new strings.

@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@expo

expo Bot commented Oct 27, 2026

Copy link
Copy Markdown

No installed development build can load this pull request as an update: its native fingerprint is 9d26f603f51c and no development build has it. Add the mobile-build label to build one.

@github-actions

github-actions Bot commented Oct 27, 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! 🎉

Replace the right pane's add-tab dropdown with a full New Tab pane that lists
the pane types as large tiles. The + button opens it, the empty right pane
shows it, and splitting a right-pane pane (header button or context menu)
opens it in the new split. Picking a tile replaces the New Tab pane in place.

- panes: Workspace takes onAddTab for a + button without a menu
- new 'new-tab' pane kind; picking unpins first, since a header click pins
  the pane and replacePane skips pinned panes
- drop RightPaneAddMenu, RightPaneEmptyState and page.tsx's addRightPane
Opening the right pane with no tabs (toggle, hotkey, full screen) now adds a
New Tab tab instead of showing an empty area. The hook reacts to the pane
opening and the layout loading, not to tabs emptying, so closing the last tab
still closes the pane. Flows that open the pane and place a tab in the same
step (move to right side, open page/URL/file) add nothing extra.
…n PRs

The right pane's New Tab now has three sections, titled like the cloud
sidebar's hover card: Tools (the center empty state's rows, with their
hotkeys), this workspace's newest pages (PagesListCard) and the org's newest
open PRs (CloudPullRequestRow). Picking any of them replaces the New Tab in
place; a page or PR that is already open is retargeted and focused instead.

When a New Tab is the focused pane, cmd+T, cmd+shift+B and cmd+shift+G
replace it with a terminal, browser or Changes pane instead of opening a
new tab.

- replaceNewTabPane is the one path for picks, page/PR clicks and hotkeys
- PagesListCard moves up to be shared by PagesListPane and the New Tab
- EmptyTabActionButton takes a className
… tab

The tab already says "New Tab", so the pane header repeated it. Panes get an
optional hideHeader(context); the New Tab uses it only when the pane is not in
a split, where the header is how you tell the panes apart and close one.
…space is open

Each New Tab ran its own queries, so after five minutes with no New Tab on
screen React Query dropped the cache and the next New Tab loaded from empty,
with its sections popping in. useNewTabLists now owns both queries; the right
pane area, mounted for as long as the workspace is open, keeps them observed
and refreshes them every minute, and the New Tab reads the same cache.
With many right-pane tabs, + added a New Tab off-screen. The active tab now
scrolls fully into view whenever it changes, and again when the bar first
starts overflowing and the add button leaves the strip.
…he fade

- An overflowing tab bar no longer keeps the inline + slot, which left 40px
  of empty scroll past the last tab and kept the right fade on over it.
- A revealed tab keeps the 24px fade width clear at the right edge.
- The reveal scrolls smoothly instead of jumping.
The Pull requests section showed the org's newest open PRs from the GitHub
App table, which in a busy org were mostly other people's, and was empty
without the App. It now lists every PR linked to this workspace from the
host's PR history, which works for local and cloud workspaces alike, newest
link first, in any state.

- Each PR shows once: a repository rename leaves an older link to the same
  PR number under the previous URL.
- The host keeps no +/- counts, so CloudPullRequestRow hides the counts when
  they are missing.
The host's PR history keeps no line counts. A cloud workspace's PRs are also
in the cloud's GitHub App table, which has them, so the New Tab fills them in
by PR number there. Local workspaces keep rows without counts until
host-service stores them (TODO left in useNewTabLists).
Local workspaces showed PR rows without counts. Each row now reads its
counts from the PR detail query the pull-request pane uses, for local and
cloud workspaces alike, which replaces the cloud-only fill-in and its TODO.
The right pane area keeps those queries observed while the workspace is
open, so the counts are there when a New Tab opens and opening the PR from
it hits a warm cache.
CloudPullRequestRow fits its content, so with a short title the counts sat
right after it. A fullWidth option spans the row and lets the title take the
free space; the New Tab uses it, the hover card and record views don't.
@saddlepaddle
saddlepaddle marked this pull request as ready for review October 28, 2026 04:04
@saddlepaddle
saddlepaddle merged commit 84f9a90 into main Oct 28, 2026
20 checks passed
@saddlepaddle
saddlepaddle deleted the saddlepaddle/right-pane-codex-style-new-tab-screen branch October 28, 2026 04:04
@greptile-apps

greptile-apps Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The PR changes how people start and fill panes in the desktop workspace.

The PR appears safe to merge, with non-blocking improvements to PR-count fetching and add-menu behavior.

Findings

  1. P2 Hidden lists fetch PR activity ▶
  2. P2 Opening menus adds tabs ▶
Fix with agent prompt
### Issue 1
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/RightPaneArea/RightPaneArea.tsx:75-77
`RightPaneArea` fetches full details for every historical PR, even when no New Tab is visible. `usePullRequestCounts` calls `usePullRequestDetail`, which requests activity as well as counts. Since workspace history has no limit, opening a long-lived workspace can start many expensive GitHub reads just to display two numbers. Use a lightweight counts query, or limit which PRs get full-detail prefetches.

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!

### Issue 2
packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx:72
`onAddTab` still runs when `renderAddTabMenu` is provided, despite the new API saying it is ignored in that case. The same button keeps its `onClick` when wrapped by `DropdownMenuTrigger`, so a caller supplying both props adds a tab while opening the menu. Only attach `onAddTab` when no menu renderer is supplied.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The right pane now opens a New Tab screen with tools, recent pages, and linked PRs.

  • The right pane’s New Tab screen brings tools, recent pages, and pull requests together.
  • The right pane opens a New Tab when people add, split, or reopen it empty.
  • Picks and shortcuts replace a focused New Tab with the chosen pane.
  • The shared pane workspace can add tabs directly and keep new tabs visible.
  • Page thumbnails keep their placeholder visible until the image loads.

Acknowledged limits:

  • saddlepaddle explicitly identified the sidebar reveal gap as unchanged behavior.
  • saddlepaddle attributed blank local page bodies to the development content server not running, not to this change.
  • saddlepaddle explicitly chose to skip terminal presets when opening a terminal from New Tab and to retain split actions in the context menu when the header is hidden.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["Right pane opens empty or user clicks +"] --> B["New Tab"]
  C["Right-pane split"] --> B
  B --> D["Choose tool, page, or PR"]
  D --> E{"Matching keyed pane exists?"}
  E -->|Yes| F["Update and focus existing pane"]
  E -->|No| G["Unpin and replace New Tab"]
  G --> H["Focus new pane"]
Loading

Reviews (1) · Last reviewed commit: "fix(desktop): New Tab PR rows right-alig..." · Reviewed by Greptile

Comment on lines +75 to +77
{pullRequests.map((pr) => (
<PullRequestCountsPrefetch key={pr.url} pullRequest={pr.ref} />
))}

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 Hidden lists fetch PR activity

RightPaneArea fetches full details for every historical PR, even when no New Tab is visible. usePullRequestCounts calls usePullRequestDetail, which requests activity as well as counts. Since workspace history has no limit, opening a long-lived workspace can start many expensive GitHub reads just to display two numbers. Use a lightweight counts query, or limit which PRs get full-detail prefetches.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/RightPaneArea/RightPaneArea.tsx
Line: 75-77

Comment:
**Hidden lists fetch PR activity**

`RightPaneArea` fetches full details for every historical PR, even when no New Tab is visible. `usePullRequestCounts` calls `usePullRequestDetail`, which requests activity as well as counts. Since workspace history has no limit, opening a long-lived workspace can start many expensive GitHub reads just to display two numbers. Use a lightweight counts query, or limit which PRs get full-detail prefetches.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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!

size="icon"
type="button"
variant="ghost"
onClick={onAddTab}

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 Opening menus adds tabs

onAddTab still runs when renderAddTabMenu is provided, despite the new API saying it is ignored in that case. The same button keeps its onClick when wrapped by DropdownMenuTrigger, so a caller supplying both props adds a tab while opening the menu. Only attach onAddTab when no menu renderer is supplied.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx
Line: 72

Comment:
**Opening menus adds tabs**

`onAddTab` still runs when `renderAddTabMenu` is provided, despite the new API saying it is ignored in that case. The same button keeps its `onClick` when wrapped by `DropdownMenuTrigger`, so a caller supplying both props adds a tab while opening the menu. Only attach `onAddTab` when no menu renderer is supplied.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

This branch was previously deployed

1 inactive deployment
preview — 1826ac14 Deployed Oct 28, 2026 by saddlepaddle via Deploy Docs #13034
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