import Box from "@mui/material/Box"; import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import { Table, Pagination, StatusLabel, ColoredLabel, } from "@/Components/design-elements"; import { SPACING } from "@/Utils/Theme/constants"; import type { Header } from "@/Components/design-elements/Table"; import { ActionsMenu, type ActionMenuItem } from "@/Components/actions-menu"; import { ArrowUp, ArrowDown } from "lucide-react"; import { useTranslation } from "react-i18next"; import useMediaQuery from "@mui/material/useMediaQuery"; import { useTheme } from "@mui/material/styles"; import { useNavigate } from "react-router-dom"; import { usePost } from "@/Hooks/UseApi"; import type { Monitor } from "@/Types/Monitor"; import type { Tag } from "@/Types/Tag"; import type { DockerContainerSummary } from "@/Types/Check"; import { Checkbox } from "@/Components/inputs"; const summaryOf = (monitor: Monitor): DockerContainerSummary | undefined => { const recentChecks = monitor.recentChecks ?? []; return recentChecks[recentChecks.length - 1]?.containerSummary; }; interface DockerMonitorsTableProps { monitors: Monitor[]; tags: Tag[]; refetch: () => void; setSelectedMonitor: (monitor: Monitor | null) => void; sortField: string; setSortField: (field: string) => void; sortOrder: "asc" | "desc"; setSortOrder: (order: "asc" | "desc") => void; count: number; page: number; setPage: (page: number) => void; rowsPerPage: number; setRowsPerPage: (rowsPerPage: number) => void; selectedRows?: string[]; onSelectionChange?: (selected: string[]) => void; } export const DockerMonitorsTable = ({ monitors, tags, refetch, setSelectedMonitor, sortField, setSortField, sortOrder, setSortOrder, count, page, setPage, rowsPerPage, setRowsPerPage, selectedRows = [], onSelectionChange, }: DockerMonitorsTableProps) => { const { t } = useTranslation(); const theme = useTheme(); const isSmall = useMediaQuery(theme.breakpoints.down("md")); const navigate = useNavigate(); const { post } = usePost, Monitor>(); const selectedSet = new Set(selectedRows); const isAllSelected = monitors.length > 0 && monitors.every((m) => selectedSet.has(m.id)); const isSomeSelected = selectedRows.length > 0 && !isAllSelected; const handleSelectAll = (checked: boolean) => { onSelectionChange?.(checked ? monitors.map((m) => m.id) : []); }; const handleSelectRow = (id: string, checked: boolean) => { if (!onSelectionChange) return; onSelectionChange( checked ? [...selectedRows, id] : selectedRows.filter((rowId) => rowId !== id) ); }; const isRowSelected = (id: string) => selectedSet.has(id); const handlePageChange = ( _e: React.MouseEvent | null, newPage: number ) => { setPage(newPage); }; const handleRowsPerPageChange = ( e: React.ChangeEvent ) => { const value = Number(e.target.value); setPage(0); setRowsPerPage(value); }; const handleSort = (e: React.MouseEvent, field: string) => { e.preventDefault(); e.stopPropagation(); if (sortField === field) { const newOrder = sortOrder === "asc" ? "desc" : "asc"; setSortOrder(newOrder); } else { setSortField(field); setSortOrder("asc"); } refetch(); }; const getActions = (monitor: Monitor): ActionMenuItem[] => { return [ { id: 2, label: t("pages.common.monitors.actions.details"), action: () => { navigate(`${monitor.id}`); }, }, { id: 3, label: t("pages.common.monitors.actions.incidents"), action: () => { navigate(`/incidents?monitorId=${monitor.id}`); }, }, { id: 4, label: t("pages.common.monitors.actions.configure"), action: () => { navigate(`/docker/configure/${monitor.id}`); }, }, { id: 6, label: monitor.isActive === false ? t("common.buttons.resume") : t("common.buttons.pause"), action: async () => { await post(`/monitors/pause/${monitor.id}`, {}); refetch(); }, closeMenu: true, }, { id: 7, label: ( {t("common.buttons.delete")} ), action: () => { setSelectedMonitor(monitor); }, closeMenu: true, }, ]; }; const getHeaders = () => { const renderSortIcon = (isActive: boolean) => ( {isActive ? ( sortOrder === "asc" ? ( ) : ( ) ) : null} ); const headers: Header[] = [ { id: "selection", content: ( handleSelectAll(e.target.checked)} /> ), hideMobileLabel: true, render: (row) => ( { handleSelectRow(row.id, e.target.checked); }} onClick={(e) => e.stopPropagation()} /> ), onClick: (e) => e?.stopPropagation(), }, { id: "name", align: "left", mobileLabel: t("pages.docker.table.headers.host"), content: ( handleSort(e, "name")} sx={{ cursor: "pointer" }} > {t("pages.docker.table.headers.host")} {renderSortIcon(sortField === "name")} ), render: (row) => { return ( {row.name} {row.url} ); }, }, { id: "status", mobileLabel: t("common.table.headers.status"), content: ( handleSort(e, "status")} sx={{ cursor: "pointer" }} > {t("common.table.headers.status")} {renderSortIcon(sortField === "status")} ), render: (row) => { return ; }, }, { id: "containers", content: t("pages.docker.table.headers.containers"), render: (row) => { const summary = summaryOf(row); return ( {summary ? t("pages.docker.table.containersRunning", { running: summary.running, total: summary.total, }) : "—"} ); }, }, { id: "tags", content: t("common.table.headers.tags"), render: (row) => { if (row.tags.length === 0) return "-"; return ( {row.tags.map((tagId) => { const fullTag = tags.find((t) => t.id === tagId); if (!fullTag) return null; return ( ); })} ); }, }, { id: "actions", content: t("common.table.headers.actions"), render: (row) => { return ; }, }, ]; return headers; }; let headers = getHeaders(); if (isSmall) { headers = headers.filter((h) => h.id !== "histogram"); } return ( { navigate(`/docker/host/${row.id}`); }} getRowSx={(row) => ({ backgroundColor: isRowSelected(row.id) ? theme.palette.action.selected : "inherit", })} /> ); };