docker details tweaks
This commit is contained in:
1 parent
5c9d6b5523
commit
86cfc89545
5 files changed
+85
-43
No files matched your search
@@ -12,9 +12,11 @@ import {
|
||||
} from "recharts";
|
||||
import { XTick } from "@/components/monitors/ChartResponseTime";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
import { BaseBox } from "@/components/design-elements";
|
||||
import { useAppSelector } from "@/hooks/AppHooks";
|
||||
import { formatDateWithTz, tooltipDateFormatLookup } from "@/utils/TimeUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type Datum = Record<string, unknown> & { _id: string | number };
|
||||
|
||||
@@ -33,11 +35,12 @@ export const BarDockerCount = ({
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const hasData = Array.isArray(data) && data.length > 0;
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const uiTimezone = useAppSelector((state: any) => state.ui.timezone);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const CountTooltip = ({ active, payload, label }: any) => {
|
||||
if (!active || !payload || !label) return null;
|
||||
console.log(JSON.stringify(payload, null, 2));
|
||||
const fmt = tooltipDateFormatLookup(range);
|
||||
const value = payload?.[0]?.payload?.[dataKey] ?? 0;
|
||||
return (
|
||||
@@ -45,20 +48,29 @@ export const BarDockerCount = ({
|
||||
<Typography>
|
||||
{formatDateWithTz(String(label), fmt, uiTimezone)}
|
||||
</Typography>
|
||||
<Typography>Containers: {value}</Typography>
|
||||
<Typography>
|
||||
{t("monitors.docker.details.tooltips.containers", { value })}
|
||||
</Typography>
|
||||
</BaseBox>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseChart title={title} icon={null}>
|
||||
<BaseChart
|
||||
title={title}
|
||||
icon={null}
|
||||
padding={{ xs: theme.spacing(4), md: theme.spacing(8) }}
|
||||
>
|
||||
{!hasData ? (
|
||||
<Stack height={"100%"} alignItems={"center"} justifyContent={"center"}>
|
||||
<Typography variant="h2">{emptyText || "No data"}</Typography>
|
||||
</Stack>
|
||||
) : (
|
||||
<ResponsiveContainer width="100%" height={200}>
|
||||
<BarChart data={data}>
|
||||
<BarChart
|
||||
data={data}
|
||||
margin={{ top: 8, right: 8, left: isSmall ? 4 : 12, bottom: 8 }}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id={"gradient"} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop
|
||||
@@ -82,7 +94,12 @@ export const BarDockerCount = ({
|
||||
dataKey={"_id"}
|
||||
tick={(props) => <XTick {...props} range={range} />}
|
||||
/>
|
||||
<YAxis allowDecimals={false} />
|
||||
<YAxis
|
||||
allowDecimals={false}
|
||||
width={isSmall ? 24 : 36}
|
||||
tick={{ fontSize: isSmall ? 10 : 11 }}
|
||||
tickMargin={4}
|
||||
/>
|
||||
<Tooltip content={<CountTooltip />} cursor={false} />
|
||||
<Bar dataKey={dataKey} fill={`url(#gradient)`} />
|
||||
</BarChart>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BaseBox } from "../design-elements";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import type { ResponsiveStyleValue } from "@mui/system";
|
||||
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
@@ -10,6 +11,7 @@ type BaseChartProps = React.PropsWithChildren<{
|
||||
title: string;
|
||||
width?: number | string;
|
||||
maxWidth?: number | string;
|
||||
padding?: number | string | ResponsiveStyleValue<number | string>;
|
||||
}>;
|
||||
|
||||
export const BaseChart = ({
|
||||
@@ -18,13 +20,13 @@ export const BaseChart = ({
|
||||
title,
|
||||
width = "100%",
|
||||
maxWidth = "100%",
|
||||
padding,
|
||||
}: BaseChartProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<BaseBox
|
||||
sx={{
|
||||
padding: theme.spacing(8),
|
||||
padding: padding ?? theme.spacing(8),
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
width: width,
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "recharts";
|
||||
import { XTick } from "@/components/monitors/ChartResponseTime";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
|
||||
export const HistogramDockerPercentage = ({
|
||||
data,
|
||||
@@ -26,17 +27,25 @@ export const HistogramDockerPercentage = ({
|
||||
emptyText?: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const hasData = Array.isArray(data) && data.length > 0;
|
||||
|
||||
return (
|
||||
<BaseChart title={title} icon={null}>
|
||||
<BaseChart
|
||||
title={title}
|
||||
icon={null}
|
||||
padding={{ xs: theme.spacing(4), md: theme.spacing(8) }}
|
||||
>
|
||||
{!hasData ? (
|
||||
<Stack height={"100%"} alignItems={"center"} justifyContent={"center"}>
|
||||
<Typography variant="h2">{emptyText || "No data"}</Typography>
|
||||
</Stack>
|
||||
) : (
|
||||
<ResponsiveContainer width="100%" height={155}>
|
||||
<AreaChart data={data}>
|
||||
<ResponsiveContainer width="100%" height={200}>
|
||||
<AreaChart
|
||||
data={data}
|
||||
margin={{ top: 8, right: 8, left: isSmall ? 0 : 8, bottom: 8 }}
|
||||
>
|
||||
<CartesianGrid
|
||||
stroke={theme.palette.divider}
|
||||
strokeWidth={1}
|
||||
@@ -60,9 +69,15 @@ export const HistogramDockerPercentage = ({
|
||||
</defs>
|
||||
<XAxis
|
||||
dataKey={"_id"}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={(props) => <XTick {...props} range={range} />}
|
||||
/>
|
||||
<YAxis />
|
||||
<YAxis
|
||||
width={isSmall ? 24 : 36}
|
||||
tick={{ fontSize: isSmall ? 10 : 11 }}
|
||||
tickMargin={4}
|
||||
/>
|
||||
<Area
|
||||
dataKey={dataKey}
|
||||
stroke={theme.palette.primary.main}
|
||||
|
||||
@@ -547,6 +547,9 @@
|
||||
"runningCountChart": {
|
||||
"empty": "No data",
|
||||
"title": "# of running containers"
|
||||
},
|
||||
"tooltips": {
|
||||
"containers": "Containers: {{value}}"
|
||||
}
|
||||
},
|
||||
"fallback": {
|
||||
@@ -585,7 +588,7 @@
|
||||
"optionCpuUsage": "CPU usage (%)",
|
||||
"optionDiskUsage": "Disk usage (%)",
|
||||
"optionMemoryUsage": "Memory usage (%)",
|
||||
"optionTemperature": "Temperature (°C)",
|
||||
"optionTemperature": "Temperature (\u00b0C)",
|
||||
"title": "Thresholds for alerts"
|
||||
}
|
||||
},
|
||||
@@ -715,7 +718,7 @@
|
||||
},
|
||||
"form": {
|
||||
"discord": {
|
||||
"description": "Configure your Discord webhook URL. Create one in Discord: Settings & administration → Manage apps → Custom Integrations → Incoming Webhooks",
|
||||
"description": "Configure your Discord webhook URL. Create one in Discord: Settings & administration \u2192 Manage apps \u2192 Custom Integrations \u2192 Incoming Webhooks",
|
||||
"option": "Webhook URL",
|
||||
"placeholder": "https://discord.com/api/webhooks/YOUR/WEBHOOK/URL",
|
||||
"title": "Discord configuration"
|
||||
@@ -733,7 +736,7 @@
|
||||
"title": "Channel name"
|
||||
},
|
||||
"slack": {
|
||||
"description": "Configure your Slack webhook URL. Create one in Slack: Settings & administration → Manage apps → Custom Integrations → Incoming Webhooks",
|
||||
"description": "Configure your Slack webhook URL. Create one in Slack: Settings & administration \u2192 Manage apps \u2192 Custom Integrations \u2192 Incoming Webhooks",
|
||||
"option": "Webhook URL",
|
||||
"placeholder": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
|
||||
"title": "Slack configuration"
|
||||
@@ -891,4 +894,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,34 +86,39 @@ const DockerDetailsPage = () => {
|
||||
<CardDockerContainer key={c.container_id} container={c} />
|
||||
))}
|
||||
</Stack>
|
||||
<BarDockerCount
|
||||
data={checks}
|
||||
dataKey="healthyContainers"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.healthyCountChart.title")}
|
||||
emptyText={t("monitors.docker.details.healthyCountChart.empty")}
|
||||
/>
|
||||
<BarDockerCount
|
||||
data={checks}
|
||||
dataKey="runningContainers"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.runningCountChart.title")}
|
||||
emptyText={t("monitors.docker.details.runningCountChart.empty")}
|
||||
/>
|
||||
<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.healthyChart.title")}
|
||||
emptyText={t("monitors.docker.details.healthyChart.empty")}
|
||||
/>
|
||||
<Stack gap={theme.spacing(6)} direction={{ xs: "column", lg: "row" }}>
|
||||
<HistogramDockerPercentage
|
||||
data={checks}
|
||||
dataKey="healthyPercent"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.healthyChart.title")}
|
||||
emptyText={t("monitors.docker.details.healthyChart.empty")}
|
||||
/>
|
||||
<BarDockerCount
|
||||
data={checks}
|
||||
dataKey="healthyContainers"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.healthyCountChart.title")}
|
||||
emptyText={t("monitors.docker.details.healthyCountChart.empty")}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Stack gap={theme.spacing(6)} direction={{ xs: "column", lg: "row" }}>
|
||||
<HistogramDockerPercentage
|
||||
data={checks}
|
||||
dataKey="runningPercent"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.runningChart.title")}
|
||||
emptyText={t("monitors.docker.details.runningChart.empty")}
|
||||
/>
|
||||
<BarDockerCount
|
||||
data={checks}
|
||||
dataKey="runningContainers"
|
||||
range={range}
|
||||
title={t("monitors.docker.details.runningCountChart.title")}
|
||||
emptyText={t("monitors.docker.details.runningCountChart.empty")}
|
||||
/>
|
||||
</Stack>
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user