80 lines
2.9 KiB
TypeScript
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>
|
|
);
|
|
}
|