Show blocklist import error badge in navigation
When the most recent scheduled import completed with errors, surface the failure in the persistent app shell: - A warning MessageBar appears at top of main content area - An amber badge is rendered on the Blocklists sidebar nav item Backend: add last_run_errors: bool | None to ScheduleInfo model and populate it in get_schedule_info() from the latest import_log row. Frontend: extend ScheduleInfo type, add useBlocklistStatus polling hook, wire both indicators into MainLayout. Tests: 3 new service tests + 1 new router test (433 total, all pass).
This commit is contained in:
@@ -264,3 +264,59 @@ Every IP that has a valid geographic mapping should display its country. Failed
|
||||
| Frontend | `frontend/src/pages/MapPage.tsx` |
|
||||
| Tests | `backend/tests/test_services/test_geo_service.py` |
|
||||
| Tests | `backend/tests/test_routers/test_geo.py` |
|
||||
|
||||
---
|
||||
|
||||
## Task 5 — Blocklist Import Error Badge in Navigation ✅ DONE
|
||||
|
||||
**Completed:** Added `last_run_errors: bool | None` to `ScheduleInfo` model and updated `get_schedule_info()` to derive it from the last import log entry. Frontend: added `last_run_errors` to `ScheduleInfo` type; added `useBlocklistStatus` hook that polls `GET /api/blocklists/schedule` every 60 s; `MainLayout` renders a warning `MessageBar` and an amber badge on the Blocklists nav item when `hasErrors` is `true`. Tests: 3 new service tests + 1 new router test; 433 tests pass.
|
||||
|
||||
### Problem
|
||||
|
||||
[Features.md § 8](Features.md) requires: *"Show a warning badge in the navigation if the most recent import encountered errors"* and *"Notify the user (via the UI status bar) when a scheduled import fails so it does not go unnoticed."*
|
||||
|
||||
Currently `ScheduleInfo` (returned by `GET /api/blocklists/schedule`) contains `last_run_at` but no indicator of whether the last run had errors. The `MainLayout` sidebar only warns about fail2ban being offline; there is no blocklist-import failure indicator anywhere in the shell.
|
||||
|
||||
### Goal
|
||||
|
||||
When the most recent blocklist import run completed with errors, a warning indicator must be visible in the persistent app shell until the condition clears (i.e. a successful import runs). Concretely:
|
||||
|
||||
1. A warning `MessageBar` appears at the top of the main content area (alongside the existing fail2ban-offline bar).
|
||||
2. A small warning badge is rendered on the **Blocklists** navigation item in the sidebar.
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**Backend — expose error flag in `ScheduleInfo`**
|
||||
|
||||
1. **`app/models/blocklist.py`** — Add `last_run_errors: bool | None = None` to `ScheduleInfo`. `True` means the most recent run's `errors` column was non-null; `None` means no run has ever completed.
|
||||
2. **`app/services/blocklist_service.py`** — In `get_schedule_info()`, after fetching `last_log`, set `last_run_errors = last_log["errors"] is not None` when `last_log` is not `None`, else leave it as `None`.
|
||||
|
||||
**Frontend — poll and display**
|
||||
|
||||
3. **`frontend/src/types/blocklist.ts`** — Add `last_run_errors: boolean | null` to `ScheduleInfo`.
|
||||
4. **`frontend/src/hooks/useBlocklist.ts`** — Add a new exported hook `useBlocklistStatus` that polls `GET /api/blocklists/schedule` every 60 seconds (plus on mount) and returns `{ hasErrors: boolean }`. Errors from the poll itself should not surface to the user — silently treat as "unknown".
|
||||
5. **`frontend/src/layouts/MainLayout.tsx`**:
|
||||
- Import and call `useBlocklistStatus`.
|
||||
- When `hasErrors` is `true`, render a second `MessageBar` (intent `"warning"`) in the warning-bar slot describing the blocklist import failure.
|
||||
- Add a small amber `Badge` (number `!` or just the dot shape) to the Blocklists `NavLink` entry so users see the indicator even when they're on another page.
|
||||
|
||||
**Tests**
|
||||
|
||||
6. **`backend/tests/test_services/test_blocklist_service.py`** — Three new tests in `TestSchedule`:
|
||||
- `test_get_schedule_info_no_errors_when_log_has_no_errors` — inserts a successful import log entry (errors=None), asserts `info.last_run_errors is False`.
|
||||
- `test_get_schedule_info_errors_when_log_has_errors` — inserts a log entry with a non-null `errors` string, asserts `info.last_run_errors is True`.
|
||||
- `test_get_schedule_info_none_when_no_log` — already covered by the existing test; verify it now also asserts `info.last_run_errors is None`.
|
||||
7. **`backend/tests/test_routers/test_blocklist.py`** — One new test in `TestGetSchedule`:
|
||||
- `test_schedule_response_includes_last_run_errors` — patches `get_schedule_info` to return a `ScheduleInfo` with `last_run_errors=True`, confirms the JSON field is present and `True`.
|
||||
|
||||
### Files Touched
|
||||
|
||||
| Layer | File |
|
||||
|-------|------|
|
||||
| Model | `backend/app/models/blocklist.py` |
|
||||
| Service | `backend/app/services/blocklist_service.py` |
|
||||
| Frontend type | `frontend/src/types/blocklist.ts` |
|
||||
| Frontend hook | `frontend/src/hooks/useBlocklist.ts` |
|
||||
| Frontend layout | `frontend/src/layouts/MainLayout.tsx` |
|
||||
| Tests | `backend/tests/test_services/test_blocklist_service.py` |
|
||||
| Tests | `backend/tests/test_routers/test_blocklist.py` |
|
||||
|
||||
Reference in New Issue
Block a user