"use client"; import { useState, useEffect } from "react"; import { BarChart3 } from "lucide-react"; import type { RuntimeUsage } from "@/shared/types"; import { api } from "@/shared/api"; import { formatTokens, estimateCost, aggregateByDate } from "../utils"; import { TokenCard } from "./shared"; import { ActivityHeatmap, HourlyActivityChart, DailyTokenChart, DailyCostChart, ModelDistributionChart, } from "./charts"; const TIME_RANGES = [ { label: "7d", days: 7 }, { label: "30d", days: 30 }, { label: "90d", days: 90 }, ] as const; type TimeRange = (typeof TIME_RANGES)[number]["days"]; export function UsageSection({ runtimeId }: { runtimeId: string }) { const [usage, setUsage] = useState([]); const [loading, setLoading] = useState(true); const [days, setDays] = useState(30); useEffect(() => { setLoading(true); api .getRuntimeUsage(runtimeId, { days: 90 }) // always fetch 90d, filter client-side .then(setUsage) .catch(() => setUsage([])) .finally(() => setLoading(false)); }, [runtimeId]); if (loading) { return (
Loading usage...
); } if (usage.length === 0) { return (

No usage data yet

); } // Filter by selected time range const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - days); const cutoff = cutoffDate.toISOString().slice(0, 10); const filtered = usage.filter((u) => u.date >= cutoff); // Compute totals const totals = filtered.reduce( (acc, u) => ({ input: acc.input + u.input_tokens, output: acc.output + u.output_tokens, cacheRead: acc.cacheRead + u.cache_read_tokens, cacheWrite: acc.cacheWrite + u.cache_write_tokens, cost: acc.cost + estimateCost(u), }), { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 }, ); const { dailyTokens, dailyCost, modelDist } = aggregateByDate(filtered); // Group by date for the table const byDate = new Map(); for (const u of filtered) { const existing = byDate.get(u.date) ?? []; existing.push(u); byDate.set(u.date, existing); } return (
{/* Time range selector */}
{TIME_RANGES.map((range) => ( ))}
{/* Summary cards */}
{totals.cost > 0 && (
Estimated cost ({days}d):{" "} ${totals.cost.toFixed(2)}
)} {/* Heatmap + Hourly */}
{/* Token & Cost charts */}
{/* Daily breakdown table */}
Date
Model
Input
Output
Cache R
Cache W
{[...byDate.entries()].map(([date, rows]) => rows.map((row, i) => (
{date}
{row.model}
{formatTokens(row.input_tokens)}
{formatTokens(row.output_tokens)}
{formatTokens(row.cache_read_tokens)}
{formatTokens(row.cache_write_tokens)}
)), )}
); }