Overhaul uptime monitor: time ranges, bar glow, tooltips, degraded state, immediate ping

- Add 24H/7D/30D/1Y time range selector with dynamic SQL bucketing
- Add bar glow (colored box-shadow) for up/degraded/down states
- Replace native title tooltips with positioned tooltips showing uptime % and check counts
- Add "degraded" (amber) state for buckets with mixed up/down checks
- Immediate HEAD ping on service add so status appears without 60s wait
- Taller bars (h-3 list, h-6 modal), rounded-sm, hover:scale-y-[1.3]
- Increase list bar opacity from 50% to 70%
- Add DB index on uptime_logs(service_name, timestamp)
- Extend data retention from 90 to 400 days for yearly view
This commit is contained in:
Shivam Patel
2026-02-09 03:28:24 -05:00
parent a0612d74b1
commit 702d61bdef
5 changed files with 287 additions and 69 deletions

View File

@@ -30,9 +30,35 @@ export async function POST(request: Request) {
}
const db = await getDb();
await db.run('INSERT INTO monitored_services (name, url) VALUES (?, ?)', name.trim(), url.trim());
const trimmedName = name.trim();
const trimmedUrl = url.trim();
await db.run('INSERT INTO monitored_services (name, url) VALUES (?, ?)', trimmedName, trimmedUrl);
return NextResponse.json({ success: true });
// Immediate ping so the service has data right away
let initialStatus = 'down';
let initialLatency = 0;
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const start = performance.now();
const res = await fetch(trimmedUrl, {
method: 'HEAD',
signal: controller.signal,
});
clearTimeout(timeout);
initialLatency = Math.round(performance.now() - start);
initialStatus = res.status < 500 ? 'up' : 'down';
} catch {
initialStatus = 'down';
initialLatency = 0;
}
await db.run(
'INSERT INTO uptime_logs (service_name, url, status, latency, timestamp) VALUES (?, ?, ?, ?, ?)',
trimmedName, trimmedUrl, initialStatus, initialLatency, new Date().toISOString()
);
return NextResponse.json({ success: true, initialStatus, initialLatency });
} catch (error: unknown) {
const msg = error instanceof Error ? error.message : 'Unknown error';
if (msg.includes('UNIQUE constraint')) {