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 <yuneng-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-04-23 12:41:28 +00:00
parent fa9d5ae6d9
commit d5df40b9c4
No known key found for this signature in database

View file

@ -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<EndpointUsageTableProps> = ({ 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<EndpointUsageTableProps> = ({
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<EndpointRow> = [
{
title: "Endpoint",
dataIndex: "endpoint",
key: "endpoint",
render: (text: string) => <span className="font-medium">{text}</span>,
},
{
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<string, string> = {
"0%": "#22c55e",
};
if (successPercentage > 0 && successPercentage < 100) {
strokeColorConfig[`${successPercentage}%`] = "#22c55e";
strokeColorConfig[`${successPercentage + 0.01}%`] = "#ef4444";
}
strokeColorConfig["100%"] = failurePercentage > 0 ? "#ef4444" : "#22c55e";
return (
<div className="flex items-center space-x-3">
<div className="flex-1 relative">
<Progress percent={totalPercentage} size="small" strokeColor={strokeColorConfig} showInfo={false} />
</div>
<div className="flex items-center space-x-2 text-sm min-w-[100px]">
<span className="text-green-600 font-medium">{record.successful_requests.toLocaleString()}</span>
<span className="text-gray-400">/</span>
<span className="text-red-600 font-medium">{record.failed_requests.toLocaleString()}</span>
</div>
</div>
);
},
},
{
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 (
<span
className={
value >= 95
? "text-green-600 font-medium"
: value >= 80
? "text-yellow-600 font-medium"
: "text-red-600 font-medium"
}
>
{successRateStr}%
</span>
);
},
},
{
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 <Table columns={columns} dataSource={dataSource} pagination={false} />;
return (
<div className="border border-border rounded-md overflow-hidden">
<Table>
<TableHeader>
<TableRow>
<TableHead>Endpoint</TableHead>
<TableHead>Successful / Failed</TableHead>
<TableHead>Total Request</TableHead>
<TableHead>Success Rate</TableHead>
<TableHead>Total Tokens</TableHead>
<TableHead>Spend</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rows.map((record) => {
const successPercentage =
record.api_requests > 0
? (record.successful_requests / record.api_requests) * 100
: 0;
const successRateStr = record.successRate.toFixed(2);
return (
<TableRow key={record.key}>
<TableCell className="font-medium">
{record.endpoint}
</TableCell>
<TableCell>
<div className="flex items-center space-x-3">
<div className="flex-1 relative">
<Progress value={successPercentage} className="h-2" />
</div>
<div className="flex items-center space-x-2 text-sm min-w-[100px]">
<span className="text-emerald-600 dark:text-emerald-400 font-medium">
{record.successful_requests.toLocaleString()}
</span>
<span className="text-muted-foreground">/</span>
<span className="text-destructive font-medium">
{record.failed_requests.toLocaleString()}
</span>
</div>
</div>
</TableCell>
<TableCell>
{record.api_requests.toLocaleString()}
</TableCell>
<TableCell>
<span
className={cn(
"font-medium",
record.successRate >= 95
? "text-emerald-600 dark:text-emerald-400"
: record.successRate >= 80
? "text-amber-600 dark:text-amber-400"
: "text-destructive",
)}
>
{successRateStr}%
</span>
</TableCell>
<TableCell>
{record.total_tokens.toLocaleString()}
</TableCell>
<TableCell>
${formatNumberWithCommas(record.spend, 2)}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
};
export default EndpointUsageTable;