[Feature] UI - Tag Usage Top Model Table View and Label Fix (#16249)

* Tag Usage Top Model Table View and Label Fix

* Removed unused state
This commit is contained in:
yuneng-jiang 2025-11-04 14:24:43 -08:00 committed by GitHub
parent 4d756a62d9
commit 2ed95e216c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 256 additions and 13 deletions

View file

@ -29,6 +29,7 @@ import { formatNumberWithCommas } from "@/utils/dataUtils";
import { valueFormatterSpend } from "./usage/utils/value_formatters";
import { getProviderLogoAndName } from "./provider_info_helpers";
import { UsageExportHeader } from "./EntityUsageExport";
import TopModelView from "./top_model_view";
interface EntityMetrics {
metrics: {
@ -550,17 +551,7 @@ const EntityUsage: React.FC<EntityUsageProps> = ({
<Col numColSpan={1}>
<Card>
<Title>Top Models</Title>
<BarChart
className="mt-4 h-40"
data={getTopModels()}
index="display_key"
categories={["spend"]}
colors={["cyan"]}
valueFormatter={(value) => `$${formatNumberWithCommas(value, 2)}`}
layout="vertical"
yAxisWidth={200}
showLegend={false}
/>
<TopModelView topModels={getTopModels()} />
</Card>
</Col>

View file

@ -0,0 +1,110 @@
import { render } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import TopKeyView from "./top_key_view";
describe("TopKeyView", () => {
it("should render", () => {
const { container } = render(
<TopKeyView
topKeys={[]}
accessToken={null}
userID={null}
userRole={null}
teams={null}
premiumUser={false}
showTags={false}
/>,
);
expect(container).toBeTruthy();
});
it("should have a table view button", () => {
const { getByText } = render(
<TopKeyView
topKeys={[]}
accessToken={null}
userID={null}
userRole={null}
teams={null}
premiumUser={false}
showTags={false}
/>,
);
expect(getByText("Table View")).toBeInTheDocument();
});
it("should have a chart view", () => {
const { getByText } = render(
<TopKeyView
topKeys={[]}
accessToken={null}
userID={null}
userRole={null}
teams={null}
premiumUser={false}
showTags={false}
/>,
);
expect(getByText("Chart View")).toBeInTheDocument();
});
["Key ID", "Key Alias", "Spend (USD)"].forEach((header) => {
it(`should have a ${header} column`, () => {
const { getByText } = render(
<TopKeyView
topKeys={[]}
accessToken={null}
userID={null}
userRole={null}
teams={null}
premiumUser={false}
showTags={false}
/>,
);
expect(getByText(header)).toBeInTheDocument();
});
});
it("should have a Tags column when showTags is true", () => {
const { getByText } = render(
<TopKeyView
topKeys={[]}
accessToken={null}
userID={null}
userRole={null}
teams={null}
premiumUser={false}
showTags={true}
/>,
);
expect(getByText("Tags")).toBeInTheDocument();
});
it("should show the key's information on the table", () => {
const { getByText } = render(
<TopKeyView
topKeys={[
{
api_key: "key-123",
key_alias: "Test Key",
spend: 100,
tags: [
{ tag: "tag-1", usage: 50 },
{ tag: "tag-2", usage: 30 },
],
},
]}
accessToken="test-token"
userID={null}
userRole={null}
teams={null}
premiumUser={false}
showTags={true}
/>,
);
expect(getByText("Test Key")).toBeInTheDocument();
expect(getByText(/tag-1/)).toBeInTheDocument();
expect(getByText(/tag-2/)).toBeInTheDocument();
expect(getByText("$100.00")).toBeInTheDocument();
});
});

View file

@ -216,9 +216,8 @@ const TopKeyView: React.FC<TopKeyViewProps> = ({
yAxisWidth={120}
tickGap={5}
layout="vertical"
showXAxis={false}
showLegend={false}
valueFormatter={(value) => (value ? `$${formatNumberWithCommas(value, 2)}` : "No Key Alias")}
valueFormatter={(value) => `$${formatNumberWithCommas(value, 2)}`}
onValueChange={(item) => handleKeyClick(item)}
showTooltip={true}
customTooltip={(props) => {

View file

@ -0,0 +1,48 @@
import { render } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import TopModelView from "./top_model_view";
describe("TopModelView", () => {
it("should render", () => {
const { container } = render(<TopModelView topModels={[]} />);
expect(container).toBeTruthy();
});
it("should have a table view button", () => {
const { getByText } = render(<TopModelView topModels={[]} />);
expect(getByText("Table View")).toBeInTheDocument();
});
it("should have a chart view", () => {
const { getByText } = render(<TopModelView topModels={[]} />);
expect(getByText("Chart View")).toBeInTheDocument();
});
["Model", "Spend (USD)", "Successful", "Failed", "Tokens"].forEach((header) => {
it(`should have a ${header} column`, () => {
const { getByText } = render(<TopModelView topModels={[]} />);
expect(getByText(header)).toBeInTheDocument();
});
});
it("should show the model's information on the table", () => {
const { getByText } = render(
<TopModelView
topModels={[
{
key: "gpt-4",
spend: 150.5,
successful_requests: 100,
failed_requests: 5,
tokens: 50000,
},
]}
/>,
);
expect(getByText("gpt-4")).toBeInTheDocument();
expect(getByText("$150.50")).toBeInTheDocument();
expect(getByText("100")).toBeInTheDocument();
expect(getByText("5")).toBeInTheDocument();
expect(getByText("50,000")).toBeInTheDocument();
});
});

View file

@ -0,0 +1,95 @@
import { BarChart } from "@tremor/react";
import { formatNumberWithCommas } from "../utils/dataUtils";
import { useState } from "react";
import { DataTable } from "./view_logs/table";
interface TopModel {
key: string;
spend: number;
successful_requests: number;
failed_requests: number;
tokens: number;
}
interface TopModelViewProps {
topModels: TopModel[];
}
export default function TopModelView({ topModels }: TopModelViewProps) {
const [modelViewMode, setModelViewMode] = useState<"chart" | "table">("table");
const columns = [
{
header: "Model",
accessorKey: "key",
cell: (info: any) => info.getValue() || "-",
},
{
header: "Spend (USD)",
accessorKey: "spend",
cell: (info: any) => {
const value = info.getValue();
return `$${formatNumberWithCommas(value, 2)}`;
},
},
{
header: "Successful",
accessorKey: "successful_requests",
cell: (info: any) => <span className="text-green-600">{info.getValue()?.toLocaleString() || 0}</span>,
},
{
header: "Failed",
accessorKey: "failed_requests",
cell: (info: any) => <span className="text-red-600">{info.getValue()?.toLocaleString() || 0}</span>,
},
{
header: "Tokens",
accessorKey: "tokens",
cell: (info: any) => info.getValue()?.toLocaleString() || 0,
},
];
return (
<>
<div className="mb-4 flex justify-end items-center">
<div className="flex space-x-2">
<button
onClick={() => setModelViewMode("table")}
className={`px-3 py-1 text-sm rounded-md ${modelViewMode === "table" ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-700"}`}
>
Table View
</button>
<button
onClick={() => setModelViewMode("chart")}
className={`px-3 py-1 text-sm rounded-md ${modelViewMode === "chart" ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-700"}`}
>
Chart View
</button>
</div>
</div>
{modelViewMode === "chart" ? (
<div className="relative">
<BarChart
className="mt-4 h-40"
data={topModels}
index="key"
categories={["spend"]}
colors={["cyan"]}
valueFormatter={(value) => `$${formatNumberWithCommas(value, 2)}`}
layout="vertical"
yAxisWidth={200}
showLegend={false}
/>
</div>
) : (
<div className="border rounded-lg overflow-auto">
<DataTable
columns={columns}
data={topModels}
renderSubComponent={() => <></>}
getRowCanExpand={() => false}
/>
</div>
)}
</>
);
}