Redesign FiltersTab with active/inactive layout and assign/create dialogs (Tasks 2.3/2.4)
- Rewrite FiltersTab: use fetchFilters() for FilterConfig[] with embedded active
status; show 'Active — sshd, apache-auth' badge labels; FilterDetail sub-
component with source_file/override badges, FilterForm, Assign button, raw
config section
- New AssignFilterDialog: selects jail from enabled-jails list, calls
POST /config/jails/{name}/filter with optional fail2ban reload
- New CreateFilterDialog: name+failregex+ignoreregex form, calls
POST /config/filters, closes and selects new filter on success
- Extend ConfigListDetail: add listHeader (for Create button) and
itemBadgeLabel (for custom badge text) optional props
- Fix updateFilterFile bug: was PUT /config/filters/{name} (structured
endpoint), now correctly PUT /config/filters/{name}/raw
- Fix createFilterFile bug: was POST /config/filters, now POST /config/filters/raw
- Add updateFilter, createFilter, deleteFilter, assignFilterToJail to api/config.ts
- Add FilterUpdateRequest, FilterCreateRequest, AssignFilterRequest to types/config.ts
- Add configFiltersRaw, configJailFilter endpoints
- Tests: 24 new tests across FiltersTab, AssignFilterDialog, CreateFilterDialog
(all 89 frontend tests passing)
This commit is contained in:
@@ -9,13 +9,16 @@ import type {
|
||||
ActionConfigUpdate,
|
||||
ActivateJailRequest,
|
||||
AddLogPathRequest,
|
||||
AssignFilterRequest,
|
||||
ConfFileContent,
|
||||
ConfFileCreateRequest,
|
||||
ConfFilesResponse,
|
||||
ConfFileUpdateRequest,
|
||||
FilterConfig,
|
||||
FilterConfigUpdate,
|
||||
FilterCreateRequest,
|
||||
FilterListResponse,
|
||||
FilterUpdateRequest,
|
||||
GlobalConfig,
|
||||
GlobalConfigUpdate,
|
||||
InactiveJailListResponse,
|
||||
@@ -224,17 +227,19 @@ export async function fetchFilterFile(name: string): Promise<ConfFileContent> {
|
||||
return get<ConfFileContent>(ENDPOINTS.configFilterRaw(name));
|
||||
}
|
||||
|
||||
/** Save raw content to a filter definition file (``PUT /filters/{name}/raw``). */
|
||||
export async function updateFilterFile(
|
||||
name: string,
|
||||
req: ConfFileUpdateRequest
|
||||
): Promise<void> {
|
||||
await put<undefined>(ENDPOINTS.configFilter(name), req);
|
||||
await put<undefined>(ENDPOINTS.configFilterRaw(name), req);
|
||||
}
|
||||
|
||||
/** Create a new raw filter file (``POST /filters/raw``). */
|
||||
export async function createFilterFile(
|
||||
req: ConfFileCreateRequest
|
||||
): Promise<ConfFileContent> {
|
||||
return post<ConfFileContent>(ENDPOINTS.configFilters, req);
|
||||
return post<ConfFileContent>(ENDPOINTS.configFiltersRaw, req);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -263,7 +268,7 @@ export async function createActionFile(
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Parsed filter config (Task 2.2)
|
||||
// Parsed filter config (Task 2.2 / legacy /parsed endpoint)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export async function fetchParsedFilter(name: string): Promise<FilterConfig> {
|
||||
@@ -277,6 +282,69 @@ export async function updateParsedFilter(
|
||||
await put<undefined>(ENDPOINTS.configFilterParsed(name), update);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Filter structured update / create / delete (Task 2.3)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update a filter's editable fields via the structured endpoint.
|
||||
*
|
||||
* Writes only the supplied fields to the ``.local`` override. Fields set
|
||||
* to ``null`` are cleared; omitted fields are left unchanged.
|
||||
*
|
||||
* @param name - Filter base name (e.g. ``"sshd"``)
|
||||
* @param req - Partial update payload.
|
||||
*/
|
||||
export async function updateFilter(
|
||||
name: string,
|
||||
req: FilterUpdateRequest
|
||||
): Promise<void> {
|
||||
await put<undefined>(ENDPOINTS.configFilter(name), req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a brand-new user-defined filter in ``filter.d/{name}.local``.
|
||||
*
|
||||
* @param req - Name and optional regex patterns.
|
||||
* @returns The newly created FilterConfig.
|
||||
*/
|
||||
export async function createFilter(
|
||||
req: FilterCreateRequest
|
||||
): Promise<FilterConfig> {
|
||||
return post<FilterConfig>(ENDPOINTS.configFilters, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a filter's ``.local`` override file.
|
||||
*
|
||||
* Only custom ``.local``-only filters can be deleted. Attempting to delete a
|
||||
* filter that is backed by a shipped ``.conf`` file returns 409.
|
||||
*
|
||||
* @param name - Filter base name.
|
||||
*/
|
||||
export async function deleteFilter(name: string): Promise<void> {
|
||||
await del<undefined>(ENDPOINTS.configFilter(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a filter to a jail by writing ``filter = {filter_name}`` to the
|
||||
* jail's ``.local`` config file.
|
||||
*
|
||||
* @param jailName - Jail name.
|
||||
* @param req - The filter to assign.
|
||||
* @param reload - When ``true``, trigger a fail2ban reload after writing.
|
||||
*/
|
||||
export async function assignFilterToJail(
|
||||
jailName: string,
|
||||
req: AssignFilterRequest,
|
||||
reload = false
|
||||
): Promise<void> {
|
||||
const url = reload
|
||||
? `${ENDPOINTS.configJailFilter(jailName)}?reload=true`
|
||||
: ENDPOINTS.configJailFilter(jailName);
|
||||
await post<undefined>(url, req);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Filter discovery with active/inactive status (Task 2.1)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user