From 95a0c30a05da5dd6d39d573b5641a1ef09ccd443 Mon Sep 17 00:00:00 2001 From: ryan-crabbe-berri Date: Wed, 24 Jun 2026 17:13:10 -0700 Subject: [PATCH] fix(ui): render logos under a custom server_root_path (#31156) The App Router migration moved pages to deeper path segments and the proxy can be mounted under a sub-path (e.g. /litellm behind a reverse proxy). Local logo asset paths were emitted without the server root prefix, so they resolved off the origin root and 404'd. Route every local logo src through a single resolver that prefixes the live server root path and leaves external URLs untouched, fixing provider, guardrail, vector store, callback, MCP and audit-log logos at any route depth and root path. --- .../components/add_margin_form.tsx | 3 +- .../components/add_provider_form.tsx | 3 +- .../components/provider_display_helpers.ts | 3 +- .../SearchTools/CreateSearchTools.tsx | 13 ++-- .../src/components/agents/add_agent_form.tsx | 13 +++- .../src/components/callback_info_helpers.tsx | 2 +- .../guardrails/add_guardrail_form.tsx | 5 +- .../guardrails/edit_guardrail_form.tsx | 3 +- .../guardrails/guardrail_garden_card.tsx | 3 +- .../guardrails/guardrail_garden_data.ts | 2 +- .../guardrails/guardrail_garden_detail.tsx | 3 +- .../guardrails/guardrail_info_helpers.tsx | 8 ++- .../src/components/logging_settings_view.tsx | 5 +- .../components/mcp_tools/MCPLogoSelector.tsx | 5 +- .../components/mcp_tools/ToolTestPanel.tsx | 3 +- .../mcp_tools/create_mcp_server.tsx | 5 +- .../components/mcp_tools/mcp_discovery.tsx | 5 +- .../src/components/mcp_tools/mcp_tools.tsx | 3 +- .../model_add/AddCredentialModal.tsx | 3 +- .../model_add/EditCredentialModal.tsx | 3 +- .../src/components/networking.tsx | 7 ++- .../components/provider_info_helpers.test.tsx | 24 ++++++++ .../src/components/provider_info_helpers.tsx | 6 +- .../src/components/settings.tsx | 8 ++- .../src/components/team/LoggingSettings.tsx | 7 ++- .../CreateVectorStore.tsx | 3 +- .../VectorStoreForm.tsx | 3 +- .../vector_store_info.tsx | 5 +- .../src/components/vector_store_providers.tsx | 6 +- .../src/components/view_logs/audit_logs.tsx | 5 +- .../src/lib/assetPaths.test.ts | 60 +++++++++++++++++++ ui/litellm-dashboard/src/lib/assetPaths.ts | 27 +++++++++ .../src/lib/http/resolveApiBase.ts | 2 +- .../src/lib/serverRootPath.ts | 12 ++++ 34 files changed, 214 insertions(+), 54 deletions(-) create mode 100644 ui/litellm-dashboard/src/lib/assetPaths.test.ts create mode 100644 ui/litellm-dashboard/src/lib/assetPaths.ts create mode 100644 ui/litellm-dashboard/src/lib/serverRootPath.ts diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_margin_form.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_margin_form.tsx index 56b34d6a68b..f2c06387301 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_margin_form.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_margin_form.tsx @@ -3,6 +3,7 @@ import { TextInput, Button } from "@tremor/react"; import { Select as AntdSelect, Form, Tooltip, Radio } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import { Providers, provider_map, providerLogoMap } from "@/components/provider_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import { MarginConfig } from "./types"; import { handleImageError } from "./provider_display_helpers"; @@ -73,7 +74,7 @@ const AddMarginForm: React.FC = ({
{`${providerEnum} handleImageError(e, providerDisplayName)} diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_provider_form.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_provider_form.tsx index 61ba3194607..c4961263533 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_provider_form.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/add_provider_form.tsx @@ -3,6 +3,7 @@ import { TextInput, Button } from "@tremor/react"; import { Select as AntdSelect, Form, Tooltip } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import { Providers, provider_map, providerLogoMap } from "@/components/provider_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import { DiscountConfig } from "./types"; import { handleImageError } from "./provider_display_helpers"; @@ -60,7 +61,7 @@ const AddProviderForm: React.FC = ({
{`${providerEnum} handleImageError(e, providerDisplayName)} diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/provider_display_helpers.ts b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/provider_display_helpers.ts index cd088da09da..5489eb12487 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/provider_display_helpers.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/components/provider_display_helpers.ts @@ -1,4 +1,5 @@ import { Providers, provider_map, providerLogoMap } from "@/components/provider_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; export interface ProviderDisplayInfo { displayName: string; @@ -16,7 +17,7 @@ export const getProviderDisplayInfo = (providerValue: string): ProviderDisplayIn if (enumKey) { const displayName = Providers[enumKey as keyof typeof Providers]; - const logo = providerLogoMap[displayName]; + const logo = resolveLogoSrc(providerLogoMap[displayName]) ?? ""; return { displayName, logo, enumKey }; } diff --git a/ui/litellm-dashboard/src/components/SearchTools/CreateSearchTools.tsx b/ui/litellm-dashboard/src/components/SearchTools/CreateSearchTools.tsx index cf355961d11..a8ed1a5e005 100644 --- a/ui/litellm-dashboard/src/components/SearchTools/CreateSearchTools.tsx +++ b/ui/litellm-dashboard/src/components/SearchTools/CreateSearchTools.tsx @@ -3,8 +3,8 @@ import { InfoCircleOutlined } from "@ant-design/icons"; import { useQuery } from "@tanstack/react-query"; import { Button, TextInput } from "@tremor/react"; import { Form, Input, Modal, Select, Tooltip, Typography } from "antd"; -import Image from "next/image"; import React, { useState } from "react"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import NotificationsManager from "../molecules/notifications_manager"; import { createSearchTool, fetchAvailableSearchProviders } from "../networking"; import SearchConnectionTest from "./SearchConnectionTest"; @@ -13,7 +13,7 @@ import { AvailableSearchProvider, SearchTool } from "./types"; const { TextArea } = Input; // Search provider logos folder path (matches existing provider logo pattern) -const searchProviderLogosFolder = "../ui/assets/logos/"; +const searchProviderLogosFolder = "/ui/assets/logos/"; // Helper function to get logo path for a search provider const getSearchProviderLogo = (providerName: string): string => { @@ -28,12 +28,13 @@ interface SearchProviderLabelProps { const SearchProviderLabel: React.FC = ({ providerName, displayName }) => (
- = ({ visible, onClose, accessTok value={info.agent_type} label={
- + {info.agent_type_display_name}
} >
- {info.agent_type_display_name} + {info.agent_type_display_name}
{info.agent_type_display_name}
{info.description &&
{info.description}
} @@ -942,7 +947,9 @@ const AddAgentForm: React.FC = ({ visible, onClose, accessTok - {selectedLogo && currentStep < 1 && Agent} + {selectedLogo && currentStep < 1 && ( + Agent + )}

Add New Agent

} diff --git a/ui/litellm-dashboard/src/components/callback_info_helpers.tsx b/ui/litellm-dashboard/src/components/callback_info_helpers.tsx index 0334c55f66c..3c6b3829fef 100644 --- a/ui/litellm-dashboard/src/components/callback_info_helpers.tsx +++ b/ui/litellm-dashboard/src/components/callback_info_helpers.tsx @@ -7,7 +7,7 @@ interface CallbackConfig { description: string; } -const asset_logos_folder = "../ui/assets/logos/"; +const asset_logos_folder = "/ui/assets/logos/"; export const CALLBACK_CONFIGS: CallbackConfig[] = [ { diff --git a/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx b/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx index 41a2dd7f67c..4ac4242b8ab 100644 --- a/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/add_guardrail_form.tsx @@ -20,6 +20,7 @@ import { shouldRenderLLMJudgeFields, shouldRenderPIIConfigSettings, } from "./guardrail_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import GuardrailOptionalParams from "./guardrail_optional_params"; import GuardrailProviderFields from "./guardrail_provider_fields"; import LLMJudgeFields from "./llm_judge/LLMJudgeFields"; @@ -689,7 +690,7 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a
{guardrailLogoMap[value] && ( = ({ visible, onClose, a
{guardrailLogoMap[value] && ( = ({
{guardrailLogoMap[value] && ( = ({ src, name }) => { const [hasError, setHasError] = useState(false); @@ -29,7 +30,7 @@ const LogoWithFallback: React.FC<{ src: string; name: string }> = ({ src, name } return ( setHasError(true)} diff --git a/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_data.ts b/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_data.ts index c49eedaac23..f81277f13c3 100644 --- a/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_data.ts +++ b/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_data.ts @@ -16,7 +16,7 @@ export interface GuardrailCardInfo { providerKey?: string; } -const ASSET_PREFIX = "../ui/assets/logos/"; +const ASSET_PREFIX = "/ui/assets/logos/"; export const LITELLM_CONTENT_FILTER_CARDS: GuardrailCardInfo[] = [ { diff --git a/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_detail.tsx b/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_detail.tsx index 00daeeb8f01..c92486bbad9 100644 --- a/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_detail.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/guardrail_garden_detail.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { Button } from "antd"; import { ArrowLeftOutlined } from "@ant-design/icons"; import AddGuardrailForm from "./add_guardrail_form"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import { GUARDRAIL_PRESETS } from "./guardrail_garden_configs"; import { GuardrailCardInfo } from "./guardrail_garden_data"; @@ -60,7 +61,7 @@ const GuardrailDetailView: React.FC = ({ card, onBack, {/* ── Header block (Vertex-style) ── */}
{ diff --git a/ui/litellm-dashboard/src/components/guardrails/guardrail_info_helpers.tsx b/ui/litellm-dashboard/src/components/guardrails/guardrail_info_helpers.tsx index 837d0cf83fc..3ac9fe4087a 100644 --- a/ui/litellm-dashboard/src/components/guardrails/guardrail_info_helpers.tsx +++ b/ui/litellm-dashboard/src/components/guardrails/guardrail_info_helpers.tsx @@ -1,3 +1,5 @@ +import { resolveLogoSrc } from "@/lib/assetPaths"; + // Legacy enum - keeping for backward compatibility export enum GuardrailProviders { PresidioPII = "Presidio PII", @@ -113,7 +115,7 @@ export const shouldRenderLLMJudgeFields = (provider: string | null) => { return guardrail_provider_map[provider] === "llm_as_a_judge"; }; -const asset_logos_folder = "../ui/assets/logos/"; +const asset_logos_folder = "/ui/assets/logos/"; export const guardrailLogoMap: Record = { "Zscaler AI Guard": `${asset_logos_folder}zscaler.svg`, @@ -163,9 +165,9 @@ export const getGuardrailLogoAndName = (guardrailValue: string): { logo: string; // Get the display name from current GuardrailProviders and logo from map const currentProviders = getGuardrailProviders(); const displayName = currentProviders[enumKey as keyof typeof currentProviders]; - const logo = guardrailLogoMap[displayName as keyof typeof guardrailLogoMap]; + const logo = resolveLogoSrc(guardrailLogoMap[displayName as keyof typeof guardrailLogoMap]) ?? ""; - return { logo: logo || "", displayName: displayName || guardrailValue }; + return { logo, displayName: displayName || guardrailValue }; }; /** Tri-state UI value for `litellm_params.skip_system_message_in_guardrail` (inherit = use global). */ diff --git a/ui/litellm-dashboard/src/components/logging_settings_view.tsx b/ui/litellm-dashboard/src/components/logging_settings_view.tsx index aeb83f255bc..5124d98da5d 100644 --- a/ui/litellm-dashboard/src/components/logging_settings_view.tsx +++ b/ui/litellm-dashboard/src/components/logging_settings_view.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Tag } from "antd"; import { CogIcon, BanIcon } from "@heroicons/react/outline"; import { callbackInfo, callback_map, reverse_callback_map } from "./callback_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; interface LoggingConfig { callback_name: string; @@ -68,7 +69,7 @@ export function LoggingSettingsView({
{loggingConfigs.map((config, index) => { const displayName = getLoggingDisplayName(config.callback_name); - const logoUrl = callbackInfo[displayName]?.logo; + const logoUrl = resolveLogoSrc(callbackInfo[displayName]?.logo); return (
{ // Handle both display names and internal values const displayName = reverse_callback_map[callbackName] || callbackName; - const logoUrl = callbackInfo[displayName]?.logo; + const logoUrl = resolveLogoSrc(callbackInfo[displayName]?.logo); return (
= ({ value, onChange }) => {value && (
Selected logo { @@ -96,7 +97,7 @@ const MCPLogoSelector: React.FC = ({ value, onChange }) => style={{ width: 40, height: 40 }} > {logo.name} handleImgError(logo.url)} diff --git a/ui/litellm-dashboard/src/components/mcp_tools/ToolTestPanel.tsx b/ui/litellm-dashboard/src/components/mcp_tools/ToolTestPanel.tsx index e3e84cb7434..a8fbe1c1fbc 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/ToolTestPanel.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/ToolTestPanel.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Button, TextInput } from "@tremor/react"; import { MCPTool, InputSchema, InputSchemaProperty } from "./types"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import { Form, Select, Tooltip } from "antd"; import { InfoCircleOutlined } from "@ant-design/icons"; import NotificationsManager from "../molecules/notifications_manager"; @@ -301,7 +302,7 @@ export function ToolTestPanel({ {tool.mcp_info.logo_url && ( // eslint-disable-next-line @next/next/no-img-element {`${tool.mcp_info.server_name} diff --git a/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx b/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx index ddcc9f65d38..b45c902b9d7 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/create_mcp_server.tsx @@ -29,8 +29,9 @@ import NotificationsManager from "../molecules/notifications_manager"; import { useMcpOAuthFlow } from "@/hooks/useMcpOAuthFlow"; import { useTestMCPConnection } from "@/hooks/useTestMCPConnection"; import { getSecureItem, setSecureItem } from "@/utils/secureStorage"; +import { resolveLogoSrc } from "@/lib/assetPaths"; -const asset_logos_folder = "../ui/assets/logos/"; +const asset_logos_folder = "/ui/assets/logos/"; export const mcpLogoImg = `${asset_logos_folder}mcp_logo.png`; interface CreateMCPServerProps { @@ -586,7 +587,7 @@ const CreateMCPServer: React.FC = ({ )} MCP Logo = ({
MCP Logo = ({ > {server.icon_url ? ( {server.title} {tool.mcp_info.logo_url && ( {`${tool.mcp_info.server_name} diff --git a/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx b/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx index 2324cbdd0e9..b86a379d3d1 100644 --- a/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx +++ b/ui/litellm-dashboard/src/components/model_add/AddCredentialModal.tsx @@ -4,6 +4,7 @@ import type { UploadProps } from "antd/es/upload"; import React, { useState } from "react"; import ProviderSpecificFields from "../add_model/provider_specific_fields"; import { Providers, providerLogoMap } from "../provider_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import { resetCredentialFormOnProviderChange } from "./credential_form_helpers"; const { Link } = Typography; @@ -67,7 +68,7 @@ const AddCredentialsModal: React.FC = ({ open, onCance
{`${providerEnum} { diff --git a/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx b/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx index f504ba7a78a..d087edc1069 100644 --- a/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx +++ b/ui/litellm-dashboard/src/components/model_add/EditCredentialModal.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from "react"; import ProviderSpecificFields from "../add_model/provider_specific_fields"; import { CredentialItem } from "../networking"; import { Providers, providerLogoMap } from "../provider_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import { resetCredentialFormOnProviderChange } from "./credential_form_helpers"; const { Link } = Typography; @@ -100,7 +101,7 @@ export default function EditCredentialsModal({
{`${providerEnum} { diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 3d15aea8fdd..f5bae832e64 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -32,6 +32,9 @@ import NotificationsManager from "./molecules/notifications_manager"; import type { MCPUserEnvVarsStatus } from "./mcp_tools/types"; import { createApiClient, deriveErrorMessage } from "@/lib/http/client"; import { resolveApiBase } from "@/lib/http/resolveApiBase"; +import { serverRootPath, setServerRootPath } from "@/lib/serverRootPath"; + +export { serverRootPath }; export { deriveErrorMessage }; export { ApiError } from "@/lib/http/client"; @@ -46,8 +49,6 @@ const resolveDefaultBase = (fallback: string | null): string | null => ? "http://localhost:4000" : fallback; const defaultProxyBaseUrl = resolveDefaultBase(null); -const defaultServerRootPath = "/"; -export let serverRootPath = defaultServerRootPath; const WORKER_URL_KEY = "litellm_worker_url"; // If a worker URL is in localStorage, use it as the initial proxyBaseUrl. // This survives page navigation and the sessionStorage.clear() in user_dashboard. @@ -92,7 +93,7 @@ const updateProxyBaseUrl = (serverRootPath: string, receivedProxyBaseUrl: string }; const updateServerRootPath = (receivedServerRootPath: string) => { - serverRootPath = receivedServerRootPath; + setServerRootPath(receivedServerRootPath); }; export const getProxyBaseUrl = (): string => { diff --git a/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx b/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx index a73cf699ac8..dbbcc2dcc54 100644 --- a/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx +++ b/ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx @@ -403,3 +403,27 @@ describe("provider_info_helpers", () => { }); }); }); + +describe("getProviderLogoAndName under a custom server_root_path", () => { + afterEach(() => { + vi.resetModules(); + vi.doUnmock("@/lib/serverRootPath"); + }); + + // Regression: under SERVER_ROOT_PATH=/litellm the logo must be requested at + // /litellm/ui/assets/logos/... A bare /ui/... path is served off the root and + // 404s behind the reverse proxy. + it("prefixes the server root path onto the resolved logo", async () => { + vi.resetModules(); + vi.doMock("@/lib/serverRootPath", () => ({ serverRootPath: "/litellm" })); + const { getProviderLogoAndName } = await import("./provider_info_helpers"); + expect(getProviderLogoAndName("openai").logo).toBe("/litellm/ui/assets/logos/openai_small.svg"); + }); + + it("leaves the logo at /ui/... when mounted at the root", async () => { + vi.resetModules(); + vi.doMock("@/lib/serverRootPath", () => ({ serverRootPath: "/" })); + const { getProviderLogoAndName } = await import("./provider_info_helpers"); + expect(getProviderLogoAndName("openai").logo).toBe("/ui/assets/logos/openai_small.svg"); + }); +}); diff --git a/ui/litellm-dashboard/src/components/provider_info_helpers.tsx b/ui/litellm-dashboard/src/components/provider_info_helpers.tsx index 727eebfe951..1fed23dc96d 100644 --- a/ui/litellm-dashboard/src/components/provider_info_helpers.tsx +++ b/ui/litellm-dashboard/src/components/provider_info_helpers.tsx @@ -1,3 +1,5 @@ +import { resolveLogoSrc } from "@/lib/assetPaths"; + export enum Providers { A2A_Agent = "A2A Agent", AI21 = "Ai21", @@ -314,7 +316,7 @@ export const getProviderLogoAndName = (providerValue: string): { logo: string; d // Handle special case for "gemini" provider value if (providerValue.toLowerCase() === "gemini") { const displayName = Providers.Google_AI_Studio; - const logo = providerLogoMap[displayName]; + const logo = resolveLogoSrc(providerLogoMap[displayName]) ?? ""; return { logo, displayName }; } @@ -329,7 +331,7 @@ export const getProviderLogoAndName = (providerValue: string): { logo: string; d // Get the display name from Providers enum and logo from map const displayName = Providers[enumKey as keyof typeof Providers]; - const logo = providerLogoMap[displayName as keyof typeof providerLogoMap]; + const logo = resolveLogoSrc(providerLogoMap[displayName as keyof typeof providerLogoMap]) ?? ""; return { logo, displayName }; }; diff --git a/ui/litellm-dashboard/src/components/settings.tsx b/ui/litellm-dashboard/src/components/settings.tsx index ed45d95222d..bff0dbb35b8 100644 --- a/ui/litellm-dashboard/src/components/settings.tsx +++ b/ui/litellm-dashboard/src/components/settings.tsx @@ -22,6 +22,7 @@ import React, { useEffect, useState } from "react"; import { Button as Button2, Form, Input, Modal, Select, Typography } from "antd"; import EmailSettings from "./email_settings"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import NotificationsManager from "./molecules/notifications_manager"; const { Title, Paragraph } = Typography; @@ -53,7 +54,7 @@ interface genericCallbackParams { litellm_callback_params: string[] | null; // known required params for this callback } -const assetsLogoFolder = "../ui/assets/logos/"; +const assetsLogoFolder = "/ui/assets/logos/"; interface DynamicParamsFieldsProps { params: string[]; @@ -156,10 +157,11 @@ const CallbackSelector: React.FC = ({ > {callbackConfigs.map((callbackConfig) => { const logo = callbackConfig.logo; - const logoSrc = + const logoSrc = resolveLogoSrc( logo && (logo.includes("/") || logo.startsWith("data:") || logo.startsWith("http")) ? logo - : `${assetsLogoFolder}${logo}`; + : `${assetsLogoFolder}${logo}`, + ); return ( diff --git a/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx b/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx index 56d2e23a90c..49602fd5b05 100644 --- a/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx +++ b/ui/litellm-dashboard/src/components/team/LoggingSettings.tsx @@ -6,6 +6,7 @@ import { InfoCircleOutlined } from "@ant-design/icons"; import { Button, Card, TextInput } from "@tremor/react"; import { PlusIcon, TrashIcon, CogIcon, BanIcon } from "@heroicons/react/outline"; import { callbackInfo, callback_map, mapDisplayToInternalNames } from "../callback_info_helpers"; +import { resolveLogoSrc } from "@/lib/assetPaths"; import NumericalInput from "../shared/numerical_input"; const { Option } = Select; @@ -178,7 +179,7 @@ const LoggingSettings: React.FC = ({ optionLabelProp="label" > {allCallbacks.map((callbackName) => { - const logo = callbackInfo[callbackName]?.logo; + const logo = resolveLogoSrc(callbackInfo[callbackName]?.logo); const description = callbackInfo[callbackName]?.description; return (