From 3e4f688484a0d6c5ccb29a964f6195b7cc6abe88 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 14 Mar 2026 09:51:00 +0100 Subject: [PATCH] Fix vertical alignment of DNS Mode dropdown in jail config Add alignItems: "end" to the fieldRow grid style so that all grid cells align their content to the bottom edge of the row. This ensures the DNS Mode ` dropdowns; Date Pattern is a `` with presets. Both are wired to auto-save. The `JailConfigDetail` component also gained a `readOnly` prop (wired throughout all fields, toggles, and buttons) in preparation for Task 3. Backend updated `JailConfigUpdate` model to accept `backend` and `log_encoding`, and `update_jail_config` sends them to the daemon. +**Status:** Completed — Added `alignItems: "end"` to `fieldRow` in `configStyles.ts`. The two dropdowns now baseline-align to the bottom of their grid row regardless of the "Date Pattern" hint text. Verified no regressions in any other `fieldRow` usages (all other rows have consistent hint presence across their fields). ---- +**Component:** `frontend/src/components/config/JailsTab.tsx` +**Styles:** `frontend/src/components/config/configStyles.ts` -## ✅ Task 2 — Fix Raw Action Configuration Always Blank in Actions Tab +### Problem -**Completed.** Added `key={selectedAction.name}` to `` in `ActionsTab.tsx` and `key={selectedFilter.name}` to `` in `FiltersTab.tsx`. This forces a full remount on item switch, resetting `RawConfigSection`'s `loadedRef` so it re-fetches content for every selected item. +In the jail configuration detail view (`JailConfigDetail`), the "Date Pattern" and "DNS Mode" fields sit side-by-side in a 2-column CSS grid row (class `fieldRow`). The "Date Pattern" `` has a `hint` prop (`"Leave blank for auto-detect."`) which renders extra text between the label and the input, pushing the `` control downward. The "DNS Mode" `` has no `hint`, so its `` without a `hint` prop. -**Completed.** Extended `InactiveJail` backend Pydantic model with all config fields (`ban_time_seconds`, `find_time_seconds`, `log_encoding`, `backend`, `date_pattern`, `use_dns`, `prefregex`, `fail_regex`, `ignore_regex`, `bantime_escalation`). Added `_parse_time_to_seconds` helper to `config_file_service.py` and updated `_build_inactive_jail` to populate all new fields. Extended the `InactiveJail` TypeScript type to match. Rewrote `InactiveJailDetail` to map fields into a `JailConfig`-compatible object and render `JailConfigDetail` with `readOnly=true`, showing filter/port/source_file as informational fields above the shared form. +### Acceptance criteria ---- +1. The bottom edges of the "Date Pattern" dropdown and the "DNS Mode" dropdown must be visually aligned on the same horizontal line. +2. The fix must not break the responsive layout (on narrow screens the grid collapses to a single column via `@media (max-width: 900px)`). +3. No other fields in the jail config form should be affected. -## ✅ Task 4 — Fix `banaction` Interpolation Error When Activating Jails +### Suggested approach -**Completed.** `_write_local_override_sync` now always writes `banaction = iptables-multiport` and `banaction_allports = iptables-allports` into the per-jail `.local` file (Option A), ensuring fail2ban can resolve the `%(banaction)s` interpolation used in `action_`. +**Option A — Align grid items to the end (preferred):** +In `configStyles.ts`, add `alignItems: "end"` to the `fieldRow` style. This makes each grid cell align its content to the bottom, so the two inputs line up regardless of whether one field has a hint and the other doesn't. Verify that this does not break other rows that also use `fieldRow` (Backend/Log Encoding row, and any rows in `DefaultsTab.tsx` or `FiltersTab.tsx`). +**Option B — Add a matching hint to DNS Mode:** +Add a `hint` with a non-breaking space (`hint={"\u00A0"}`) to the DNS Mode `` so it takes up the same vertical space as the Date Pattern hint. This is simpler but slightly hacky. +### Files to modify -**Problem:** In the Config → Jails page, the **Backend**, **Log Encoding**, and **Date Pattern** fields for active jails are currently plain text `` fields (Backend and Log Encoding are read-only, Date Pattern is a free-text input). These should be `` fields with `` fields. Wire their `onChange` to local state and include them in the auto-save payload sent to the backend. -2. The backend model at `backend/app/models/config.py` line 67 already accepts `backend: str` and `log_encoding: str`, so no backend changes are needed unless you want to add server-side validation. -3. Date Pattern should use a Fluent UI `Combobox` (editable dropdown) instead of a `Select`, so users can still type a custom pattern. -4. Follow the existing DNS Mode dropdown pattern at lines 271–280 of `JailsTab.tsx` as a reference for styling and onChange handling. - ---- - -## Task 2 — Fix Raw Action Configuration Always Blank in Actions Tab - -**Problem:** In the Config → Actions page, the **"Raw Action Configuration"** accordion section is always blank when expanded. - -**Where to look:** - -- **`frontend/src/components/config/ActionsTab.tsx`** — the `ActionDetail` component (lines 65–185). The `fetchRaw` callback (line 82) calls `fetchActionFile(action.name)` and returns `result.content`. -- **`frontend/src/components/config/RawConfigSection.tsx`** — the collapsible raw editor. It uses a `loadedRef` (line 62) to fetch content only on first accordion expansion, and never resets. -- **`frontend/src/api/config.ts`** line 257 — `fetchActionFile()` calls `GET /config/actions/{name}`. -- **`backend/app/services/file_config_service.py`** line 734 — `get_action_file()` reads from `action.d/` using `_read_conf_file()`, which tries `.conf` first, then `.local`. - -**Root cause investigation — check these two possibilities:** - -### Possibility A: Stale `loadedRef` across action switches -`ActionDetail` at line 301 of `ActionsTab.tsx` is rendered **without a `key` prop**: -```tsx - { setAssignOpen(true); }} - onRemovedFromJail={handleRemovedFromJail} -/> -``` -Without `key={selectedAction.name}`, React reuses the same component instance when switching between actions. The `RawConfigSection` inside `ActionDetail` keeps its `loadedRef.current = true` from a previous expansion, so it never re-fetches for the new action. - -**Fix:** Add `key={selectedAction.name}` to `ActionDetail` so it fully unmounts/remounts on action switch, resetting all internal state including `loadedRef`. - -### Possibility B: Backend returning empty content -The `_read_conf_file` function at `file_config_service.py` line 492 tries `.conf` first then `.local`. If the action only has a `.conf` file and it's readable, content should be returned. Verify by: -1. Checking browser DevTools Network tab for the `GET /api/config/actions/{name}` response body. -2. Confirming the response has a non-empty `content` field. - -**Implementation:** - -1. Add `key={selectedAction.name}` to the `` component in `ActionsTab.tsx` line 301. -2. Test by selecting different actions and expanding the raw config accordion — each should show the correct file content. -3. If the backend is returning empty content, debug `_read_conf_file` to check which file path it resolves and whether it can read the file. - ---- - -## Task 3 — Give Inactive Jail Configs the Same GUI as Active Ones - -**Problem:** In the Config → Jails page, **inactive jails** show a minimal read-only preview (`InactiveJailDetail` component) with only basic fields (filter, port, ban time, find time, max retry, log paths, actions, source file). **Active jails** like `bangui-sim` show a full editable form (`JailConfigDetail` component) with all fields including Backend, Log Encoding, Date Pattern, DNS Mode, Prefix Regex, editable log paths, Fail/Ignore Regex lists, Ban-time Escalation, and a Raw Configuration editor. - -The inactive jail detail should display the same rich GUI as the active one — same layout, same fields — but in read-only mode (since the jail is not running on fail2ban). - -**Where to change:** - -- **`frontend/src/components/config/JailsTab.tsx`**: - - `InactiveJailDetail` component (lines 493–580): the current minimal read-only view. - - `JailConfigDetail` component (lines ~200–490): the full editable form for active jails. - - Selection logic at lines 721–752 determines which component renders based on jail kind. - -- **`frontend/src/types/config.ts`** — `InactiveJail` type (around line 484) defines the data shape for inactive jails. Compare with `JailConfig` to see which fields are missing. - -- **Backend** — check that the inactive jail endpoint returns enough data. The backend model `InactiveJail` may need additional fields (backend, log_encoding, date_pattern, dns_mode, prefix_regex, failregex, ignoreregex, ban-time escalation settings) to match the active `JailConfig` model. - -**Implementation approach:** - -1. **Extend the `InactiveJail` model** in the backend (`backend/app/models/config.py`) to include all fields that `JailConfig` has: `backend`, `log_encoding`, `date_pattern`, `usedns`, `prefixregex`, `failregex`, `ignoreregex`, `bantime_increment` (escalation settings), etc. -2. **Update the backend service** that parses inactive jail configs to extract these additional fields from the `.conf`/`.local` files. -3. **Rewrite `InactiveJailDetail`** to mirror `JailConfigDetail`'s layout but with all fields in **read-only** mode (all `` have `readOnly`, all `