Refactor BlocklistsPage into section components and fix frontend lint issues
This commit is contained in:
105
frontend/src/components/blocklist/BlocklistImportLogSection.tsx
Normal file
105
frontend/src/components/blocklist/BlocklistImportLogSection.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Button, Badge, Table, TableBody, TableCell, TableCellLayout, TableHeader, TableHeaderCell, TableRow, Text, MessageBar, MessageBarBody, Spinner } from "@fluentui/react-components";
|
||||
import { ArrowClockwiseRegular } from "@fluentui/react-icons";
|
||||
import { useCommonSectionStyles } from "../../theme/commonStyles";
|
||||
import { useImportLog } from "../../hooks/useBlocklist";
|
||||
import { useBlocklistStyles } from "./blocklistStyles";
|
||||
|
||||
export function BlocklistImportLogSection(): React.JSX.Element {
|
||||
const styles = useBlocklistStyles();
|
||||
const sectionStyles = useCommonSectionStyles();
|
||||
const { data, loading, error, page, setPage, refresh } = useImportLog(undefined, 20);
|
||||
|
||||
return (
|
||||
<div className={sectionStyles.section}>
|
||||
<div className={sectionStyles.sectionHeader}>
|
||||
<Text size={500} weight="semibold">
|
||||
Import Log
|
||||
</Text>
|
||||
<Button icon={<ArrowClockwiseRegular />} appearance="secondary" onClick={refresh}>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<MessageBar intent="error">
|
||||
<MessageBarBody>{error}</MessageBarBody>
|
||||
</MessageBar>
|
||||
)}
|
||||
|
||||
{loading ? (
|
||||
<div className={styles.centred}>
|
||||
<Spinner label="Loading log…" />
|
||||
</div>
|
||||
) : !data || data.items.length === 0 ? (
|
||||
<div className={styles.centred}>
|
||||
<Text>No import runs recorded yet.</Text>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.tableWrapper}>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>Timestamp</TableHeaderCell>
|
||||
<TableHeaderCell>Source URL</TableHeaderCell>
|
||||
<TableHeaderCell>Imported</TableHeaderCell>
|
||||
<TableHeaderCell>Skipped</TableHeaderCell>
|
||||
<TableHeaderCell>Status</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.items.map((entry) => (
|
||||
<TableRow key={entry.id} className={entry.errors ? styles.errorRow : undefined}>
|
||||
<TableCell>
|
||||
<TableCellLayout>
|
||||
<span className={styles.mono}>{entry.timestamp}</span>
|
||||
</TableCellLayout>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<TableCellLayout>
|
||||
<span className={styles.mono}>{entry.source_url}</span>
|
||||
</TableCellLayout>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<TableCellLayout>{entry.ips_imported}</TableCellLayout>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<TableCellLayout>{entry.ips_skipped}</TableCellLayout>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<TableCellLayout>
|
||||
{entry.errors ? (
|
||||
<Badge appearance="filled" color="danger">
|
||||
Error
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge appearance="filled" color="success">
|
||||
OK
|
||||
</Badge>
|
||||
)}
|
||||
</TableCellLayout>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
|
||||
{data.total_pages > 1 && (
|
||||
<div className={styles.pagination}>
|
||||
<Button size="small" appearance="secondary" disabled={page <= 1} onClick={() => { setPage(page - 1); }}>
|
||||
Previous
|
||||
</Button>
|
||||
<Text size={200}>
|
||||
Page {page} of {data.total_pages}
|
||||
</Text>
|
||||
<Button size="small" appearance="secondary" disabled={page >= data.total_pages} onClick={() => { setPage(page + 1); }}>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user