Skip to content

Add full-width split pane toggle#7252

Open
tofunori wants to merge 3 commits into
stablyai:mainfrom
tofunori:codex/7244-full-width-tabs
Open

Add full-width split pane toggle#7252
tofunori wants to merge 3 commits into
stablyai:mainfrom
tofunori:codex/7244-full-width-tabs

Conversation

@tofunori

@tofunori tofunori commented Jul 3, 2026

Copy link
Copy Markdown

Summary

  • add per-worktree split-group maximize state so a pane can temporarily span the full workspace width
  • render only the maximized split group while preserving the underlying split layout tree
  • add a direct maximize/restore icon button in focused split pane chrome, plus overlay visibility guards for terminal/browser/simulator panes

Fixes #7244

Testing

  • pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/tab-group/TabGroupSplitLayout.test.ts src/renderer/src/store/slices/tabs.test.ts src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.focus.test.ts src/renderer/src/components/browser-pane/BrowserPaneOverlayLayer.test.tsx src/renderer/src/components/emulator-pane/MobileEmulatorTabIntroCallout.test.tsx src/renderer/src/components/terminal-pane/TerminalPaneHeaderOverlay.test.tsx
  • pnpm run typecheck
  • pnpm run verify:localization-catalog
  • local Electron smoke test: maximize/restore browser pane in a two-column workspace via the direct icon button

Copilot AI review requested due to automatic review settings July 3, 2026 15:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a per-worktree “maximize split pane” (full-width) presentation mode that renders only the selected tab group while preserving the underlying split layout tree, with UI affordances and overlay visibility guards across panes.

Changes:

  • Introduces maximizedGroupIdByWorktree state with toggle/set APIs and cleanup behavior.
  • Updates split layout rendering to optionally render only the maximized leaf/group while retaining split-context behavior.
  • Adds a focused-pane maximize/restore button and ensures terminal/browser/emulator overlays respect the maximized group.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/renderer/src/store/slices/worktrees.ts Purges maximize state on worktree purge (but needs additional rename/remove coverage).
src/renderer/src/store/slices/tabs.ts Adds maximize state + toggle/set actions and clears state when closing a maximized group.
src/renderer/src/store/slices/tabs.test.ts Adds tests for maximize toggle and cleanup on group close.
src/renderer/src/i18n/locales/en.json Adds English strings for maximize/restore.
src/renderer/src/i18n/locales/zh.json Adds new keys (currently English values).
src/renderer/src/i18n/locales/ko.json Adds new keys (currently English values).
src/renderer/src/i18n/locales/ja.json Adds new keys (currently English values).
src/renderer/src/i18n/locales/es.json Adds new keys (currently English values).
src/renderer/src/components/Terminal.tsx Plumbs per-worktree maximized group into split surface and overlay layers.
src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx Hides overlays for non-maximized groups when a group is maximized.
src/renderer/src/components/browser-pane/BrowserPaneOverlayLayer.tsx Hides overlays for non-maximized groups when a group is maximized.
src/renderer/src/components/emulator-pane/EmulatorPaneOverlayLayer.tsx Hides overlays for non-maximized groups when a group is maximized.
src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts Exposes isGroupMaximized + toggle command to the panel model.
src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.focus.test.ts Updates focus-model test harness/mocks for maximize toggling.
src/renderer/src/components/tab-group/TabGroupSplitLayout.tsx Renders only the maximized group leaf while preserving split context.
src/renderer/src/components/tab-group/TabGroupSplitLayout.test.ts Adds coverage for maximized rendering behavior.
src/renderer/src/components/tab-group/TabGroupPanel.tsx Adds maximize/restore icon button with tooltip + aria-label.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/renderer/src/store/slices/tabs.ts Outdated
groupsByWorktree: Record<string, TabGroup[]>
activeGroupIdByWorktree: Record<string, string>
layoutByWorktree: Record<string, TabGroupLayoutNode>
maximizedGroupIdByWorktree: Record<string, string>
Comment on lines 2006 to 2011
unifiedTabsByWorktree: omitByWorktree(s.unifiedTabsByWorktree),
groupsByWorktree: omitByWorktree(s.groupsByWorktree),
layoutByWorktree: omitByWorktree(s.layoutByWorktree),
activeGroupIdByWorktree: omitByWorktree(s.activeGroupIdByWorktree),
maximizedGroupIdByWorktree: omitByWorktree(s.maximizedGroupIdByWorktree),
// Git status caches
Comment thread src/renderer/src/i18n/locales/zh.json Outdated
Comment on lines +2579 to +2582
"addSplitPane": "添加拆分窗格",
"closePaneColumn": "关闭拆分窗格"
"closePaneColumn": "关闭拆分窗格",
"restoreSplitLayout": "Restore split layout",
"maximizePane": "Maximize pane"
Comment thread src/renderer/src/i18n/locales/ko.json Outdated
Comment on lines +2579 to +2582
"addSplitPane": "분할 창 추가",
"closePaneColumn": "분할 창 닫기"
"closePaneColumn": "분할 창 닫기",
"restoreSplitLayout": "Restore split layout",
"maximizePane": "Maximize pane"
Comment thread src/renderer/src/i18n/locales/ja.json Outdated
Comment on lines +2579 to +2582
"addSplitPane": "分割ペインを追加",
"closePaneColumn": "分割ペインを閉じる"
"closePaneColumn": "分割ペインを閉じる",
"restoreSplitLayout": "Restore split layout",
"maximizePane": "Maximize pane"
Comment thread src/renderer/src/i18n/locales/es.json Outdated
Comment on lines +2579 to +2582
"addSplitPane": "Agregar panel dividido",
"closePaneColumn": "Cerrar panel dividido"
"closePaneColumn": "Cerrar panel dividido",
"restoreSplitLayout": "Restore split layout",
"maximizePane": "Maximize pane"
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0bb5db87-b466-4a57-a2fd-97d5ffb6e385

📥 Commits

Reviewing files that changed from the base of the PR and between de11c05 and 3684d71.

📒 Files selected for processing (4)
  • src/renderer/src/components/tab-group/TabGroupPanel.tsx
  • src/renderer/src/components/tab-group/TabGroupSplitLayout.tsx
  • src/renderer/src/store/slices/tabs.test.ts
  • src/renderer/src/store/slices/tabs.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/renderer/src/components/tab-group/TabGroupPanel.tsx
  • src/renderer/src/components/tab-group/TabGroupSplitLayout.tsx
  • src/renderer/src/store/slices/tabs.ts

📝 Walkthrough

Walkthrough

This change adds per-worktree maximized tab-group state, toggle actions, and cleanup in the tabs and worktree stores. The tab-group workspace model exposes maximize state and a toggle command, and the tab-group panel adds a focused split-pane maximize/restore control with new locale labels. Split layout rendering now accepts a maximized group id and renders the matching leaf, while Terminal.tsx derives and forwards the maximized group id into split layout and overlay layers. The terminal, browser, and emulator overlays update their active/visible checks to respect the maximized group.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers summary and testing, but it omits required Screenshots, AI Review Report, Security Audit, and Notes sections. Add the missing template sections, include checkbox-style testing entries, and summarize AI review, security, and platform-specific notes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main change: a full-width split pane toggle.
Linked Issues check ✅ Passed The changes implement per-worktree maximize state, preserve split layouts, add toggle actions, and update terminal/browser overlays as required by #7244.
Out of Scope Changes check ✅ Passed The changes stay focused on full-width maximize support, related state handling, UI wiring, tests, and localization updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/src/components/Terminal.tsx (1)

1264-1592: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a keyboard or menu trigger for tab-group maximize/restore

I only see the toolbar button in TabGroupPanel; toggleGroupMaximize doesn’t have a matching shortcut or menu action, so the requested keyboard/menu path is still missing.

🧹 Nitpick comments (4)
src/renderer/src/components/tab-group/TabGroupSplitLayout.tsx (1)

226-238: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a short comment explaining the maximize-render contract.

hasSplits/edge-touch flags are intentionally computed from the full layout, not renderedLayout, so split affordances (restore button, edge borders) stay correct while only the maximized leaf is mounted. This is a non-obvious constraint (confirmed by the new test) and isn't documented inline.

As per path instructions: "When writing or modifying code driven by a design doc or non-obvious constraint, add a comment explaining why the code behaves the way it does. Keep comments short — one or two lines, capturing only the non-obvious reason."

♻️ Suggested comment
   const dragSplit = useTabDragSplit({ worktreeId, enabled: isWorktreeActive })
   const hasSplits = layout.type === 'split'
+  // Why: derive hasSplits/edge flags from the full layout (not renderedLayout) so
+  // split-affordance chrome (e.g. restore button, borders) stays correct while a
+  // group is maximized and its siblings are unmounted below.
   const maximizedLeaf = maximizedGroupId ? findLeafForGroup(layout, maximizedGroupId) : null
   const renderedLayout = maximizedLeaf ?? layout

Source: Path instructions

src/renderer/src/components/tab-group/TabGroupPanel.tsx (2)

259-300: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the hasSplitGroups gating rationale.

The maximize/restore button is only rendered when hasSplitGroups is true, but unlike the other conditionals in this file (e.g., the border/edge logic, focusedActionChromeClassName), there's no comment explaining why maximize is hidden for single-pane groups. As per path instructions: "When writing or modifying code driven by a design doc or non-obvious constraint, add a comment explaining why the code behaves the way it does. Keep comments short — one or two lines, capturing only the non-obvious reason."

📝 Suggested comment
+              {/* Why: maximizing a single-pane group is a no-op — spanning across
+                  the workspace only makes sense when there are sibling split panes. */}
               {isFocused && hasSplitGroups ? (
                 <Tooltip>

Source: Path instructions


262-286: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding aria-pressed for the toggle button.

The button already switches aria-label/icon based on model.isGroupMaximized, but adding aria-pressed={model.isGroupMaximized} would make the toggle state explicit for assistive tech, matching common toggle-button a11y patterns.

src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx (1)

359-364: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the maximize-gating condition into a shared helper.

The identical isWorktreeActive && assignment.isActiveInGroup && (maximizedGroupId === null || assignment.groupId === maximizedGroupId) boolean gate is duplicated across TerminalPaneOverlayLayer, BrowserPaneOverlayLayer, and EmulatorPaneOverlayLayer (each with slightly different variable names). A tiny shared utility (e.g. isVisibleUnderMaximize(isWorktreeActive, isActiveInGroup, groupId, maximizedGroupId)) would keep the semantics in one place and avoid the three copies drifting apart on future changes.

♻️ Proposed shared helper
// e.g. src/renderer/src/components/tab-group/maximize-visibility.ts
export function isVisibleUnderMaximizedGroup(
  isWorktreeActive: boolean,
  isActiveInGroup: boolean,
  groupId: string | undefined,
  maximizedGroupId: string | null
): boolean {
  return Boolean(
    isWorktreeActive &&
      isActiveInGroup &&
      (maximizedGroupId === null || groupId === maximizedGroupId)
  )
}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7ea61c6a-bb3b-4c0c-ac74-d1eb4d6a87e9

📥 Commits

Reviewing files that changed from the base of the PR and between 1403467 and 461a4e5.

📒 Files selected for processing (17)
  • src/renderer/src/components/Terminal.tsx
  • src/renderer/src/components/browser-pane/BrowserPaneOverlayLayer.tsx
  • src/renderer/src/components/emulator-pane/EmulatorPaneOverlayLayer.tsx
  • src/renderer/src/components/tab-group/TabGroupPanel.tsx
  • src/renderer/src/components/tab-group/TabGroupSplitLayout.test.ts
  • src/renderer/src/components/tab-group/TabGroupSplitLayout.tsx
  • src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.focus.test.ts
  • src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts
  • src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/store/slices/tabs.test.ts
  • src/renderer/src/store/slices/tabs.ts
  • src/renderer/src/store/slices/worktrees.ts

Comment thread src/renderer/src/store/slices/tabs.ts
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.

Support tab spanning across split panes / full-width tab mode

2 participants