Skip to content

Commit d041cab

Browse files
Redesign Usage breakdown + recent runs with column headers
Replace the ambiguous "runs · cost" dot layout in the By mode/provider/ task-type cards with proper aligned columns (name, runs, cost) under column headers, plus a cost bar per row. Cap and truncate long provider/ model labels (with tooltips) so they no longer overflow. Add header row and a width-capped, truncating route column to the recent runs table. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 4aab674 commit d041cab

1 file changed

Lines changed: 45 additions & 24 deletions

File tree

packages/app/src/pages/Usage.tsx

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,31 @@ export function UsagePage(): React.ReactElement {
3030
</Section>
3131

3232
<div className="grid gap-6 md:grid-cols-3">
33-
<BreakdownTable title="By mode" rows={data.byMode} />
34-
<BreakdownTable title="By provider" rows={data.byProvider} />
35-
<BreakdownTable title="By task type" rows={data.byTaskType} />
33+
<BreakdownTable title="By mode" nameLabel="Mode" rows={data.byMode} />
34+
<BreakdownTable title="By provider" nameLabel="Provider · model" rows={data.byProvider} />
35+
<BreakdownTable title="By task type" nameLabel="Task type" rows={data.byTaskType} />
3636
</div>
3737

3838
<Section title="Recent runs">
39-
<div className="card divide-y divide-border p-0">
40-
{data.recentRuns.slice(0, 25).map((r) => (
41-
<div key={r.id} className="flex items-center gap-3 px-3 py-2 text-sm">
42-
<span className="w-16 shrink-0 text-xs text-muted">{r.mode}</span>
43-
<span className="min-w-0 flex-1 truncate">{r.prompt}</span>
44-
<span className="shrink-0 text-xs text-muted">{r.route}</span>
45-
<span className="w-16 shrink-0 text-right text-xs">{money(r.costUsd)}</span>
46-
<span className="w-16 shrink-0 text-right text-xs text-muted">{timeAgo(r.createdAt)}</span>
47-
</div>
48-
))}
39+
<div className="card p-0 text-sm">
40+
<div className="flex items-center gap-3 border-b border-border px-3 py-2 text-[11px] font-medium uppercase tracking-wide text-muted">
41+
<span className="w-16 shrink-0">Mode</span>
42+
<span className="min-w-0 flex-1">Prompt</span>
43+
<span className="hidden w-48 shrink-0 lg:block">Route</span>
44+
<span className="w-16 shrink-0 text-right">Cost</span>
45+
<span className="w-16 shrink-0 text-right">When</span>
46+
</div>
47+
<div className="divide-y divide-border">
48+
{data.recentRuns.slice(0, 25).map((r) => (
49+
<div key={r.id} className="flex items-center gap-3 px-3 py-2">
50+
<span className="w-16 shrink-0 truncate text-xs text-muted">{r.mode}</span>
51+
<span className="min-w-0 flex-1 truncate" title={r.prompt}>{r.prompt}</span>
52+
<span className="hidden w-48 shrink-0 truncate text-xs text-muted lg:block" title={r.route}>{r.route}</span>
53+
<span className="w-16 shrink-0 text-right text-xs tabular-nums">{money(r.costUsd)}</span>
54+
<span className="w-16 shrink-0 text-right text-xs text-muted">{timeAgo(r.createdAt)}</span>
55+
</div>
56+
))}
57+
</div>
4958
</div>
5059
</Section>
5160
</div>
@@ -61,19 +70,31 @@ function Metric({ label, value }: { label: string; value: string }): React.React
6170
);
6271
}
6372

64-
function BreakdownTable({ title, rows }: { title: string; rows: Breakdown[] }): React.ReactElement {
73+
function BreakdownTable({ title, nameLabel, rows }: { title: string; nameLabel: string; rows: Breakdown[] }): React.ReactElement {
74+
const maxCost = Math.max(1e-9, ...rows.map((r) => r.costUsd));
6575
return (
6676
<Section title={title}>
67-
<div className="card space-y-1">
68-
{rows.length === 0 && <div className="text-sm text-muted"></div>}
69-
{rows.map((r) => (
70-
<div key={r.key} className="flex items-center justify-between text-sm">
71-
<span className="truncate text-muted">{r.label}</span>
72-
<span>
73-
{r.runs} · {money(r.costUsd)}
74-
</span>
75-
</div>
76-
))}
77+
<div className="card p-0 text-sm">
78+
<div className="flex items-center gap-3 border-b border-border px-3 py-2 text-[11px] font-medium uppercase tracking-wide text-muted">
79+
<span className="min-w-0 flex-1 truncate">{nameLabel}</span>
80+
<span className="w-10 shrink-0 text-right">Runs</span>
81+
<span className="w-16 shrink-0 text-right">Cost</span>
82+
</div>
83+
{rows.length === 0 && <div className="px-3 py-3 text-muted">No data yet.</div>}
84+
<div className="divide-y divide-border/60">
85+
{rows.map((r) => (
86+
<div key={r.key} className="px-3 py-2">
87+
<div className="flex items-center gap-3">
88+
<span className="min-w-0 flex-1 truncate" title={r.label}>{r.label}</span>
89+
<span className="w-10 shrink-0 text-right tabular-nums text-muted">{r.runs}</span>
90+
<span className="w-16 shrink-0 text-right tabular-nums">{money(r.costUsd)}</span>
91+
</div>
92+
<div className="mt-1.5 h-1 w-full overflow-hidden rounded-full bg-panel2">
93+
<div className="h-full rounded-full bg-accent/70" style={{ width: `${(r.costUsd / maxCost) * 100}%` }} />
94+
</div>
95+
</div>
96+
))}
97+
</div>
7798
</div>
7899
</Section>
79100
);

0 commit comments

Comments
 (0)