docker monitors skeleotn
This commit is contained in:
1 parent
378a40ce84
commit
a4d818e0c5
6 files changed
+219
-1
No files matched your search
@@ -3,6 +3,7 @@ import {
|
||||
Monitor,
|
||||
Gauge,
|
||||
Server,
|
||||
Boxes,
|
||||
AlertTriangle,
|
||||
LayoutList,
|
||||
ListChecks,
|
||||
@@ -36,6 +37,11 @@ export const getMenu = (t: Function, user: IUser) => {
|
||||
path: "infrastructure",
|
||||
icon: <Server size={20} strokeWidth={1.5} />,
|
||||
},
|
||||
{
|
||||
name: t("menu.docker"),
|
||||
path: "docker",
|
||||
icon: <Boxes size={20} strokeWidth={1.5} />,
|
||||
},
|
||||
{
|
||||
name: t("menu.notifications"),
|
||||
path: "notification-channels",
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
"incidents": "Incidents",
|
||||
"limitReached": "Your plan's limit has been reached",
|
||||
"no": "No",
|
||||
"home": "Return home",
|
||||
"pause": "Pause",
|
||||
"range": {
|
||||
"all": "All",
|
||||
@@ -447,6 +448,7 @@
|
||||
"checks": "Checks",
|
||||
"diagnostics": "Diagnostics",
|
||||
"discussions": "Discussions",
|
||||
"docker": "Docker",
|
||||
"docs": "Documentation",
|
||||
"incidents": "Incidents",
|
||||
"infrastructure": "Infrastructure",
|
||||
@@ -513,6 +515,18 @@
|
||||
"up": "up"
|
||||
}
|
||||
},
|
||||
"docker": {
|
||||
"fallback": {
|
||||
"actionButton": "Create a monitor!",
|
||||
"checks": [
|
||||
"Discover running Docker containers and track their lifecycle",
|
||||
"Determine container health based on runtime state or health checks",
|
||||
"Track exposed ports and network availability",
|
||||
"Provide visibility into what is running on each Docker host"
|
||||
],
|
||||
"title": "A Docker monitor is used to:"
|
||||
}
|
||||
},
|
||||
"infrastructure": {
|
||||
"fallback": {
|
||||
"actionButton": "Create a monitor!",
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
import {
|
||||
MonitorBasePageWithStates,
|
||||
UpStatusBox,
|
||||
DownStatusBox,
|
||||
PausedStatusBox,
|
||||
InfoBox,
|
||||
} from "@/components/design-elements";
|
||||
import { HeaderCreate } from "@/components/common";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { Dialog } from "@/components/inputs";
|
||||
import { DockerMonitorsTable } from "@/pages/docker/DockerMonitorsTable";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useGet } from "@/hooks/UseApi";
|
||||
import type { ApiResponse } from "@/types/api";
|
||||
import type { IMonitor, IMonitorWithStats } from "@/types/monitor";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
import { useState } from "react";
|
||||
import { useDelete } from "@/hooks/UseApi";
|
||||
import { InitializingStatusBox } from "@/components/design-elements/StatusBox";
|
||||
import { config } from "@/config/index";
|
||||
import { useLimitReached } from "@/hooks/UsePlanEntitlements";
|
||||
|
||||
const GLOBAL_REFRESH = config.GLOBAL_REFRESH;
|
||||
|
||||
const DockerMonitorsPage = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
|
||||
const [selectedMonitor, setSelectedMonitor] = useState<IMonitor | null>(null);
|
||||
const isDialogOpen = Boolean(selectedMonitor);
|
||||
const [sortField] = useState<string>("name");
|
||||
const [sortOrder] = useState<"asc" | "desc">("desc");
|
||||
const [page, setPage] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
||||
const { deleteFn, loading: isDeleting } = useDelete();
|
||||
const requestParams = [
|
||||
"embedChecks=true",
|
||||
"type=docker",
|
||||
`sortField=${sortField}`,
|
||||
`sortOrder=${sortOrder}`,
|
||||
`page=${page}`,
|
||||
`rowsPerPage=${rowsPerPage}`,
|
||||
];
|
||||
|
||||
const monitorRequestUrl = `/monitors?${requestParams.join("&")}`;
|
||||
|
||||
const { response, loading, isValidating, error, refetch } = useGet<
|
||||
ApiResponse<IMonitorWithStats>
|
||||
>(
|
||||
monitorRequestUrl,
|
||||
{},
|
||||
{
|
||||
refreshInterval: GLOBAL_REFRESH,
|
||||
keepPreviousData: true,
|
||||
dedupingInterval: 0,
|
||||
},
|
||||
{
|
||||
useTeamIdAsKey: true,
|
||||
}
|
||||
);
|
||||
const monitors: IMonitor[] = response?.data?.monitors ?? ([] as IMonitor[]);
|
||||
const count = response?.data?.count || 0;
|
||||
const upCount = response?.data?.upCount || 0;
|
||||
const downCount = response?.data?.downCount || 0;
|
||||
const pausedCount = response?.data?.pausedCount || 0;
|
||||
|
||||
const monitorLimitReached = useLimitReached("monitorsMax", count);
|
||||
|
||||
const handleConfirm = async () => {
|
||||
await deleteFn(`/monitors/${selectedMonitor?._id}`);
|
||||
setSelectedMonitor(null);
|
||||
refetch();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setSelectedMonitor(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<MonitorBasePageWithStates
|
||||
loading={isValidating}
|
||||
error={error}
|
||||
items={monitors}
|
||||
monitorLimitReached={monitorLimitReached}
|
||||
page="docker"
|
||||
actionLink="/docker/create"
|
||||
>
|
||||
<InfoBox
|
||||
title={t("monitors.infrastructure.infoBox.title")}
|
||||
description={t("monitors.infrastructure.infoBox.description")}
|
||||
/>
|
||||
<HeaderCreate
|
||||
isLoading={loading}
|
||||
path="/docker/create"
|
||||
entitlement="monitorsMax"
|
||||
entitlementCount={count}
|
||||
/>
|
||||
<Stack direction={isSmall ? "column" : "row"} gap={theme.spacing(8)}>
|
||||
<UpStatusBox n={upCount} />
|
||||
<DownStatusBox n={downCount} />
|
||||
<PausedStatusBox n={pausedCount} />
|
||||
<InitializingStatusBox
|
||||
n={count - (upCount + downCount + pausedCount)}
|
||||
/>
|
||||
</Stack>
|
||||
<DockerMonitorsTable
|
||||
monitors={monitors}
|
||||
count={count}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
rowsPerPage={rowsPerPage}
|
||||
setRowsPerPage={setRowsPerPage}
|
||||
/>
|
||||
<Dialog
|
||||
open={isDialogOpen}
|
||||
title={t("common.dialog.delete.title")}
|
||||
content={t("common.dialog.delete.description")}
|
||||
onConfirm={handleConfirm}
|
||||
onCancel={handleCancel}
|
||||
loading={isDeleting}
|
||||
/>
|
||||
</MonitorBasePageWithStates>
|
||||
);
|
||||
};
|
||||
|
||||
export default DockerMonitorsPage;
|
||||
@@ -0,0 +1,68 @@
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Table, Pagination, StatusLabel } from "@/components/design-elements";
|
||||
import type { Header } from "@/components/design-elements/Table";
|
||||
import type { IMonitor } from "@/types/monitor";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const DockerMonitorsTable = ({
|
||||
monitors,
|
||||
count,
|
||||
page,
|
||||
setPage,
|
||||
rowsPerPage,
|
||||
setRowsPerPage,
|
||||
}: {
|
||||
monitors: IMonitor[];
|
||||
count: number;
|
||||
page: number;
|
||||
setPage: (page: number) => void;
|
||||
rowsPerPage: number;
|
||||
setRowsPerPage: (rowsPerPage: number) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handlePageChange = (
|
||||
_e: React.MouseEvent<HTMLButtonElement> | null,
|
||||
newPage: number
|
||||
) => setPage(newPage);
|
||||
|
||||
const handleRowsPerPageChange = (
|
||||
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
||||
) => {
|
||||
setPage(0);
|
||||
setRowsPerPage(Number(e.target.value));
|
||||
};
|
||||
|
||||
const headers: Header<IMonitor>[] = [
|
||||
{
|
||||
id: "name",
|
||||
content: (
|
||||
<Typography component="div">{t("common.table.headers.name")}</Typography>
|
||||
),
|
||||
render: (row) => row.name,
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
content: (
|
||||
<Typography component="div">
|
||||
{t("common.table.headers.status")}
|
||||
</Typography>
|
||||
),
|
||||
render: (row) => <StatusLabel status={row.status} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Table headers={headers} data={monitors} />
|
||||
<Pagination
|
||||
component="div"
|
||||
count={count}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
onPageChange={handlePageChange}
|
||||
onRowsPerPageChange={handleRowsPerPageChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -31,7 +31,7 @@ const NotFound = ({ title = DefaultValue.title, desc = DefaultValue.desc }) => {
|
||||
sx={{ mt: theme.spacing(10) }}
|
||||
onClick={() => navigate("/")}
|
||||
>
|
||||
{t("notFoundButton")}
|
||||
{t("common.buttons.home")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
@@ -31,6 +31,7 @@ import InfraMonitorsPage from "@/pages/infrastructure/InfraMonitors";
|
||||
import InfraDetailsPage from "@/pages/infrastructure/InfraDetails";
|
||||
import InfraConfigurePage from "@/pages/infrastructure/InfraConfig";
|
||||
import InfraCreatePage from "@/pages/infrastructure/InfraCreate";
|
||||
import DockerMonitorsPage from "@/pages/docker/DockerMonitors";
|
||||
|
||||
import MaintenancePage from "@/pages/maintenance/Maintenance";
|
||||
import MaintenanceConfigPage from "@/pages/maintenance/MaintenanceConfig";
|
||||
@@ -137,6 +138,7 @@ const Router = () => {
|
||||
/>
|
||||
<Route path="infrastructure/:id" element={<InfraDetailsPage />} />
|
||||
<Route path="infrastructure" element={<InfraMonitorsPage />} />
|
||||
<Route path="docker" element={<DockerMonitorsPage />} />
|
||||
|
||||
<Route path="maintenance" element={<MaintenancePage />} />
|
||||
<Route path="maintenance/create" element={<MaintenanceCreatePage />} />
|
||||
|
||||
Reference in new issue
Block a user