From ec488ecb71041b3ab69a6c21765b3111073ad093 Mon Sep 17 00:00:00 2001 From: Daltonganger Date: Thu, 2 Apr 2026 14:39:39 +0200 Subject: [PATCH] fix(dashboard): show remaining totals in usage donuts --- .../dashboard/components/dashboard-page.tsx | 4 +- frontend/src/features/dashboard/utils.test.ts | 41 +++++++++++++++++++ frontend/src/features/dashboard/utils.ts | 4 ++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/frontend/src/features/dashboard/components/dashboard-page.tsx b/frontend/src/features/dashboard/components/dashboard-page.tsx index 13a8cf27..7ead2743 100644 --- a/frontend/src/features/dashboard/components/dashboard-page.tsx +++ b/frontend/src/features/dashboard/components/dashboard-page.tsx @@ -135,8 +135,8 @@ export function DashboardPage() { diff --git a/frontend/src/features/dashboard/utils.test.ts b/frontend/src/features/dashboard/utils.test.ts index 1e70cb9a..db2f2668 100644 --- a/frontend/src/features/dashboard/utils.test.ts +++ b/frontend/src/features/dashboard/utils.test.ts @@ -2,11 +2,13 @@ import { describe, expect, it } from "vitest"; import { applySecondaryConstraint, + buildDashboardView, buildDepletionView, buildRemainingItems, } from "@/features/dashboard/utils"; import type { RemainingItem } from "@/features/dashboard/utils"; import type { AccountSummary, Depletion } from "@/features/dashboard/schemas"; +import { createDashboardOverview, createDefaultRequestLogs } from "@/test/mocks/factories"; import { formatCompactAccountId } from "@/utils/account-identifiers"; function account(overrides: Partial & Pick): AccountSummary { @@ -248,3 +250,42 @@ describe("buildRemainingItems", () => { expect(items[2].isEmail).toBe(true); }); }); + +describe("buildDashboardView", () => { + it("uses aggregate remaining credits for donut totals", () => { + const overview = createDashboardOverview({ + summary: { + primaryWindow: { + remainingPercent: 63.5, + capacityCredits: 1125, + remainingCredits: 790.5, + resetAt: null, + windowMinutes: 300, + }, + secondaryWindow: { + remainingPercent: 55.2, + capacityCredits: 37800, + remainingCredits: 28350, + resetAt: null, + windowMinutes: 10080, + }, + cost: { + currency: "USD", + totalUsd7d: 1.82, + }, + metrics: { + requests7d: 228, + tokensSecondaryWindow: 45000, + cachedTokensSecondaryWindow: 8200, + errorRate7d: 0.028, + topError: "rate_limit_exceeded", + }, + }, + }); + + const view = buildDashboardView(overview, createDefaultRequestLogs(), false); + + expect(view.primaryUsageTotal).toBe(790.5); + expect(view.secondaryUsageTotal).toBe(28350); + }); +}); diff --git a/frontend/src/features/dashboard/utils.ts b/frontend/src/features/dashboard/utils.ts index f65f90c0..997b5f07 100644 --- a/frontend/src/features/dashboard/utils.ts +++ b/frontend/src/features/dashboard/utils.ts @@ -50,6 +50,8 @@ export type DashboardView = { stats: DashboardStat[]; primaryUsageItems: RemainingItem[]; secondaryUsageItems: RemainingItem[]; + primaryUsageTotal: number; + secondaryUsageTotal: number; requestLogs: RequestLog[]; safeLinePrimary: SafeLineView | null; safeLineSecondary: SafeLineView | null; @@ -223,6 +225,8 @@ export function buildDashboardView( ? applySecondaryConstraint(rawPrimaryItems, secondaryUsageItems) : rawPrimaryItems, secondaryUsageItems, + primaryUsageTotal: overview.summary.primaryWindow.remainingCredits, + secondaryUsageTotal: overview.summary.secondaryWindow?.remainingCredits ?? 0, requestLogs, safeLinePrimary: buildDepletionView(overview.depletionPrimary), safeLineSecondary: buildDepletionView(overview.depletionSecondary),