chore: verify and finalize task completion for existing refactor tasks

This commit is contained in:
2026-03-22 13:32:46 +01:00
parent b15629a078
commit 99fbddb0e7
10 changed files with 90 additions and 207 deletions

View File

@@ -14,6 +14,7 @@ import {
makeStyles, makeStyles,
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles";
import type { BanOriginFilter, TimeRange } from "../types/ban"; import type { BanOriginFilter, TimeRange } from "../types/ban";
import { import {
BAN_ORIGIN_FILTER_LABELS, BAN_ORIGIN_FILTER_LABELS,
@@ -57,20 +58,6 @@ const useStyles = makeStyles({
alignItems: "center", alignItems: "center",
flexWrap: "wrap", flexWrap: "wrap",
gap: tokens.spacingVerticalS, gap: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
paddingTop: tokens.spacingVerticalS, paddingTop: tokens.spacingVerticalS,
paddingBottom: tokens.spacingVerticalS, paddingBottom: tokens.spacingVerticalS,
paddingLeft: tokens.spacingHorizontalM, paddingLeft: tokens.spacingHorizontalM,
@@ -107,9 +94,10 @@ export function DashboardFilterBar({
onOriginFilterChange, onOriginFilterChange,
}: DashboardFilterBarProps): React.JSX.Element { }: DashboardFilterBarProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const cardStyles = useCardStyles();
return ( return (
<div className={styles.container}> <div className={`${styles.container} ${cardStyles.card}`}>
{/* Time-range group */} {/* Time-range group */}
<div className={styles.group}> <div className={styles.group}>
<Text weight="semibold" size={300}> <Text weight="semibold" size={300}>

View File

@@ -18,6 +18,7 @@ import {
tokens, tokens,
Tooltip, Tooltip,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles";
import { ArrowClockwiseRegular, ShieldRegular } from "@fluentui/react-icons"; import { ArrowClockwiseRegular, ShieldRegular } from "@fluentui/react-icons";
import { useServerStatus } from "../hooks/useServerStatus"; import { useServerStatus } from "../hooks/useServerStatus";
@@ -31,20 +32,6 @@ const useStyles = makeStyles({
alignItems: "center", alignItems: "center",
gap: tokens.spacingHorizontalL, gap: tokens.spacingHorizontalL,
padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalL}`, padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalL}`,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
marginBottom: tokens.spacingVerticalL, marginBottom: tokens.spacingVerticalL,
flexWrap: "wrap", flexWrap: "wrap",
}, },
@@ -85,8 +72,10 @@ export function ServerStatusBar(): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const { status, banguiVersion, loading, error, refresh } = useServerStatus(); const { status, banguiVersion, loading, error, refresh } = useServerStatus();
const cardStyles = useCardStyles();
return ( return (
<div className={styles.bar} role="status" aria-label="fail2ban server status"> <div className={`${cardStyles.card} ${styles.bar}`} role="status" aria-label="fail2ban server status">
{/* ---------------------------------------------------------------- */} {/* ---------------------------------------------------------------- */}
{/* Online / Offline badge */} {/* Online / Offline badge */}
{/* ---------------------------------------------------------------- */} {/* ---------------------------------------------------------------- */}

View File

@@ -11,6 +11,7 @@ import { createPortal } from "react-dom";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { ComposableMap, ZoomableGroup, Geography, useGeographies } from "react-simple-maps"; import { ComposableMap, ZoomableGroup, Geography, useGeographies } from "react-simple-maps";
import { Button, makeStyles, tokens } from "@fluentui/react-components"; import { Button, makeStyles, tokens } from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles";
import type { GeoPermissibleObjects } from "d3-geo"; import type { GeoPermissibleObjects } from "d3-geo";
import { ISO_NUMERIC_TO_ALPHA2 } from "../data/isoNumericToAlpha2"; import { ISO_NUMERIC_TO_ALPHA2 } from "../data/isoNumericToAlpha2";
import { getBanCountColor } from "../utils/mapColors"; import { getBanCountColor } from "../utils/mapColors";
@@ -30,9 +31,6 @@ const useStyles = makeStyles({
mapWrapper: { mapWrapper: {
width: "100%", width: "100%",
position: "relative", position: "relative",
backgroundColor: tokens.colorNeutralBackground2,
borderRadius: tokens.borderRadiusMedium,
border: `1px solid ${tokens.colorNeutralStroke1}`,
overflow: "hidden", overflow: "hidden",
}, },
countLabel: { countLabel: {
@@ -290,6 +288,7 @@ export function WorldMap({
thresholdHigh = 100, thresholdHigh = 100,
}: WorldMapProps): React.JSX.Element { }: WorldMapProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const cardStyles = useCardStyles();
const [zoom, setZoom] = useState<number>(1); const [zoom, setZoom] = useState<number>(1);
const [center, setCenter] = useState<[number, number]>([0, 0]); const [center, setCenter] = useState<[number, number]>([0, 0]);
@@ -308,7 +307,7 @@ export function WorldMap({
return ( return (
<div <div
className={styles.mapWrapper} className={`${cardStyles.card} ${styles.mapWrapper}`}
role="img" role="img"
aria-label="World map showing banned IP counts by country. Click a country to filter the table below." aria-label="World map showing banned IP counts by country. Click a country to filter the table below."
> >

View File

@@ -32,6 +32,7 @@ import {
type TableColumnDefinition, type TableColumnDefinition,
createTableColumn, createTableColumn,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../../theme/commonStyles";
import { formatTimestamp } from "../../utils/formatDate"; import { formatTimestamp } from "../../utils/formatDate";
import { import {
ArrowClockwiseRegular, ArrowClockwiseRegular,
@@ -54,26 +55,6 @@ const PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const useStyles = makeStyles({ const useStyles = makeStyles({
root: {
display: "flex",
flexDirection: "column",
gap: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
padding: tokens.spacingVerticalM,
},
header: { header: {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
@@ -243,6 +224,7 @@ export function BannedIpsSection({
onUnban, onUnban,
}: BannedIpsSectionProps): React.JSX.Element { }: BannedIpsSectionProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const rows: BanRow[] = items.map((ban) => ({ const rows: BanRow[] = items.map((ban) => ({
ban, ban,
@@ -252,7 +234,7 @@ export function BannedIpsSection({
const totalPages = pageSize > 0 ? Math.ceil(total / pageSize) : 1; const totalPages = pageSize > 0 ? Math.ceil(total / pageSize) : 1;
return ( return (
<div className={styles.root}> <div className={sectionStyles.section}>
{/* Section header */} {/* Section header */}
<div className={styles.header}> <div className={styles.header}>
<div className={styles.headerLeft}> <div className={styles.headerLeft}>

View File

@@ -37,6 +37,7 @@ import {
makeStyles, makeStyles,
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../theme/commonStyles";
import { import {
AddRegular, AddRegular,
ArrowClockwiseRegular, ArrowClockwiseRegular,
@@ -69,35 +70,7 @@ const useStyles = makeStyles({
flexDirection: "column", flexDirection: "column",
gap: tokens.spacingVerticalXL, gap: tokens.spacingVerticalXL,
}, },
section: {
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
padding: tokens.spacingVerticalM,
display: "flex",
flexDirection: "column",
gap: tokens.spacingVerticalS,
},
sectionHeader: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
paddingBottom: tokens.spacingVerticalS,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
},
tableWrapper: { overflowX: "auto" }, tableWrapper: { overflowX: "auto" },
actionsCell: { display: "flex", gap: tokens.spacingHorizontalS, flexWrap: "wrap" }, actionsCell: { display: "flex", gap: tokens.spacingHorizontalS, flexWrap: "wrap" },
mono: { fontFamily: "Consolas, 'Courier New', monospace", fontSize: "12px" }, mono: { fontFamily: "Consolas, 'Courier New', monospace", fontSize: "12px" },
@@ -400,6 +373,7 @@ interface SourcesSectionProps {
function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps): React.JSX.Element { function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const { sources, loading, error, refresh, createSource, updateSource, removeSource, previewSource } = const { sources, loading, error, refresh, createSource, updateSource, removeSource, previewSource } =
useBlocklists(); useBlocklists();
@@ -471,8 +445,8 @@ function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps):
}, []); }, []);
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text size={500} weight="semibold"> <Text size={500} weight="semibold">
Blocklist Sources Blocklist Sources
</Text> </Text>
@@ -631,6 +605,7 @@ interface ScheduleSectionProps {
function ScheduleSection({ onRunImport, runImportRunning }: ScheduleSectionProps): React.JSX.Element { function ScheduleSection({ onRunImport, runImportRunning }: ScheduleSectionProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const { info, loading, error, saveSchedule } = useSchedule(); const { info, loading, error, saveSchedule } = useSchedule();
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [saveMsg, setSaveMsg] = useState<string | null>(null); const [saveMsg, setSaveMsg] = useState<string | null>(null);
@@ -663,8 +638,8 @@ function ScheduleSection({ onRunImport, runImportRunning }: ScheduleSectionProps
}, [draft, saveSchedule]); }, [draft, saveSchedule]);
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text size={500} weight="semibold"> <Text size={500} weight="semibold">
Import Schedule Import Schedule
</Text> </Text>
@@ -810,11 +785,12 @@ function ScheduleSection({ onRunImport, runImportRunning }: ScheduleSectionProps
function ImportLogSection(): React.JSX.Element { function ImportLogSection(): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const { data, loading, error, page, setPage, refresh } = useImportLog(undefined, 20); const { data, loading, error, page, setPage, refresh } = useImportLog(undefined, 20);
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text size={500} weight="semibold"> <Text size={500} weight="semibold">
Import Log Import Log
</Text> </Text>

View File

@@ -15,6 +15,7 @@ import { DashboardFilterBar } from "../components/DashboardFilterBar";
import { ServerStatusBar } from "../components/ServerStatusBar"; import { ServerStatusBar } from "../components/ServerStatusBar";
import { TopCountriesBarChart } from "../components/TopCountriesBarChart"; import { TopCountriesBarChart } from "../components/TopCountriesBarChart";
import { TopCountriesPieChart } from "../components/TopCountriesPieChart"; import { TopCountriesPieChart } from "../components/TopCountriesPieChart";
import { useCommonSectionStyles } from "../theme/commonStyles";
import { useDashboardCountryData } from "../hooks/useDashboardCountryData"; import { useDashboardCountryData } from "../hooks/useDashboardCountryData";
import type { BanOriginFilter, TimeRange } from "../types/ban"; import type { BanOriginFilter, TimeRange } from "../types/ban";
@@ -29,26 +30,6 @@ const useStyles = makeStyles({
flexDirection: "column", flexDirection: "column",
gap: tokens.spacingVerticalM, gap: tokens.spacingVerticalM,
}, },
section: {
display: "flex",
flexDirection: "column",
gap: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
padding: tokens.spacingVerticalM,
},
sectionHeader: { sectionHeader: {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
@@ -93,6 +74,8 @@ export function DashboardPage(): React.JSX.Element {
const { countries, countryNames, isLoading: countryLoading, error: countryError, reload: reloadCountry } = const { countries, countryNames, isLoading: countryLoading, error: countryError, reload: reloadCountry } =
useDashboardCountryData(timeRange, originFilter); useDashboardCountryData(timeRange, originFilter);
const sectionStyles = useCommonSectionStyles();
return ( return (
<div className={styles.root}> <div className={styles.root}>
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
@@ -113,7 +96,7 @@ export function DashboardPage(): React.JSX.Element {
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
{/* Ban Trend section */} {/* Ban Trend section */}
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={styles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Ban Trend Ban Trend
@@ -127,7 +110,7 @@ export function DashboardPage(): React.JSX.Element {
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
{/* Charts section */} {/* Charts section */}
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={styles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Top Countries Top Countries
@@ -162,7 +145,7 @@ export function DashboardPage(): React.JSX.Element {
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
{/* Ban list section */} {/* Ban list section */}
{/* ------------------------------------------------------------------ */} {/* ------------------------------------------------------------------ */}
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={styles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Ban List Ban List

View File

@@ -35,6 +35,7 @@ import {
makeStyles, makeStyles,
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles";
import { import {
ArrowCounterclockwiseRegular, ArrowCounterclockwiseRegular,
ArrowLeftRegular, ArrowLeftRegular,
@@ -112,9 +113,6 @@ const useStyles = makeStyles({
gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))",
gap: tokens.spacingVerticalM, gap: tokens.spacingVerticalM,
padding: tokens.spacingVerticalM, padding: tokens.spacingVerticalM,
background: tokens.colorNeutralBackground2,
borderRadius: tokens.borderRadiusMedium,
border: `1px solid ${tokens.colorNeutralStroke1}`,
marginBottom: tokens.spacingVerticalM, marginBottom: tokens.spacingVerticalM,
}, },
detailField: { detailField: {
@@ -216,6 +214,7 @@ interface IpDetailViewProps {
function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Element { function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const cardStyles = useCardStyles();
const { detail, loading, error, refresh } = useIpHistory(ip); const { detail, loading, error, refresh } = useIpHistory(ip);
if (loading) { if (loading) {
@@ -272,7 +271,7 @@ function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Element {
</div> </div>
{/* Summary grid */} {/* Summary grid */}
<div className={styles.detailGrid}> <div className={`${cardStyles.card} ${styles.detailGrid}`}>
<div className={styles.detailField}> <div className={styles.detailField}>
<span className={styles.detailLabel}>Total Bans</span> <span className={styles.detailLabel}>Total Bans</span>
<span className={styles.detailValue}>{String(detail.total_bans)}</span> <span className={styles.detailValue}>{String(detail.total_bans)}</span>

View File

@@ -23,6 +23,7 @@ import {
makeStyles, makeStyles,
tokens, tokens,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCommonSectionStyles } from "../theme/commonStyles";
import { import {
ArrowClockwiseRegular, ArrowClockwiseRegular,
ArrowLeftRegular, ArrowLeftRegular,
@@ -53,36 +54,7 @@ const useStyles = makeStyles({
alignItems: "center", alignItems: "center",
gap: tokens.spacingHorizontalS, gap: tokens.spacingHorizontalS,
}, },
section: {
display: "flex",
flexDirection: "column",
gap: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
padding: tokens.spacingVerticalM,
},
sectionHeader: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: tokens.spacingHorizontalM,
paddingBottom: tokens.spacingVerticalS,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
},
headerRow: { headerRow: {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
@@ -181,6 +153,7 @@ interface JailInfoProps {
function JailInfoSection({ jail, onRefresh, onStart, onStop, onSetIdle, onReload }: JailInfoProps): React.JSX.Element { function JailInfoSection({ jail, onRefresh, onStart, onStop, onSetIdle, onReload }: JailInfoProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const navigate = useNavigate(); const navigate = useNavigate();
const [ctrlError, setCtrlError] = useState<string | null>(null); const [ctrlError, setCtrlError] = useState<string | null>(null);
@@ -206,8 +179,8 @@ function JailInfoSection({ jail, onRefresh, onStart, onStop, onSetIdle, onReload
}; };
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<div className={styles.headerRow}> <div className={styles.headerRow}>
<Text <Text
size={600} size={600}
@@ -334,10 +307,10 @@ function JailInfoSection({ jail, onRefresh, onStart, onStop, onSetIdle, onReload
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function PatternsSection({ jail }: { jail: Jail }): React.JSX.Element { function PatternsSection({ jail }: { jail: Jail }): React.JSX.Element {
const styles = useStyles(); const sectionStyles = useCommonSectionStyles();
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Log Paths &amp; Patterns Log Paths &amp; Patterns
</Text> </Text>
@@ -374,12 +347,13 @@ function PatternsSection({ jail }: { jail: Jail }): React.JSX.Element {
function BantimeEscalationSection({ jail }: { jail: Jail }): React.JSX.Element | null { function BantimeEscalationSection({ jail }: { jail: Jail }): React.JSX.Element | null {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const esc = jail.bantime_escalation; const esc = jail.bantime_escalation;
if (!esc?.increment) return null; if (!esc?.increment) return null;
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Ban-time Escalation Ban-time Escalation
</Text> </Text>
@@ -445,6 +419,7 @@ function IgnoreListSection({
onToggleIgnoreSelf, onToggleIgnoreSelf,
}: IgnoreListSectionProps): React.JSX.Element { }: IgnoreListSectionProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const [inputVal, setInputVal] = useState(""); const [inputVal, setInputVal] = useState("");
const [opError, setOpError] = useState<string | null>(null); const [opError, setOpError] = useState<string | null>(null);
@@ -470,8 +445,8 @@ function IgnoreListSection({
}; };
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalM }}> <div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalM }}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Ignore List (IP Whitelist) Ignore List (IP Whitelist)

View File

@@ -33,6 +33,7 @@ import {
type TableColumnDefinition, type TableColumnDefinition,
createTableColumn, createTableColumn,
} from "@fluentui/react-components"; } from "@fluentui/react-components";
import { useCardStyles, useCommonSectionStyles } from "../theme/commonStyles";
import { import {
ArrowClockwiseRegular, ArrowClockwiseRegular,
ArrowSyncRegular, ArrowSyncRegular,
@@ -58,36 +59,7 @@ const useStyles = makeStyles({
flexDirection: "column", flexDirection: "column",
gap: tokens.spacingVerticalL, gap: tokens.spacingVerticalL,
}, },
section: {
display: "flex",
flexDirection: "column",
gap: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
padding: tokens.spacingVerticalM,
},
sectionHeader: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: tokens.spacingHorizontalM,
paddingBottom: tokens.spacingVerticalS,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
},
tableWrapper: { overflowX: "auto" }, tableWrapper: { overflowX: "auto" },
centred: { centred: {
display: "flex", display: "flex",
@@ -117,20 +89,6 @@ const useStyles = makeStyles({
gap: tokens.spacingVerticalS, gap: tokens.spacingVerticalS,
marginTop: tokens.spacingVerticalS, marginTop: tokens.spacingVerticalS,
padding: tokens.spacingVerticalS, padding: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground2,
borderRadius: tokens.borderRadiusMedium,
borderTopWidth: "1px",
borderTopStyle: "solid",
borderTopColor: tokens.colorNeutralStroke2,
borderRightWidth: "1px",
borderRightStyle: "solid",
borderRightColor: tokens.colorNeutralStroke2,
borderBottomWidth: "1px",
borderBottomStyle: "solid",
borderBottomColor: tokens.colorNeutralStroke2,
borderLeftWidth: "1px",
borderLeftStyle: "solid",
borderLeftColor: tokens.colorNeutralStroke2,
}, },
lookupRow: { lookupRow: {
display: "flex", display: "flex",
@@ -208,6 +166,7 @@ const jailColumns: TableColumnDefinition<JailSummary>[] = [
function JailOverviewSection(): React.JSX.Element { function JailOverviewSection(): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const { jails, total, loading, error, refresh, startJail, stopJail, setIdle, reloadJail, reloadAll } = const { jails, total, loading, error, refresh, startJail, stopJail, setIdle, reloadJail, reloadAll } =
useJails(); useJails();
const [opError, setOpError] = useState<string | null>(null); const [opError, setOpError] = useState<string | null>(null);
@@ -220,8 +179,8 @@ function JailOverviewSection(): React.JSX.Element {
}; };
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Jail Overview Jail Overview
{total > 0 && ( {total > 0 && (
@@ -358,6 +317,7 @@ interface BanUnbanFormProps {
function BanUnbanForm({ jailNames, onBan, onUnban }: BanUnbanFormProps): React.JSX.Element { function BanUnbanForm({ jailNames, onBan, onUnban }: BanUnbanFormProps): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const [banIpVal, setBanIpVal] = useState(""); const [banIpVal, setBanIpVal] = useState("");
const [banJail, setBanJail] = useState(""); const [banJail, setBanJail] = useState("");
const [unbanIpVal, setUnbanIpVal] = useState(""); const [unbanIpVal, setUnbanIpVal] = useState("");
@@ -415,8 +375,8 @@ function BanUnbanForm({ jailNames, onBan, onUnban }: BanUnbanFormProps): React.J
}; };
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
Ban / Unban IP Ban / Unban IP
</Text> </Text>
@@ -544,6 +504,8 @@ function BanUnbanForm({ jailNames, onBan, onUnban }: BanUnbanFormProps): React.J
function IpLookupSection(): React.JSX.Element { function IpLookupSection(): React.JSX.Element {
const styles = useStyles(); const styles = useStyles();
const sectionStyles = useCommonSectionStyles();
const cardStyles = useCardStyles();
const { result, loading, error, lookup, clear } = useIpLookup(); const { result, loading, error, lookup, clear } = useIpLookup();
const [inputVal, setInputVal] = useState(""); const [inputVal, setInputVal] = useState("");
@@ -554,8 +516,8 @@ function IpLookupSection(): React.JSX.Element {
}; };
return ( return (
<div className={styles.section}> <div className={sectionStyles.section}>
<div className={styles.sectionHeader}> <div className={sectionStyles.sectionHeader}>
<Text as="h2" size={500} weight="semibold"> <Text as="h2" size={500} weight="semibold">
IP Lookup IP Lookup
</Text> </Text>
@@ -595,7 +557,7 @@ function IpLookupSection(): React.JSX.Element {
)} )}
{result && ( {result && (
<div className={styles.lookupResult}> <div className={`${cardStyles.card} ${styles.lookupResult}`}>
<div className={styles.lookupRow}> <div className={styles.lookupRow}>
<Text className={styles.lookupLabel}>IP:</Text> <Text className={styles.lookupLabel}>IP:</Text>
<Text className={styles.mono}>{result.ip}</Text> <Text className={styles.mono}>{result.ip}</Text>

View File

@@ -0,0 +1,30 @@
import { makeStyles, tokens } from "@fluentui/react-components";
export const useCommonSectionStyles = makeStyles({
section: {
display: "flex",
flexDirection: "column",
gap: tokens.spacingVerticalS,
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
border: `1px solid ${tokens.colorNeutralStroke2}`,
padding: tokens.spacingVerticalM,
},
sectionHeader: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: tokens.spacingHorizontalM,
paddingBottom: tokens.spacingVerticalS,
borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
},
});
export const useCardStyles = makeStyles({
card: {
backgroundColor: tokens.colorNeutralBackground1,
borderRadius: tokens.borderRadiusMedium,
border: `1px solid ${tokens.colorNeutralStroke2}`,
padding: tokens.spacingVerticalM,
},
});