client
This commit is contained in:
1 parent
4f4863db75
commit
445b594cab
5 files changed
+234
-7
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { BaseBox } from "@/components/design-elements";
|
||||
|
||||
type ExposedPort = { port: string; protocol: string };
|
||||
|
||||
export type DockerContainerSummary = {
|
||||
container_id: string;
|
||||
container_name: string;
|
||||
base_image?: string;
|
||||
exposed_ports?: ExposedPort[];
|
||||
status?: string;
|
||||
health?: { healthy?: boolean; source?: string; message?: string };
|
||||
};
|
||||
|
||||
const shortId = (id?: string) => (id ? id.slice(0, 12) : "-");
|
||||
const portsText = (ports?: ExposedPort[]) =>
|
||||
(ports || [])
|
||||
.map((p) => `${p.port}${p.protocol ? "/" + p.protocol : ""}`)
|
||||
.join(", ");
|
||||
|
||||
export const CardDockerContainer = ({
|
||||
container,
|
||||
}: {
|
||||
container: DockerContainerSummary;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<BaseBox p={4} width={{ xs: "100%", md: 420 }}>
|
||||
<Stack spacing={6} sx={{ width: "100%" }}>
|
||||
<Typography variant="h6" color="textPrimary">
|
||||
{t("monitors.docker.details.dockerContainerCard.title", {
|
||||
name: container.container_name || "-",
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid size={4}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("monitors.docker.details.dockerContainerCard.fields.status")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Typography variant="body2">{container.status || "-"}</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid size={4}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("monitors.docker.details.dockerContainerCard.fields.health")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Typography variant="body2">
|
||||
{container.health?.healthy === true
|
||||
? t(
|
||||
"monitors.docker.details.dockerContainerCard.values.healthy"
|
||||
)
|
||||
: container.health?.healthy === false
|
||||
? t(
|
||||
"monitors.docker.details.dockerContainerCard.values.unhealthy"
|
||||
)
|
||||
: "-"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid size={4}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("monitors.docker.details.dockerContainerCard.fields.id")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Typography variant="body2">
|
||||
{shortId(container.container_id)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid size={4}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("monitors.docker.details.dockerContainerCard.fields.image")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Typography variant="body2">
|
||||
{container.base_image || "-"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid size={4}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("monitors.docker.details.dockerContainerCard.fields.ports")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Typography variant="body2">
|
||||
{portsText(container.exposed_ports)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</BaseBox>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { BaseChart } from "@/components/monitors/Chart";
|
||||
import {
|
||||
ResponsiveContainer,
|
||||
AreaChart,
|
||||
Area,
|
||||
XAxis,
|
||||
YAxis,
|
||||
CartesianGrid,
|
||||
} from "recharts";
|
||||
import { XTick } from "@/components/monitors/ChartResponseTime";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
export const HistogramDockerPercentage = ({
|
||||
data,
|
||||
dataKey,
|
||||
range,
|
||||
title,
|
||||
emptyText,
|
||||
}: {
|
||||
data: any[];
|
||||
dataKey: string;
|
||||
range: string;
|
||||
title: string;
|
||||
emptyText?: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const hasData = Array.isArray(data) && data.length > 0;
|
||||
|
||||
return (
|
||||
<BaseChart title={title} icon={null}>
|
||||
{!hasData ? (
|
||||
<Stack height={"100%"} alignItems={"center"} justifyContent={"center"}>
|
||||
<Typography variant="h2">{emptyText || "No data"}</Typography>
|
||||
</Stack>
|
||||
) : (
|
||||
<ResponsiveContainer width="100%" height={155}>
|
||||
<AreaChart data={data}>
|
||||
<CartesianGrid
|
||||
stroke={theme.palette.divider}
|
||||
strokeWidth={1}
|
||||
strokeOpacity={1}
|
||||
fill="transparent"
|
||||
vertical={false}
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={theme.palette.primary.main}
|
||||
stopOpacity={0.8}
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={theme.palette.primary.light}
|
||||
stopOpacity={0}
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<XAxis
|
||||
dataKey={"_id"}
|
||||
tick={(props) => <XTick {...props} range={range} />}
|
||||
/>
|
||||
<YAxis />
|
||||
<Area
|
||||
dataKey={dataKey}
|
||||
stroke={theme.palette.primary.main}
|
||||
fill="url(#area)"
|
||||
type="monotone"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
)}
|
||||
</BaseChart>
|
||||
);
|
||||
};
|
||||
@@ -5,5 +5,6 @@ export { HeaderControls } from "./HeaderControls";
|
||||
export { ChartResponseTime } from "./ChartResponseTime";
|
||||
export { HistogramPageSpeed } from "./HistogramPageSpeed";
|
||||
export { HistogramInfrastructure } from "./HistogramInfrastructure";
|
||||
|
||||
export { CardDockerContainer } from "./CardDockerContainer";
|
||||
export { HeaderFilter } from "./HeaderFilter";
|
||||
export { HistogramDockerPercentage } from "./HistogramDockerPercentage";
|
||||
@@ -149,6 +149,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"common": {
|
||||
"appName": "Checkmate",
|
||||
"breadcrumbs": {
|
||||
@@ -530,6 +531,30 @@
|
||||
"headers": {
|
||||
"runningContainers": "Running containers"
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"dockerContainerCard": {
|
||||
"title": "Container: {{name}}",
|
||||
"fields": {
|
||||
"status": "Status",
|
||||
"health": "Health",
|
||||
"id": "ID",
|
||||
"image": "Image",
|
||||
"ports": "Ports"
|
||||
},
|
||||
"values": {
|
||||
"healthy": "Healthy",
|
||||
"unhealthy": "Unhealthy"
|
||||
}
|
||||
},
|
||||
"healthyChart": {
|
||||
"title": "Healthy container %",
|
||||
"empty": "No data"
|
||||
},
|
||||
"runningChart": {
|
||||
"title": "Running container %",
|
||||
"empty": "No data"
|
||||
}
|
||||
}
|
||||
},
|
||||
"infrastructure": {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { BasePage, StatBox } from "@/components/design-elements";
|
||||
import { HeaderControls, HeaderRange } from "@/components/monitors";
|
||||
import {
|
||||
HeaderControls,
|
||||
HeaderRange,
|
||||
HistogramDockerPercentage,
|
||||
} from "@/components/monitors";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Box from "@mui/material/Box";
|
||||
import { CardDockerContainer } from "@/components/monitors";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import prettyMilliseconds from "pretty-ms";
|
||||
@@ -35,6 +39,8 @@ const DockerDetailsPage = () => {
|
||||
const stats = response?.data?.stats;
|
||||
const checks = (response?.data?.checks || []) as any;
|
||||
const latestCheck = checks[0];
|
||||
const snapshot = latestCheck?.runningContainersSnapshot || [];
|
||||
console.log(checks);
|
||||
const palette = getStatusPalette(monitor?.status || "initializing");
|
||||
|
||||
const streakDuration = stats?.currentStreakStartedAt
|
||||
@@ -76,11 +82,25 @@ const DockerDetailsPage = () => {
|
||||
/>
|
||||
</Stack>
|
||||
<HeaderRange loading={loading} range={range} setRange={setRange} />
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Box component="pre" sx={{ whiteSpace: "pre-wrap" }}>
|
||||
{JSON.stringify(latestCheck, null, 2)}
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(6)} direction={{ xs: "column", md: "row" }}>
|
||||
{snapshot.map((c: any) => (
|
||||
<CardDockerContainer key={c.container_id} container={c} />
|
||||
))}
|
||||
</Stack>
|
||||
<HistogramDockerPercentage
|
||||
data={checks}
|
||||
dataKey="healthyPercent"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.healthyChart.title")}
|
||||
emptyText={t("monitors.docker.details.healthyChart.empty")}
|
||||
/>
|
||||
<HistogramDockerPercentage
|
||||
data={checks}
|
||||
dataKey="runningPercent"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.runningChart.title")}
|
||||
emptyText={t("monitors.docker.details.runningChart.empty")}
|
||||
/>
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user