"use client"; /** * Model Breakdown table for Usage analytics (#8769). * Extracted from charts.tsx so sort logic can be fixed/tested without * growing the frozen charts god-file. */ import { useCallback, useMemo, useState } from "react"; import { useTranslations } from "next-intl"; import Card from "../Card"; import { getModelColor } from "@/shared/constants/colors"; import { fmtCompact as fmt, fmtFull, fmtCost } from "@/shared/utils/formatting"; import { nextModelBreakdownSort, sortModelBreakdownRows, withModelBreakdownShare, type ModelBreakdownRow, type ModelBreakdownSortField, type ModelBreakdownSortOrder, } from "./modelBreakdownSort"; interface ModelTableProps { byModel?: ModelBreakdownRow[] | null; summary?: { totalTokens?: number | null } | null; } type Column = { field: ModelBreakdownSortField; labelKey: string; align: "left" | "right"; }; const COLUMNS: Column[] = [ { field: "model", labelKey: "chartModel", align: "left" }, { field: "requests", labelKey: "chartRequests", align: "right" }, { field: "promptTokens", labelKey: "chartInput", align: "right" }, { field: "completionTokens", labelKey: "chartOutput", align: "right" }, { field: "totalTokens", labelKey: "chartTotal", align: "right" }, { field: "cost", labelKey: "chartCost", align: "right" }, ]; function SortIndicator({ active, sortOrder }: { active: boolean; sortOrder: string }) { if (!active) { return ( unfold_more ); } return ( {sortOrder === "asc" ? "expand_less" : "expand_more"} ); } export function ModelTable({ byModel, summary }: ModelTableProps) { const t = useTranslations("analytics"); const [sort, setSort] = useState<{ by: ModelBreakdownSortField; order: ModelBreakdownSortOrder; }>({ by: "totalTokens", order: "desc" }); const toggleSort = useCallback((field: ModelBreakdownSortField) => { setSort((prev) => { const next = nextModelBreakdownSort(prev.by, prev.order, field); return { by: next.sortBy, order: next.sortOrder }; }); }, []); const rowsWithShare = useMemo( () => withModelBreakdownShare(byModel, summary?.totalTokens), [byModel, summary?.totalTokens] ); const sorted = useMemo( () => sortModelBreakdownRows(rowsWithShare, sort.by, sort.order), [rowsWithShare, sort.by, sort.order] ); return (

{t("chartModelBreakdown")}

{COLUMNS.map((col) => ( ))} {sorted.map((m, i) => ( ))}
{t("chartShare")}
{m.model}
{fmtFull(m.requests)} {fmt(m.promptTokens)} {fmt(m.completionTokens)} {fmt(m.totalTokens)} {fmtCost(m.cost)}
{m.pct ?? 0}%
); } export default ModelTable;