From 0b362379a1ad19d45cb4eee8c4556f0ba91f0ef9 Mon Sep 17 00:00:00 2001 From: Austin Liu Date: Sun, 26 Jul 2026 18:14:26 +0930 Subject: [PATCH] fix(providers): sync provider search query to URL query param (#8624) Add syncSearchToUrl helper in providerPageUtils and hook it up in providers page useEffect so searching updates the ?search= URL param seamlessly. --- .../(dashboard)/dashboard/providers/page.tsx | 5 +++++ .../dashboard/providers/providerPageUtils.ts | 17 +++++++++++++++++ tests/unit/sync-search-to-url-8624.test.ts | 11 +++++++++++ 3 files changed, 33 insertions(+) create mode 100644 tests/unit/sync-search-to-url-8624.test.ts diff --git a/src/app/(dashboard)/dashboard/providers/page.tsx b/src/app/(dashboard)/dashboard/providers/page.tsx index d378122a3582..cac4648d3b91 100644 --- a/src/app/(dashboard)/dashboard/providers/page.tsx +++ b/src/app/(dashboard)/dashboard/providers/page.tsx @@ -30,6 +30,7 @@ import { shouldFilterProviderEntriesForDisplayMode, shouldShowFirstProviderHint, shouldShowProviderSection, + syncSearchToUrl, upsertProviderNodeById, loadProviderPageData, } from "./providerPageUtils"; @@ -239,6 +240,10 @@ export default function ProvidersPage() { } }, [searchParams]); + useEffect(() => { + syncSearchToUrl(searchQuery); + }, [searchQuery]); + useEffect(() => { const fetchData = async () => { try { diff --git a/src/app/(dashboard)/dashboard/providers/providerPageUtils.ts b/src/app/(dashboard)/dashboard/providers/providerPageUtils.ts index 6362149cc36a..31f1abf80629 100644 --- a/src/app/(dashboard)/dashboard/providers/providerPageUtils.ts +++ b/src/app/(dashboard)/dashboard/providers/providerPageUtils.ts @@ -70,6 +70,23 @@ export function shouldShowFirstProviderHint( return connectionCount === 0 && !searchQuery?.trim(); } +export function syncSearchToUrl(searchQuery: string): void { + if (typeof window === "undefined") return; + + const url = new URL(window.location.href); + const currentSearch = url.searchParams.get("search") || ""; + + if (searchQuery.trim()) { + if (currentSearch !== searchQuery) { + url.searchParams.set("search", searchQuery); + window.history.replaceState(window.history.state, "", url.toString()); + } + } else if (url.searchParams.has("search")) { + url.searchParams.delete("search"); + window.history.replaceState(window.history.state, "", url.toString()); + } +} + export function shouldShowProviderSection( category: string, activeCategory: string | null, diff --git a/tests/unit/sync-search-to-url-8624.test.ts b/tests/unit/sync-search-to-url-8624.test.ts new file mode 100644 index 000000000000..5d754cd5f3d6 --- /dev/null +++ b/tests/unit/sync-search-to-url-8624.test.ts @@ -0,0 +1,11 @@ +import { describe, it } from "node:test"; +import assert from "node:assert/strict"; +import { syncSearchToUrl } from "../../src/app/(dashboard)/dashboard/providers/providerPageUtils.ts"; + +describe("syncSearchToUrl (#8624)", () => { + it("does not throw when window is undefined (SSR environment)", () => { + assert.doesNotThrow(() => { + syncSearchToUrl("openai"); + }); + }); +});