From 01394cc6afc473ce9bbcc092b8a3874c3d5eea9f Mon Sep 17 00:00:00 2001 From: OrangerXu Date: Wed, 14 Oct 2026 07:39:35 +0800 Subject: [PATCH] fix(ui): use the configured dark logo in the Connect/Chat navbar The navbar rendered on /ui/connect and /ui/chat computed both logo variants from logoUrl alone, so once any custom logo was configured the dark showed the light logo and UI_LOGO_PATH_DARK / logo_url_dark never appeared there - only the main dashboard's leftnav honored it. The dark variant now uses logoUrlDark with the same precedence the leftnav uses: dark logo, then light logo, then the server default (?theme=dark). Fixes #46316 --- .../src/components/navbar.test.tsx | 37 +++++++++++++++++++ .../src/components/navbar.tsx | 8 +++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/ui/litellm-dashboard/src/components/navbar.test.tsx b/ui/litellm-dashboard/src/components/navbar.test.tsx index 9d80a89f83e..99d239d2956 100644 --- a/ui/litellm-dashboard/src/components/navbar.test.tsx +++ b/ui/litellm-dashboard/src/components/navbar.test.tsx @@ -261,6 +261,43 @@ describe("Navbar", () => { mockUseThemeImpl = () => ({ logoUrl: null }); }); + it("should use the dark logo for the dark variant when one is configured", () => { + // Regression test for #46316: the Connect/Chat navbar used the light + // logo for both variants, so UI_LOGO_PATH_DARK never showed there. + mockUseThemeImpl = () => ({ + logoUrl: "https://example.com/custom-logo.png", + logoUrlDark: "https://example.com/custom-logo-dark.png", + }); + + renderWithProviders(); + + const logoImg = screen.getByAltText("LiteLLM Brand"); + expect(logoImg).toHaveAttribute("src", "https://example.com/custom-logo.png"); + const darkLogoImg = Array.from(document.querySelectorAll("img")).find( + (img) => img.getAttribute("aria-hidden") === "true" + ); + expect(darkLogoImg).toBeDefined(); + expect(darkLogoImg).toHaveAttribute("src", "https://example.com/custom-logo-dark.png"); + + // Reset mock + mockUseThemeImpl = () => ({ logoUrl: null }); + }); + + it("should fall back to the light logo for the dark variant when no dark logo is configured", () => { + mockUseThemeImpl = () => ({ logoUrl: "https://example.com/custom-logo.png" }); + + renderWithProviders(); + + const darkLogoImg = Array.from(document.querySelectorAll("img")).find( + (img) => img.getAttribute("aria-hidden") === "true" + ); + expect(darkLogoImg).toBeDefined(); + expect(darkLogoImg).toHaveAttribute("src", "https://example.com/custom-logo.png"); + + // Reset mock + mockUseThemeImpl = () => ({ logoUrl: null }); + }); + it("should hide user dropdown and notifications on public pages", () => { const publicPageProps = { ...defaultProps, isPublicPage: true }; renderWithProviders(); diff --git a/ui/litellm-dashboard/src/components/navbar.tsx b/ui/litellm-dashboard/src/components/navbar.tsx index 8bc9b06969e..04401532527 100644 --- a/ui/litellm-dashboard/src/components/navbar.tsx +++ b/ui/litellm-dashboard/src/components/navbar.tsx @@ -37,7 +37,7 @@ const Navbar: React.FC = ({ onToggleSidebar, }) => { const baseUrl = getProxyBaseUrl(); - const { logoUrl } = useTheme(); + const { logoUrl, logoUrlDark } = useTheme(); const { data: healthData } = useHealthReadinessDetails(accessToken); const version = healthData?.litellm_version; const disableBouncingIcon = useDisableBouncingIcon(); @@ -45,8 +45,12 @@ const Navbar: React.FC = ({ const { isControlPlane, selectedWorker } = useWorker(); const showWorkerSwitch = isControlPlane && selectedWorker !== null; + // Same precedence as the leftnav: an explicit dark logo wins, then the + // light logo, then the server default (which honors UI_LOGO_PATH_DARK via + // ?theme=dark). Using logoUrl for the dark variant silently dropped the + // dark logo on the Connect/Chat pages (#46316). const imageUrl = logoUrl || `${baseUrl}/get_image`; - const darkImageUrl = logoUrl || `${baseUrl}/get_image?theme=dark`; + const darkImageUrl = logoUrlDark || logoUrl || `${baseUrl}/get_image?theme=dark`; const handleLogout = useLogout(accessToken);