refactor(ui): migrate cost-optimization to shadcn

Replace the antd Tabs, Alert and Collapse on the Cost Optimization page
with the shadcn tabs, a token-styled notice, and the shadcn collapsible.
Markup only; no behaviour or data-fetching change.

Tab panels now use useVisitedTabs with keepMounted so a visited panel
keeps its state across tab switches, matching what antd Tabs did.

The characterisation tests from the previous commit pass unedited
against both the antd and the shadcn markup. Retires the two
no-restricted-imports suppressions these files held.
This commit is contained in:
Yuneng Jiang 2026-07-24 23:05:00 -07:00
parent 2cb1a2a0c0
commit 1ab43be42b
No known key found for this signature in database
3 changed files with 73 additions and 79 deletions

View file

@ -215,21 +215,11 @@
"count": 1
}
},
"src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/app/(dashboard)/cost-optimization/_components/PromptCompressionTab.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/app/(dashboard)/cost-optimization/_components/UsageTab.tsx": {
"no-restricted-imports": {
"count": 1
}
},
"src/app/(dashboard)/cost-tracking/_components/add_margin_form.tsx": {
"local/filename-pascal-case": {
"count": 1

View file

@ -1,9 +1,10 @@
"use client";
import React from "react";
import { PiggyBank } from "lucide-react";
import { Alert, Tabs } from "antd";
import { Info, PiggyBank } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useVisitedTabs } from "@/hooks/useVisitedTabs";
import UsageTab from "./UsageTab";
import PromptCompressionTab from "./PromptCompressionTab";
import AutorouterTab from "./AutorouterTab";
@ -18,29 +19,7 @@ interface CostOptimizationViewProps {
const CostOptimizationView: React.FC<CostOptimizationViewProps> = ({ accessToken, userId, userRole }) => {
const activity = useDailyActivityRange(accessToken, userId, userRole);
const items = [
{
key: "usage",
label: "Usage",
children: <UsageTab accessToken={accessToken} activity={activity} />,
},
{
key: "compression",
label: "Prompt Compression",
children: <PromptCompressionTab accessToken={accessToken} />,
},
{
key: "autorouter",
label: "Autorouter",
children: <AutorouterTab accessToken={accessToken} userId={userId} userRole={userRole} />,
},
{
key: "caching",
label: "Prompt Caching",
children: <PromptCachingTab accessToken={accessToken} activity={activity} />,
},
];
const { onTabChange, hasVisited } = useVisitedTabs("usage");
return (
<div className="w-full space-y-6 p-6">
@ -54,26 +33,53 @@ const CostOptimizationView: React.FC<CostOptimizationViewProps> = ({ accessToken
</p>
</div>
<Alert
type="info"
showIcon
message="This is an experimental dashboard"
description={
<span>
<div role="alert" className="flex gap-2.5 rounded-lg border bg-card px-4 py-3 text-sm">
<Info className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<div>
<p className="font-medium text-foreground">This is an experimental dashboard</p>
<p className="mt-0.5 text-muted-foreground">
Have feedback? Join the discussion{" "}
<a
href="https://github.com/BerriAI/litellm/discussions/32172"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline"
className="underline underline-offset-4 hover:text-foreground"
>
here
</a>
</span>
}
/>
</p>
</div>
</div>
<Tabs defaultActiveKey="usage" items={items} />
<Tabs defaultValue="usage" onValueChange={onTabChange}>
<TabsList variant="line" className="h-auto w-full justify-start rounded-none border-b p-0">
<TabsTrigger value="usage" className="flex-none rounded-none px-4 py-2">
Usage
</TabsTrigger>
<TabsTrigger value="compression" className="flex-none rounded-none px-4 py-2">
Prompt Compression
</TabsTrigger>
<TabsTrigger value="autorouter" className="flex-none rounded-none px-4 py-2">
Autorouter
</TabsTrigger>
<TabsTrigger value="caching" className="flex-none rounded-none px-4 py-2">
Prompt Caching
</TabsTrigger>
</TabsList>
<TabsContent keepMounted={hasVisited("usage")} value="usage" className="pt-4">
<UsageTab accessToken={accessToken} activity={activity} />
</TabsContent>
<TabsContent keepMounted={hasVisited("compression")} value="compression" className="pt-4">
<PromptCompressionTab accessToken={accessToken} />
</TabsContent>
<TabsContent keepMounted={hasVisited("autorouter")} value="autorouter" className="pt-4">
<AutorouterTab accessToken={accessToken} userId={userId} userRole={userRole} />
</TabsContent>
<TabsContent keepMounted={hasVisited("caching")} value="caching" className="pt-4">
<PromptCachingTab accessToken={accessToken} activity={activity} />
</TabsContent>
</Tabs>
</div>
);
};

View file

@ -1,11 +1,12 @@
"use client";
import React, { useEffect, useMemo, useState } from "react";
import { Collapse } from "antd";
import { ChevronRight } from "lucide-react";
import { AreaChart, BarChart, DonutChart, DEFAULT_COLOR_CYCLE } from "@/components/shared/charts";
import AdvancedDatePicker from "@/components/shared/advanced_date_picker";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { getToolSpend, ToolSpendResponse } from "@/components/networking";
import { SpendMetrics } from "@/components/UsagePage/types";
import { formatNumberWithCommas } from "@/utils/dataUtils";
@ -35,38 +36,35 @@ const cachingOf = (m: SpendMetrics): number => m.prompt_caching_savings_spend ??
const savedTokensOf = (m: SpendMetrics): number => m.compression_saved_tokens ?? 0;
const MethodologyNote = () => (
<Collapse
ghost
items={[
{
key: "methodology",
label: <span className="text-sm font-medium">How savings are calculated</span>,
children: (
<div className="space-y-3 text-sm text-muted-foreground">
<p>
Savings are computed for each request when it is logged, using the provider&apos;s reported usage and the
model&apos;s pricing, then summed into a daily rollup. Totals below are read from that rollup over the
selected date range, so the numbers never require a scan of raw request logs.
</p>
<p>
Compression savings are the tokens Headroom removed before the call, priced at the model&apos;s input
rate: <code>compression_saved_tokens * input_cost_per_token</code>
</p>
<p>
Prompt caching savings are the tokens the provider served from cache (Anthropic{" "}
<code>cache_read_input_tokens</code>, or OpenAI-style <code>prompt_tokens_details.cached_tokens</code>),
priced at the discount between the normal input rate and the cache-read rate:{" "}
<code>cache_read_input_tokens * max(input_cost_per_token - cache_read_input_token_cost, 0)</code>
</p>
<p>
Total saved is the sum of both drivers. Models without a separate cache-read price in the pricing map
contribute zero caching savings rather than erroring.
</p>
</div>
),
},
]}
/>
<Collapsible>
<CollapsibleTrigger className="group flex items-center gap-1.5 rounded-md py-1 text-sm font-medium text-foreground hover:text-muted-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none">
<ChevronRight className="size-4 shrink-0 transition-transform group-data-[panel-open]:rotate-90" />
How savings are calculated
</CollapsibleTrigger>
<CollapsibleContent>
<div className="space-y-3 pt-2 pl-[22px] text-sm text-muted-foreground">
<p>
Savings are computed for each request when it is logged, using the provider&apos;s reported usage and the
model&apos;s pricing, then summed into a daily rollup. Totals below are read from that rollup over the
selected date range, so the numbers never require a scan of raw request logs.
</p>
<p>
Compression savings are the tokens Headroom removed before the call, priced at the model&apos;s input rate:{" "}
<code>compression_saved_tokens * input_cost_per_token</code>
</p>
<p>
Prompt caching savings are the tokens the provider served from cache (Anthropic{" "}
<code>cache_read_input_tokens</code>, or OpenAI-style <code>prompt_tokens_details.cached_tokens</code>),
priced at the discount between the normal input rate and the cache-read rate:{" "}
<code>cache_read_input_tokens * max(input_cost_per_token - cache_read_input_token_cost, 0)</code>
</p>
<p>
Total saved is the sum of both drivers. Models without a separate cache-read price in the pricing map
contribute zero caching savings rather than erroring.
</p>
</div>
</CollapsibleContent>
</Collapsible>
);
const SummaryCard = ({ label, value, hint }: { label: string; value: string; hint?: string }) => (