fix(browser): focus unified tab on browser page palette activation (#16366)

* fix(browser): focus unified tab on browser page palette activation

When activating a browser page from the palette, find and focus the
corresponding unified tab before setting active state. Ensures the
tab group receives focus. Also increase e2e test timeouts to improve
stability on slower runners.

* test(e2e): read latest restored terminal frame

* Fail browser page activation when unified tab is missing

Without a unified tab, the workspace can't render in the pane. Reporting
success leaves the previous tab on screen. Fail the activation to prevent
this confusing state.
This commit is contained in:
Jinjing
2026-08-25 04:00:59 -07:00
committed by GitHub
parent e361da7fb7
commit 32df073e44
6 changed files with 30 additions and 9 deletions
@@ -2579,7 +2579,7 @@ function WorktreeJumpPaletteContent({
const activation = activateBrowserPagePaletteResult(result)
if (activation.status === 'failed') {
toast.error(
activation.reason === 'missing-page'
activation.reason !== 'missing-worktree'
? translate(
'auto.components.WorktreeJumpPalette.d7d496a451',
'Browser page no longer exists'
@@ -201,7 +201,10 @@ describe('activateBrowserPagePaletteResult', () => {
worktreesByRepo: {},
folderWorkspaces: [makeFolderWorkspace({ executionHostId: 'ssh:host-1' })],
browserTabsByWorktree: { [worktreeId]: [makeWorkspace({ worktreeId })] },
browserPagesByWorkspace: { 'ws-1': [makePage({ worktreeId })] }
browserPagesByWorkspace: { 'ws-1': [makePage({ worktreeId })] },
unifiedTabsByWorktree: { [worktreeId]: [makeBrowserTab({ worktreeId })] },
groupsByWorktree: { [worktreeId]: [makeGroup({ worktreeId })] },
activeGroupIdByWorktree: { [worktreeId]: 'group-1' }
})
expect(
@@ -335,12 +338,15 @@ describe('activateBrowserPagePaletteResult group focus', () => {
expect(useAppStore.getState().activeGroupIdByWorktree['wt-1']).toBe('group-1')
})
it('still activates the page when no unified tab backs the browser workspace', () => {
// Nothing renders the workspace without its unified tab, so reporting success
// would leave the previously active tab on screen.
it('fails instead of activating when no unified tab backs the browser workspace', () => {
seedStore({ unifiedTabsByWorktree: {}, groupsByWorktree: { 'wt-1': [] } })
expect(activateBrowserPagePaletteResult(target)).toMatchObject({
status: 'activated'
expect(activateBrowserPagePaletteResult(target)).toEqual({
status: 'failed',
reason: 'missing-tab'
})
expect(useAppStore.getState().activeBrowserTabId).toBe('ws-1')
expect(useAppStore.getState().activeBrowserTabId).toBeNull()
})
})
@@ -3,7 +3,10 @@ import type { ExecutionHostId } from '../../../shared/execution-host'
import { isBlankBrowserUrl } from './browser-palette-search'
import { activateAndRevealWorktree } from './worktree-activation'
export type BrowserPagePaletteActivationFailure = 'missing-page' | 'missing-worktree'
export type BrowserPagePaletteActivationFailure =
| 'missing-page'
| 'missing-tab'
| 'missing-worktree'
export type BrowserPageFocusTarget = 'address-bar' | 'webview'
@@ -57,6 +60,16 @@ export function activateBrowserPagePaletteResult({
}
const state = useAppStore.getState()
const matchingUnifiedTab = (state.unifiedTabsByWorktree[worktree.id] ?? []).find(
(candidate) => candidate.contentType === 'browser' && candidate.entityId === workspace.id
)
// Why: the pane renders whatever the group's active tab is, so without a unified
// tab the browser state would go active behind a tab that never shows the page.
if (!matchingUnifiedTab) {
return { status: 'failed', reason: 'missing-tab' }
}
state.focusGroup(worktree.id, matchingUnifiedTab.groupId)
state.activateTab(matchingUnifiedTab.id)
state.setActiveBrowserTab(workspace.id)
state.setActiveBrowserPage(workspace.id, pageId)
return { status: 'activated', pageId, focusTarget }