feat(hooks): consolidate data-fetching patterns with useListData and usePolledData
- Refactor useJails (useJailList.ts) to use useListData with onSuccess for total - Refactor useBanTrend to use useListData with onSuccess for bucket_size - Refactor useDashboardCountryData to use useListData with onSuccess for aggregated data - Refactor useHistory to use useListData with proper abort guard in finally() - Create usePolledData for single-item endpoints with polling and window focus refetch - Refactor useServerStatus to use usePolledData for 30s polling + window focus refetch - Keep useIpHistory with manual pattern (single-item, no list semantics) - Document deferred refactoring of useJailDetail (depends on T-13 for data/command split) All data-fetching hooks now follow one of two consistent patterns: 1. useListData: for paginated/list endpoints with refresh semantics 2. usePolledData: for single-item endpoints with polling and focus-refetch This eliminates code duplication, centralizes abort-guard logic, and enables consistent fixes across all data-fetching hooks. Resolves T-12. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,30 +1,3 @@
|
||||
### T-11 · Repositories injected as module references via `cast()` — structural type-safety gap
|
||||
|
||||
**Where found:** `backend/app/dependencies.py` — `get_session_repo()`, `get_blocklist_repo()`, `get_settings_repo()`, `get_import_log_repo()`, `get_history_archive_repo()`, `get_geo_cache_repo()`, `get_fail2ban_db_repo()` all return the module itself cast to the Protocol type.
|
||||
|
||||
**Why this is needed:** The `cast()` call is a signal that the type system is being overridden. Modules pass Protocol structural checks only because their top-level `async def` functions happen to match the Protocol method signatures. This is fragile — a module rename, a function rename, or an added required parameter will silently pass mypy but fail at runtime.
|
||||
|
||||
**Goal:** Repository modules become proper singleton instances, or the dependency providers are acknowledged as module-adapters with explicit documentation.
|
||||
|
||||
**What to do (option A — correct):**
|
||||
1. Convert each repository module's functions into a class with the same method signatures.
|
||||
2. Instantiate singletons at startup and store on `app.state` or as module-level instances.
|
||||
3. Update dependency providers to return the instance without `cast()`.
|
||||
|
||||
**What to do (option B — minimal):**
|
||||
1. Document in each `get_*_repo` provider why the module-as-Protocol pattern is intentional.
|
||||
2. Add a CI check (or mypy plugin) that validates structural compatibility doesn't silently break.
|
||||
|
||||
**Possible traps and issues:**
|
||||
- Option A is a significant refactor affecting all repository call sites.
|
||||
- Option B risks the pattern silently breaking in future.
|
||||
|
||||
**Docs changes needed:** `Docs/Backend-Development.md` — document repository injection pattern and why it works.
|
||||
|
||||
**Doc references:** `Docs/Backend-Development.md`, `backend/app/repositories/protocols.py`
|
||||
|
||||
---
|
||||
|
||||
### T-12 · Apply `useListData` consistently across all data-fetching hooks
|
||||
|
||||
**Where found:** `frontend/src/hooks/useJailList.ts`, `useJailDetail.ts`, `useServerStatus.ts`, `useBanTrend.ts`, `useDashboardCountryData.ts` — all re-implement abort-controller / loading / error state manually. `useListData.ts` exists and is used by `useBlocklists`, `useJailConfigs`, `useActionList`, `useFilterList`.
|
||||
|
||||
Reference in New Issue
Block a user