mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 00:03:46 +00:00
Harden Cmd+J incomplete hydration re-rank latch
Clear the provisional order latch when the ranked list goes empty so a brief tab wipe cannot freeze an empty Recent section, and assert that a user-moved selection survives the incomplete→complete re-rank.
This commit is contained in:
@@ -769,7 +769,7 @@ describe('WorktreeJumpPalette recent chats & terminals', () => {
|
||||
|
||||
it('re-ranks once when terminal entities hydrate after unified tabs', async () => {
|
||||
// Why split hydration: unified tabs can land before tabsByWorktree; without a re-capture every
|
||||
// row ranks IDLE and the blocked chat stays under focus recency until reopen.
|
||||
// row ranks IDLE. A deliberate second-row highlight must survive that one re-rank.
|
||||
const hydrated = makeRecentTabState({
|
||||
agentStatusByPaneKey: {
|
||||
[`term-alpha:${LEAF_ID}`]: makeAgentEntry('term-alpha', 'blocked', Date.now())
|
||||
@@ -778,23 +778,17 @@ describe('WorktreeJumpPalette recent chats & terminals', () => {
|
||||
})
|
||||
await renderPalette({ ...hydrated, tabsByWorktree: {} })
|
||||
expect(getTabRowIds()).toEqual(['tab-beta', 'tab-alpha'])
|
||||
|
||||
const movedTo = `workspace-tab:${getTabRowIds()[1]}`
|
||||
await act(async () => {
|
||||
setCommandSelection?.(movedTo)
|
||||
})
|
||||
await flushEffects()
|
||||
await act(async () => {
|
||||
useAppStore.setState({ tabsByWorktree: hydrated.tabsByWorktree } as Partial<AppState>)
|
||||
})
|
||||
await flushEffects()
|
||||
expect(getTabRowIds()).toEqual(['tab-alpha', 'tab-beta'])
|
||||
|
||||
// Why: incomplete→complete re-rank is one-shot — later status churn still freezes positions.
|
||||
await act(async () => {
|
||||
useAppStore.setState({
|
||||
agentStatusByPaneKey: {
|
||||
[`term-beta:${LEAF_ID}`]: makeAgentEntry('term-beta', 'blocked', Date.now())
|
||||
}
|
||||
} as Partial<AppState>)
|
||||
})
|
||||
await flushEffects()
|
||||
expect(getTabRowIds()).toEqual(['tab-alpha', 'tab-beta'])
|
||||
expect(getCommandValue()).toBe(movedTo)
|
||||
})
|
||||
|
||||
it('ranks a blocked agent above a more recently visited idle tab', async () => {
|
||||
|
||||
@@ -1098,7 +1098,10 @@ export default function WorktreeJumpPalette(): React.JSX.Element | null {
|
||||
if (order.length === 0) {
|
||||
// Why: tabs can arrive after the palette opens (cold start, session restore, a late tab
|
||||
// mirror). Latching an empty snapshot would leave Recent dead — and digits inert — until
|
||||
// close+reopen, so stay unlatched; the stable empty ref keeps this a no-op re-render.
|
||||
// close+reopen. Also clear a provisional latch: incomplete→complete fallthrough can hit empty
|
||||
// if open tabs briefly vanish, and keeping captured would freeze an empty Recent forever.
|
||||
recentTabOrderCapturedRef.current = false
|
||||
recentTabOrderAttentionReadyRef.current = false
|
||||
setRecentTabOrder(EMPTY_RECENT_TAB_ORDER)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user