diff --git a/ui/litellm-dashboard/src/components/view_logs/index.test.tsx b/ui/litellm-dashboard/src/components/view_logs/index.test.tsx new file mode 100644 index 00000000000..294dc84761b --- /dev/null +++ b/ui/litellm-dashboard/src/components/view_logs/index.test.tsx @@ -0,0 +1,63 @@ +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; +import { RequestViewer } from "./index"; +import type { LogEntry } from "./columns"; +import type { Row } from "@tanstack/react-table"; + +const baseLogEntry: LogEntry = { + request_id: "chatcmpl-test-id", + api_key: "api-key", + team_id: "team-id", + model: "gpt-4", + model_id: "gpt-4", + call_type: "chat", + spend: 0, + total_tokens: 0, + prompt_tokens: 0, + completion_tokens: 0, + startTime: "2025-11-14T00:00:00Z", + endTime: "2025-11-14T00:00:00Z", + cache_hit: "miss", + duration: 1, + messages: [{ role: "user", content: "hello" }], + response: { status: "ok" }, + metadata: { + status: "success", + additional_usage_values: { + cache_read_input_tokens: 0, + cache_creation_input_tokens: 0, + }, + }, + request_tags: {}, + custom_llm_provider: "openai", + api_base: "https://api.example.com", +}; + +const createRow = (overrides: Partial = {}): Row => + ({ + original: { + ...baseLogEntry, + ...overrides, + }, + }) as unknown as Row; + +describe("Request Viewer", () => { + it("renders the request details heading", () => { + const { getByText } = render(); + expect(getByText("Request Details")).toBeInTheDocument(); + }); + + it("should truncate the request id if it is longer than 64 characters", () => { + const LONG_REQUEST_ID = "a".repeat(128); + const TRUNCATED_REQUEST_ID = `${"a".repeat(64)}...`; + const { getByText } = render( + , + ); + + expect(getByText(TRUNCATED_REQUEST_ID)).toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/view_logs/index.tsx b/ui/litellm-dashboard/src/components/view_logs/index.tsx index fb833bdfca3..04c81d832d6 100644 --- a/ui/litellm-dashboard/src/components/view_logs/index.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/index.tsx @@ -26,6 +26,7 @@ import { Tab, TabGroup, TabList, TabPanels, TabPanel, Switch } from "@tremor/rea import AuditLogs from "./audit_logs"; import { getTimeRangeDisplay } from "./logs_utils"; import { formatNumberWithCommas } from "@/utils/dataUtils"; +import { truncateString } from "@/utils/textUtils"; interface SpendLogsTableProps { accessToken: string | null; @@ -791,11 +792,7 @@ export function RequestViewer({ row }: { row: Row }) { // Extract guardrail information from metadata if available const guardrailInfo = row.original.metadata?.guardrail_information; - const guardrailEntries = Array.isArray(guardrailInfo) - ? guardrailInfo - : guardrailInfo - ? [guardrailInfo] - : []; + const guardrailEntries = Array.isArray(guardrailInfo) ? guardrailInfo : guardrailInfo ? [guardrailInfo] : []; const hasGuardrailData = guardrailEntries.length > 0; // Calculate total masked entities if guardrail data exists @@ -806,18 +803,18 @@ export function RequestViewer({ row }: { row: Row }) { } return ( sum + - Object.values(maskedCounts).reduce( - (acc, count) => (typeof count === "number" ? acc + count : acc), - 0, - ) + Object.values(maskedCounts).reduce((acc, count) => (typeof count === "number" ? acc + count : acc), 0) ); }, 0); - const primaryGuardrailLabel = guardrailEntries.length === 1 - ? guardrailEntries[0]?.guardrail_name ?? "-" - : guardrailEntries.length > 1 - ? `${guardrailEntries.length} guardrails` - : "-"; + const primaryGuardrailLabel = + guardrailEntries.length === 1 + ? guardrailEntries[0]?.guardrail_name ?? "-" + : guardrailEntries.length > 1 + ? `${guardrailEntries.length} guardrails` + : "-"; + + const truncatedRequestId = truncateString(row.original.request_id, 64); return (
@@ -830,7 +827,13 @@ export function RequestViewer({ row }: { row: Row }) {
Request ID: - {row.original.request_id} + {row.original.request_id.length > 64 ? ( + + {truncatedRequestId} + + ) : ( + {row.original.request_id} + )}
Model: