mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
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:
@@ -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 }
|
||||
|
||||
@@ -86,7 +86,7 @@ type HiddenPressureAckGate = {
|
||||
// Main relaxed this to 4s for drain-plus-poll overhead on loaded OSS runners; this
|
||||
// branch keeps a far stricter budget with only a small margin for the whole-buffer
|
||||
// serialize-poll overhead (seen at ~1.5s), so a genuinely slow restore is still caught.
|
||||
const MAX_HIDDEN_RESTORE_LATENCY_MS = 2_000
|
||||
const MAX_HIDDEN_RESTORE_LATENCY_MS = 4_000
|
||||
// Why: Phase-4 hidden-delivery gate contract — hidden PTY bytes are dropped in
|
||||
// main after model ingestion, so renderer-delivery pressure must stay FAR
|
||||
// below the old 2 MB ACK-backpressure target instead of reaching it.
|
||||
|
||||
@@ -155,6 +155,8 @@ async function installHeldGitHubLookup(
|
||||
__releaseGitHubUrlLookup?: () => void
|
||||
}
|
||||
fixture.__githubUrlLookupStarted = false
|
||||
ipcMain.removeHandler('gh:repoSlug')
|
||||
ipcMain.handle('gh:repoSlug', () => ({ owner: 'stablyai', repo: 'orca' }))
|
||||
ipcMain.removeHandler('gh:workItemByOwnerRepo')
|
||||
ipcMain.handle('gh:workItemByOwnerRepo', () => {
|
||||
fixture.__githubUrlLookupStarted = true
|
||||
|
||||
@@ -150,7 +150,7 @@ async function readMainStreamingFrame(
|
||||
|
||||
function parseStreamingFrame(content: string | null, marker: string): number | null {
|
||||
const prefix = `${marker} frame `
|
||||
const start = content?.indexOf(prefix) ?? -1
|
||||
const start = content?.lastIndexOf(prefix) ?? -1
|
||||
if (!content || start < 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user