From d5df40b9c40b25bf87e3bac638d51d98f1e1128d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 12:41:28 +0000 Subject: [PATCH] feat(ui): EndpointUsageTable to shadcn - antd Table/Progress \u2192 shadcn Table/Progress. Success rate and success/fail counts use categorical emerald/amber/destructive palette (already in overrides from prior commits). - Progress bar simplified to a single success-percentage bar since Radix Progress doesn't support multi-stop strokeColor gradients. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang --- .../components/EndpointUsageTable.tsx | 201 +++++++++--------- 1 file changed, 103 insertions(+), 98 deletions(-) diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EndpointUsage/components/EndpointUsageTable.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EndpointUsage/components/EndpointUsageTable.tsx index f5cfb553370..2304b526740 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EndpointUsage/components/EndpointUsageTable.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EndpointUsage/components/EndpointUsageTable.tsx @@ -1,6 +1,14 @@ import React from "react"; -import { Table, Progress } from "antd"; -import type { ColumnsType } from "antd/es/table"; +import { Progress } from "@/components/ui/progress"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { cn } from "@/lib/utils"; import { formatNumberWithCommas } from "@/utils/dataUtils"; import { MetricWithMetadata } from "../../../types"; @@ -19,104 +27,101 @@ interface EndpointRow { successRate: number; } -const EndpointUsageTable: React.FC = ({ endpointData }) => { - const calculateSuccessRate = (successful: number, total: number): number => { - if (total === 0) return 0; - return (successful / total) * 100; - }; +const calculateSuccessRate = (successful: number, total: number): number => { + if (total === 0) return 0; + return (successful / total) * 100; +}; - const dataSource: EndpointRow[] = Object.entries(endpointData).map(([endpoint, data]) => ({ - key: endpoint, - endpoint, - successful_requests: data.metrics.successful_requests, - failed_requests: data.metrics.failed_requests, - api_requests: data.metrics.api_requests, - total_tokens: data.metrics.total_tokens, - spend: data.metrics.spend, - successRate: calculateSuccessRate(data.metrics.successful_requests, data.metrics.api_requests), - })); +const EndpointUsageTable: React.FC = ({ + endpointData, +}) => { + const rows: EndpointRow[] = Object.entries(endpointData).map( + ([endpoint, data]) => ({ + key: endpoint, + endpoint, + successful_requests: data.metrics.successful_requests, + failed_requests: data.metrics.failed_requests, + api_requests: data.metrics.api_requests, + total_tokens: data.metrics.total_tokens, + spend: data.metrics.spend, + successRate: calculateSuccessRate( + data.metrics.successful_requests, + data.metrics.api_requests, + ), + }), + ); - const columns: ColumnsType = [ - { - title: "Endpoint", - dataIndex: "endpoint", - key: "endpoint", - render: (text: string) => {text}, - }, - { - title: "Successful / Failed", - key: "requests", - render: (_: any, record: EndpointRow) => { - const successPercentage = - record.api_requests > 0 ? (record.successful_requests / record.api_requests) * 100 : 0; - const failurePercentage = record.api_requests > 0 ? (record.failed_requests / record.api_requests) * 100 : 0; - const totalPercentage = successPercentage + failurePercentage; - - const strokeColorConfig: Record = { - "0%": "#22c55e", - }; - if (successPercentage > 0 && successPercentage < 100) { - strokeColorConfig[`${successPercentage}%`] = "#22c55e"; - strokeColorConfig[`${successPercentage + 0.01}%`] = "#ef4444"; - } - strokeColorConfig["100%"] = failurePercentage > 0 ? "#ef4444" : "#22c55e"; - - return ( -
-
- -
-
- {record.successful_requests.toLocaleString()} - / - {record.failed_requests.toLocaleString()} -
-
- ); - }, - }, - { - title: "Total Request", - dataIndex: "api_requests", - key: "api_requests", - render: (value: number) => value.toLocaleString(), - }, - { - title: "Success Rate", - dataIndex: "successRate", - key: "successRate", - render: (value: number) => { - const successRateStr = value.toFixed(2); - return ( - = 95 - ? "text-green-600 font-medium" - : value >= 80 - ? "text-yellow-600 font-medium" - : "text-red-600 font-medium" - } - > - {successRateStr}% - - ); - }, - }, - { - title: "Total Tokens", - dataIndex: "total_tokens", - key: "total_tokens", - render: (value: number) => value.toLocaleString(), - }, - { - title: "Spend", - dataIndex: "spend", - key: "spend", - render: (value: number) => `$${formatNumberWithCommas(value, 2)}`, - }, - ]; - - return ; + return ( +
+
+ + + Endpoint + Successful / Failed + Total Request + Success Rate + Total Tokens + Spend + + + + {rows.map((record) => { + const successPercentage = + record.api_requests > 0 + ? (record.successful_requests / record.api_requests) * 100 + : 0; + const successRateStr = record.successRate.toFixed(2); + return ( + + + {record.endpoint} + + +
+
+ +
+
+ + {record.successful_requests.toLocaleString()} + + / + + {record.failed_requests.toLocaleString()} + +
+
+
+ + {record.api_requests.toLocaleString()} + + + = 95 + ? "text-emerald-600 dark:text-emerald-400" + : record.successRate >= 80 + ? "text-amber-600 dark:text-amber-400" + : "text-destructive", + )} + > + {successRateStr}% + + + + {record.total_tokens.toLocaleString()} + + + ${formatNumberWithCommas(record.spend, 2)} + +
+ ); + })} +
+
+ + ); }; export default EndpointUsageTable;