Files
BanGUI/frontend/src/pages/BlocklistsPage.tsx

80 lines
2.9 KiB
TypeScript

/**
* BlocklistsPage — external IP blocklist source management.
*
* Responsible for composition of sources, schedule, and import log sections.
*/
import { useCallback, useState } from "react";
import { Button, MessageBar, MessageBarBody, Text } from "@fluentui/react-components";
import { useBlocklistStyles } from "../components/blocklist/blocklistStyles";
import { BlocklistSourcesSection } from "../components/blocklist/BlocklistSourcesSection";
import { BlocklistScheduleSection } from "../components/blocklist/BlocklistScheduleSection";
import { BlocklistImportLogSection } from "../components/blocklist/BlocklistImportLogSection";
import { useRunImport } from "../hooks/useBlocklist";
import type { ImportRunResult } from "../types/blocklist";
interface ImportResultDialogProps {
open: boolean;
result: ImportRunResult | null;
onClose: () => void;
}
function ImportResultDialog({ open, result, onClose }: ImportResultDialogProps): React.JSX.Element {
if (!open || !result) return <></>;
return (
<div style={{ position: "fixed", top: 0, left: 0, width: "100%", height: "100%", backgroundColor: "rgba(0, 0, 0, 0.5)", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 1000 }}>
<div style={{ background: "white", padding: "24px", borderRadius: "8px", maxWidth: "520px", minWidth: "300px" }}>
<Text as="h2" size={500} weight="semibold">
Import Complete
</Text>
<Text size={200} style={{ marginTop: "12px" }}>
Total imported: {result.total_imported} | Skipped: {result.total_skipped} | Sources with errors: {result.errors_count}
</Text>
<div style={{ marginTop: "16px", textAlign: "right" }}>
<Button appearance="primary" onClick={onClose}>
Close
</Button>
</div>
</div>
</div>
);
}
export function BlocklistsPage(): React.JSX.Element {
const safeUseBlocklistStyles = useBlocklistStyles as unknown as () => { root: string };
const styles = safeUseBlocklistStyles();
const { running, lastResult, error: importError, runNow } = useRunImport();
const [importResultOpen, setImportResultOpen] = useState(false);
const handleRunImport = useCallback((): void => {
void runNow().then(() => {
setImportResultOpen(true);
});
}, [runNow]);
return (
<div className={styles.root}>
<Text as="h1" size={700} weight="semibold">
Blocklists
</Text>
{importError && (
<MessageBar intent="error">
<MessageBarBody>Import error: {importError}</MessageBarBody>
</MessageBar>
)}
<BlocklistSourcesSection onRunImport={handleRunImport} runImportRunning={running} />
<BlocklistScheduleSection onRunImport={handleRunImport} runImportRunning={running} />
<BlocklistImportLogSection />
<ImportResultDialog
open={importResultOpen}
result={lastResult}
onClose={() => { setImportResultOpen(false); }}
/>
</div>
);
}