[verified] refactor: unify dashboard rate windows

This commit is contained in:
2026-05-09 16:54:32 +09:00
parent c763926b32
commit 1fb40fd5fe
6 changed files with 445 additions and 64 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -30,7 +30,7 @@ import {
import { toast, Toaster } from 'sonner';
import { api } from '@/lib/api';
import { clearToken, getToken, setToken } from '@/lib/storage';
import { flattenNumericMetrics, formatDate, titleizeMetric } from '@/lib/utils';
import { summarizeUsageWindows, formatDate, formatDurationSeconds } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import {
Card,
@@ -568,10 +568,6 @@ function Dashboard() {
onError: (error: Error) => toast.error(error.message),
});
const metricCards = useMemo(() => {
return flattenNumericMetrics(summaryQuery.data?.aggregatedUsage).slice(0, 6);
}, [summaryQuery.data?.aggregatedUsage]);
if (summaryQuery.isLoading || userQuery.isLoading) {
return (
<div className="flex min-h-screen items-center justify-center text-slate-300">
@@ -601,12 +597,27 @@ function Dashboard() {
const summary = summaryQuery.data!;
const user = userQuery.data!;
const firstMetric = metricCards[0]?.value ?? 0;
const secondMetric = metricCards[1]?.value ?? 0;
const progressValue =
firstMetric + secondMetric > 0
? (firstMetric / (firstMetric + secondMetric)) * 100
: 0;
const usageWindows = summarizeUsageWindows(
summary.accounts.map((account) => account.usage),
);
const windowCards = [
{
title: 'Primary window',
tone: 'text-sky-300',
window: usageWindows.primary,
},
{
title: 'Secondary window',
tone: 'text-violet-300',
window: usageWindows.secondary,
},
].filter(
(item): item is {
title: string;
tone: string;
window: NonNullable<typeof usageWindows.primary>;
} => item.window !== null,
);
return (
<div className="mx-auto min-h-screen max-w-7xl px-4 py-5 sm:px-6 lg:px-8">
@@ -647,25 +658,53 @@ function Dashboard() {
<CardTitle>Unified capacity</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-end justify-between gap-4">
{windowCards.length > 0 ? (
<div className="grid gap-4 md:grid-cols-2">
{windowCards.map((item) => {
const usedPercent = item.window.usedPercent;
const progressValue =
usedPercent !== null && usedPercent !== undefined
? Math.max(0, Math.min(100, usedPercent))
: 0;
return (
<div
key={item.title}
className="rounded-2xl border border-white/10 bg-white/4 p-4"
>
<div className="flex items-start justify-between gap-4">
<div>
<div className="text-4xl font-semibold text-white">
{firstMetric.toLocaleString()}
<div className="text-sm text-slate-400">{item.title}</div>
<div className={`mt-2 text-3xl font-semibold ${item.tone}`}>
{usedPercent !== null && usedPercent !== undefined
? `${usedPercent.toFixed(0)}%`
: '—'}
</div>
<div className="mt-1 text-sm text-slate-400">
{titleizeMetric(metricCards[0]?.label ?? 'Primary metric')}
<div className="mt-1 text-xs uppercase tracking-[0.2em] text-slate-500">
{item.window.accountCount
? `Window data from ${item.window.accountCount} account${item.window.accountCount === 1 ? '' : 's'}`
: 'Used'}
</div>
</div>
<div className="text-right">
<div className="text-2xl font-semibold text-slate-100">
{secondMetric.toLocaleString()}
</div>
<div className="mt-1 text-sm text-slate-500">
{titleizeMetric(metricCards[1]?.label ?? 'Secondary metric')}
<div className="text-right text-sm text-slate-400">
{item.window.limitWindowSeconds !== null ? (
<div>{formatDurationSeconds(item.window.limitWindowSeconds)}</div>
) : null}
<div className={item.window.limitWindowSeconds !== null ? 'mt-1' : ''}>
Resets {formatDate(item.window.resetAt)}
</div>
</div>
</div>
<Progress value={progressValue} />
<Progress value={progressValue} className="mt-4" />
</div>
);
})}
</div>
) : (
<div className="rounded-2xl border border-dashed border-white/10 bg-white/3 p-6 text-sm text-slate-400">
No rate-limit window data yet. Connect an OpenAI account and refresh to load Codex usage windows.
</div>
)}
<div className="flex flex-wrap gap-3 text-sm text-slate-400">
<span>Accounts: {summary.totals.totalAccounts}</span>
<span>Healthy: {summary.totals.activeAccounts}</span>
@@ -705,35 +744,6 @@ function Dashboard() {
</div>
</div>
<Card className="mt-6 min-w-0">
<CardHeader>
<CardTitle>Usage metrics</CardTitle>
</CardHeader>
<CardContent className="min-w-0">
{metricCards.length === 0 ? (
<div className="rounded-2xl border border-dashed border-white/10 bg-white/3 p-6 text-sm text-slate-400">
No usage data yet. Connect an OpenAI account and complete the sign-in flow to start refreshing.
</div>
) : (
<div className="grid gap-3 sm:grid-cols-2">
{metricCards.map((metric) => (
<div
key={metric.label}
className="min-w-0 rounded-2xl border border-white/10 bg-white/4 p-4"
>
<div className="text-sm text-slate-400 break-words">
{titleizeMetric(metric.label)}
</div>
<div className="mt-3 text-2xl font-semibold text-white">
{metric.value.toLocaleString()}
</div>
</div>
))}
</div>
)}
</CardContent>
</Card>
<Card className="mt-6">
<CardHeader>
<CardTitle>Connected OpenAI accounts</CardTitle>

View File

@@ -13,6 +13,181 @@ export function formatDate(value: string | null) {
}).format(new Date(value));
}
type UsageWindowSummary = {
usedPercent: number | null;
limitWindowSeconds: number | null;
resetAt: string | null;
};
type AggregatedUsageWindowSummary = UsageWindowSummary & {
accountCount: number;
};
function isRecord(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function toFiniteNumber(value: unknown) {
return typeof value === 'number' && Number.isFinite(value) ? value : null;
}
function getPath(value: unknown, path: string[]) {
let current: unknown = value;
for (const segment of path) {
if (!isRecord(current) || !(segment in current)) {
return null;
}
current = current[segment];
}
return current;
}
function normalizeResetAt(value: unknown) {
if (typeof value === 'string' && value.trim()) {
return value;
}
if (typeof value === 'number' && Number.isFinite(value)) {
return new Date(value * 1000).toISOString();
}
return null;
}
function extractWindow(value: unknown, paths: string[][]): UsageWindowSummary | null {
for (const path of paths) {
const windowValue = getPath(value, path);
if (!isRecord(windowValue)) {
continue;
}
const summary = {
usedPercent: toFiniteNumber(windowValue.used_percent),
limitWindowSeconds:
toFiniteNumber(windowValue.limit_window_seconds) ??
(toFiniteNumber(windowValue.window_minutes) !== null
? toFiniteNumber(windowValue.window_minutes)! * 60
: null),
resetAt: normalizeResetAt(windowValue.reset_at ?? windowValue.resets_at),
};
if (
summary.usedPercent === null &&
summary.limitWindowSeconds === null &&
summary.resetAt === null
) {
continue;
}
return summary;
}
return null;
}
export function extractUsageWindows(value: unknown) {
return {
primary: extractWindow(value, [
['rate_limit', 'primary_window'],
['rate_limits', 'primary'],
['primary_window'],
]),
secondary: extractWindow(value, [
['rate_limit', 'secondary_window'],
['rate_limits', 'secondary'],
['secondary_window'],
]),
};
}
function average(values: number[]) {
if (values.length === 0) {
return null;
}
return values.reduce((sum, value) => sum + value, 0) / values.length;
}
function earliestDate(values: Array<string | null>) {
const validDates = values
.filter((value): value is string => Boolean(value))
.map((value) => ({ value, timestamp: Date.parse(value) }))
.filter((value) => Number.isFinite(value.timestamp))
.sort((left, right) => left.timestamp - right.timestamp);
return validDates[0]?.value ?? null;
}
function summarizeWindowCollection(
windows: Array<UsageWindowSummary | null>,
): AggregatedUsageWindowSummary | null {
const presentWindows = windows.filter(
(window): window is UsageWindowSummary => window !== null,
);
if (presentWindows.length === 0) {
return null;
}
const usedPercentValues = presentWindows
.map((window) => window.usedPercent)
.filter((value): value is number => value !== null);
const limitWindowValues = presentWindows
.map((window) => window.limitWindowSeconds)
.filter((value): value is number => value !== null);
const uniqueLimitWindowValues = [...new Set(limitWindowValues)];
return {
accountCount: presentWindows.length,
usedPercent: average(usedPercentValues),
limitWindowSeconds:
limitWindowValues.length === presentWindows.length &&
uniqueLimitWindowValues.length === 1
? uniqueLimitWindowValues[0]
: null,
resetAt: earliestDate(presentWindows.map((window) => window.resetAt)),
};
}
export function summarizeUsageWindows(values: Array<unknown>) {
const extractedWindows = values.map((value) => extractUsageWindows(value));
return {
primary: summarizeWindowCollection(
extractedWindows.map((windows) => windows.primary),
),
secondary: summarizeWindowCollection(
extractedWindows.map((windows) => windows.secondary),
),
};
}
export function formatDurationSeconds(value: number | null) {
if (!value || value <= 0) {
return 'Unknown window';
}
if (value % 86_400 === 0) {
const days = value / 86_400;
return `${days}d window`;
}
if (value % 3_600 === 0) {
const hours = value / 3_600;
return `${hours}h window`;
}
if (value % 60 === 0) {
const minutes = value / 60;
return `${minutes}m window`;
}
return `${value}s window`;
}
export function flattenNumericMetrics(
value: unknown,
path: string[] = [],

View File

@@ -0,0 +1,20 @@
import { describe, expect, test } from 'bun:test';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
const appSource = readFileSync(join(import.meta.dir, '../src/App.tsx'), 'utf8');
describe('dashboard unified capacity windows', () => {
test('shows primary and secondary windows inside unified capacity and removes usage metrics card', () => {
expect(appSource).toContain('<CardTitle>Unified capacity</CardTitle>');
expect(appSource).toContain('Primary window');
expect(appSource).toContain('Secondary window');
expect(appSource).toContain('const windowCards = [');
expect(appSource).toContain("} => item.window !== null,");
expect(appSource).toContain('item.window.limitWindowSeconds !== null ? (');
expect(appSource).not.toContain('<CardTitle>Usage metrics</CardTitle>');
expect(appSource).not.toContain('flattenNumericMetrics(summaryQuery.data?.aggregatedUsage).slice(0, 6)');
expect(appSource).not.toContain('const firstMetric = metricCards[0]?.value ?? 0;');
expect(appSource).not.toContain('const secondMetric = metricCards[1]?.value ?? 0;');
});
});

View File

@@ -7,8 +7,10 @@ const appSource = readFileSync(join(import.meta.dir, '../src/App.tsx'), 'utf8');
describe('dashboard card copy', () => {
test('removes verbose dashboard card descriptions and keeps concise labels', () => {
expect(appSource).toContain('<CardTitle>Unified capacity</CardTitle>');
expect(appSource).toContain('<CardTitle>Usage metrics</CardTitle>');
expect(appSource).toContain('<CardTitle>Connected OpenAI accounts</CardTitle>');
expect(appSource).toContain('Primary window');
expect(appSource).toContain('Secondary window');
expect(appSource).not.toContain('<CardTitle>Usage metrics</CardTitle>');
expect(appSource).toContain(">Merged by default. Inspect each account below.<");
expect(appSource).not.toContain(
'Fast glance card for the first two numeric metrics extracted from the merged usage payload.',

View File

@@ -5,11 +5,10 @@ import { join } from 'node:path';
const appSource = readFileSync(join(import.meta.dir, '../src/App.tsx'), 'utf8');
describe('mobile overflow guards', () => {
test('usage metrics cards allow long metric labels to wrap on mobile', () => {
expect(appSource).toContain('className="mt-6 min-w-0"');
expect(appSource).toContain('className="grid gap-3 sm:grid-cols-2"');
expect(appSource).toContain('className="min-w-0 rounded-2xl border border-white/10 bg-white/4 p-4"');
expect(appSource).toContain('className="text-sm text-slate-400 break-words"');
test('unified capacity window cards stay in a responsive two-column grid', () => {
expect(appSource).toContain('className="grid gap-4 md:grid-cols-2"');
expect(appSource).toContain('className="rounded-2xl border border-white/10 bg-white/4 p-4"');
expect(appSource).toContain('className="text-sm text-slate-400">{item.title}</div>');
});
test('connected account tabs no longer render a side-by-side payload column', () => {

View File

@@ -0,0 +1,175 @@
import { describe, expect, test } from 'bun:test';
import {
extractUsageWindows,
formatDurationSeconds,
summarizeUsageWindows,
} from '../src/lib/utils';
describe('usage window helpers', () => {
test('extracts primary and secondary windows from codex rate_limit payloads', () => {
const windows = extractUsageWindows({
rate_limit: {
primary_window: {
used_percent: 14,
limit_window_seconds: 18_000,
reset_at: '2026-05-09T12:00:00.000Z',
},
secondary_window: {
used_percent: 19,
limit_window_seconds: 604_800,
reset_at: '2026-05-16T12:00:00.000Z',
},
},
});
expect(windows).toEqual({
primary: {
usedPercent: 14,
limitWindowSeconds: 18_000,
resetAt: '2026-05-09T12:00:00.000Z',
},
secondary: {
usedPercent: 19,
limitWindowSeconds: 604_800,
resetAt: '2026-05-16T12:00:00.000Z',
},
});
});
test('formats canonical codex limit windows into readable labels', () => {
expect(formatDurationSeconds(18_000)).toBe('5h window');
expect(formatDurationSeconds(604_800)).toBe('7d window');
expect(formatDurationSeconds(null)).toBe('Unknown window');
});
test('summarizes windows across multiple account payloads without summing percentages', () => {
const windows = summarizeUsageWindows([
{
rate_limit: {
primary_window: {
used_percent: 20,
limit_window_seconds: 18_000,
reset_at: '2026-05-09T12:00:00.000Z',
},
secondary_window: {
used_percent: 40,
limit_window_seconds: 604_800,
reset_at: '2026-05-16T12:00:00.000Z',
},
},
},
{
rate_limit: {
primary_window: {
used_percent: 60,
limit_window_seconds: 18_000,
reset_at: '2026-05-09T10:00:00.000Z',
},
secondary_window: {
used_percent: 80,
limit_window_seconds: 604_800,
reset_at: '2026-05-15T10:00:00.000Z',
},
},
},
]);
expect(windows).toEqual({
primary: {
accountCount: 2,
usedPercent: 40,
limitWindowSeconds: 18_000,
resetAt: '2026-05-09T10:00:00.000Z',
},
secondary: {
accountCount: 2,
usedPercent: 60,
limitWindowSeconds: 604_800,
resetAt: '2026-05-15T10:00:00.000Z',
},
});
});
test('keeps window summaries null-safe for partial or inconsistent account data', () => {
const windows = summarizeUsageWindows([
{
rate_limit: {
primary_window: {
limit_window_seconds: 18_000,
reset_at: '2026-05-09T12:00:00.000Z',
},
},
},
{
rate_limit: {
primary_window: {
used_percent: 50,
reset_at: '2026-05-09T11:00:00.000Z',
},
secondary_window: {
used_percent: 22,
limit_window_seconds: 604_800,
reset_at: '2026-05-16T12:00:00.000Z',
},
},
},
{
rate_limit: {
secondary_window: {
used_percent: 44,
limit_window_seconds: 86_400,
reset_at: '2026-05-15T12:00:00.000Z',
},
},
},
]);
expect(windows).toEqual({
primary: {
accountCount: 2,
usedPercent: 50,
limitWindowSeconds: null,
resetAt: '2026-05-09T11:00:00.000Z',
},
secondary: {
accountCount: 2,
usedPercent: 33,
limitWindowSeconds: null,
resetAt: '2026-05-15T12:00:00.000Z',
},
});
});
test('ignores empty window shells with no meaningful values', () => {
expect(
extractUsageWindows({
rate_limit: {
primary_window: {},
secondary_window: null,
},
}),
).toEqual({ primary: null, secondary: null });
});
test('falls back to later candidate paths when earlier window shells are empty', () => {
expect(
extractUsageWindows({
rate_limit: {
primary_window: {},
},
primary_window: {
used_percent: 42,
limit_window_seconds: 18_000,
reset_at: '2026-05-09T12:00:00.000Z',
},
}),
).toEqual({
primary: {
usedPercent: 42,
limitWindowSeconds: 18_000,
resetAt: '2026-05-09T12:00:00.000Z',
},
secondary: null,
});
});
});