Refactor frontend API calls into hooks and complete task states
This commit is contained in:
@@ -51,7 +51,6 @@ import {
|
||||
useRunImport,
|
||||
useSchedule,
|
||||
} from "../hooks/useBlocklist";
|
||||
import { previewBlocklist } from "../api/blocklist";
|
||||
import type {
|
||||
BlocklistSource,
|
||||
ImportRunResult,
|
||||
@@ -262,9 +261,10 @@ interface PreviewDialogProps {
|
||||
open: boolean;
|
||||
source: BlocklistSource | null;
|
||||
onClose: () => void;
|
||||
fetchPreview: (id: number) => Promise<PreviewResponse>;
|
||||
}
|
||||
|
||||
function PreviewDialog({ open, source, onClose }: PreviewDialogProps): React.JSX.Element {
|
||||
function PreviewDialog({ open, source, onClose, fetchPreview }: PreviewDialogProps): React.JSX.Element {
|
||||
const styles = useStyles();
|
||||
const [data, setData] = useState<PreviewResponse | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -276,7 +276,7 @@ function PreviewDialog({ open, source, onClose }: PreviewDialogProps): React.JSX
|
||||
setData(null);
|
||||
setError(null);
|
||||
setLoading(true);
|
||||
previewBlocklist(source.id)
|
||||
fetchPreview(source.id)
|
||||
.then((result) => {
|
||||
setData(result);
|
||||
setLoading(false);
|
||||
@@ -285,7 +285,7 @@ function PreviewDialog({ open, source, onClose }: PreviewDialogProps): React.JSX
|
||||
setError(err instanceof Error ? err.message : "Failed to fetch preview");
|
||||
setLoading(false);
|
||||
});
|
||||
}, [source]);
|
||||
}, [source, fetchPreview]);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
@@ -400,7 +400,7 @@ interface SourcesSectionProps {
|
||||
|
||||
function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps): React.JSX.Element {
|
||||
const styles = useStyles();
|
||||
const { sources, loading, error, refresh, createSource, updateSource, removeSource } =
|
||||
const { sources, loading, error, refresh, createSource, updateSource, removeSource, previewSource } =
|
||||
useBlocklists();
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
@@ -410,7 +410,7 @@ function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps):
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [saveError, setSaveError] = useState<string | null>(null);
|
||||
const [previewOpen, setPreviewOpen] = useState(false);
|
||||
const [previewSource, setPreviewSource] = useState<BlocklistSource | null>(null);
|
||||
const [previewSourceItem, setPreviewSourceItem] = useState<BlocklistSource | null>(null);
|
||||
|
||||
const openAdd = useCallback((): void => {
|
||||
setDialogMode("add");
|
||||
@@ -466,7 +466,7 @@ function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps):
|
||||
);
|
||||
|
||||
const handlePreview = useCallback((source: BlocklistSource): void => {
|
||||
setPreviewSource(source);
|
||||
setPreviewSourceItem(source);
|
||||
setPreviewOpen(true);
|
||||
}, []);
|
||||
|
||||
@@ -594,10 +594,11 @@ function SourcesSection({ onRunImport, runImportRunning }: SourcesSectionProps):
|
||||
|
||||
<PreviewDialog
|
||||
open={previewOpen}
|
||||
source={previewSource}
|
||||
source={previewSourceItem}
|
||||
onClose={() => {
|
||||
setPreviewOpen(false);
|
||||
}}
|
||||
fetchPreview={previewSource}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
StopRegular,
|
||||
} from "@fluentui/react-icons";
|
||||
import { Link, useNavigate, useParams } from "react-router-dom";
|
||||
import { useJailDetail } from "../hooks/useJails";
|
||||
import { useJailDetail, useJailBannedIps } from "../hooks/useJails";
|
||||
import type { Jail } from "../types/jail";
|
||||
import { BannedIpsSection } from "../components/jail/BannedIpsSection";
|
||||
|
||||
@@ -574,6 +574,21 @@ export function JailDetailPage(): React.JSX.Element {
|
||||
const { name = "" } = useParams<{ name: string }>();
|
||||
const { jail, ignoreList, ignoreSelf, loading, error, refresh, addIp, removeIp, toggleIgnoreSelf, start, stop, reload, setIdle } =
|
||||
useJailDetail(name);
|
||||
const {
|
||||
items,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
loading: bannedLoading,
|
||||
error: bannedError,
|
||||
opError,
|
||||
refresh: refreshBanned,
|
||||
setPage,
|
||||
setPageSize,
|
||||
setSearch,
|
||||
unban,
|
||||
} = useJailBannedIps(name);
|
||||
|
||||
if (loading && !jail) {
|
||||
return (
|
||||
@@ -618,7 +633,21 @@ export function JailDetailPage(): React.JSX.Element {
|
||||
</div>
|
||||
|
||||
<JailInfoSection jail={jail} onRefresh={refresh} onStart={start} onStop={stop} onReload={reload} onSetIdle={setIdle} />
|
||||
<BannedIpsSection jailName={name} />
|
||||
<BannedIpsSection
|
||||
items={items}
|
||||
total={total}
|
||||
page={page}
|
||||
pageSize={pageSize}
|
||||
search={search}
|
||||
loading={bannedLoading}
|
||||
error={bannedError}
|
||||
opError={opError}
|
||||
onSearch={setSearch}
|
||||
onPageChange={setPage}
|
||||
onPageSizeChange={setPageSize}
|
||||
onRefresh={refreshBanned}
|
||||
onUnban={unban}
|
||||
/>
|
||||
<PatternsSection jail={jail} />
|
||||
<BantimeEscalationSection jail={jail} />
|
||||
<IgnoreListSection
|
||||
|
||||
@@ -29,7 +29,7 @@ import { ArrowCounterclockwiseRegular, DismissRegular } from "@fluentui/react-ic
|
||||
import { DashboardFilterBar } from "../components/DashboardFilterBar";
|
||||
import { WorldMap } from "../components/WorldMap";
|
||||
import { useMapData } from "../hooks/useMapData";
|
||||
import { fetchMapColorThresholds } from "../api/config";
|
||||
import { useMapColorThresholds } from "../hooks/useMapColorThresholds";
|
||||
import type { TimeRange } from "../types/map";
|
||||
import type { BanOriginFilter } from "../types/ban";
|
||||
|
||||
@@ -79,28 +79,25 @@ export function MapPage(): React.JSX.Element {
|
||||
const [range, setRange] = useState<TimeRange>("24h");
|
||||
const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
|
||||
const [selectedCountry, setSelectedCountry] = useState<string | null>(null);
|
||||
const [thresholdLow, setThresholdLow] = useState<number>(20);
|
||||
const [thresholdMedium, setThresholdMedium] = useState<number>(50);
|
||||
const [thresholdHigh, setThresholdHigh] = useState<number>(100);
|
||||
|
||||
const { countries, countryNames, bans, total, loading, error, refresh } =
|
||||
useMapData(range, originFilter);
|
||||
|
||||
// Fetch color thresholds on mount
|
||||
const {
|
||||
thresholds: mapThresholds,
|
||||
error: mapThresholdError,
|
||||
} = useMapColorThresholds();
|
||||
|
||||
const thresholdLow = mapThresholds?.threshold_low ?? 20;
|
||||
const thresholdMedium = mapThresholds?.threshold_medium ?? 50;
|
||||
const thresholdHigh = mapThresholds?.threshold_high ?? 100;
|
||||
|
||||
useEffect(() => {
|
||||
const loadThresholds = async (): Promise<void> => {
|
||||
try {
|
||||
const thresholds = await fetchMapColorThresholds();
|
||||
setThresholdLow(thresholds.threshold_low);
|
||||
setThresholdMedium(thresholds.threshold_medium);
|
||||
setThresholdHigh(thresholds.threshold_high);
|
||||
} catch (err) {
|
||||
// Silently fall back to defaults if fetch fails
|
||||
console.warn("Failed to load map color thresholds:", err);
|
||||
}
|
||||
};
|
||||
void loadThresholds();
|
||||
}, []);
|
||||
if (mapThresholdError) {
|
||||
// Silently fall back to defaults if fetch fails
|
||||
console.warn("Failed to load map color thresholds:", mapThresholdError);
|
||||
}
|
||||
}, [mapThresholdError]);
|
||||
|
||||
/** Bans visible in the companion table (filtered by selected country). */
|
||||
const visibleBans = useMemo(() => {
|
||||
|
||||
@@ -41,6 +41,21 @@ const {
|
||||
// Mock the jail detail hook — tests control the returned state directly.
|
||||
vi.mock("../../hooks/useJails", () => ({
|
||||
useJailDetail: vi.fn(),
|
||||
useJailBannedIps: vi.fn(() => ({
|
||||
items: [],
|
||||
total: 0,
|
||||
page: 1,
|
||||
pageSize: 25,
|
||||
search: "",
|
||||
loading: false,
|
||||
error: null,
|
||||
opError: null,
|
||||
refresh: vi.fn(),
|
||||
setPage: vi.fn(),
|
||||
setPageSize: vi.fn(),
|
||||
setSearch: vi.fn(),
|
||||
unban: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
// Mock API functions used by JailInfoSection control buttons to avoid side effects.
|
||||
|
||||
Reference in New Issue
Block a user