mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
fix(mobile): clear state after closing final tab (#11637)
* fix(mobile): clear state after closing final tab * fix(mobile): clear terminal on empty snapshots * fix(mobile): preserve terminal during transient empty snapshot
This commit is contained in:
@@ -1894,6 +1894,7 @@ export default function SessionScreen() {
|
||||
setActiveHandle(active.terminal)
|
||||
subscribeToTerminal(active.terminal)
|
||||
} else if (active) {
|
||||
// Why: an empty snapshot can transiently omit a live terminal; explicit close clears it on RPC success.
|
||||
const previous = activeHandleRef.current
|
||||
if (previous) {
|
||||
unsubscribeTerminal(previous)
|
||||
@@ -4133,6 +4134,7 @@ export default function SessionScreen() {
|
||||
reason: 'user'
|
||||
})
|
||||
if (response.ok) {
|
||||
const remainingTabs = sessionTabsRef.current.filter((candidate) => candidate.id !== tab.id)
|
||||
if (tab.type === 'browser' && tab.browserPageId === pendingBrowserFocusPageIdRef.current) {
|
||||
pendingBrowserFocusPageIdRef.current = null
|
||||
}
|
||||
@@ -4143,14 +4145,16 @@ export default function SessionScreen() {
|
||||
initializedHandlesRef.current.delete(terminalHandle)
|
||||
clearTerminalLiveInputDefault(terminalHandle)
|
||||
}
|
||||
setSessionTabs((prev) => prev.filter((candidate) => candidate.id !== tab.id))
|
||||
sessionTabsRef.current = remainingTabs
|
||||
setSessionTabs(remainingTabs)
|
||||
// Why: tombstone the closed tab and rely on the snapshot, not a blind refetch that often re-added the not-yet-closed tab.
|
||||
closedTabTombstonesRef.current.set(tab.id, Date.now() + 10_000)
|
||||
// Why: bulk close re-activates the anchor before awaiting each close;
|
||||
// the render-synced ref sees that switch while this closure would not,
|
||||
// so comparing against the ref keeps the anchor from being nulled out.
|
||||
if (activeSessionTabIdRef.current === tab.id) {
|
||||
if (activeSessionTabIdRef.current === tab.id || remainingTabs.length === 0) {
|
||||
activeSessionTabTypeRef.current = null
|
||||
activeSessionTabIdRef.current = null
|
||||
setActiveSessionTabId(null)
|
||||
activeHandleRef.current = null
|
||||
setActiveHandle(null)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const sessionRouteSource = readFileSync(
|
||||
new URL('../../app/h/[hostId]/session/[worktreeId].tsx', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
describe('mobile session last-tab close', () => {
|
||||
it('preserves terminal identity while an empty snapshot may be transient', () => {
|
||||
const start = sessionRouteSource.indexOf('const applySessionTabs = useCallback')
|
||||
const end = sessionRouteSource.indexOf('const readMarkdownTab', start)
|
||||
const block = sessionRouteSource.slice(start, end)
|
||||
|
||||
expect(block).toContain('} else if (active) {')
|
||||
})
|
||||
|
||||
it('clears stale active identity when closing leaves no tabs', () => {
|
||||
const start = sessionRouteSource.indexOf('async function handleCloseSessionTab')
|
||||
const end = sessionRouteSource.indexOf('const bulkCloseActions', start)
|
||||
const block = sessionRouteSource.slice(start, end)
|
||||
|
||||
expect(block).toContain(
|
||||
'activeSessionTabIdRef.current === tab.id || remainingTabs.length === 0'
|
||||
)
|
||||
expect(block).toContain('activeSessionTabIdRef.current = null')
|
||||
expect(block).toContain('activeHandleRef.current = null')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user