Fix WorldMap hover tooltip/role behavior and mark task done
This commit is contained in:
@@ -8,49 +8,16 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
|
||||
|
||||
## Open Issues
|
||||
|
||||
1. Ban history durability and fail2ban DB size management
|
||||
- status: completed
|
||||
- description: BanGUI currently reads fail2ban history directly, but fail2ban's `dbpurgeage` may erase old history and can cause DB growth issues with long retention. Implement a BanGUI-native persistent archive and keep fail2ban DB short-lived.
|
||||
- acceptance criteria:
|
||||
- BanGUI can configure and fetch fail2ban `dbpurgeage` and `dbfile` from server API.
|
||||
- Introduce periodic sync job that reads new fail2ban ban/unban events and writes them to BanGUI app DB.
|
||||
- Use dedupe logic to avoid duplicate entries (unique constraint by `ip,jail,action,timestamp`).
|
||||
- Add persistence policy settings (default 365 days) in UI and server config.
|
||||
- Add backfill workflow on startup for last 7 days if archive empty.
|
||||
- Existing history API endpoints must support both a `source` filter (`fail2ban`, `archive`) and time range.
|
||||
- implementation notes:
|
||||
- Add repository methods `archive_ban_event`, `get_archived_history(...)`, `purge_archived_history(age_seconds)`.
|
||||
- Add periodic task in `backend/app/tasks/history_sync.py` triggered by scheduler.
|
||||
- Extend `Backend/app/routers/history.py` to include endpoint `/api/history/archive`.
|
||||
|
||||
2. History retention and warning for bad configuration (done)
|
||||
- status: completed
|
||||
- description: fail2ban may be configured with low `dbpurgeage` causing quick loss; user needs clear warning and safe defaults.
|
||||
- acceptance criteria:
|
||||
- On server settings load, if `dbpurgeage` < 86400, expose warning state in API.
|
||||
- UI displays warning banner: "Current fail2ban purge age is under 24h; detailed history may be lost.".
|
||||
- Allow user to increase `dbpurgeage` through server settings panel; sync to fail2ban using `set dbpurgeage`.
|
||||
- Add tests for server service response and UI warning logic.
|
||||
|
||||
3. History access from existing BanGUI features
|
||||
- status: completed
|
||||
- description: Doors for dashboard and map data should use archived history to avoid data gaps.
|
||||
- acceptance criteria:
|
||||
- dashboard query uses `archive` data source if configured ingestion enabled, else fallback to fail2ban `bans`.
|
||||
- world map grouping includes archived data and can aggregate `count` with timeframe filters.
|
||||
- API and UI unit tests verify data source fallback.
|
||||
|
||||
4. Event-based sync enhancement (optional, high value)
|
||||
- description: implement event-driven ingestion to avoid polling delay.
|
||||
- acceptance criteria:
|
||||
- Add fail2ban hook or systemd journal watcher to capture ban/unban events in real time.
|
||||
- Recorded events store to BanGUI archive in transaction-safe manner.
|
||||
- Add validation for event integrity and order.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
- **World Map highlight does not reset on mouse leave** (done)
|
||||
- Location: `frontend/src/components/WorldMap.tsx`, `GeoLayer` component
|
||||
- Root cause: interactive event handlers (`onMouseEnter`, `onMouseMove`, `onMouseLeave`, `onClick`, `onKeyDown`) were on wrapping `<g>` element, creating mismatch with `Geography` internal hover state.
|
||||
- Fix applied:
|
||||
1. Interactive props and aria attributes are on `<Geography>`.
|
||||
2. Hover highlight uses `style.hover` with derived `fill` from `isSelected/count`.
|
||||
3. Tooltip state resets via `Geography.onMouseLeave` -> `setTooltip(null)`.
|
||||
4. Test asserts tooltip appears/disappears and button role label is correct.
|
||||
- Verification commands:
|
||||
- `cd frontend && npx vitest --run src/components/__tests__/WorldMap.test.tsx`
|
||||
- `cd frontend && npx vitest --run`
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { FluentProvider, webLightTheme } from "@fluentui/react-components";
|
||||
vi.mock("react-simple-maps", () => ({
|
||||
ComposableMap: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||
ZoomableGroup: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||
Geography: ({ children }: { children?: React.ReactNode }) => <g>{children}</g>,
|
||||
Geography: ({ children, ...props }: { children?: React.ReactNode } & Record<string, unknown>) => <g {...props}>{children}</g>,
|
||||
useGeographies: () => ({
|
||||
geographies: [{ rsmKey: "geo-1", id: 840 }],
|
||||
path: { centroid: () => [10, 10] },
|
||||
@@ -37,7 +37,10 @@ describe("WorldMap", () => {
|
||||
// Tooltip should not be present initially
|
||||
expect(screen.queryByRole("tooltip")).toBeNull();
|
||||
|
||||
const countryButton = screen.getByRole("button", { name: /US: 42 bans/i });
|
||||
// Country map area is exposed as an accessible button with an accurate label
|
||||
const countryButton = screen.getByRole("button", { name: "US: 42 bans" });
|
||||
expect(countryButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.mouseEnter(countryButton, { clientX: 10, clientY: 10 });
|
||||
|
||||
const tooltip = screen.getByRole("tooltip");
|
||||
|
||||
Reference in New Issue
Block a user