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:
2026-03-11 17:01:19 +01:00
parent df0528b2c2
commit fe8eefa173
13 changed files with 799 additions and 6 deletions

View File

@@ -110,3 +110,31 @@ export interface BanTrendResponse {
/** Human-readable bucket size label, e.g. `"1h"`, `"6h"`, `"1d"`, `"7d"`. */
bucket_size: string;
}
// ---------------------------------------------------------------------------
// Bans by jail
// ---------------------------------------------------------------------------
/**
* A single jail entry in the bans-by-jail aggregation.
*
* Mirrors `JailBanCount` from `backend/app/models/ban.py`.
*/
export interface JailBanCount {
/** Jail name. */
jail: string;
/** Number of bans recorded in this jail for the selected window. */
count: number;
}
/**
* Response from `GET /api/dashboard/bans/by-jail`.
*
* Mirrors `BansByJailResponse` from `backend/app/models/ban.py`.
*/
export interface BansByJailResponse {
/** Jails ordered by ban count descending. */
jails: JailBanCount[];
/** Total ban count in the selected window. */
total: number;
}