From 4268ebbe040f344588b55e54df1741cc46452a4b Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Sat, 8 Aug 2026 16:42:58 -0700 Subject: [PATCH] fix(web): usage page loses the cost quality panel, gains a back button Co-Authored-By: Claude Fable 5 --- apps/web/src/components/usage/UsagePage.tsx | 269 ++++++++++---------- 1 file changed, 128 insertions(+), 141 deletions(-) diff --git a/apps/web/src/components/usage/UsagePage.tsx b/apps/web/src/components/usage/UsagePage.tsx index 417e490d37c..91e659ad5dd 100644 --- a/apps/web/src/components/usage/UsagePage.tsx +++ b/apps/web/src/components/usage/UsagePage.tsx @@ -1,5 +1,6 @@ import type { UsageProviderKind } from "@t3tools/contracts"; -import { RefreshCwIcon } from "lucide-react"; +import { useCanGoBack, useNavigate, useRouter } from "@tanstack/react-router"; +import { ArrowLeftIcon, RefreshCwIcon } from "lucide-react"; import { useMemo, useState } from "react"; import { cn } from "../../lib/utils"; @@ -27,6 +28,9 @@ export function UsagePage() { const [windowDays, setWindowDays] = useState(30); const [metric, setMetric] = useState("cost"); const [breakdown, setBreakdown] = useState<"model" | "day">("model"); + const canGoBack = useCanGoBack(); + const navigate = useNavigate(); + const router = useRouter(); // Recomputed only when the window length changes, so a re-render does not // shift the range and refetch every environment. @@ -57,11 +61,27 @@ export function UsagePage() {
-
-

Usage

-

- {formatDayShort(window.sinceDay)} to {formatDayShort(window.untilDay)} -

+
+ +
+

Usage

+

+ {formatDayShort(window.sinceDay)} to {formatDayShort(window.untilDay)} +

+
@@ -222,140 +242,116 @@ export function UsagePage() { /> -
-
-
-

Breakdown

-
- {(["model", "day"] as const).map((option) => ( - - ))} -
+
+
+

Breakdown

+
+ {(["model", "day"] as const).map((option) => ( + + ))}
+
- {breakdown === "model" ? ( - - - - - - - + {breakdown === "model" ? ( +
ModelCostShareTokens
+ + + + + + + + + + {merged.models.length === 0 ? ( + + - - - {merged.models.length === 0 ? ( - - + + + + - ) : ( - merged.models.map((model) => ( - - - - - - - )) - )} - -
ModelCostShareTokens
+ No activity in this window. +
- No activity in this window. + ) : ( + merged.models.map((model) => ( +
+ + + {model.model} + + + {formatUsd(model.costUsd)} + + {formatPercent(model.costShare)} + + {formatTokens(model.totalTokens)}
- - - {model.model} - - - {formatUsd(model.costUsd)} - - {formatPercent(model.costShare)} - - {formatTokens(model.totalTokens)} -
- ) : ( - - - - - {PROVIDER_ORDER.map((provider) => ( - - ))} - - + )) + )} + +
Day - {PROVIDER_LABEL[provider]} - TotalTokens
+ ) : ( + + + + + {PROVIDER_ORDER.map((provider) => ( + + ))} + + + + + + {recentDays.length === 0 ? ( + + - - - {recentDays.length === 0 ? ( - - + + {PROVIDER_ORDER.map((provider) => ( + + ))} + + - ) : ( - recentDays.map((day) => ( - - - {PROVIDER_ORDER.map((provider) => ( - - ))} - - - - )) - )} - -
Day + {PROVIDER_LABEL[provider]} + TotalTokens
+ No activity in this window. +
- No activity in this window. + ) : ( + recentDays.map((day) => ( +
{formatDayShort(day.day)} + {formatUsd(day.byProvider.get(provider)?.costUsd ?? 0)} + + {formatUsd(day.costUsd)} + + {formatTokens(day.totalTokens)}
{formatDayShort(day.day)} - {formatUsd(day.byProvider.get(provider)?.costUsd ?? 0)} - - {formatUsd(day.costUsd)} - - {formatTokens(day.totalTokens)} -
- )} -
- -
-

Cost quality

-
- - - - -
-
+ )) + )} + + + )}
)} @@ -394,15 +390,6 @@ function Metric({ ); } -function QualityRow({ label, value }: { readonly label: string; readonly value: string }) { - return ( -
-
{label}
-
{value}
-
- ); -} - /** * Says plainly when the totals are incomplete: an environment still answering, * one that failed, or one whose transcripts another environment already