diff --git a/docs/widgets/services/glances.md b/docs/widgets/services/glances.md index 562cf57a2..d28462eb1 100644 --- a/docs/widgets/services/glances.md +++ b/docs/widgets/services/glances.md @@ -51,6 +51,8 @@ The metric field in the configuration determines the type of system monitoring d `process`: Top 5 processes based on CPU usage. Gives an overview of which processes are consuming the most resources. +`containers`: Docker or Kubernetes containers list. Shows up to 5 containers running on the system and their resource usage. + `network:<interface_name>`: Network data usage for the specified interface. Replace `<interface_name>` with the name of your network interface, e.g., `network:enp0s25`, as specified in glances. `sensor:<sensor_id>`: Temperature of the specified sensor, typically used to monitor CPU temperature. Replace `<sensor_id>` with the name of your sensor, e.g., `sensor:Package id 0` as specified in glances. diff --git a/src/widgets/glances/component.jsx b/src/widgets/glances/component.jsx index df916b4ba..bff31ac16 100644 --- a/src/widgets/glances/component.jsx +++ b/src/widgets/glances/component.jsx @@ -7,6 +7,7 @@ import Disk from "./metrics/disk"; import GPU from "./metrics/gpu"; import Info from "./metrics/info"; import Fs from "./metrics/fs"; +import Containers from "./metrics/containers"; export default function Component({ service }) { const { widget } = service; @@ -23,6 +24,10 @@ export default function Component({ service }) { return <Process service={service} />; } + if (widget.metric === "containers") { + return <Containers service={service} />; + } + if (widget.metric === "cpu") { return <Cpu service={service} />; } diff --git a/src/widgets/glances/metrics/containers.jsx b/src/widgets/glances/metrics/containers.jsx new file mode 100644 index 000000000..dac52be3c --- /dev/null +++ b/src/widgets/glances/metrics/containers.jsx @@ -0,0 +1,73 @@ +import { useTranslation } from "next-i18next"; + +import Container from "../components/container"; +import Block from "../components/block"; + +import useWidgetAPI from "utils/proxy/use-widget-api"; +import ResolvedIcon from "components/resolvedicon"; + +const statusMap = { + running: <ResolvedIcon icon="mdi-circle" width={32} height={32} />, + paused: <ResolvedIcon icon="mdi-circle-outline" width={32} height={32} />, +}; + +const defaultInterval = 1000; + +export default function Component({ service }) { + const { t } = useTranslation(); + const { widget } = service; + const { chart, refreshInterval = defaultInterval, version = 3 } = widget; + + const idKey = version === 3 ? "Id" : "id"; + const statusKey = version === 3 ? "Status" : "status"; + + const { data, error } = useWidgetAPI(service.widget, `${version}/containers`, { + refreshInterval: Math.max(defaultInterval, refreshInterval), + }); + + if (error) { + return <Container service={service} widget={widget} />; + } + + if (!data) { + return ( + <Container chart={chart}> + <Block position="bottom-3 left-3">-</Block> + </Container> + ); + } + + data.splice(chart ? 5 : 1); + + return ( + <Container chart={chart}> + <Block position="top-4 right-3 left-3"> + <div className="flex items-center text-xs"> + <div className="grow" /> + <div className="w-14 text-right italic">{t("resources.cpu")}</div> + <div className="w-14 text-right">{t("resources.mem")}</div> + </div> + </Block> + + <Block position="bottom-4 right-3 left-3"> + <div className="pointer-events-none text-theme-900 dark:text-theme-200"> + {data.map((item) => ( + <div key={item[idKey]} className="text-[0.75rem] h-[0.8rem]"> + <div className="flex items-center"> + <div className="w-3 h-3 mr-1.5 opacity-50">{statusMap[item[statusKey]]}</div> + <div className="opacity-75 grow truncate">{item.name}</div> + <div className="opacity-25 w-14 text-right">{item.cpu_percent.toFixed(1)}%</div> + <div className="opacity-25 w-14 text-right"> + {t("common.bytes", { + value: item.memory.usage, + maximumFractionDigits: 0, + })} + </div> + </div> + </div> + ))} + </div> + </Block> + </Container> + ); +} diff --git a/src/widgets/glances/widget.js b/src/widgets/glances/widget.js index 00d3ac5ad..38da4fd79 100644 --- a/src/widgets/glances/widget.js +++ b/src/widgets/glances/widget.js @@ -3,7 +3,7 @@ import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; const widget = { api: "{url}/api/{endpoint}", proxyHandler: credentialedProxyHandler, - allowedEndpoints: /\d\/quicklook|diskio|cpu|fs|gpu|system|mem|network|processlist|sensors/, + allowedEndpoints: /\d\/quicklook|diskio|cpu|fs|gpu|system|mem|network|processlist|sensors|containers/, }; export default widget;