1
0
forked from wrenn/wrenn
Files
wrenn-releases/frontend/src/lib/api/stats.ts
pptx704 fee66bda50 Add live stats page with metrics sampling and route split
- New sandbox_metrics_snapshots table sampled every 10s (60-day retention)
- Background MetricsSampler goroutine wired into control plane startup
- GET /v1/sandboxes/stats?range=5m|1h|6h|24h|30d endpoint with adaptive
  polling intervals; reserved CPU/RAM uses ceil(paused/2) formula
- StatsPanel component: 4 stat cards + 2 Chart.js line charts (straight
  lines, integer y-axis for running count, dual-axis for CPU/RAM)
- Range filter persisted in URL query param; polls update data silently
  (no blink — loading state only shown on initial mount)
- Split /dashboard/capsules into /list and /stats sub-routes with shared
  layout; capsuleRunningCount store syncs badge across routes
- CreateCapsuleDialog extracted as reusable component
2026-03-25 14:41:05 +06:00

45 lines
905 B
TypeScript

import { apiFetch, type ApiResult } from '$lib/api/client';
export type TimeRange = '5m' | '1h' | '6h' | '24h' | '30d';
export type StatsResponse = {
range: TimeRange;
current: {
running_count: number;
vcpus_reserved: number;
memory_mb_reserved: number;
sampled_at?: string;
};
peaks: {
running_count: number;
vcpus: number;
memory_mb: number;
};
series: {
labels: string[];
running: number[];
vcpus: number[];
memory_mb: number[];
};
};
export async function fetchStats(range: TimeRange): Promise<ApiResult<StatsResponse>> {
return apiFetch('GET', `/api/v1/sandboxes/stats?range=${range}`);
}
export const POLL_INTERVALS: Record<TimeRange, number> = {
'5m': 15_000,
'1h': 30_000,
'6h': 60_000,
'24h': 120_000,
'30d': 300_000,
};
export const RANGE_LABELS: Record<TimeRange, string> = {
'5m': '5m',
'1h': '1h',
'6h': '6h',
'24h': '24h',
'30d': '30d',
};