Add full-width split pane toggle#7252
Conversation
There was a problem hiding this comment.
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
maximizedGroupIdByWorktreestate 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.
| groupsByWorktree: Record<string, TabGroup[]> | ||
| activeGroupIdByWorktree: Record<string, string> | ||
| layoutByWorktree: Record<string, TabGroupLayoutNode> | ||
| maximizedGroupIdByWorktree: Record<string, string> |
| unifiedTabsByWorktree: omitByWorktree(s.unifiedTabsByWorktree), | ||
| groupsByWorktree: omitByWorktree(s.groupsByWorktree), | ||
| layoutByWorktree: omitByWorktree(s.layoutByWorktree), | ||
| activeGroupIdByWorktree: omitByWorktree(s.activeGroupIdByWorktree), | ||
| maximizedGroupIdByWorktree: omitByWorktree(s.maximizedGroupIdByWorktree), | ||
| // Git status caches |
| "addSplitPane": "添加拆分窗格", | ||
| "closePaneColumn": "关闭拆分窗格" | ||
| "closePaneColumn": "关闭拆分窗格", | ||
| "restoreSplitLayout": "Restore split layout", | ||
| "maximizePane": "Maximize pane" |
| "addSplitPane": "분할 창 추가", | ||
| "closePaneColumn": "분할 창 닫기" | ||
| "closePaneColumn": "분할 창 닫기", | ||
| "restoreSplitLayout": "Restore split layout", | ||
| "maximizePane": "Maximize pane" |
| "addSplitPane": "分割ペインを追加", | ||
| "closePaneColumn": "分割ペインを閉じる" | ||
| "closePaneColumn": "分割ペインを閉じる", | ||
| "restoreSplitLayout": "Restore split layout", | ||
| "maximizePane": "Maximize pane" |
| "addSplitPane": "Agregar panel dividido", | ||
| "closePaneColumn": "Cerrar panel dividido" | ||
| "closePaneColumn": "Cerrar panel dividido", | ||
| "restoreSplitLayout": "Restore split layout", | ||
| "maximizePane": "Maximize pane" |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThis 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)
✅ Passed checks (4 passed)
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. Comment |
There was a problem hiding this comment.
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 winAdd a keyboard or menu trigger for tab-group maximize/restore
I only see the toolbar button in
TabGroupPanel;toggleGroupMaximizedoesn’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 winAdd a short comment explaining the maximize-render contract.
hasSplits/edge-touch flags are intentionally computed from the fulllayout, notrenderedLayout, 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 ?? layoutSource: Path instructions
src/renderer/src/components/tab-group/TabGroupPanel.tsx (2)
259-300: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the
hasSplitGroupsgating rationale.The maximize/restore button is only rendered when
hasSplitGroupsis 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 winConsider adding
aria-pressedfor the toggle button.The button already switches
aria-label/icon based onmodel.isGroupMaximized, but addingaria-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 winConsider extracting the maximize-gating condition into a shared helper.
The identical
isWorktreeActive && assignment.isActiveInGroup && (maximizedGroupId === null || assignment.groupId === maximizedGroupId)boolean gate is duplicated acrossTerminalPaneOverlayLayer,BrowserPaneOverlayLayer, andEmulatorPaneOverlayLayer(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
📒 Files selected for processing (17)
src/renderer/src/components/Terminal.tsxsrc/renderer/src/components/browser-pane/BrowserPaneOverlayLayer.tsxsrc/renderer/src/components/emulator-pane/EmulatorPaneOverlayLayer.tsxsrc/renderer/src/components/tab-group/TabGroupPanel.tsxsrc/renderer/src/components/tab-group/TabGroupSplitLayout.test.tssrc/renderer/src/components/tab-group/TabGroupSplitLayout.tsxsrc/renderer/src/components/tab-group/useTabGroupWorkspaceModel.focus.test.tssrc/renderer/src/components/tab-group/useTabGroupWorkspaceModel.tssrc/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsxsrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/renderer/src/store/slices/tabs.test.tssrc/renderer/src/store/slices/tabs.tssrc/renderer/src/store/slices/worktrees.ts
Summary
Fixes #7244
Testing