Switch dashboard/map/history views to archive source for long-term data

Update fail2ban dbpurgeage to 648000 and history sync backfill/pagination for archive-based 7.5 day history.
This commit is contained in:
2026-04-05 20:21:54 +02:00
parent 7d09b78437
commit ffaa14f864
21 changed files with 149 additions and 37 deletions

View File

@@ -7,7 +7,7 @@
*/
import { useState } from "react";
import { Text, makeStyles, tokens } from "@fluentui/react-components";
import { Badge, Text, makeStyles, tokens } from "@fluentui/react-components";
import { BanTable } from "../components/BanTable";
import { BanTrendChart } from "../components/BanTrendChart";
import { ChartStateWrapper } from "../components/ChartStateWrapper";
@@ -71,8 +71,10 @@ export function DashboardPage(): React.JSX.Element {
const [timeRange, setTimeRange] = useState<TimeRange>("24h");
const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
const source = timeRange === "24h" ? "fail2ban" : "archive";
const { countries, countryNames, isLoading: countryLoading, error: countryError, reload: reloadCountry } =
useDashboardCountryData(timeRange, originFilter);
useDashboardCountryData(timeRange, originFilter, source);
const sectionStyles = useCommonSectionStyles();
@@ -86,12 +88,17 @@ export function DashboardPage(): React.JSX.Element {
{/* ------------------------------------------------------------------ */}
{/* Global filter bar */}
{/* ------------------------------------------------------------------ */}
<DashboardFilterBar
timeRange={timeRange}
onTimeRangeChange={setTimeRange}
originFilter={originFilter}
onOriginFilterChange={setOriginFilter}
/>
<div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalM, flexWrap: "wrap" }}>
<DashboardFilterBar
timeRange={timeRange}
onTimeRangeChange={setTimeRange}
originFilter={originFilter}
onOriginFilterChange={setOriginFilter}
/>
<Badge appearance="filled" color={source === "archive" ? "brand" : "success"}>
{source === "archive" ? "Archive (BanGUI DB)" : "Live (fail2ban DB)"}
</Badge>
</div>
{/* ------------------------------------------------------------------ */}
{/* Ban Trend section */}
@@ -103,7 +110,7 @@ export function DashboardPage(): React.JSX.Element {
</Text>
</div>
<div className={styles.tabContent}>
<BanTrendChart timeRange={timeRange} origin={originFilter} />
<BanTrendChart timeRange={timeRange} origin={originFilter} source={source} />
</div>
</div>
@@ -154,7 +161,7 @@ export function DashboardPage(): React.JSX.Element {
{/* Ban table */}
<div className={styles.tabContent}>
<BanTable timeRange={timeRange} origin={originFilter} />
<BanTable timeRange={timeRange} origin={originFilter} source={source} />
</div>
</div>
</div>

View File

@@ -143,6 +143,7 @@ function areHistoryQueriesEqual(
a.origin === b.origin &&
a.jail === b.jail &&
a.ip === b.ip &&
a.source === b.source &&
a.page === b.page &&
a.page_size === b.page_size
);
@@ -386,11 +387,12 @@ export function HistoryPage(): React.JSX.Element {
const styles = useStyles();
// Filter state
const [range, setRange] = useState<TimeRange>("24h");
const [range, setRange] = useState<TimeRange>("7d");
const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
const [jailFilter, setJailFilter] = useState("");
const [ipFilter, setIpFilter] = useState("");
const [appliedQuery, setAppliedQuery] = useState<HistoryQuery>({
source: "archive",
page_size: PAGE_SIZE,
});
@@ -400,12 +402,15 @@ export function HistoryPage(): React.JSX.Element {
const { items, total, page, loading, error, setPage, refresh } =
useHistory(appliedQuery);
const sourceLabel = "Archive (BanGUI DB)";
useEffect((): void => {
const nextQuery: HistoryQuery = {
range,
origin: originFilter !== "all" ? originFilter : undefined,
jail: jailFilter.trim() || undefined,
ip: ipFilter.trim() || undefined,
source: "archive",
page: 1,
page_size: PAGE_SIZE,
};
@@ -485,6 +490,9 @@ export function HistoryPage(): React.JSX.Element {
setIpFilter(value);
}}
/>
<Badge appearance="filled" color="brand" style={{ alignSelf: "flex-start" }}>
{sourceLabel}
</Badge>
</div>
{/* ---------------------------------------------------------------- */}

View File

@@ -98,8 +98,10 @@ export function MapPage(): React.JSX.Element {
const PAGE_SIZE_OPTIONS = [25, 50, 100] as const;
const source = range === "24h" ? "fail2ban" : "archive";
const { countries, countryNames, bans, total, loading, error, refresh } =
useMapData(range, originFilter);
useMapData(range, originFilter, source);
const {
thresholds: mapThresholds,
@@ -163,6 +165,9 @@ export function MapPage(): React.JSX.Element {
setSelectedCountry(null);
}}
/>
<Badge appearance="filled" color={source === "archive" ? "brand" : "success"}>
{source === "archive" ? "Archive (BanGUI DB)" : "Live (fail2ban DB)"}
</Badge>
<Button
icon={<ArrowCounterclockwiseRegular />}
onClick={(): void => {

View File

@@ -50,7 +50,8 @@ describe("HistoryPage", () => {
// Initial load should include the auto-applied default query.
await waitFor(() => {
expect(lastQuery).toEqual({
range: "24h",
range: "7d",
source: "archive",
origin: undefined,
jail: undefined,
ip: undefined,