import { useMemo, useState } from "react"; import { Link } from "react-router-dom"; import { formatSeconds } from "../../utils/formatDate"; import { Badge, Button, DataGrid, DataGridBody, DataGridCell, DataGridHeader, DataGridHeaderCell, DataGridRow, MessageBar, MessageBarBody, Spinner, Text, Tooltip, makeStyles, tokens, } from "@fluentui/react-components"; import { ArrowClockwiseRegular, ArrowSyncRegular, PauseRegular, PlayRegular, StopRegular, } from "@fluentui/react-icons"; import { useCommonSectionStyles } from "../../components/commonStyles"; import { useJailsPageStyles } from "./jailsPageStyles"; import { useJails } from "../../hooks/useJails"; import type { JailSummary } from "../../types/jail"; const useOverviewStyles = makeStyles({ link: { textDecoration: "none", }, jailName: { fontFamily: tokens.fontFamilyMonospace, fontSize: tokens.fontSizeBase200, }, badgeCount: { marginLeft: tokens.spacingHorizontalXS, }, statusActionGroup: { display: "flex", gap: tokens.spacingHorizontalS, alignItems: "center", }, }); export function JailOverviewSection(): React.JSX.Element { const pageStyles = useJailsPageStyles(); const overviewStyles = useOverviewStyles(); const sectionStyles = useCommonSectionStyles(); const { jails, total, loading, error, refresh, startJail, stopJail, setIdle, reloadJail, reloadAll } = useJails(); const [opError, setOpError] = useState(null); const handle = (fn: () => Promise): void => { setOpError(null); fn().catch((err: unknown) => { setOpError(err instanceof Error ? err.message : String(err)); }); }; const jailColumns = useMemo( () => [ { columnId: "name", renderHeaderCell: () => "Jail", renderCell: (j: JailSummary) => ( {j.name} ), compare: (a: JailSummary, b: JailSummary) => a.name.localeCompare(b.name), }, { columnId: "status", renderHeaderCell: () => "Status", renderCell: (j: JailSummary) => { if (!j.running) return stopped; if (j.idle) return idle; return running; }, compare: (a: JailSummary, b: JailSummary) => { if (a.running !== b.running) return a.running ? -1 : 1; if (a.idle !== b.idle) return a.idle ? 1 : -1; return 0; }, }, { columnId: "backend", renderHeaderCell: () => "Backend", renderCell: (j: JailSummary) => {j.backend}, compare: (a: JailSummary, b: JailSummary) => a.backend.localeCompare(b.backend), }, { columnId: "banned", renderHeaderCell: () => "Banned", renderCell: (j: JailSummary) => {j.status ? String(j.status.currently_banned) : "—"}, compare: (a: JailSummary, b: JailSummary) => (a.status?.currently_banned ?? 0) - (b.status?.currently_banned ?? 0), }, { columnId: "failed", renderHeaderCell: () => "Failed", renderCell: (j: JailSummary) => {j.status ? String(j.status.currently_failed) : "—"}, compare: (a: JailSummary, b: JailSummary) => (a.status?.currently_failed ?? 0) - (b.status?.currently_failed ?? 0), }, { columnId: "findTime", renderHeaderCell: () => "Find Time", renderCell: (j: JailSummary) => {formatSeconds(j.find_time)}, compare: (a: JailSummary, b: JailSummary) => a.find_time - b.find_time, }, { columnId: "banTime", renderHeaderCell: () => "Ban Time", renderCell: (j: JailSummary) => {formatSeconds(j.ban_time)}, compare: (a: JailSummary, b: JailSummary) => a.ban_time - b.ban_time, }, { columnId: "maxRetry", renderHeaderCell: () => "Max Retry", renderCell: (j: JailSummary) => {String(j.max_retry)}, compare: (a: JailSummary, b: JailSummary) => a.max_retry - b.max_retry, }, ], [overviewStyles], ); return (
Jail Overview {total > 0 && ( {String(total)} )}
{opError && ( {opError} )} {error && ( Failed to load jails: {error} )} {loading && jails.length === 0 ? (
) : (
j.name} focusMode="composite"> {({ renderHeaderCell }) => {renderHeaderCell()}} > {({ item }) => ( key={item.name}> {({ renderCell, columnId }) => { if (columnId === "status") { return (
{renderCell(item)}
); } return {renderCell(item)}; }} )}
)}
); }