diff --git a/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js b/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js index 22020ff2..5d64c085 100644 --- a/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js +++ b/src/app/(dashboard)/dashboard/usage/components/OverviewCards.js @@ -9,25 +9,25 @@ const fmtCost = (n) => `$${(n || 0).toFixed(2)}`; export default function OverviewCards({ stats }) { return (
- - Total Requests - {fmt(stats.totalRequests)} + + Total Requests + {fmt(stats.totalRequests)} - - Total Input Tokens - {fmt(stats.totalPromptTokens)} + + Total Input Tokens + {fmt(stats.totalPromptTokens)} - - Cached Tokens - {fmt(stats.totalCachedTokens)} + + Cached Tokens + {fmt(stats.totalCachedTokens)} - - Output Tokens - {fmt(stats.totalCompletionTokens)} + + Output Tokens + {fmt(stats.totalCompletionTokens)} - - Est. Cost - ~{fmtCost(stats.totalCost)} + + Est. Cost + ~{fmtCost(stats.totalCost)} Estimated, not actual billing
diff --git a/src/app/(dashboard)/dashboard/usage/page.js b/src/app/(dashboard)/dashboard/usage/page.js index 075b211a..2b43198b 100644 --- a/src/app/(dashboard)/dashboard/usage/page.js +++ b/src/app/(dashboard)/dashboard/usage/page.js @@ -11,6 +11,7 @@ const PERIODS = [ { value: "7d", label: "7D" }, { value: "30d", label: "30D" }, { value: "60d", label: "60D" }, + { value: "all", label: "All" }, ]; export default function UsagePage() { diff --git a/src/app/api/usage/chart/route.js b/src/app/api/usage/chart/route.js index 063cedd6..0321c3a4 100644 --- a/src/app/api/usage/chart/route.js +++ b/src/app/api/usage/chart/route.js @@ -1,7 +1,7 @@ import { NextResponse } from "next/server"; import { getChartData } from "@/lib/usageDb"; -const VALID_PERIODS = new Set(["today", "24h", "7d", "30d", "60d"]); +const VALID_PERIODS = new Set(["today", "24h", "7d", "30d", "60d", "all"]); export async function GET(request) { try { diff --git a/src/lib/db/repos/usageRepo.js b/src/lib/db/repos/usageRepo.js index 75267847..2f86ff14 100644 --- a/src/lib/db/repos/usageRepo.js +++ b/src/lib/db/repos/usageRepo.js @@ -335,12 +335,12 @@ export async function getUsageHistory(filter = {}) { function loadDaysInRange(adapter, maxDays) { if (maxDays == null) { - return adapter.all(`SELECT dateKey, data FROM usageDaily`); + return adapter.all(`SELECT dateKey, data FROM usageDaily ORDER BY dateKey ASC`); } const today = new Date(); const cutoff = new Date(today.getFullYear(), today.getMonth(), today.getDate() - maxDays + 1); const cutoffKey = `${cutoff.getFullYear()}-${String(cutoff.getMonth() + 1).padStart(2, "0")}-${String(cutoff.getDate()).padStart(2, "0")}`; - return adapter.all(`SELECT dateKey, data FROM usageDaily WHERE dateKey >= ?`, [cutoffKey]); + return adapter.all(`SELECT dateKey, data FROM usageDaily WHERE dateKey >= ? ORDER BY dateKey ASC`, [cutoffKey]); } export async function getUsageStats(period = "all") { @@ -718,9 +718,35 @@ export async function getChartData(period = "7d") { return buckets; } + const labelFn = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); + + if (period === "all") { + const dayRows = loadDaysInRange(db, null); + if (!dayRows.length) return []; + const dayMap = {}; + for (const r of dayRows) dayMap[r.dateKey] = parseJson(r.data, {}); + + const earliest = new Date(dayRows[0].dateKey + "T00:00:00"); + const today = new Date(); + today.setHours(0, 0, 0, 0); + const diffDays = Math.max(1, Math.round((today - earliest) / 86400000) + 1); + + return Array.from({ length: diffDays }, (_, i) => { + const d = new Date(earliest); + d.setDate(d.getDate() + i); + const dateKey = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`; + const dayData = dayMap[dateKey]; + return { + label: labelFn(d), + tokens: dayData ? (dayData.promptTokens || 0) + (dayData.completionTokens || 0) : 0, + cost: dayData ? (dayData.cost || 0) : 0, + requests: dayData ? (dayData.requests || 0) : 0, + }; + }); + } + const bucketCount = period === "7d" ? 7 : period === "30d" ? 30 : 60; const today = new Date(); - const labelFn = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); // Build map of dateKey → day data const dayRows = loadDaysInRange(db, bucketCount); diff --git a/src/shared/components/UsageStats.js b/src/shared/components/UsageStats.js index 093c8b3a..bcac0bad 100644 --- a/src/shared/components/UsageStats.js +++ b/src/shared/components/UsageStats.js @@ -200,6 +200,7 @@ const PERIODS = [ { value: "7d", label: "7D" }, { value: "30d", label: "30D" }, { value: "60d", label: "60D" }, + { value: "all", label: "All" }, ]; export default function UsageStats({ period: periodProp, setPeriod: setPeriodProp, hidePeriodSelector = false } = {}) { @@ -448,7 +449,7 @@ export default function UsageStats({ period: periodProp, setPeriod: setPeriodPro {/* Period selector (hidden when controlled by parent) */} {!hidePeriodSelector && (
-
+
{PERIODS.map((p) => (