fix(app): focus session search when the Home shortcut opens Home (#53761)

Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
This commit is contained in:
opencode-agent[bot]
2026-10-08 11:51:02 +08:00
committed by GitHub
Unverified
parent c9e1ed7080
commit a80ca68c96
4 changed files with 61 additions and 6 deletions
+29 -2
View File
@@ -1,9 +1,9 @@
import { expect, test, type Page } from "@playwright/test"
import { holdRoute, NO_PROVIDER, project, REMOTE_SERVER, seed, sessionHref } from "../utils/app"
import { expectPath, holdRoute, NO_PROVIDER, project, REMOTE_SERVER, seed, sessionHref } from "../utils/app"
import { mockOpenCodeServer } from "../utils/mock-server"
import { fixture, mockStressTimeline } from "../utils/session-fixture"
import { mockRemoteServer } from "../utils/workspace"
import { expectAppVisible } from "../utils/waits"
import { APP_READY_TIMEOUT, expectAppVisible } from "../utils/waits"
test.use({ serviceWorkers: "block" })
@@ -77,6 +77,33 @@ test("the session context menu renames, exports, and deletes a Home session", as
await expect(renamedRow).toBeHidden()
})
test("the Home shortcut focuses session search, and the Home button leaves focus alone", async ({ page }) => {
await mockStressTimeline(page)
await seed(page, {
projects: { local: [{ worktree: fixture.directory, expanded: true }] },
lastProject: { local: fixture.directory },
tabs: [fixture.sourceID],
})
await page.goto(sessionHref(fixture.sourceID))
const editor = page.locator('[data-component="composer-editor"]')
await expect(editor).toBeEditable({ timeout: APP_READY_TIMEOUT })
await editor.click()
await page.keyboard.press("ControlOrMeta+b")
const search = page.getByRole("textbox", { name: /Search sessions/ })
await expect(search).toBeFocused()
await page.keyboard.type("jump")
await expect(page.getByRole("option")).toHaveCount(1)
await expect(page.getByRole("option")).toContainText(fixture.expected.targetTitle)
await page.keyboard.press("ControlOrMeta+b")
await expectPath(page, sessionHref(fixture.sourceID))
await page.getByRole("button", { name: "Home", exact: true }).click()
await expect(search).toHaveValue("")
await expect(search).not.toBeFocused()
})
test("Home shows loaded sessions before the location request resolves", async ({ page }) => {
const location = await holdRoute(page, (url) => url.pathname === "/api/location")
await openHome(page)
+14 -3
View File
@@ -1,10 +1,11 @@
import { useCommand } from "@/shell/commands/command"
import { useLayout } from "@/shell/state/layout"
import { useLanguage } from "@/runtime/i18n/language"
import { serverName } from "@/runtime/server/registry"
import { displayName } from "@opencode/ui/project-avatar"
import { sessionLabel } from "@/session/title"
import { makeEventListener } from "@solid-primitives/event-listener"
import { createMemo, onCleanup } from "solid-js"
import { createMemo, onCleanup, onMount } from "solid-js"
import { createStore } from "solid-js/store"
import type { HomeController } from "../model"
import { homeSessionSearchKey, type HomeSessionRecord, type HomeSessionsController } from "./controller"
@@ -15,12 +16,19 @@ type HomeSessionSearchSource = Pick<HomeSessionsController, "data" | "session">
export function createHomeSessionSearchController(home: HomeController, sessions: HomeSessionSearchSource) {
const command = useCommand()
const language = useLanguage()
const layout = useLayout()
const [state, setState] = createStore({
const [state, setState] = createStore<{
value: string
focused: boolean
highlighted: string
exact: HomeSessionRecord | undefined
lookingUp: boolean
}>({
value: "",
focused: false,
highlighted: "",
exact: undefined as HomeSessionRecord | undefined,
exact: undefined,
lookingUp: false,
})
@@ -78,6 +86,9 @@ export function createHomeSessionSearchController(home: HomeController, sessions
}),
)
onCleanup(() => lookup++)
onMount(() => {
if (layout.home.searchFocus.take()) focus()
})
command.register("home.search", () => [
{
+14
View File
@@ -214,6 +214,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
sessionTabPreview: {},
})
// Opening Home with its shortcut focuses session search, so typing filters immediately.
let homeSearchFocus = false
// Names of other session-scoped stores, e.g. extension storage, so pruning drops them with the layout state.
const [scoped, setScoped, , scopedReady] = persisted(
Persist.global("layout.scoped"),
@@ -355,6 +358,17 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
setSelection(selection: HomeProjectSelection) {
setStore("home", "selection", reconcile(selection))
},
searchFocus: {
request() {
homeSearchFocus = true
},
take() {
const requested = homeSearchFocus
homeSearchFocus = false
return requested
},
},
},
sessionState: {
/** Records a session-scoped store, so pruning a session's layout state drops it too. */
+4 -1
View File
@@ -452,7 +452,10 @@ export function Titlebar(props: { verticalTabs?: { mount?: HTMLElement } }) {
category: language.t("command.category.view"),
keybind: windows() ? "alt+home" : "mod+b",
hidden: true,
onSelect: toggleHome,
onSelect: () => {
if (layout.route().type !== "home") layout.home.searchFocus.request()
toggleHome()
},
},
])