diff --git a/ui/litellm-dashboard/src/components/view_logs/index.tsx b/ui/litellm-dashboard/src/components/view_logs/index.tsx index 813e610f74e..c44015cd9e7 100644 --- a/ui/litellm-dashboard/src/components/view_logs/index.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/index.tsx @@ -338,15 +338,23 @@ export default function SpendLogsTable({ } } + // Demo drift scores: first 10 rows (most recent) get high drift, rest get low + const DEMO_HIGH_DRIFT = [91, 88, 85, 89, 83, 87, 82, 90, 86, 84]; + const DEMO_LOW_DRIFT = [4, 6, 3, 5, 7, 4, 3, 6, 5, 4]; + const filteredData = searchedLogs - .map((log) => { + .map((log, idx) => { const sessionComposition = log.session_id ? sessionCompositionById[log.session_id] : undefined; + const driftScore = initialKeyAlias + ? (idx < 10 ? DEMO_HIGH_DRIFT[idx % DEMO_HIGH_DRIFT.length] : DEMO_LOW_DRIFT[idx % DEMO_LOW_DRIFT.length]) + : undefined; return { ...log, duration: (Date.parse(log.endTime) - Date.parse(log.startTime)) / 1000, session_llm_count: sessionComposition?.llm ?? undefined, session_mcp_count: sessionComposition?.mcp ?? undefined, + _driftScore: driftScore, onKeyHashClick: (keyHash: string) => setSelectedKeyIdInfoView(keyHash), onSessionClick: (sessionId: string) => { if (sessionId) { @@ -702,18 +710,36 @@ export default function SpendLogsTable({ )} { - setSortBy(newSortBy); - setSortOrder(newSortOrder); - setCurrentPage(1); - }, - })} + columns={[ + ...createColumns({ + sortBy, + sortOrder, + onSortChange: (newSortBy, newSortOrder) => { + setSortBy(newSortBy); + setSortOrder(newSortOrder); + setCurrentPage(1); + }, + }), + ...(initialKeyAlias ? [{ + id: "_driftScore", + header: () => Drift Score, + cell: ({ row }: { row: { original: { _driftScore?: number } } }) => { + const score = row.original._driftScore; + if (score === undefined) return null; + return ( + 50 ? "text-orange-600" : "text-green-600"}`}> + {score}% + + ); + }, + }] : []), + ]} data={filteredData} onRowClick={handleRowClick} isLoading={logs.isLoading} + getRowClassName={(row: { _driftScore?: number }) => + row._driftScore !== undefined && row._driftScore > 50 ? "!bg-orange-50" : "" + } /> diff --git a/ui/litellm-dashboard/src/components/view_logs/table.tsx b/ui/litellm-dashboard/src/components/view_logs/table.tsx index 77cb273d4fe..ad35a84e2c7 100644 --- a/ui/litellm-dashboard/src/components/view_logs/table.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/table.tsx @@ -12,6 +12,7 @@ interface DataTableProps { /** Renders directly in tbody as sibling table rows (used by MCP children) */ renderChildRows?: (props: { row: Row }) => React.ReactNode; getRowCanExpand?: (row: Row) => boolean; + getRowClassName?: (row: TData) => string; isLoading?: boolean; loadingMessage?: string; noDataMessage?: string; @@ -24,6 +25,7 @@ export function DataTable({ renderSubComponent, renderChildRows, getRowCanExpand, + getRowClassName, isLoading = false, loadingMessage = "🚅 Loading logs...", noDataMessage = "No logs found", @@ -71,7 +73,7 @@ export function DataTable({ table.getRowModel().rows.map((row) => ( onRowClick?.(row.original)} > {row.getVisibleCells().map((cell) => (