Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/components/dashboard/chart-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,12 @@ export function formatDuration(ms: number): string {
}
return `${Math.round(ms)}ms`;
}

export function formatCost(usd: number): string {
if (usd === 0) return "$0.00";
if (usd >= 1_000_000) return `$${(usd / 1_000_000).toFixed(2)}M`;
if (usd >= 1_000) return `$${(usd / 1_000).toFixed(2)}K`;
if (usd >= 0.01) return `$${usd.toFixed(2)}`;
// 小于一分时保留四位小数,既能让真实存在的消费显示出来,又不会过长
return `$${usd.toFixed(4)}`;
}
8 changes: 1 addition & 7 deletions src/components/dashboard/leaderboard-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Card, CardContent } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import type { StatsLeaderboardResponse, DistributionItem } from "@/types/api";

import { formatNumber, UPSTREAM_COLORS_DARK } from "./chart-theme";
import { formatCost, formatNumber, UPSTREAM_COLORS_DARK } from "./chart-theme";
import { DashboardLoadingBlock, DashboardLoadingSurface } from "./dashboard-loading";

interface LeaderboardSectionProps {
Expand Down Expand Up @@ -40,12 +40,6 @@ function getTtftClass(ttftMs: number): string {
return "text-status-success";
}

function formatCost(usd: number): string {
if (usd === 0) return "$0.00";
if (usd < 0.01) return `$${usd.toFixed(6)}`;
return `$${usd.toFixed(4)}`;
}

const RANK_ROW_BASE =
"flex items-center gap-3 rounded-cf-sm border-l-2 px-2.5 py-1.5 transition-colors bg-surface-300/42 hover:bg-surface-400/55";

Expand Down
8 changes: 1 addition & 7 deletions src/components/dashboard/stats-cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { Card, CardContent } from "@/components/ui/card";
import { cn } from "@/lib/utils";

import { formatDuration, formatNumber } from "./chart-theme";
import { formatCost, formatDuration, formatNumber } from "./chart-theme";
import { DashboardLoadingBlock, DashboardLoadingSurface } from "./dashboard-loading";

interface StatsCardsProps {
Expand Down Expand Up @@ -52,12 +52,6 @@ function formatCacheRate(rate: number): string {
return `${normalizedRate.toFixed(2)}%`;
}

function formatCost(usd: number): string {
if (usd === 0) return "$0.00";
if (usd < 0.01) return `$${usd.toFixed(6)}`;
return `$${usd.toFixed(4)}`;
}

interface DeltaBadgeProps {
today: number;
yesterday: number;
Expand Down
30 changes: 30 additions & 0 deletions tests/components/dashboard/leaderboard-section.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,36 @@ describe("LeaderboardSection", () => {
expect(screen.getByText("10.0K")).toBeInTheDocument();
});

it("renders costs with two decimals", () => {
render(<LeaderboardSection data={mockData} isLoading={false} />);

expect(screen.getByText("$12.50")).toBeInTheDocument();
expect(screen.getByText("$8.00")).toBeInTheDocument();
expect(screen.getByText("$0.50")).toBeInTheDocument();
});

it("renders sub-cent cost with four decimals", () => {
const data: StatsLeaderboardResponse = {
api_keys: [
{
id: "key-tiny",
name: "Tiny Key",
key_prefix: "sk-tiny",
request_count: 1,
total_tokens: 10,
total_cost_usd: 0.006599,
model_distribution: [],
},
],
upstreams: [],
models: [],
};

render(<LeaderboardSection data={data} isLoading={false} />);

expect(screen.getByText("$0.0066")).toBeInTheDocument();
});

it("renders distribution pie charts with fixed dimensions", () => {
render(<LeaderboardSection data={mockData} isLoading={false} />);

Expand Down
32 changes: 32 additions & 0 deletions tests/components/dashboard/stats-cards.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,38 @@ describe("StatsCards", () => {
});
});

describe("Cost formatting", () => {
it("renders zero cost as $0.00", () => {
render(<StatsCards {...defaultProps} totalCostToday={0} />);

expect(screen.getByText("$0.00")).toBeInTheDocument();
});

it("renders sub-cent cost with four decimals", () => {
render(<StatsCards {...defaultProps} totalCostToday={0.006599} />);

expect(screen.getByText("$0.0066")).toBeInTheDocument();
});

it("renders regular cost with two decimals", () => {
render(<StatsCards {...defaultProps} totalCostToday={12.5} />);

expect(screen.getByText("$12.50")).toBeInTheDocument();
});

it("abbreviates thousand-dollar cost with K suffix", () => {
render(<StatsCards {...defaultProps} totalCostToday={1234.5} />);

expect(screen.getByText("$1.23K")).toBeInTheDocument();
});

it("abbreviates million-dollar cost with M suffix", () => {
render(<StatsCards {...defaultProps} totalCostToday={2_500_000} />);

expect(screen.getByText("$2.50M")).toBeInTheDocument();
});
});

describe("Icons", () => {
it("renders activity icon for requests", () => {
render(
Expand Down
Loading