From 7724a7f562b9889d46a397b7641a6e26aa45b059 Mon Sep 17 00:00:00 2001 From: Zhifei Li Date: Thu, 4 Jun 2026 23:40:45 -0700 Subject: [PATCH] fix(web): browser back from search results no longer jumps to the agent page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Search results were applied with router.replace, so they never became a history entry — pressing back from results landed on whatever preceded the home page (often /chat, hence 'why does back go to the agent?'). Make ?q= the source of truth: a successful search PUSHES /?q=... as its own entry, and a searchParams effect reacts to back/forward — back to '/' clears results, returning to a ?q= entry re-runs that search. The reset arrow also pushes so back can restore the results. Verified end-to-end with a scripted browser: /chat -> home -> search -> back lands on the clean home, second back returns to /chat. --- web/app/page.tsx | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/web/app/page.tsx b/web/app/page.tsx index 8961786..5332247 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -87,9 +87,13 @@ function SearchPageContent() { addHistory(query) } - // Update URL with query param + // Push the results page as its own history entry so the browser back + // button returns to the clean search page (not whatever preceded it, + // e.g. /chat). lastRunQuery guards the searchParams effect below from + // re-running the search we just did. if (query) { - router.replace(`?q=${encodeURIComponent(query)}`, { scroll: false }) + lastRunQuery.current = query + router.push(`?q=${encodeURIComponent(query)}`, { scroll: false }) } } catch (err) { setError(err instanceof Error ? err.message : "Search failed") @@ -115,17 +119,30 @@ function SearchPageContent() { setSelectedHits(new Set()) setShowCompare(false) setLightboxHit(null) - router.replace("/", { scroll: false }) + router.push("/", { scroll: false }) } - // Auto-search if q param is present on mount + // The URL's ?q= drives search state, so back/forward work naturally: + // arriving at ?q= (mount, forward, or back) runs that search; navigating + // back to "/" clears the results. + const lastRunQuery = React.useRef(null) React.useEffect(() => { - if (initialQuery) { - handleSearchRef.current?.(initialQuery) + const q = searchParams.get("q") + if (q && q !== lastRunQuery.current) { + lastRunQuery.current = q + handleSearchRef.current?.(q) + } else if (!q && lastRunQuery.current) { + lastRunQuery.current = null + setGroups([]) + setAllHits([]) + setResultMeta(null) + setError(null) + setHasSearched(false) + setSelectedHits(new Set()) + setShowCompare(false) + setLightboxHit(null) } - // Only run on mount - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [searchParams]) function handleSelectHit(hit: Hit) { setSelectedHits((prev) => {