From f6b20865020026612e05fb51ba8e993fc91d9486 Mon Sep 17 00:00:00 2001 From: Ishaan Date: Fri, 23 Oct 2026 16:55:13 -0700 Subject: [PATCH] fix(chat): recognize the development preview workspace (#48123) --- .../Navbar/ViewSwitcher.integration.test.tsx | 15 +++++++++++++++ .../src/components/Navbar/ViewSwitcher.tsx | 10 ++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.integration.test.tsx b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.integration.test.tsx index a3817e0acdc..e963f77927e 100644 --- a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.integration.test.tsx @@ -56,6 +56,7 @@ describe("ViewSwitcher", () => { setServerRootPath("/"); vi.clearAllMocks(); vi.unstubAllGlobals(); + vi.unstubAllEnvs(); }); it("should render the workspace selector and keep disabled Chat unavailable", async () => { @@ -130,6 +131,20 @@ describe("ViewSwitcher", () => { expect(localStorage.getItem("litellm_plugin_mode")).toBe("metrics"); }); + it.each(["/chat", "/ui/chat", "/ui/chat/models"])( + "should keep Chat identity and gateway navigation at the development route %s", + async (pathname) => { + vi.stubEnv("NODE_ENV", "development"); + state.pathname = pathname; + const user = userEvent.setup(); + renderSwitcher(); + + await user.click(screen.getByRole("button", { name: "Switch workspace, current: Chat" })); + await user.click(await screen.findByRole("menuitem", { name: "AI Gateway" })); + expect(assignSpy).toHaveBeenCalledWith("/"); + }, + ); + it.each(["/ui/moyai", "/ui/moyai/sessions/one"])( "should show Moyai's icon at %s and let users switch to Chat", async (pathname) => { diff --git a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx index 15a21f8b4c2..1f75140a763 100644 --- a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx +++ b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.tsx @@ -20,8 +20,10 @@ const CHAT = "chat"; const MOYAI = "moyai"; type WorkspaceIconName = typeof GATEWAY | typeof CHAT | typeof MOYAI; -function isRoute(pathname: string, href: string): boolean { - return pathname === href || pathname.startsWith(`${href}/`); +function isWorkspaceRoute(pathname: string, workspace: string): boolean { + const routes = [uiHref(workspace)]; + if (process.env.NODE_ENV === "development") routes.push(`/ui/${workspace}`); + return routes.some((route) => pathname === route || pathname.startsWith(`${route}/`)); } function activeWorkspaceFor( @@ -85,8 +87,8 @@ export default function ViewSwitcher({ className, contentClassName }: ViewSwitch const moyaiUrl = (uiSettings?.values?.moyai_url as string | undefined) ?? null; const normalizedPathname = (pathname ?? "").replace(/\/+$/, ""); - const isChatRoute = isRoute(normalizedPathname, uiHref(CHAT)); - const isMoyaiRoute = isRoute(normalizedPathname, uiHref(MOYAI)); + const isChatRoute = isWorkspaceRoute(normalizedPathname, CHAT); + const isMoyaiRoute = isWorkspaceRoute(normalizedPathname, MOYAI); const isStandaloneRoute = isChatRoute || isMoyaiRoute; const { label: activeLabel, icon: activeIcon } = activeWorkspaceFor(