mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
fix(wsl): Commits history wakes a stopped distro only on the user's own act (#35854)
* fix(wsl): Commits history wakes a stopped distro only on the user's own act Showing Commits woke the distro on every mount, remount and re-show. Now only the user expanding Commits in the same worktree, or the user's own switch to the workspace (once per switch), may start it; the Refresh button keeps its explicit wake (E9). * test: a mount and a base-ref move read Commits history in the background #35778's base-move refetch test expected every shown-history read to wake a stopped WSL distro; only the user's own act does now.
This commit is contained in:
+77
-23
@@ -1,7 +1,11 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { act, cleanup, renderHook } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
noteUserWorkspaceSwitch,
|
||||
resetWorkspaceSwitchUserActsForTests
|
||||
} from '@/lib/workspace-switch-user-act'
|
||||
|
||||
const getRuntimeGitHistoryMock = vi.hoisted(() => vi.fn())
|
||||
vi.mock('@/runtime/runtime-git-status-client', () => ({
|
||||
@@ -11,33 +15,83 @@ vi.mock('@/lib/connection-context', () => ({ getConnectionId: () => null }))
|
||||
|
||||
import { useSourceControlGitHistory } from './use-git-history'
|
||||
|
||||
type Props = Parameters<typeof useSourceControlGitHistory>[0]
|
||||
|
||||
const props = (overrides: Partial<Props> = {}): Props => ({
|
||||
activeRepoTarget: { kind: 'local' },
|
||||
activeWorktreeId: 'wt-1',
|
||||
worktreePath: '\\\\wsl.localhost\\Ubuntu\\repo',
|
||||
compareBaseRef: 'main',
|
||||
isFolder: false,
|
||||
isBranchVisible: true,
|
||||
isGitHistoryExpanded: true,
|
||||
isGitHistoryVisible: true,
|
||||
worktreeMap: new Map([
|
||||
['wt-1', {}],
|
||||
['wt-2', {}]
|
||||
]),
|
||||
...overrides
|
||||
})
|
||||
|
||||
const wakes = (): unknown[] =>
|
||||
getRuntimeGitHistoryMock.mock.calls.map((call) => call[1].wakeWslDistro)
|
||||
|
||||
beforeEach(() => {
|
||||
getRuntimeGitHistoryMock.mockReset().mockResolvedValue({ items: [] })
|
||||
resetWorkspaceSwitchUserActsForTests()
|
||||
})
|
||||
afterEach(cleanup)
|
||||
|
||||
// E9: showing Commits (or its Refresh) is a user act; a refresh after a Git action is not.
|
||||
// E9: only the user's own act may start a stopped WSL distro for a Commits read.
|
||||
describe('Commits history and a stopped WSL distro', () => {
|
||||
it('wakes for the read that shows Commits, not for a later ref-driven refresh', async () => {
|
||||
getRuntimeGitHistoryMock.mockReset().mockResolvedValue({ items: [] })
|
||||
const { result } = renderHook(() =>
|
||||
useSourceControlGitHistory({
|
||||
activeRepoTarget: { kind: 'local' },
|
||||
activeWorktreeId: 'wt-1',
|
||||
worktreePath: '\\\\wsl.localhost\\Ubuntu\\repo',
|
||||
compareBaseRef: 'main',
|
||||
isFolder: false,
|
||||
isBranchVisible: true,
|
||||
isGitHistoryExpanded: true,
|
||||
isGitHistoryVisible: true,
|
||||
worktreeMap: new Map([['wt-1', {}]])
|
||||
})
|
||||
)
|
||||
it('stays background on a mount or remount with Commits already open', async () => {
|
||||
const first = renderHook(() => useSourceControlGitHistory(props()))
|
||||
await act(async () => {})
|
||||
first.unmount()
|
||||
renderHook(() => useSourceControlGitHistory(props()))
|
||||
await act(async () => {})
|
||||
expect(wakes()).toEqual([undefined, undefined])
|
||||
})
|
||||
|
||||
it('wakes once for the user switching to the workspace, never again on a remount', async () => {
|
||||
noteUserWorkspaceSwitch('wt-1')
|
||||
const first = renderHook(() => useSourceControlGitHistory(props()))
|
||||
await act(async () => {})
|
||||
first.unmount()
|
||||
renderHook(() => useSourceControlGitHistory(props()))
|
||||
await act(async () => {})
|
||||
expect(wakes()).toEqual([true, undefined])
|
||||
})
|
||||
|
||||
it('wakes when the user expands Commits, not when Orca re-shows it or a refresh follows', async () => {
|
||||
const { result, rerender } = renderHook((p: Props) => useSourceControlGitHistory(p), {
|
||||
initialProps: props({ isGitHistoryExpanded: false })
|
||||
})
|
||||
await act(async () => {})
|
||||
rerender(props())
|
||||
await act(async () => {})
|
||||
// Hidden and shown again by Orca (a sidebar re-show), with no switch.
|
||||
rerender(props({ isGitHistoryVisible: false }))
|
||||
rerender(props())
|
||||
await act(async () => {})
|
||||
await act(async () => result.current.refreshGitHistoryRef.current())
|
||||
await act(async () => result.current.refreshGitHistory({ wakeWslDistro: true }))
|
||||
expect(wakes()).toEqual([true, undefined, undefined])
|
||||
})
|
||||
|
||||
expect(getRuntimeGitHistoryMock.mock.calls.map((call) => call[1].wakeWslDistro)).toEqual([
|
||||
true,
|
||||
undefined,
|
||||
true
|
||||
])
|
||||
it("does not take another worktree's restored expanded view as a click", async () => {
|
||||
const { rerender } = renderHook((p: Props) => useSourceControlGitHistory(p), {
|
||||
initialProps: props({ isGitHistoryExpanded: false })
|
||||
})
|
||||
await act(async () => {})
|
||||
rerender(props({ activeWorktreeId: 'wt-2' }))
|
||||
await act(async () => {})
|
||||
expect(wakes()).toEqual([undefined])
|
||||
})
|
||||
|
||||
it("keeps the Refresh button's explicit wake", async () => {
|
||||
const { result } = renderHook(() => useSourceControlGitHistory(props()))
|
||||
await act(async () => {})
|
||||
await act(async () => result.current.refreshGitHistory({ wakeWslDistro: true }))
|
||||
expect(wakes()).toEqual([undefined, true])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,12 +4,15 @@ import type { RuntimeClientTarget } from '../../../../../../shared/runtime-clien
|
||||
import { getConnectionId } from '@/lib/connection-context'
|
||||
import { getRuntimeGitHistory } from '@/runtime/runtime-git-status-client'
|
||||
import type { GitHistoryPanelState } from './git-history-panel'
|
||||
import { takeWorkspaceSwitchWake } from '@/lib/workspace-switch-user-act'
|
||||
|
||||
const EMPTY_GIT_HISTORY_STATE: GitHistoryPanelState = { status: 'idle' }
|
||||
|
||||
/** `wakeWslDistro`: showing Commits or its Refresh, a user act that may start a stopped WSL distro. */
|
||||
/** `wakeWslDistro`: the user opening Commits or its Refresh, a user act that may start a stopped WSL distro. */
|
||||
type HistoryRefresh = { wakeWslDistro?: boolean }
|
||||
const SHOWN_HISTORY_LOAD: HistoryRefresh = { wakeWslDistro: true }
|
||||
// The mounts and re-shows a user's own workspace switch causes land within this window.
|
||||
const SWITCH_MOUNT_WINDOW_MS = 10_000
|
||||
|
||||
/** Cache/prune history per worktree and reject superseded requests; refreshGitHistoryRef lets effects refresh without callback resubscription. */
|
||||
export function useSourceControlGitHistory({
|
||||
@@ -150,13 +153,27 @@ export function useSourceControlGitHistory({
|
||||
refreshGitHistoryRef.current = refreshGitHistory
|
||||
}, [refreshGitHistory])
|
||||
|
||||
// Expanded at mount, or restored with another worktree's view, is not a click: only an expand
|
||||
// within the same worktree counts as the user opening Commits.
|
||||
const lastExpandedRef = useRef({ worktreeId: activeWorktreeId, expanded: isGitHistoryExpanded })
|
||||
useEffect(() => {
|
||||
const last = lastExpandedRef.current
|
||||
const userExpanded =
|
||||
isGitHistoryExpanded && !last.expanded && last.worktreeId === activeWorktreeId
|
||||
lastExpandedRef.current = { worktreeId: activeWorktreeId, expanded: isGitHistoryExpanded }
|
||||
// Defer Git subprocesses until Commits is expanded and visible, especially for large/remote repos.
|
||||
if (!isBranchVisible || !isGitHistoryExpanded || !isGitHistoryVisible) {
|
||||
return
|
||||
}
|
||||
// The user is looking at Commits; refreshes after Git actions stay background (E9).
|
||||
void refreshGitHistoryRef.current(SHOWN_HISTORY_LOAD)
|
||||
// Only the user's own act may start a stopped WSL distro: opening Commits, or switching to this
|
||||
// workspace (once per switch). A remount, restore or Orca's own re-show stays background (E9).
|
||||
const userAct =
|
||||
userExpanded ||
|
||||
(activeWorktreeId !== null &&
|
||||
takeWorkspaceSwitchWake(activeWorktreeId, 'git-history', {
|
||||
withinMs: SWITCH_MOUNT_WINDOW_MS
|
||||
}))
|
||||
void refreshGitHistoryRef.current(userAct ? SHOWN_HISTORY_LOAD : undefined)
|
||||
}, [
|
||||
// History uses compareBaseRef, which can move independently of effectiveBaseRef.
|
||||
activeWorktreeId,
|
||||
|
||||
@@ -219,8 +219,8 @@ describe('useSourceControlGitHistory stale completion', () => {
|
||||
await flush()
|
||||
expect(mocks.getRuntimeGitHistory).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ worktreeId: 'A', worktreePath: '/a' }),
|
||||
// Showing Commits is a user act, so it may start a stopped WSL distro.
|
||||
{ limit: 50, baseRef: 'origin/main', wakeWslDistro: true }
|
||||
// A mount with Commits already open is restored state, not a user act: no WSL wake (E9).
|
||||
{ limit: 50, baseRef: 'origin/main' }
|
||||
)
|
||||
|
||||
await act(async () => {
|
||||
@@ -228,10 +228,10 @@ describe('useSourceControlGitHistory stale completion', () => {
|
||||
})
|
||||
await flush()
|
||||
expect(mocks.getRuntimeGitHistory).toHaveBeenCalledTimes(2)
|
||||
// A base-ref move refetches in the background; it never starts a stopped distro.
|
||||
expect(mocks.getRuntimeGitHistory).toHaveBeenLastCalledWith(expect.anything(), {
|
||||
limit: 50,
|
||||
baseRef: 'origin/dev',
|
||||
wakeWslDistro: true
|
||||
baseRef: 'origin/dev'
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user