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

Merged
SA
5d ago
+885-307

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

CaseExpectedChecked
Open an empty right paneOne New TabApp + hook test
Close the only tab / reopenPane closes, not refilled / fresh New TabApp + hook test
"Move to Right Side" while closedOnly the moved paneApp
"+"Adds a New TabApp
"+" with the tab bar overflowing (2 → 15 tabs)New tab fully visible every timeApp + unit test
Split from header or context menuNew split is a New TabApp + unit test
Lone New Tab / New Tab in a splitNo header / header shownApp
Pick a tool (Browser, Files, Changes, Terminal)Replaces in place, takes focusApp
Pick after a header click (pinned)Still replacesApp + unit test
⌘T / ⌘⇧B / ⌘⇧G with a New Tab focusedReplaces it in place, no extra tabApp
⌘⇧B with another pane focusedAdds a browser tab as beforeApp
New Tab after 60 s with none on screenLists in the first render, 0 requests; background refresh ran once at 60 sApp
Click a page card / PR rowPage / PR pane in place of the New TabApp
PR pane already open elsewhereRetargets it, New Tab staysUnit test
Desktop/Mobile tilesOnly on a sandbox / with mobile-paneUnit 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.