feat(web-ui): better stats and ergonomics

Usage page: add 7-day trend chart (activity/tokens/cost tabs),
framework breakdown panel with per-framework run/tool/error counts
and proportional bars, and 7d aggregate pills above the chart.

Dashboard: add avg cost/run metric pill to the metrics strip.

Run detail: extract and display prompt preview from the first agent
span's payload above the spans table.

Bug fixes: stat-list bars now render correctly (flex-direction:column),
right-panel-tab active background uses correct accent color, missing
framework colors added for hermes/codex/gemini/copilot. Dead code
renderSessionRow removed from sessions.js. Hardcoded font-family
replaced with CSS variable in metric-pill-value and token-stat-value.
Usage page cleanup() wired into router teardown.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
William Valentin
2026-05-21 16:49:05 -07:00
parent 1b01f0b0cd
commit 8753c0c9d5
6 changed files with 455 additions and 90 deletions
@@ -19,6 +19,15 @@ export function cleanup() {
runLiveOps = {};
}
function extractPromptPreview(spans) {
for (const sp of spans) {
const inner = (sp.payload || {}).payload || {};
if (inner.prompt_preview) return inner.prompt_preview;
if (inner.message_preview) return inner.message_preview;
}
return null;
}
function renderSpanPayload(sp) {
const outer = sp.payload || {};
const inner = outer.payload || {};
@@ -361,6 +370,7 @@ export async function renderRun(runID, routeToken) {
? formatDuration(new Date(r.ended_at) - new Date(r.started_at))
: 'ongoing';
const runUsage = extractRunUsage(spans);
const promptPreview = extractPromptPreview(spans);
app.innerHTML = `
<a href="/sessions/${escapeHTML(r.session_id)}" class="back-link">&larr; Back to Session</a>
@@ -382,6 +392,11 @@ export async function renderRun(runID, routeToken) {
</div>
</div>
${!r.ended_at ? '<div class="run-live-ops" id="run-live-ops"></div>' : ''}
${promptPreview ? `
<div class="prompt-preview-section">
<div class="prompt-preview-label">Prompt</div>
<pre class="prompt-preview-text">${escapeHTML(promptPreview)}</pre>
</div>` : ''}
<div class="section-title">
Spans <span class="count" id="run-detail-span-count">${spans.length}</span>
${!r.ended_at ? '<span class="live-indicator" style="margin-left:0.5rem"><span class="live-dot"></span>Live</span>' : ''}