Fix split pane shortcuts targeting hidden worktrees (#676)
This commit is contained in:
parent
d22a466ece
commit
aad7d04997
|
|
@ -896,6 +896,7 @@ function Terminal(): React.JSX.Element | null {
|
|||
layout={layout}
|
||||
worktreeId={worktree.id}
|
||||
focusedGroupId={activeGroupIdByWorktree[worktree.id]}
|
||||
isWorktreeActive={isVisible}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const setTabGroupSplitRatioMock = vi.fn()
|
||||
const useAppStoreMock = vi.fn(
|
||||
(selector: (state: { setTabGroupSplitRatio: () => void }) => unknown) =>
|
||||
selector({ setTabGroupSplitRatio: setTabGroupSplitRatioMock })
|
||||
)
|
||||
vi.mock('../../store', () => ({
|
||||
useAppStore: (selector: (state: { setTabGroupSplitRatio: () => void }) => unknown) =>
|
||||
useAppStoreMock(selector)
|
||||
}))
|
||||
|
||||
vi.mock('./TabGroupPanel', () => ({
|
||||
default: (props: unknown) => ({ __mock: 'TabGroupPanel', props })
|
||||
}))
|
||||
|
||||
import TabGroupSplitLayout from './TabGroupSplitLayout'
|
||||
|
||||
describe('TabGroupSplitLayout', () => {
|
||||
function getLeafPanelProps(isWorktreeActive: boolean) {
|
||||
const element = TabGroupSplitLayout({
|
||||
layout: { type: 'leaf', groupId: 'group-1' },
|
||||
worktreeId: 'wt-1',
|
||||
focusedGroupId: 'group-1',
|
||||
isWorktreeActive
|
||||
})
|
||||
|
||||
const splitNodeElement = element.props.children
|
||||
const tabGroupPanelElement = splitNodeElement.type(splitNodeElement.props)
|
||||
return tabGroupPanelElement.props as {
|
||||
groupId: string
|
||||
worktreeId: string
|
||||
isFocused: boolean
|
||||
hasSplitGroups: boolean
|
||||
}
|
||||
}
|
||||
|
||||
it('does not mark an offscreen worktree group as focused', () => {
|
||||
expect(getLeafPanelProps(false)).toEqual(
|
||||
expect.objectContaining({
|
||||
groupId: 'group-1',
|
||||
worktreeId: 'wt-1',
|
||||
isFocused: false,
|
||||
hasSplitGroups: false
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps the visible worktree focused group active', () => {
|
||||
expect(getLeafPanelProps(true)).toEqual(
|
||||
expect.objectContaining({
|
||||
groupId: 'group-1',
|
||||
worktreeId: 'wt-1',
|
||||
isFocused: true,
|
||||
hasSplitGroups: false
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
@ -84,12 +84,14 @@ function SplitNode({
|
|||
nodePath,
|
||||
worktreeId,
|
||||
focusedGroupId,
|
||||
isWorktreeActive,
|
||||
hasSplitGroups
|
||||
}: {
|
||||
node: TabGroupLayoutNode
|
||||
nodePath: string
|
||||
worktreeId: string
|
||||
focusedGroupId?: string
|
||||
isWorktreeActive: boolean
|
||||
hasSplitGroups: boolean
|
||||
}): React.JSX.Element {
|
||||
const setTabGroupSplitRatio = useAppStore((state) => state.setTabGroupSplitRatio)
|
||||
|
|
@ -99,7 +101,11 @@ function SplitNode({
|
|||
<TabGroupPanel
|
||||
groupId={node.groupId}
|
||||
worktreeId={worktreeId}
|
||||
isFocused={node.groupId === focusedGroupId}
|
||||
// Why: hidden worktrees stay mounted so their PTYs and split layouts
|
||||
// survive worktree switches, but only the visible worktree may own the
|
||||
// global terminal shortcuts. If an offscreen group's pane stays
|
||||
// "focused", Cmd/Ctrl+W and split shortcuts can hit the wrong worktree.
|
||||
isFocused={isWorktreeActive && node.groupId === focusedGroupId}
|
||||
hasSplitGroups={hasSplitGroups}
|
||||
/>
|
||||
)
|
||||
|
|
@ -119,6 +125,7 @@ function SplitNode({
|
|||
nodePath={nodePath.length > 0 ? `${nodePath}.first` : 'first'}
|
||||
worktreeId={worktreeId}
|
||||
focusedGroupId={focusedGroupId}
|
||||
isWorktreeActive={isWorktreeActive}
|
||||
hasSplitGroups={hasSplitGroups}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -132,6 +139,7 @@ function SplitNode({
|
|||
nodePath={nodePath.length > 0 ? `${nodePath}.second` : 'second'}
|
||||
worktreeId={worktreeId}
|
||||
focusedGroupId={focusedGroupId}
|
||||
isWorktreeActive={isWorktreeActive}
|
||||
hasSplitGroups={hasSplitGroups}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -142,11 +150,13 @@ function SplitNode({
|
|||
export default function TabGroupSplitLayout({
|
||||
layout,
|
||||
worktreeId,
|
||||
focusedGroupId
|
||||
focusedGroupId,
|
||||
isWorktreeActive
|
||||
}: {
|
||||
layout: TabGroupLayoutNode
|
||||
worktreeId: string
|
||||
focusedGroupId?: string
|
||||
isWorktreeActive: boolean
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<div className="flex flex-1 min-w-0 min-h-0 overflow-hidden">
|
||||
|
|
@ -155,6 +165,7 @@ export default function TabGroupSplitLayout({
|
|||
nodePath=""
|
||||
worktreeId={worktreeId}
|
||||
focusedGroupId={focusedGroupId}
|
||||
isWorktreeActive={isWorktreeActive}
|
||||
hasSplitGroups={layout.type === 'split'}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue