Global tab provided the same four editable fields as Server tab: log_level, log_target, db_purge_age, db_max_matches. Server tab already has these fields plus additional read-only info (db_path, syslog_socket) and a Flush Logs button. - Add hint text to DB Purge Age and DB Max Matches fields in ServerTab - Remove GlobalTab component import from ConfigPage - Remove 'global' from TabValue type - Remove Global tab element from TabList - Remove conditional render for GlobalTab - Remove GlobalTab from barrel export (index.ts) - Delete GlobalTab.tsx file - Update ConfigPage test to remove Global tab test case All 123 frontend tests pass.
10 KiB
BanGUI — Task List
This document breaks the entire BanGUI project into development stages, ordered so that each stage builds on the previous one. Every task is described in prose with enough detail for a developer to begin work. References point to the relevant documentation.
Task 3 — Fix Transparent Pie Chart Slices and Match Legend Label Colors to Slice Colors
Root Cause
The pie chart slices appear transparent because resolveFluentToken in frontend/src/utils/chartTheme.ts fails to resolve Fluent UI CSS custom properties. It calls getComputedStyle(document.documentElement) — but document.documentElement is the <html> element, and Fluent UI v9's FluentProvider injects its CSS custom properties on its own wrapper <div class="fui-FluentProvider ...">, not on <html> or :root. Therefore:
getComputedStyle(document.documentElement).getPropertyValue('--colorPaletteBlueBorderActive')returns""(empty string).resolveFluentTokenfalls back to returning the raw token string, e.g."var(--colorPaletteBlueBorderActive)".- Recharts internally parses colour values for SVG rendering and animation interpolation. It cannot parse a
var(...)reference so the SVGfillattribute ends up transparent/unset.
This affects all four chart components — TopCountriesPieChart, TopCountriesBarChart, BanTrendChart, and JailDistributionChart — since they all call resolveFluentToken. However the pie chart is the most visually obvious case because its slices have no fallback colour.
Fix
File: frontend/src/utils/chartTheme.ts — resolveFluentToken function (around line 30)
Change the element passed to getComputedStyle from document.documentElement to the FluentProvider's wrapper element. The FluentProvider wrapper always has the CSS class fui-FluentProvider (this is a stable class name defined in @fluentui/react-provider). Query for it with document.querySelector:
export function resolveFluentToken(tokenValue: string): string {
const match = /var\((--[^,)]+)/.exec(tokenValue);
if (match == null || match[1] == null) return tokenValue;
// FluentProvider injects CSS custom properties on its own wrapper <div>,
// not on :root. Query that element so we resolve actual colour values.
const el =
document.querySelector(".fui-FluentProvider") ?? document.documentElement;
const resolved = getComputedStyle(el)
.getPropertyValue(match[1])
.trim();
return resolved !== "" ? resolved : tokenValue;
}
This is the only change needed in this file. Do not modify CHART_PALETTE or any other export.
Verification
After applying the fix above:
- Open the Dashboard page in the browser.
- The pie chart slices must be filled with the palette colours (blue, red, green, gold, purple).
- The bar chart, area chart, and jail distribution chart should also display their colours correctly.
- The legend labels next to the pie chart must have the same font colour as their corresponding slice (this was already implemented by the previous agent in
TopCountriesPieChart.tsxvia thelegendFormatterthat wraps text in a<span style={{ color: entry.color }}>). Sinceentry.colorcomes from the Recharts payload which reads the Cellfill, once the fill values are real hex strings the legend colours will also be correct.
What NOT to change
- Do not modify
TopCountriesPieChart.tsx— thelegendFormatterchanges already applied there are correct and will work once colours resolve properly. - Do not modify
CHART_PALETTEor switch from Fluent tokens to hard-coded hex values — the token-based approach is correct; only the resolution target element was wrong. - Do not add refs or hooks to individual chart components — the single-line fix in
resolveFluentTokenis sufficient.
Task 4 — Merge Global Tab into Server Tab (Remove Duplicates)
The Global tab (frontend/src/components/config/GlobalTab.tsx) and the Server tab (frontend/src/components/config/ServerTab.tsx) both expose the same four editable fields: Log Level, Log Target, DB Purge Age, and DB Max Matches. The server tab additionally shows read-only DB Path and Syslog Socket fields, plus a Flush Logs button. Having both tabs is confusing and can cause conflicting writes.
Changes
-
Remove the Global tab entirely.
- In
frontend/src/pages/ConfigPage.tsx:- Remove
"global"from theTabValueunion type. - Remove the
<Tab value="global">Global</Tab>element from the<TabList>. - Remove the
{tab === "global" && <GlobalTab />}conditional render. - Remove the
GlobalTabimport.
- Remove
- In the barrel export file (
frontend/src/components/config/index.ts): remove theGlobalTabre-export. - Delete the file
frontend/src/components/config/GlobalTab.tsx.
- In
-
Ensure the Server tab retains all functionality. It already has all four editable fields plus extra read-only info and Flush Logs. No changes needed in
ServerTab.tsx— it already covers everything Global had. Verify the field hints from Global ("Ban records older than this…" and "Maximum number of log-line matches…") are present on the Server tab's DB Purge Age and DB Max Matches fields. If they are missing, copy them over fromGlobalTab.tsxbefore deleting it. -
Backend: No backend changes needed. The
PUT /api/config/globalendpoint stays; the Server tab already uses its own update mechanism viauseServerSettings.
Task 5 — Merge Map Tab into Server Tab
The Map tab (frontend/src/components/config/MapTab.tsx) configures map color thresholds (Low / Medium / High). Move this section into the Server tab so all server-side and display configuration is in one place.
Changes
-
Add a "Map Color Thresholds" section to
ServerTab.tsx.- Below the existing server settings card and Flush Logs button, add a new
sectionCardblock containing the map threshold form fields (Low, Medium, High) with the same validation logic currently inMapTab.tsx(high > medium > low, all positive integers). - Use
useAutoSaveto save thresholds, callingupdateMapColorThresholdsfromfrontend/src/api/config.ts. Fetch initial values withfetchMapColorThresholds. - Add a section heading: "Map Color Thresholds" and the description text explaining how thresholds drive country fill colors on the World Map page.
- Below the existing server settings card and Flush Logs button, add a new
-
Remove the Map tab.
- In
frontend/src/pages/ConfigPage.tsx: remove"map"fromTabValue, remove the<Tab value="map">Map</Tab>element, remove the conditional render, remove theMapTabimport. - In the barrel export: remove the
MapTabre-export. - Delete
frontend/src/components/config/MapTab.tsx.
- In
-
Backend: No changes needed. The
GET/PUT /api/config/map-color-thresholdsendpoints stay as-is.
Task 6 — Merge Log Tab into Server Tab
The Log tab (frontend/src/components/config/LogTab.tsx) shows a Service Health panel and a log viewer. Move both into the Server tab to consolidate all server-related views.
Changes
-
Add a "Service Health" section to
ServerTab.tsx.- Below the map thresholds section (from Task 5), add the service health grid showing: online status badge, fail2ban version, active jail count, total bans, total failures, log level (read-only), log target (read-only). Fetch this data from
fetchServiceStatusinfrontend/src/api/config.ts.
- Below the map thresholds section (from Task 5), add the service health grid showing: online status badge, fail2ban version, active jail count, total bans, total failures, log level (read-only), log target (read-only). Fetch this data from
-
Add the "Log Viewer" section to
ServerTab.tsx.- Below the health panel, add the log viewer with all its existing controls: line count selector, filter input, refresh button, auto-refresh toggle, and the colour-coded log display. Migrate all the log-related state, refs, and helper functions from
LogTab.tsx. - Keep the line-severity colour coding (ERROR=red, WARNING=yellow, DEBUG=gray).
- Below the health panel, add the log viewer with all its existing controls: line count selector, filter input, refresh button, auto-refresh toggle, and the colour-coded log display. Migrate all the log-related state, refs, and helper functions from
-
Remove the Log tab.
- In
frontend/src/pages/ConfigPage.tsx: remove"log"fromTabValue, remove the<Tab value="log">Log</Tab>element, remove the conditional render, remove theLogTabimport. - In the barrel export: remove the
LogTabre-export. - Delete
frontend/src/components/config/LogTab.tsx.
- In
-
Alternatively, if the Server tab becomes too large, extract the service health + log viewer into a sub-component (e.g.
ServerHealthSection.tsx) and render it insideServerTab.tsx. This keeps the code manageable but still presents a single tab to the user. -
Backend: No changes needed.
Task 7 — Add Reload / Restart Button to Server Section
Add a button (or two buttons) in the Server tab that allows the user to reload or restart the fail2ban service on demand.
Backend
A reload endpoint already exists: POST /api/config/reload (see backend/app/routers/config.py, around line 342). It calls jail_service.reload_all() which stops and restarts all jails with the current config. No new backend endpoint is needed for reload.
For a restart (full daemon restart, not just reload), check whether the backend already supports it. If not, add a new endpoint:
POST /api/config/restart— callsjail_service.restart()(or equivalentfail2ban-client restart). This should fully stop and restart the fail2ban daemon. Return 204 on success, 502 if fail2ban is unreachable.
Frontend
File: frontend/src/components/config/ServerTab.tsx
A frontend API function reloadConfig already exists in frontend/src/api/config.ts (around line 94).
-
In the Server tab's button row (next to the existing "Flush Logs" button), add two new buttons:
- "Reload fail2ban" — calls
reloadConfig(). Show a loading spinner while in progress, and a success/errorMessageBarwhen done. Use a descriptive icon such asArrowSync24RegularorArrowClockwise24Regular. - "Restart fail2ban" — calls the restart API (if added above, or the same reload endpoint if a full restart is not available). Use a warning-style appearance or a confirmation dialog before executing, since a restart briefly takes fail2ban offline.
- "Reload fail2ban" — calls
-
Display feedback: success message ("fail2ban reloaded successfully") or error message on failure.
-
Optionally, after a successful reload/restart, re-fetch the service health data so the health panel updates immediately.
Frontend API
If a restart endpoint was added to the backend, add a corresponding function in frontend/src/api/config.ts:
export async function restartFail2Ban(): Promise<void> {
await post<undefined>(ENDPOINTS.configRestart, undefined);
}
And add configRestart: "/api/config/restart" to the ENDPOINTS object.