Show BanGUI app version in sidebar, fix version tooltips

- Inject __APP_VERSION__ at build time via vite.config.ts define (reads
  frontend/package.json#version); declare the global in vite-env.d.ts.
- Render 'BanGUI v{__APP_VERSION__}' in the sidebar footer (MainLayout)
  when expanded; hidden when collapsed.
- Rename fail2ban version tooltip to 'fail2ban daemon version' in
  ServerStatusBar so it is visually distinct from the app version.
- Sync frontend/package.json version (0.9.0 → 0.9.3) to match
  Docker/VERSION; update release.sh to keep them in sync on every bump.
- Add vitest define stub for __APP_VERSION__ so tests compile cleanly.
- Add ServerStatusBar and MainLayout test suites (10 new test cases).
This commit is contained in:
2026-03-16 19:45:55 +01:00
parent abb224e01b
commit e7834a888e
10 changed files with 295 additions and 59 deletions

View File

@@ -4,82 +4,52 @@ This document breaks the entire BanGUI project into development stages, ordered
---
## Task: Ensure Required fail2ban Jail Config Files Exist ✅ DONE
## Open Issues
**Implemented:** `backend/app/utils/jail_config.py``ensure_jail_configs(jail_d_path)` creates missing `manual-Jail.conf`, `manual-Jail.local`, `blocklist-import.conf`, and `blocklist-import.local` files with correct default content. Called from the lifespan hook in `main.py` using `Path(settings.fail2ban_config_dir) / "jail.d"`. Tests in `backend/tests/test_utils/test_jail_config.py` (6 cases: all missing, all present, only locals missing, directory creation, idempotency, correct content).
### ~~1. Dashboard — Version Tag Mismatch~~ ✅ Done
The backend must guarantee that two specific jail configuration files are present inside the fail2ban jail directory before the application starts (or on first use). If either file is missing it must be created with the correct default content. The files live inside the directory that fail2ban uses for per-jail drop-in configs (e.g. `jail.d/`). The path to that directory should be read from the application settings (config key `fail2ban_jail_d_path` or equivalent); do not hard-code it.
**Implemented:**
- `frontend/vite.config.ts`: reads `package.json#version` at build time and injects it as the global `__APP_VERSION__` via Vite `define`.
- `frontend/src/vite-env.d.ts`: adds `declare const __APP_VERSION__: string` so TypeScript knows about the global.
- `frontend/src/layouts/MainLayout.tsx`: renders `BanGUI v{__APP_VERSION__}` in the sidebar footer when expanded (hidden when collapsed).
- `frontend/src/components/ServerStatusBar.tsx`: tooltip changed from `"fail2ban version"` to `"fail2ban daemon version"`.
- `Docker/release.sh`: after bumping `VERSION`, also updates `frontend/package.json#version` via `sed` to keep them in sync.
- `frontend/package.json`: version bumped from `0.9.0` to `0.9.3` to match `Docker/VERSION`.
- Tests added: `src/components/__tests__/ServerStatusBar.test.tsx`, `src/layouts/__tests__/MainLayout.test.tsx`.
### Files to create if missing
**Problem:** The `ServerStatusBar` component on the Dashboard displays `v{status.version}`, which is the **fail2ban daemon version** (e.g. `v1.1.0`). The BanGUI application version lives in `Docker/VERSION` (e.g. `v0.9.3`) and is unrelated to the fail2ban version. Users see a version number they don't recognise and assume it reflects the BanGUI release.
**`manual-Jail.conf`**
The file must contain a `[manual-Jail]` section with `enabled = false` and all other jail parameters (filter, logpath, backend, maxretry, findtime, bantime, ignoreip) set to the same defaults already documented in `Docker/fail2ban-dev-config/fail2ban/jail.d/manual-Jail.conf`. Only `enabled` must be forced to `false` in this template — it is the `.local` override (see below) that activates the jail.
**Goal:** Make the distinction clear and expose the BanGUI application version.
**`blocklist-import.conf`**
The file must contain a `[blocklist-import]` section with `enabled = false` and all other jail parameters (filter, logpath, backend, maxretry, findtime, bantime, ignoreip) set to the same defaults already documented in `Docker/fail2ban-dev-config/fail2ban/jail.d/blocklist-import.conf`. Same rule: `enabled = false` here; the `.local` file enables it.
**Suggested approach:**
1. Inject the BanGUI app version at build time — add a `define` entry in `frontend/vite.config.ts` that reads the `version` field from `frontend/package.json` (e.g. `__APP_VERSION__`). Keep `frontend/package.json` and `Docker/VERSION` in sync (update the release script `Docker/release.sh` or `Makefile` to write `package.json#version` from `VERSION`).
2. Show the BanGUI version in the sidebar footer inside `MainLayout.tsx` (collapsed view: show only when expanded, or via tooltip). This is the natural place for an "about" version tag.
3. Update the fail2ban version tooltip in `ServerStatusBar.tsx` from the generic `"fail2ban version"` to something like `"fail2ban daemon version"` so the two are no longer visually indistinguishable.
### Local override files
For each `.conf` file above there must also be a corresponding `.local` file checked — and created if missing. The `.local` files must contain **only** the section header and the single `enabled = true` line. Nothing else. fail2ban merges `.local` on top of `.conf` at startup, so all other settings come from the `.conf`.
```
[manual-Jail]
enabled = true
```
```
[blocklist-import]
enabled = true
```
### Implementation notes
- Perform the check in a backend startup routine (e.g. in a `lifespan` hook or a dedicated `ensure_jail_configs()` function called from `main.py`).
- Only create a file if it does **not** already exist. Never overwrite an existing file.
- Log an `INFO` message for each file that is created and a `DEBUG` message when a file already exists.
- Add unit tests that exercise: (a) all four files missing → all four created with correct content, (b) all four files present → nothing is overwritten, (c) only the `.local` files missing → only they are created.
**Files:** `frontend/vite.config.ts`, `frontend/package.json`, `Docker/VERSION`, `Docker/release.sh`, `frontend/src/layouts/MainLayout.tsx`, `frontend/src/components/ServerStatusBar.tsx`.
---
## Task: World Map — Country Tooltip on Hover
### 2. Dashboard — Improve "Failures" Tooltip
Currently the world map (`WorldMap.tsx`) shows a ban-count label painted directly onto each country's SVG path and reacts to click events. Add a floating tooltip that appears when the user hovers over a country.
**Problem:** The `ServerStatusBar` shows a "Failures: 42" counter with the tooltip `"Currently failing IPs"`. In fail2ban terminology *failures* are individual **failed authentication attempts** tracked in the fail2ban DB, not the number of unique IPs that failed. The current wording is ambiguous and misleading — users may think it means broken connections or error states.
### Required behaviour
**Goal:** Replace the tooltip with accurate, self-explanatory wording.
- When the mouse enters a country geography, display a small floating tooltip near the cursor that shows:
- The country's full name (already available via `country_names` from `useMapData()`).
- The ban count for that country (from the `countries` map; show `0` if the country has no entry).
- The tooltip must follow the mouse while inside the country (or at minimum appear near the cursor when it first enters).
- When the mouse leaves the country the tooltip must disappear.
- Countries with zero bans must also show the tooltip (name + "0 bans").
**Suggested fix:** Change the `Tooltip` content for the Failures stat in `ServerStatusBar.tsx` from `"Currently failing IPs"` to something like `"Total failed authentication attempts currently tracked by fail2ban across all active jails"`. Additionally, consider renaming the label from `"Failures:"` to `"Failed Attempts:"` to match the tooltip language.
### Implementation notes
- Store tooltip state (visible, content, x, y) in a `useState` hook local to `WorldMap.tsx`.
- Use `onMouseEnter`, `onMouseMove`, and `onMouseLeave` props on the `<Geography>` element (react-simple-maps already forwards these as standard SVG mouse events).
- Render the tooltip as an absolutely-positioned `<div>` overlaid on the map container. Apply a `pointer-events: none` style so it does not interfere with hover detection on the map itself.
- Reuse the existing Fluent UI design tokens (background, border, shadow, typography) so the tooltip matches the rest of the UI. Do not introduce a new third-party tooltip library.
- Add a Vitest / React Testing Library test that mounts `WorldMap` with mock data, fires a `mouseenter` event on a geography, and asserts the tooltip text is visible.
**Files:** `frontend/src/components/ServerStatusBar.tsx`.
---
## Task: Main Menu — Tooltips on Navigation Items
### 3. Config → Server Tab — Move "Service Health" to Top
The main navigation sidebar (or top bar, whichever is used) currently has no tooltips. Add a tooltip to each navigation item so that users who are unfamiliar with icon-only or collapsed menus can see the destination name without navigating.
**Problem:** In the Config page → Server tab, the `Service Health` panel (`ServerHealthSection`) is rendered at the bottom of the tab, after all settings sections (log level, log target, DB purge settings, map thresholds, reload/restart buttons). This means users must scroll past all editable fields to check service connectivity status, even though the health status is the most critical piece of context — it indicates whether the server is reachable at all.
### Required behaviour
**Goal:** Move the `<ServerHealthSection />` block to the **top** of the `ServerTab` render output, before any settings fields.
- Each navigation item must show a tooltip containing the item's label (e.g. "Dashboard", "Map", "Blocklist", "Settings") when the user hovers over it.
- Tooltips should appear after a short delay (≈ 300 ms) to avoid flickering during fast cursor movement past the menu.
- The tooltip must be dismissed when the cursor leaves the item.
- If the menu is already showing a full text label next to the icon, the tooltip is still added (it reinforces accessibility); but consider hiding it when the sidebar is expanded and the label is already visible, to avoid redundancy.
**Suggested fix:** In `frontend/src/components/config/ServerTab.tsx`, move the `{/* Service Health & Log Viewer section */}` block (currently at the end of the JSX return around line 415) to be the first section rendered inside the tab container.
### Implementation notes
- Use the Fluent UI `<Tooltip>` component (from `@fluentui/react-components`) which is already a project dependency. Wrap each navigation `<NavLink>` (or equivalent element) with `<Tooltip content="…" relationship="label">`.
- Keep the tooltip content string co-located with the route definition so that if a label changes in one place it changes everywhere.
- Do not introduce any new npm dependencies.
- Add a Vitest / React Testing Library test that renders the navigation component, triggers a hover on each item, and asserts the correct tooltip text is present in the DOM.
**Files:** `frontend/src/components/config/ServerTab.tsx`.
---