Files
stack/apps/web/src/components/dashboard/TokenBudget.tsx
Jason Woltje 7581d26567
All checks were successful
ci/woodpecker/push/api Pipeline was successful
ci/woodpecker/push/web Pipeline was successful
Phase 2: Task Ingestion Pipeline (#459) (#460)
Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
2026-02-23 00:54:55 +00:00

118 lines
3.1 KiB
TypeScript

import type { ReactElement } from "react";
import { Card, SectionHeader, ProgressBar, type ProgressBarVariant } from "@mosaic/ui";
import type { TokenBudgetEntry } from "@/lib/api/dashboard";
export interface TokenBudgetProps {
budgets?: TokenBudgetEntry[] | undefined;
}
/* ------------------------------------------------------------------ */
/* Helpers */
/* ------------------------------------------------------------------ */
const VARIANT_CYCLE: ProgressBarVariant[] = ["blue", "teal", "purple", "amber"];
function formatTokenCount(n: number): string {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
if (n >= 1_000) return `${(n / 1_000).toFixed(0)}K`;
return String(n);
}
interface ModelBudgetDisplay {
id: string;
label: string;
usage: string;
value: number;
variant: ProgressBarVariant;
}
function mapBudgetToDisplay(entry: TokenBudgetEntry, index: number): ModelBudgetDisplay {
const percent = entry.limit > 0 ? Math.round((entry.used / entry.limit) * 100) : 0;
const usage =
entry.limit > 0
? `${formatTokenCount(entry.used)} / ${formatTokenCount(entry.limit)}`
: "unlimited";
return {
id: entry.model,
label: entry.model,
usage,
value: percent,
variant: VARIANT_CYCLE[index % VARIANT_CYCLE.length] ?? "blue",
};
}
/* ------------------------------------------------------------------ */
/* Components */
/* ------------------------------------------------------------------ */
interface ModelRowProps {
model: ModelBudgetDisplay;
}
function ModelRow({ model }: ModelRowProps): ReactElement {
return (
<div style={{ marginBottom: 14 }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
marginBottom: 5,
}}
>
<span
style={{
fontSize: "0.8rem",
fontWeight: 600,
color: "var(--text-2)",
fontFamily: "var(--mono)",
}}
>
{model.label}
</span>
<span
style={{
fontSize: "0.72rem",
color: "var(--muted)",
fontFamily: "var(--mono)",
}}
>
{model.usage}
</span>
</div>
<ProgressBar
value={model.value}
variant={model.variant}
label={`${model.label} token usage`}
/>
</div>
);
}
export function TokenBudget({ budgets }: TokenBudgetProps): ReactElement {
const displayModels = budgets ? budgets.map(mapBudgetToDisplay) : [];
return (
<Card>
<SectionHeader title="Token Budget" subtitle="Usage by model" />
<div>
{displayModels.length > 0 ? (
displayModels.map((model) => <ModelRow key={model.id} model={model} />)
) : (
<div
style={{
padding: "24px 0",
textAlign: "center",
fontSize: "0.8rem",
color: "var(--muted)",
}}
>
No budget data
</div>
)}
</div>
</Card>
);
}