a7a66ff370
Add BackupJobsTable, BackupRunsTable, BackupAlertsTable, BackupDashboardWidget, and BackupsPage components for backup monitoring dashboard.
104 lines
3.8 KiB
TypeScript
104 lines
3.8 KiB
TypeScript
import {
|
|
Chip,
|
|
FormControl,
|
|
InputLabel,
|
|
MenuItem,
|
|
Paper,
|
|
Select,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableContainer,
|
|
TableHead,
|
|
TableRow,
|
|
} from "@mui/material";
|
|
import { useState } from "react";
|
|
import { BackupRun } from "../types/backups";
|
|
|
|
interface Props {
|
|
runs: BackupRun[];
|
|
}
|
|
|
|
function formatBytes(bytes: number | null): string {
|
|
if (bytes === null || bytes === undefined) return "—";
|
|
if (bytes < 1024) return `${bytes} B`;
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
}
|
|
|
|
function formatDuration(ms: number | null): string {
|
|
if (ms === null || ms === undefined) return "—";
|
|
if (ms < 1000) return `${ms}ms`;
|
|
if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
|
|
if (ms < 3600_000) return `${(ms / 60_000).toFixed(1)}m`;
|
|
return `${(ms / 3600_000).toFixed(1)}h`;
|
|
}
|
|
|
|
function formatTimestamp(ts: number): string {
|
|
return new Date(ts * 1000).toLocaleString();
|
|
}
|
|
|
|
export default function BackupRunsTable({ runs }: Props) {
|
|
const [statusFilter, setStatusFilter] = useState<string>("all");
|
|
|
|
const filteredRuns = statusFilter === "all"
|
|
? runs
|
|
: runs.filter((r) => r.status === statusFilter);
|
|
|
|
return (
|
|
<>
|
|
<FormControl sx={{ minWidth: 120, mb: 2 }}>
|
|
<InputLabel>Status</InputLabel>
|
|
<Select
|
|
value={statusFilter}
|
|
label="Status"
|
|
onChange={(e) => setStatusFilter(e.target.value)}
|
|
>
|
|
<MenuItem value="all">All</MenuItem>
|
|
<MenuItem value="success">Success</MenuItem>
|
|
<MenuItem value="failure">Failure</MenuItem>
|
|
<MenuItem value="in_progress">In Progress</MenuItem>
|
|
</Select>
|
|
</FormControl>
|
|
|
|
<TableContainer component={Paper}>
|
|
<Table>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell>Job</TableCell>
|
|
<TableCell>Status</TableCell>
|
|
<TableCell>Duration</TableCell>
|
|
<TableCell>Size</TableCell>
|
|
<TableCell>Started</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{filteredRuns.map((run) => (
|
|
<TableRow key={run.id} hover>
|
|
<TableCell>{run.job_id}</TableCell>
|
|
<TableCell>
|
|
<Chip
|
|
label={run.status}
|
|
color={
|
|
run.status === "success"
|
|
? "success"
|
|
: run.status === "failure"
|
|
? "error"
|
|
: "warning"
|
|
}
|
|
size="small"
|
|
/>
|
|
</TableCell>
|
|
<TableCell>{formatDuration(run.duration_ms)}</TableCell>
|
|
<TableCell>{formatBytes(run.bytes_transferred)}</TableCell>
|
|
<TableCell>{formatTimestamp(run.started_at)}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
</>
|
|
);
|
|
}
|