Drill into a single alert from the stats page
The stats page could only say how many alerts fired. It now answers when
one alert fires, how often, and how fast it is picked up and fixed: each
row of the top-alerts list opens /stats/alert/{name}, with a timeline,
by-hour and by-weekday charts, time-to-resolve per occurrence and a table
of every occurrence linking to its incident. The overview gains a
weekday-by-hour heatmap and a few derived observations.
An occurrence is an incident, not an alert row. Alert rows are reused per
fingerprint and mutated in place, so they carry no history; incidents are
the only record of each time something fired and was answered. That means
/api/stats/alerts/top now counts incidents opened (filtered on
triggered_at) so the list and the drilldown agree. The response keeps name
and count and only adds fields, so existing clients keep working, but the
counts can differ from before.
No migration: the lookups use incidents_signature_idx. Label breakdown,
team and severity filters and period-over-period deltas from the design
draft are left for later.
Claude-Session: https://claude.ai/code/session_016mBLURvJoMuUEr9cB2RpUN
This commit is contained in:
@@ -59,6 +59,8 @@ function parseRoute(pathname) {
|
||||
// /admin/teams/7 fall through to the queue.
|
||||
const g = pathname.match(/^\/admin\/teams\/(\d+)\/?$/);
|
||||
if (g) return { section: 'adminteam', team: Number(g[1]) };
|
||||
const sa = pathname.match(/^\/stats\/alert\/([^/]+)\/?$/);
|
||||
if (sa) return { section: 'stats', alert: decodeURIComponent(sa[1]) };
|
||||
const name = pathname.replace(/^\/|\/$/g, '');
|
||||
// The Admin and Team tabs' sub-sections are routes of their own. Each view
|
||||
// owns the table of its own, since each also builds the strip that links to
|
||||
@@ -147,7 +149,7 @@ function render() {
|
||||
// the settings should not land you halfway down them. So does a changed
|
||||
// subject — one team to the next is two pages, not one scrolled page.
|
||||
else if (prev.section !== route.section || prev.tab !== route.tab
|
||||
|| prev.user !== route.user || prev.team !== route.team) window.scrollTo(0, 0);
|
||||
|| prev.user !== route.user || prev.team !== route.team || prev.alert !== route.alert) window.scrollTo(0, 0);
|
||||
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user