import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { getGatewayKeyUsage } from '../../api';
interface Props {
keyId: string;
onClose: () => void;
}
function fmtTokens(n: number): string {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(2)}M`;
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
return n.toLocaleString();
}
/**
* Per-key usage detail. Shows current-month stats (with a progress bar
* vs budget) and a simple bar chart of the last 6-12 months of token
* usage. No external chart library — pure CSS bars keep the UI bundle
* lean.
*/
export function GatewayKeyUsagePanel({ keyId, onClose }: Props) {
const { t } = useTranslation('settings');
const { data, isLoading, error } = useQuery({
queryKey: ['gateway-key-usage', keyId],
queryFn: () => getGatewayKeyUsage(keyId),
staleTime: 5_000,
});
const maxHistTokens = data
? Math.max(1, ...data.history.map(h => h.tokensIn + h.tokensOut))
: 1;
const pctUsed =
data && data.tokensBudget !== null && data.tokensBudget > 0
? Math.min(100, (data.tokensTotal / data.tokensBudget) * 100)
: null;
return (
{t('gateway.usagePanel.title')}
{keyId}
{isLoading &&
Loading…
}
{error && (
{t('gateway.keys.fetchError', { msg: String((error as Error).message ?? error) })}
)}
{data && (
<>
{/* Current period summary */}
{t('gateway.usagePanel.thisMonth', { period: data.currentPeriod })}
Requests: {data.requestsThisMonth.toLocaleString()}
Input tokens
{fmtTokens(data.tokensIn)}
Output tokens
{fmtTokens(data.tokensOut)}
Total / Budget
{fmtTokens(data.tokensTotal)}{' '}
/ {data.tokensBudget !== null ? fmtTokens(data.tokensBudget) : '∞'}
{pctUsed !== null && (
= 100 ? 'bg-red-500' : pctUsed >= 80 ? 'bg-amber-500' : 'bg-accent'}`}
style={{ width: `${pctUsed}%` }}
/>
{pctUsed.toFixed(1)}% used
{data.remaining !== null && ` · ${fmtTokens(data.remaining)} remaining`}
)}
{data.rateLimitRpm !== null && (
Rate limit: {data.rateLimitRpm} rpm
)}
{/* History bars */}
{t('gateway.usagePanel.past12')}
{data.history.length === 0 ? (
{t('gateway.usagePanel.noHistory')}
) : (
{data.history.map((h) => {
const total = h.tokensIn + h.tokensOut;
const widthPct = (total / maxHistTokens) * 100;
return (
{h.period}
{fmtTokens(total)}
{h.requests.toLocaleString()} rq
);
})}
)}
>
)}
);
}