fix(app): preserve file search results while loading (#43836)

This commit is contained in:
Brendan Allan
2026-08-21 16:52:45 +08:00
committed by GitHub
parent f357e70779
commit b6a1f95858
3 changed files with 41 additions and 3 deletions
@@ -60,6 +60,39 @@ test("keeps the file-browser sidebar mounted when switching file tabs", async ({
await expect.poll(() => viewport.evaluate((element) => element.scrollTop)).toBe(scrolled) await expect.poll(() => viewport.evaluate((element) => element.scrollTop)).toBe(scrolled)
}) })
test("keeps previous file search results visible while the next search loads", async ({ page }) => {
const searchPending = Promise.withResolvers<void>()
await setup(page, async ({ query }) => {
if (query === "file-0") return ["file-00.ts"]
if (query === "file-7") {
await searchPending.promise
return ["file-79.ts"]
}
return []
})
await page.goto(`/server/${base64Encode(server)}/session/${sessionID}`)
await expectSessionTitle(page, title)
const panel = page.locator("#review-panel")
await panel.getByRole("button", { name: "Open file" }).click()
const filter = panel.getByRole("combobox", { name: "Filter files" })
await filter.fill("file-0")
await expect(panel.getByRole("option", { name: "file-00.ts" })).toBeVisible()
const nextSearch = page.waitForRequest((request) => {
const url = new URL(request.url())
return url.pathname === "/find/file" && url.searchParams.get("query") === "file-7"
})
await filter.fill("file-7")
await nextSearch
await expect(panel.getByRole("option", { name: "file-00.ts" })).toBeVisible()
searchPending.resolve()
await expect(panel.getByRole("option", { name: "file-79.ts" })).toBeVisible()
await expect(panel.getByRole("option", { name: "file-00.ts" })).toBeHidden()
})
type Probed = HTMLElement & { __e2eProbe?: string } type Probed = HTMLElement & { __e2eProbe?: string }
async function writeProbe(page: Page) { async function writeProbe(page: Page) {
@@ -74,7 +107,10 @@ async function readProbe(page: Page) {
.evaluate((el) => (el as Probed).__e2eProbe) .evaluate((el) => (el as Probed).__e2eProbe)
} }
async function setup(page: Page) { async function setup(
page: Page,
findFiles?: (input: { query: string; dirs?: string; limit?: number }) => unknown | Promise<unknown>,
) {
await mockOpenCodeServer(page, { await mockOpenCodeServer(page, {
directory, directory,
project: { project: {
@@ -119,6 +155,7 @@ async function setup(page: Page) {
})) }))
}, },
fileContent: (path) => ({ type: "text", content: `contents:${path}` }), fileContent: (path) => ({ type: "text", content: `contents:${path}` }),
findFiles,
pageMessages: () => ({ items: [] }), pageMessages: () => ({ items: [] }),
}) })
+1 -1
View File
@@ -26,7 +26,7 @@ export interface MockServerConfig {
questions?: unknown[] | (() => unknown[]) questions?: unknown[] | (() => unknown[])
fileList?: (path: string) => unknown | Promise<unknown> fileList?: (path: string) => unknown | Promise<unknown>
fileContent?: (path: string) => unknown | Promise<unknown> fileContent?: (path: string) => unknown | Promise<unknown>
findFiles?: (input: { query: string; dirs?: string; limit?: number }) => unknown findFiles?: (input: { query: string; dirs?: string; limit?: number }) => unknown | Promise<unknown>
sessionStatus?: Record<string, unknown> | (() => Record<string, unknown>) sessionStatus?: Record<string, unknown> | (() => Record<string, unknown>)
} }
@@ -1,5 +1,5 @@
import { createMemo, createSignal, createUniqueId, Show } from "solid-js" import { createMemo, createSignal, createUniqueId, Show } from "solid-js"
import { createQuery } from "@tanstack/solid-query" import { createQuery, keepPreviousData } from "@tanstack/solid-query"
import { Icon } from "@opencode-ai/ui/icon" import { Icon } from "@opencode-ai/ui/icon"
import { SessionFilePanelV2, SessionFilePanelV2Empty } from "@opencode-ai/session-ui/v2/session-file-panel-v2" import { SessionFilePanelV2, SessionFilePanelV2Empty } from "@opencode-ai/session-ui/v2/session-file-panel-v2"
import { SessionReviewV2Sidebar } from "@opencode-ai/session-ui/v2/session-review-v2" import { SessionReviewV2Sidebar } from "@opencode-ai/session-ui/v2/session-review-v2"
@@ -50,6 +50,7 @@ export function SessionFileBrowserTab(props: {
queryKey: ["session-open-file", workspaceKey(), value] as const, queryKey: ["session-open-file", workspaceKey(), value] as const,
enabled: value.length > 0, enabled: value.length > 0,
queryFn: ({ signal }) => file.searchFiles(value, { limit: 200, signal }), queryFn: ({ signal }) => file.searchFiles(value, { limit: 200, signal }),
placeholderData: keepPreviousData,
} }
}) })
const files = createMemo(() => { const files = createMemo(() => {