feat(runtimes): add usage charts, activity heatmap, and hourly distribution

Add comprehensive data visualization to the runtime detail page:
- Daily token usage stacked area chart and daily cost bar chart
- Model distribution donut chart with cost breakdown
- GitHub-style activity heatmap (13 weeks of daily token usage)
- Hourly task distribution bar chart with new backend endpoint
- Responsive 2-column grid layout for charts on wide screens

Backend: new GET /api/runtimes/{runtimeId}/activity endpoint
returning hourly task counts from agent_task_queue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jiayuan 2026-03-29 15:44:10 +08:00
parent c5fed182e3
commit 36798b1d76
8 changed files with 657 additions and 6 deletions

View file

@ -11,6 +11,39 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
const getRuntimeTaskHourlyActivity = `-- name: GetRuntimeTaskHourlyActivity :many
SELECT EXTRACT(HOUR FROM started_at)::int AS hour, COUNT(*)::int AS count
FROM agent_task_queue
WHERE runtime_id = $1 AND started_at IS NOT NULL
GROUP BY hour
ORDER BY hour
`
type GetRuntimeTaskHourlyActivityRow struct {
Hour int32 `json:"hour"`
Count int32 `json:"count"`
}
func (q *Queries) GetRuntimeTaskHourlyActivity(ctx context.Context, runtimeID pgtype.UUID) ([]GetRuntimeTaskHourlyActivityRow, error) {
rows, err := q.db.Query(ctx, getRuntimeTaskHourlyActivity, runtimeID)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetRuntimeTaskHourlyActivityRow{}
for rows.Next() {
var i GetRuntimeTaskHourlyActivityRow
if err := rows.Scan(&i.Hour, &i.Count); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getRuntimeUsageSummary = `-- name: GetRuntimeUsageSummary :many
SELECT provider, model,
SUM(input_tokens)::bigint AS total_input_tokens,