mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
fix(dashboard): light-mode backgrounds + aligned savings tables (#1064)
## Description Several dashboard cards and tables hardcoded a dark background (`bg-[#141414]`) that ignored the light theme. The most visible case was the **Agent Usage** section, which rendered black in light mode while every other surface flipped correctly. This converts those hardcoded backgrounds to the theme-aware `bg-card-alt` utility so the whole dashboard responds to the active theme, and tightens table column alignment. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Replace hardcoded `bg-[#141414]` with the `bg-card-alt` utility (`var(--card-alt-bg)`: `#f3f4f6` light / `#141414` dark) across Agent Usage cards, the request-count badge, and per-agent rows. 0 hardcoded darks remain. - Per-model and per-project savings tables: `table-layout:fixed` + explicit `<col>` widths for stable columns. - Recent Requests: switch table markup to a CSS grid so columns align regardless of content length. - Add a per-project savings section (progress bar, Last Active column, empty state). - Single file changed: `headroom/dashboard/templates/dashboard.html`. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ .venv/Scripts/python.exe -m pytest tests/test_dashboard_agent_usage.py -q ======================== 13 passed, 1 warning in 0.89s ======================== $ grep -c "bg-\[#141414\]" headroom/dashboard/templates/dashboard.html 0 # zero hardcoded dark backgrounds remain $ grep -c "bg-card-alt" headroom/dashboard/templates/dashboard.html 8 # all converted to the theme-aware utility ``` ## Real Behavior Proof - Environment: Windows 11, headroom proxy 0.26.0 serving `/dashboard` (template read per-request from disk, no cache). - Exact command / steps: start proxy, open `http://127.0.0.1:8787/dashboard`, toggle light mode, inspect the Agent Usage section. - Observed result: Agent Usage cards (Before/After/Saved/Savings + per-agent rows) now use the light surface (`#f3f4f6`) in light mode and `#141414` in dark mode, matching the rest of the dashboard. Confirmed visually on refresh; `grep` confirms 0 hardcoded darks remain. - Not tested: `ruff`/`mypy` (HTML template, no Python changed); no automated visual-regression test added. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Presentation-only change to a single HTML template; no Python touched, so `ruff`/`mypy` are N/A. No visual-regression test added (none exists for the dashboard); existing `test_dashboard_agent_usage.py` data tests still pass. CHANGELOG not updated (UI fix).
This commit is contained in:
parent
c98728363a
commit
5eae32ba47
1 changed files with 157 additions and 113 deletions
|
|
@ -99,6 +99,9 @@
|
|||
html:not(.dark) .text-cyan-200\/80 { color: #0e7490; }
|
||||
html:not(.dark) .text-cyan-300\/75 { color: #0891b2; }
|
||||
html:not(.dark) .text-violet-300\/75 { color: #7c3aed; }
|
||||
/* Light mode: fix hardcoded dark card backgrounds */
|
||||
.bg-card-alt { background: var(--card-alt-bg); }
|
||||
.hover-bg-surface:hover { background: var(--color-surface); }
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-gray-200 min-h-screen" x-data="dashboard()" x-init="init()">
|
||||
|
|
@ -324,26 +327,26 @@
|
|||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3 text-xs">
|
||||
<span class="text-gray-500" x-text="'Coverage: ' + agentCoverageLabel"></span>
|
||||
<span class="px-2 py-0.5 rounded border border-border bg-[#141414] font-mono text-gray-400"
|
||||
<span class="px-2 py-0.5 rounded border border-border bg-card-alt font-mono text-gray-400"
|
||||
x-text="formatNumber(stats.agent_usage?.totals?.requests || 0) + ' requests'"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-3 mb-5">
|
||||
<div class="rounded-lg border border-border bg-[#141414] p-3">
|
||||
<div class="rounded-lg border border-border bg-card-alt p-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Before</div>
|
||||
<div class="text-2xl font-light tabular-nums" x-text="formatNumber(stats.agent_usage?.totals?.before_tokens || 0)"></div>
|
||||
</div>
|
||||
<div class="rounded-lg border border-border bg-[#141414] p-3">
|
||||
<div class="rounded-lg border border-border bg-card-alt p-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">After</div>
|
||||
<div class="text-2xl font-light tabular-nums text-gray-200" x-text="formatNumber(stats.agent_usage?.totals?.after_tokens || 0)"></div>
|
||||
</div>
|
||||
<div class="rounded-lg border border-border bg-[#141414] p-3">
|
||||
<div class="rounded-lg border border-border bg-card-alt p-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Saved</div>
|
||||
<div class="text-2xl font-light tabular-nums text-accent" x-text="formatNumber(stats.agent_usage?.totals?.tokens_saved || 0)"></div>
|
||||
</div>
|
||||
<div class="rounded-lg border border-border bg-[#141414] p-3">
|
||||
<div class="rounded-lg border border-border bg-card-alt p-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Savings</div>
|
||||
<div class="text-2xl font-light tabular-nums text-emerald-400" x-text="(stats.agent_usage?.totals?.savings_percent || 0).toFixed(1) + '%'"></div>
|
||||
</div>
|
||||
|
|
@ -352,7 +355,7 @@
|
|||
<template x-if="agentRows.length > 0">
|
||||
<div class="space-y-3">
|
||||
<template x-for="agent in agentRows" :key="agent.agent">
|
||||
<div class="rounded-lg border border-border bg-[#141414] p-3">
|
||||
<div class="rounded-lg border border-border bg-card-alt p-3">
|
||||
<div class="grid grid-cols-1 gap-3 lg:grid-cols-[minmax(160px,0.9fr)_minmax(260px,1.5fr)_minmax(260px,1.2fr)] lg:items-center">
|
||||
<div class="min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
|
|
@ -1076,10 +1079,17 @@
|
|||
<span class="text-xs text-gray-500">Exact tokens saved per model</span>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<table class="w-full text-sm" style="table-layout:fixed">
|
||||
<colgroup>
|
||||
<col style="width:40%">
|
||||
<col style="width:12%">
|
||||
<col style="width:18%">
|
||||
<col style="width:18%">
|
||||
<col style="width:12%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="text-left text-xs text-gray-500 uppercase tracking-wide">
|
||||
<th class="px-4 py-3 font-medium">Model</th>
|
||||
<tr class="text-xs text-gray-500 uppercase tracking-wide">
|
||||
<th class="px-4 py-3 font-medium text-left">Model</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Requests</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Tokens Saved</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Tokens Sent</th>
|
||||
|
|
@ -1089,14 +1099,14 @@
|
|||
<tbody class="divide-y divide-border">
|
||||
<template x-for="[model, info] in Object.entries(stats.cost?.per_model || {})" :key="model">
|
||||
<tr class="hover:bg-border/30 transition-colors">
|
||||
<td class="px-4 py-3">
|
||||
<td class="px-4 py-3 text-left">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs" x-text="truncateModel(model)"></span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right font-mono" x-text="info.requests"></td>
|
||||
<td class="px-4 py-3 text-right font-mono text-accent" x-text="formatNumber(info.tokens_saved)"></td>
|
||||
<td class="px-4 py-3 text-right font-mono" x-text="formatNumber(info.tokens_sent)"></td>
|
||||
<td class="px-4 py-3 text-right font-mono tabular-nums" x-text="info.requests"></td>
|
||||
<td class="px-4 py-3 text-right font-mono tabular-nums text-accent" x-text="formatNumber(info.tokens_saved)"></td>
|
||||
<td class="px-4 py-3 text-right font-mono tabular-nums" x-text="formatNumber(info.tokens_sent)"></td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<span class="text-accent font-mono" x-text="info.reduction_pct.toFixed(1) + '%'"></span>
|
||||
<span class="text-accent font-mono tabular-nums" x-text="info.reduction_pct.toFixed(1) + '%'"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
|
@ -1107,42 +1117,78 @@
|
|||
</template>
|
||||
|
||||
<!-- Per-Project Savings Breakdown -->
|
||||
<template x-if="Object.keys(stats.savings?.per_project || {}).length > 0">
|
||||
<div class="bg-surface rounded-lg border border-border overflow-hidden mb-6">
|
||||
<div class="px-4 py-3 border-b border-border flex justify-between items-center">
|
||||
<div class="bg-surface rounded-lg border border-border overflow-hidden mb-6">
|
||||
<div class="px-4 py-3 border-b border-border flex justify-between items-center">
|
||||
<div>
|
||||
<span class="text-sm font-medium text-gray-300">Per-Project Savings</span>
|
||||
<span class="text-xs text-gray-500">Lifetime totals — all time</span>
|
||||
<div class="text-xs text-gray-500 mt-0.5">Lifetime totals — attributed requests only</div>
|
||||
</div>
|
||||
<span class="text-xs text-gray-500 font-mono"
|
||||
x-text="Object.keys(stats.savings?.per_project || {}).length + ' project(s)'"></span>
|
||||
</div>
|
||||
|
||||
<!-- Empty state: no project data yet -->
|
||||
<template x-if="Object.keys(stats.savings?.per_project || {}).length === 0">
|
||||
<div class="px-4 py-8 text-center">
|
||||
<div class="text-xs text-gray-500 mb-3">No per-project data yet.</div>
|
||||
<div class="text-xs text-gray-600 font-mono leading-relaxed">
|
||||
Add to each project's <span class="text-gray-400">.claude/settings.local.json</span>:<br>
|
||||
<span class="text-accent">ANTHROPIC_BASE_URL: http://127.0.0.1:8787/p/<project-name></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Project rows -->
|
||||
<template x-if="Object.keys(stats.savings?.per_project || {}).length > 0">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<table class="w-full text-sm" style="table-layout:fixed">
|
||||
<colgroup>
|
||||
<col style="width:25%">
|
||||
<col style="width:10%">
|
||||
<col style="width:15%">
|
||||
<col style="width:12%">
|
||||
<col style="width:18%">
|
||||
<col style="width:20%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="text-left text-xs text-gray-500 uppercase tracking-wide">
|
||||
<th class="px-4 py-3 font-medium">Project</th>
|
||||
<tr class="text-xs text-gray-500 uppercase tracking-wide">
|
||||
<th class="px-4 py-3 font-medium text-left">Project</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Requests</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Tokens Saved</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Saved $</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Savings %</th>
|
||||
<th class="px-4 py-3 font-medium text-right hidden md:table-cell">Last Active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border">
|
||||
<template x-for="[project, info] in Object.entries(stats.savings?.per_project || {})" :key="project">
|
||||
<tr class="hover:bg-border/30 transition-colors">
|
||||
<td class="px-4 py-3">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs" x-text="project"></span>
|
||||
<td class="px-4 py-3 text-left">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs font-mono" x-text="project"></span>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right font-mono" x-text="info.requests"></td>
|
||||
<td class="px-4 py-3 text-right font-mono text-accent" x-text="formatNumber(info.tokens_saved)"></td>
|
||||
<td class="px-4 py-3 text-right font-mono text-emerald-400" x-text="'$' + formatCurrency(info.compression_savings_usd || 0)"></td>
|
||||
<td class="px-4 py-3 text-right font-mono tabular-nums" x-text="info.requests"></td>
|
||||
<td class="px-4 py-3 text-right font-mono tabular-nums text-accent" x-text="formatNumber(info.tokens_saved)"></td>
|
||||
<td class="px-4 py-3 text-right font-mono tabular-nums text-emerald-400"
|
||||
x-text="'$' + formatCurrency(info.compression_savings_usd || 0)"></td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<span class="text-accent font-mono" x-text="(info.savings_percent || 0).toFixed(1) + '%'"></span>
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<div class="w-16 h-1.5 bg-border rounded-full overflow-hidden">
|
||||
<div class="h-full bg-accent rounded-full"
|
||||
:style="'width:' + Math.min(info.savings_percent || 0, 100) + '%'"></div>
|
||||
</div>
|
||||
<span class="text-accent font-mono tabular-nums text-xs w-10 text-right"
|
||||
x-text="(info.savings_percent || 0).toFixed(1) + '%'"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-right text-xs text-gray-500 font-mono hidden md:table-cell"
|
||||
x-text="info.last_activity_at ? new Date(info.last_activity_at).toLocaleString() : '—'"></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Recent Requests Table (with expandable rows) -->
|
||||
<div class="bg-surface rounded-lg border border-border overflow-hidden">
|
||||
|
|
@ -1151,98 +1197,96 @@
|
|||
<span class="text-xs text-gray-500">Last 10 — click row to expand</span>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="text-left text-xs text-gray-500 uppercase tracking-wide">
|
||||
<th class="px-4 py-3 font-medium w-6"></th>
|
||||
<th class="px-4 py-3 font-medium">Time</th>
|
||||
<th class="px-4 py-3 font-medium">Model</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Input</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Output</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Saved</th>
|
||||
<th class="px-4 py-3 font-medium text-right">Latency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border">
|
||||
<div>
|
||||
<!-- Header -->
|
||||
<div class="grid text-xs text-gray-500 uppercase tracking-wide border-b border-border"
|
||||
style="grid-template-columns: 2rem 12fr 22fr 15fr 12fr 10fr 14fr">
|
||||
<div class="px-2 py-3"></div>
|
||||
<div class="px-4 py-3 font-medium">Time</div>
|
||||
<div class="px-4 py-3 font-medium">Model</div>
|
||||
<div class="px-4 py-3 font-medium text-right">Input</div>
|
||||
<div class="px-4 py-3 font-medium text-right">Output</div>
|
||||
<div class="px-4 py-3 font-medium text-right">Saved</div>
|
||||
<div class="px-4 py-3 font-medium text-right">Latency</div>
|
||||
</div>
|
||||
<!-- Data rows -->
|
||||
<div class="divide-y divide-border">
|
||||
<template x-for="req in (stats.recent_requests || [])" :key="req.request_id">
|
||||
<tr>
|
||||
<td colspan="7" class="p-0">
|
||||
<div class="cursor-pointer" @click="toggleExpanded(req.request_id)">
|
||||
<div class="flex hover:bg-border/30 transition-colors">
|
||||
<div class="px-4 py-3 w-6 text-gray-500">
|
||||
<span x-text="expandedRows[req.request_id] ? '-' : '+'"></span>
|
||||
</div>
|
||||
<div class="px-4 py-3 font-mono text-gray-400 flex-1" x-text="formatTime(req.timestamp)"></div>
|
||||
<div class="px-4 py-3 flex-1">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs" x-text="truncateModel(req.model)"></span>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-right font-mono flex-1" x-text="formatNumber(req.input_tokens_optimized)"></div>
|
||||
<div class="px-4 py-3 text-right font-mono flex-1" x-text="formatNumber(req.output_tokens || 0)"></div>
|
||||
<div class="px-4 py-3 text-right flex-1">
|
||||
<span class="text-accent font-mono" x-text="req.savings_percent.toFixed(0) + '%'"></span>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-right font-mono text-gray-400 flex-1" x-text="(req.total_latency_ms || 0).toFixed(0) + 'ms'"></div>
|
||||
<div>
|
||||
<div class="cursor-pointer" @click="toggleExpanded(req.request_id)">
|
||||
<div class="grid hover:bg-border/30 transition-colors"
|
||||
style="grid-template-columns: 2rem 12fr 22fr 15fr 12fr 10fr 14fr">
|
||||
<div class="px-2 py-3 text-gray-500 flex items-center justify-center">
|
||||
<span x-text="expandedRows[req.request_id] ? '-' : '+'"></span>
|
||||
</div>
|
||||
<div class="px-4 py-3 font-mono text-gray-400 truncate" x-text="formatTime(req.timestamp)"></div>
|
||||
<div class="px-4 py-3 min-w-0">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs truncate" x-text="truncateModel(req.model)"></span>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-right font-mono tabular-nums" x-text="formatNumber(req.input_tokens_optimized)"></div>
|
||||
<div class="px-4 py-3 text-right font-mono tabular-nums" x-text="formatNumber(req.output_tokens || 0)"></div>
|
||||
<div class="px-4 py-3 text-right">
|
||||
<span class="text-accent font-mono tabular-nums" x-text="req.savings_percent.toFixed(0) + '%'"></span>
|
||||
</div>
|
||||
<div class="px-4 py-3 text-right font-mono tabular-nums text-gray-400" x-text="(req.total_latency_ms || 0).toFixed(0) + 'ms'"></div>
|
||||
</div>
|
||||
<!-- Expanded detail row -->
|
||||
<template x-if="expandedRows[req.request_id]">
|
||||
<div class="px-8 py-4 border-t border-border" style="background: var(--card-alt-bg);">
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 text-xs">
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Original Tokens</div>
|
||||
<div class="font-mono" x-text="formatNumber(req.input_tokens_original)"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Compressed Tokens</div>
|
||||
<div class="font-mono" x-text="formatNumber(req.input_tokens_optimized)"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Tokens Removed</div>
|
||||
<div class="font-mono text-accent" x-text="formatNumber(req.tokens_saved)"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Optimization Time</div>
|
||||
<div class="font-mono" x-text="(req.optimization_latency_ms || 0).toFixed(0) + 'ms'"></div>
|
||||
</div>
|
||||
<!-- Expanded detail row -->
|
||||
<template x-if="expandedRows[req.request_id]">
|
||||
<div class="px-8 py-4 border-t border-border" style="background: var(--card-alt-bg);">
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 text-xs">
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Original Tokens</div>
|
||||
<div class="font-mono" x-text="formatNumber(req.input_tokens_original)"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Compressed Tokens</div>
|
||||
<div class="font-mono" x-text="formatNumber(req.input_tokens_optimized)"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Tokens Removed</div>
|
||||
<div class="font-mono text-accent" x-text="formatNumber(req.tokens_saved)"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-500 uppercase tracking-wide mb-1">Optimization Time</div>
|
||||
<div class="font-mono" x-text="(req.optimization_latency_ms || 0).toFixed(0) + 'ms'"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Transforms Applied -->
|
||||
<template x-if="(req.transforms_applied || []).length > 0">
|
||||
<div class="mt-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Transforms Applied</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<template x-for="t in req.transforms_applied" :key="t">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs font-mono" x-text="t"></span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Transforms Applied -->
|
||||
<template x-if="(req.transforms_applied || []).length > 0">
|
||||
<div class="mt-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Transforms Applied</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<template x-for="t in req.transforms_applied" :key="t">
|
||||
<span class="px-2 py-0.5 bg-border rounded text-xs font-mono" x-text="t"></span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Waste Signals for this request -->
|
||||
<template x-if="req.waste_signals && Object.keys(req.waste_signals).length > 0">
|
||||
<div class="mt-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Waste Detected</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<template x-for="[signal, tokens] in Object.entries(req.waste_signals).filter(([,v]) => v > 0)" :key="signal">
|
||||
<span class="px-2 py-0.5 rounded text-xs font-mono"
|
||||
:class="wasteSignalBadgeColor(signal)"
|
||||
x-text="wasteSignalLabel(signal) + ': ' + formatNumber(tokens)"></span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Waste Signals for this request -->
|
||||
<template x-if="req.waste_signals && Object.keys(req.waste_signals).length > 0">
|
||||
<div class="mt-3">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Waste Detected</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<template x-for="[signal, tokens] in Object.entries(req.waste_signals).filter(([,v]) => v > 0)" :key="signal">
|
||||
<span class="px-2 py-0.5 rounded text-xs font-mono"
|
||||
:class="wasteSignalBadgeColor(signal)"
|
||||
x-text="wasteSignalLabel(signal) + ': ' + formatNumber(tokens)"></span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="(stats.recent_requests || []).length === 0">
|
||||
<tr>
|
||||
<td colspan="8" class="px-4 py-8 text-center text-gray-500 italic">
|
||||
No requests yet. Start using the proxy to see activity here.
|
||||
</td>
|
||||
</tr>
|
||||
<div class="px-4 py-8 text-center text-gray-500 italic">
|
||||
No requests yet. Start using the proxy to see activity here.
|
||||
</div>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1443,7 +1487,7 @@
|
|||
<tbody>
|
||||
<template x-for="row in historyModelBreakdown" :key="row.model">
|
||||
<tr class="border-t border-border text-gray-300 cursor-pointer transition-colors"
|
||||
:class="historySelectedModel === row.model ? 'bg-[#1c1c1c]' : 'hover:bg-[#181818]'"
|
||||
:class="historySelectedModel === row.model ? 'bg-card-alt' : 'hover-bg-surface'"
|
||||
@click="toggleHistoryModel(row.model)"
|
||||
:title="historySelectedModel === row.model
|
||||
? 'Show all models'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue