Alert history page and a tighter monitor health check #21

Merged
jared merged 1 commits from events-history into main 2026-11-10 20:37:46 -05:00
Owner

What changes

Alert history (/events, new "History" nav link). This page lists every alert from the last 24 hours to 90 days, both open and cleared, including ones that cleared before anyone saw them. Each row shows when the alert started, how long it lasted, how many checks failed, its ticket, and its description.

  • Filters: device (name, port or interface), alert type, severity, open or cleared, and time range. The filters are kept in the URL, so links can be shared.
  • Summary chips: one per alert type; clicking a chip filters to that type.
  • Recurring table: lists the same alert on the same target more than once in the range, most frequent first. Its "Show these" button filters the list to those alerts.
  • Links in: device pages get a "Full alert history" link, and tickets get an "Alert history for X" link.
  • Phones: each row becomes a card.
  • API: the page is backed by the new GET /api/events/history (100 per page). /api/events is unchanged.

Health check. /health, and the dashboard's monitor indicator, used a fixed 20-minute limit. They now count the monitor as stalled after five missed polls, with a minimum of 10 minutes. /health also reports monitor_age_s, so an uptime monitor can catch a hung gandalf-monitor sooner.

Testing

  • Automated: 325 tests pass (11 new), covering filter pass-through and validation, defaults, auth, and health at 200 and 503, including a long poll interval.
  • Queries against a local MariaDB with seeded history:
    • totals by type
    • recurring alerts
    • LIKE wildcards escaped, so a search for % matches nothing
    • an alert that started before the range but was still open in it is counted
  • Browser (Playwright):
    • "Show these" sets the target and type and updates the URL.
    • A link like ?target=micro1&range=90d fills in the form.
    • "Clear filters" resets them.
    • The device-page link works.
    • At 390 px the page has no horizontal scroll.
    • No JS errors, apart from the preview's missing avatar.
  • flake8 and bandit are clean; ESLint reports 0 errors.

Screenshots are in the comments.

🤖 Generated with Claude Code

## What changes **Alert history (`/events`, new "History" nav link).** This page lists every alert from the last 24 hours to 90 days, both open and cleared, including ones that cleared before anyone saw them. Each row shows when the alert started, how long it lasted, how many checks failed, its ticket, and its description. - **Filters:** device (name, port or interface), alert type, severity, open or cleared, and time range. The filters are kept in the URL, so links can be shared. - **Summary chips:** one per alert type; clicking a chip filters to that type. - **Recurring table:** lists the same alert on the same target more than once in the range, most frequent first. Its "Show these" button filters the list to those alerts. - **Links in:** device pages get a "Full alert history" link, and tickets get an "Alert history for X" link. - **Phones:** each row becomes a card. - **API:** the page is backed by the new `GET /api/events/history` (100 per page). `/api/events` is unchanged. **Health check.** `/health`, and the dashboard's monitor indicator, used a fixed 20-minute limit. They now count the monitor as stalled after five missed polls, with a minimum of 10 minutes. `/health` also reports `monitor_age_s`, so an uptime monitor can catch a hung `gandalf-monitor` sooner. ## Testing - **Automated:** 325 tests pass (11 new), covering filter pass-through and validation, defaults, auth, and health at 200 and 503, including a long poll interval. - **Queries against a local MariaDB with seeded history:** - totals by type - recurring alerts - LIKE wildcards escaped, so a search for `%` matches nothing - an alert that started before the range but was still open in it is counted - **Browser (Playwright):** - "Show these" sets the target and type and updates the URL. - A link like `?target=micro1&range=90d` fills in the form. - "Clear filters" resets them. - The device-page link works. - At 390 px the page has no horizontal scroll. - No JS errors, apart from the preview's missing avatar. - flake8 and bandit are clean; ESLint reports 0 errors. Screenshots are in the comments. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jared added 1 commit 2026-11-10 20:29:27 -05:00
Add an alert history page and tie /health staleness to the poll interval
Lint / JS (eslint) (push) Successful in 6s
Lint / Python (flake8) (push) Successful in 1m56s
Lint / Notify on failure (push) Skipped
Lint / Deploy (push) Skipped
Security / Python Security (bandit) (push) Successful in 2m3s
Test / Python Tests (pytest) (push) Successful in 1m0s
Lint / Python (flake8) (pull_request) Successful in 48s
Lint / JS (eslint) (pull_request) Successful in 6s
Lint / Notify on failure (pull_request) Skipped
Lint / Deploy (pull_request) Skipped
Security / Python Security (bandit) (pull_request) Successful in 2m7s
Test / Python Tests (pytest) (pull_request) Successful in 2m6s
9d561db703
/events lists every alert from the last 24 hours to 90 days, open or
cleared, with how long each lasted, failed checks and its ticket. Filters
(device, type, severity, state, range) live in the URL, so device pages
and tickets link straight to a device's history. A "Recurring" table
lists alerts that fired more than once on the same target. On phones the
rows become cards.

/api/events/history backs it (100 per page). The existing /api/events is
unchanged.

/health and the dashboard's monitor indicator now call the monitor
stalled after five missed polls (at least 10 minutes) instead of a fixed
20, and /health reports the monitor's age.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jared referenced this issue from a commit 2026-11-10 20:29:53 -05:00
Author
Owner

Screenshots (local preview, sample data)

History, last 7 days. Two alerts are open, there are chips for each alert type, and the Recurring table shows a flapping interface on large1.

History

After "Show these" on the recurring row. The list is filtered to that alert and target, and the URL is updated (?target=large1&type=interface_down).

Filtered

Phone (390 px). Each row becomes a card, with no horizontal scroll.

Mobile

## Screenshots (local preview, sample data) **History, last 7 days.** Two alerts are open, there are chips for each alert type, and the Recurring table shows a flapping interface on large1. ![History](https://code.lotusguild.org/LotusGuild/gandalf/raw/branch/pr-21-screenshots/1-history.png) **After "Show these" on the recurring row.** The list is filtered to that alert and target, and the URL is updated (`?target=large1&type=interface_down`). ![Filtered](https://code.lotusguild.org/LotusGuild/gandalf/raw/branch/pr-21-screenshots/2-filtered.png) **Phone (390 px).** Each row becomes a card, with no horizontal scroll. ![Mobile](https://code.lotusguild.org/LotusGuild/gandalf/raw/branch/pr-21-screenshots/3-mobile.png)
jared merged commit 29119c2235 into main 2026-11-10 20:37:46 -05:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/gandalf#21