Add jail distribution chart (Stage 5)
- backend: GET /api/dashboard/bans/by-jail endpoint - JailBanCount + BansByJailResponse Pydantic models in ban.py - bans_by_jail() service function with origin filter support - Route added to dashboard router - 17 new tests (7 service, 10 router); full suite 497 passed, 83% coverage - frontend: JailDistributionChart component - JailBanCount / BansByJailResponse types in types/ban.ts - dashboardBansByJail endpoint constant in api/endpoints.ts - fetchBansByJail() in api/dashboard.ts - useJailDistribution hook in hooks/useJailDistribution.ts - JailDistributionChart component (horizontal bar chart, Recharts) - DashboardPage: full-width Jail Distribution section below Top Countries
This commit is contained in:
@@ -353,7 +353,15 @@ Add the `BanTrendChart` to the dashboard page **above** the two country charts a
|
||||
|
||||
### Task 5.1 — Add a backend endpoint for ban counts per jail
|
||||
|
||||
**Status:** `not started`
|
||||
**Status:** `done`
|
||||
|
||||
Added `GET /api/dashboard/bans/by-jail`. New Pydantic models `JailBanCount` and
|
||||
`BansByJailResponse` added to `ban.py`. Service function `bans_by_jail()` in
|
||||
`ban_service.py` queries the `bans` table with `GROUP BY jail ORDER BY COUNT(*) DESC`
|
||||
and applies the origin filter. Route added to `dashboard.py`. 7 new service tests
|
||||
(happy path, total equality, empty DB, time-window exclusion, origin filter variants)
|
||||
and 10 new router tests — all pass, total suite 497 passed, 83% coverage.
|
||||
`ruff check` and `mypy --strict` pass.
|
||||
|
||||
The existing `GET /api/jails` endpoint returns jail metadata with `status.currently_banned` — but this counts **currently active** bans, not historical bans in the selected time window. The dashboard needs historical ban counts per jail within the selected time range.
|
||||
|
||||
@@ -395,7 +403,16 @@ class BansByJailResponse(BaseModel):
|
||||
|
||||
### Task 5.2 — Create the `JailDistributionChart` component
|
||||
|
||||
**Status:** `not started`
|
||||
**Status:** `done`
|
||||
|
||||
Created `frontend/src/components/JailDistributionChart.tsx` — a horizontal
|
||||
bar chart using Recharts `BarChart` showing ban counts per jail sorted descending.
|
||||
Added `JailBanCount`/`BansByJailResponse` types to `types/ban.ts`,
|
||||
`dashboardBansByJail` constant to `api/endpoints.ts`, `fetchBansByJail()` to
|
||||
`api/dashboard.ts`, and the `useJailDistribution` hook at
|
||||
`hooks/useJailDistribution.ts`. Component handles loading (Spinner), error
|
||||
(MessageBar), and empty states inline. `tsc --noEmit` and ESLint pass with zero
|
||||
warnings.
|
||||
|
||||
Create `frontend/src/components/JailDistributionChart.tsx`. This component renders a **horizontal bar chart** showing the distribution of bans across jails.
|
||||
|
||||
@@ -422,7 +439,14 @@ Create `frontend/src/components/JailDistributionChart.tsx`. This component rende
|
||||
|
||||
### Task 5.3 — Integrate the jail distribution chart into `DashboardPage`
|
||||
|
||||
**Status:** `not started`
|
||||
**Status:** `done`
|
||||
|
||||
Added a full-width "Jail Distribution" section card to `DashboardPage` below the
|
||||
"Top Countries" section (2-column country charts on row 1, jail chart full-width
|
||||
on row 2). The section renders `<JailDistributionChart timeRange={timeRange}
|
||||
origin={originFilter} />`, sharing the same state already used by the other
|
||||
charts. Loading, error, and empty states are handled inside
|
||||
`JailDistributionChart` itself. `tsc --noEmit` and ESLint pass with zero warnings.
|
||||
|
||||
Add the `JailDistributionChart` as a third chart card alongside the two country charts, or in a second chart row below them if space is constrained.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user