From 4c1c6892bce67e13984e931cb995cfe3b3d52fd9 Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Tue, 1 Sep 2026 04:04:33 +0300 Subject: [PATCH] status: show past incidents Signed-off-by: Anirudh Oppiliappan --- status/src/index.ts | 80 +++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/status/src/index.ts b/status/src/index.ts index 44d6353d2..ecc9196a0 100644 --- a/status/src/index.ts +++ b/status/src/index.ts @@ -459,6 +459,7 @@ interface Snapshot { activeIncidents: Incident[]; activeUpdates: Map; resolved: Incident[]; + resolvedUpdates: Map; chartIncidents: IncidentRange[]; } @@ -532,6 +533,22 @@ async function loadSnapshot(env: Env): Promise { ).all() ).results; + const resolvedUpdates = new Map(); + const resolvedRows = ( + await env.DB.prepare( + `SELECT * FROM incident_updates + WHERE incident_id IN ( + SELECT id FROM incidents WHERE state = 'resolved' ORDER BY created_at DESC LIMIT 10 + ) + ORDER BY created_at DESC`, + ).all() + ).results; + for (const u of resolvedRows) { + const list = resolvedUpdates.get(u.incident_id) ?? []; + list.push(u); + resolvedUpdates.set(u.incident_id, list); + } + // Incidents whose time range overlaps the 24h chart window (no LIMIT — an // older but still-active/long-running incident must not be dropped). const chartIncidents = ( @@ -543,7 +560,7 @@ async function loadSnapshot(env: Env): Promise { ).all() ).results; - return { services, latest, statuses, histories, enabled, overall, activeIncidents, activeUpdates, resolved, chartIncidents }; + return { services, latest, statuses, histories, enabled, overall, activeIncidents, activeUpdates, resolved, resolvedUpdates, chartIncidents }; } // --------------------------------------------------------------------------- @@ -635,38 +652,42 @@ ${items} // Public dashboard // --------------------------------------------------------------------------- +function incidentCard(inc: Incident, updates: IncidentUpdate[]): string { + const parts = [ + `
+
+ ${stateLabel(inc.state)} + ${escapeHtml(inc.title)} + ${fmt(inc.created_at)} +
`, + ]; + if (inc.description) { + parts.push(`

${escapeHtml(inc.description)}

`); + } + if (updates.length > 0) { + parts.push('
    '); + for (const u of updates) { + parts.push(`
  • + ${u.state ? `${stateLabel(u.state)}` : ''}${escapeHtml(u.body)} + ${fmt(u.created_at)} +
  • `); + } + parts.push('
'); + } + parts.push('
'); + return parts.join('\n'); +} + async function dashboard(env: Env): Promise { const snap = await loadSnapshot(env); const pill = OVERALL_STATUS_UI[snap.overall]; const body: string[] = [headerRow(pill.cls, pill.label)]; - // Active incidents if (snap.activeIncidents.length > 0) { body.push(`

Active incidents

`); for (const inc of snap.activeIncidents) { - body.push(` -
-
- ${stateLabel(inc.state)} - ${escapeHtml(inc.title)} - ${fmt(inc.created_at)} -
`); - if (inc.description) { - body.push(`

${escapeHtml(inc.description)}

`); - } - const updates = snap.activeUpdates.get(inc.id) ?? []; - if (updates.length > 0) { - body.push('
    '); - for (const u of updates) { - body.push(`
  • - ${u.state ? `${stateLabel(u.state)}` : ''}${escapeHtml(u.body)} - ${fmt(u.created_at)} -
  • `); - } - body.push('
'); - } - body.push('
'); + body.push(incidentCard(inc, snap.activeUpdates.get(inc.id) ?? [])); } body.push('
'); } @@ -710,18 +731,13 @@ async function dashboard(env: Env): Promise { } body.push(''); - // Resolved history if (snap.resolved.length > 0) { body.push(`
-

Past incidents

-
    `); +

    Past incidents

    `); for (const inc of snap.resolved) { - body.push(`
  • - ${fmt(inc.resolved_at)} - ${escapeHtml(inc.title)} -
  • `); + body.push(incidentCard(inc, snap.resolvedUpdates.get(inc.id) ?? [])); } - body.push('
'); + body.push(''); } return html(page('Tangled · Service Status', body.join('\n'), true)); -- 2.51.2