/** * ActivateJailDialog — confirmation dialog for activating an inactive jail. * * Displays the jail name and provides optional override fields for bantime, * findtime, maxretry, port and logpath. Calls the activate endpoint on * confirmation and propagates the result via callbacks. */ import { useState } from "react"; import { Button, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, Field, Input, MessageBar, MessageBarBody, Spinner, Text, tokens, } from "@fluentui/react-components"; import { activateJail } from "../../api/config"; import type { ActivateJailRequest, InactiveJail } from "../../types/config"; import { ApiError } from "../../api/client"; // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- export interface ActivateJailDialogProps { /** The inactive jail to activate, or null when the dialog is closed. */ jail: InactiveJail | null; /** Whether the dialog is currently open. */ open: boolean; /** Called when the dialog should be closed without taking action. */ onClose: () => void; /** Called after the jail has been successfully activated. */ onActivated: () => void; } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- /** * Confirmation dialog for activating an inactive jail. * * All override fields are optional — leaving them blank uses the values * already in the config files. * * @param props - Component props. * @returns JSX element. */ export function ActivateJailDialog({ jail, open, onClose, onActivated, }: ActivateJailDialogProps): React.JSX.Element { const [bantime, setBantime] = useState(""); const [findtime, setFindtime] = useState(""); const [maxretry, setMaxretry] = useState(""); const [port, setPort] = useState(""); const [logpath, setLogpath] = useState(""); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const resetForm = (): void => { setBantime(""); setFindtime(""); setMaxretry(""); setPort(""); setLogpath(""); setError(null); }; const handleClose = (): void => { if (submitting) return; resetForm(); onClose(); }; const handleConfirm = (): void => { if (!jail || submitting) return; const overrides: ActivateJailRequest = {}; if (bantime.trim()) overrides.bantime = bantime.trim(); if (findtime.trim()) overrides.findtime = findtime.trim(); if (maxretry.trim()) { const n = parseInt(maxretry.trim(), 10); if (!isNaN(n)) overrides.maxretry = n; } if (port.trim()) overrides.port = port.trim(); if (logpath.trim()) { overrides.logpath = logpath .split("\n") .map((l) => l.trim()) .filter(Boolean); } setSubmitting(true); setError(null); activateJail(jail.name, overrides) .then(() => { resetForm(); onActivated(); }) .catch((err: unknown) => { const msg = err instanceof ApiError ? err.message : err instanceof Error ? err.message : String(err); setError(msg); }) .finally(() => { setSubmitting(false); }); }; if (!jail) return <>; return ( { if (!data.open) handleClose(); }}> Activate jail “{jail.name}” This will write enabled = true to{" "} jail.d/{jail.name}.local and reload fail2ban. The jail will start monitoring immediately. Override values (leave blank to use config defaults)
{ setBantime(d.value); }} /> { setFindtime(d.value); }} /> { setMaxretry(d.value); }} /> { setPort(d.value); }} />
0 ? jail.logpath[0] : "/var/log/example.log" } value={logpath} disabled={submitting} onChange={(_e, d) => { setLogpath(d.value); }} /> {error && ( {error} )}
); }