diff --git a/src/widgets/glances/chart.jsx b/src/widgets/glances/chart.jsx deleted file mode 100644 index 448bb99b..00000000 --- a/src/widgets/glances/chart.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import { PureComponent } from "react"; -import { AreaChart, Area, ResponsiveContainer, Tooltip } from "recharts"; - -import CustomTooltip from "./custom_tooltip"; - -class Chart extends PureComponent { - render() { - const { dataPoints, formatter, label } = this.props; - - return ( -
- - - - - - - - - - } - classNames="rounded-md text-xs p-0.5" - contentStyle={{ - backgroundColor: "rgb(var(--color-800))", - color: "rgb(var(--color-100))" - }} - /> - - -
- ); - } -} - -export default Chart; diff --git a/src/widgets/glances/chart_dual.jsx b/src/widgets/glances/chart_dual.jsx deleted file mode 100644 index ceecacba..00000000 --- a/src/widgets/glances/chart_dual.jsx +++ /dev/null @@ -1,61 +0,0 @@ -import { PureComponent } from "react"; -import { AreaChart, Area, ResponsiveContainer, Tooltip } from "recharts"; - -import CustomTooltip from "./custom_tooltip"; - -class ChartDual extends PureComponent { - render() { - const { dataPoints, formatter, stack, label } = this.props; - - return ( -
- - - - - - - - - - - - - - - - } - classNames="rounded-md text-xs p-0.5" - contentStyle={{ - backgroundColor: "rgb(var(--color-800))", - color: "rgb(var(--color-100))" - }} - - /> - - -
- ); - } -} - -export default ChartDual; diff --git a/src/widgets/glances/component.jsx b/src/widgets/glances/component.jsx index 5eeff280..4fa1a9ff 100644 --- a/src/widgets/glances/component.jsx +++ b/src/widgets/glances/component.jsx @@ -1,9 +1,9 @@ -import Memory from "./memory"; -import Cpu from "./cpu"; -import Sensor from "./sensor"; -import Net from "./net"; -import Process from "./process"; -import Disk from "./disk"; +import Memory from "./metrics/memory"; +import Cpu from "./metrics/cpu"; +import Sensor from "./metrics/sensor"; +import Net from "./metrics/net"; +import Process from "./metrics/process"; +import Disk from "./metrics/disk"; export default function Component({ service }) { const { widget } = service; diff --git a/src/widgets/glances/components/block.jsx b/src/widgets/glances/components/block.jsx new file mode 100644 index 00000000..73cf86c9 --- /dev/null +++ b/src/widgets/glances/components/block.jsx @@ -0,0 +1,9 @@ +export default function Block({ position, children }) { + const positionClasses = Object.entries(position).map(([key, value]) => `${key}-${value}`).join(' '); + + return ( +
+ {children} +
+ ); +} diff --git a/src/widgets/glances/components/chart.jsx b/src/widgets/glances/components/chart.jsx new file mode 100644 index 00000000..2cd01107 --- /dev/null +++ b/src/widgets/glances/components/chart.jsx @@ -0,0 +1,48 @@ +import { PureComponent } from "react"; +import { AreaChart, Area, ResponsiveContainer, Tooltip } from "recharts"; + +import CustomTooltip from "./custom_tooltip"; + +class Chart extends PureComponent { + render() { + const { dataPoints, formatter, label } = this.props; + + return ( +
+
+ + + + + + + + + + } + classNames="rounded-md text-xs p-0.5" + contentStyle={{ + backgroundColor: "rgb(var(--color-800))", + color: "rgb(var(--color-100))" + }} + /> + + +
+
+ ); + } +} + +export default Chart; diff --git a/src/widgets/glances/components/chart_dual.jsx b/src/widgets/glances/components/chart_dual.jsx new file mode 100644 index 00000000..14f5e4e6 --- /dev/null +++ b/src/widgets/glances/components/chart_dual.jsx @@ -0,0 +1,63 @@ +import { PureComponent } from "react"; +import { AreaChart, Area, ResponsiveContainer, Tooltip } from "recharts"; + +import CustomTooltip from "./custom_tooltip"; + +class ChartDual extends PureComponent { + render() { + const { dataPoints, formatter, stack, label } = this.props; + + return ( +
+
+ + + + + + + + + + + + + + + + } + classNames="rounded-md text-xs p-0.5" + contentStyle={{ + backgroundColor: "rgb(var(--color-800))", + color: "rgb(var(--color-100))" + }} + + /> + + +
+
+ ); + } +} + +export default ChartDual; diff --git a/src/widgets/glances/components/container.jsx b/src/widgets/glances/components/container.jsx new file mode 100644 index 00000000..d141cab6 --- /dev/null +++ b/src/widgets/glances/components/container.jsx @@ -0,0 +1,8 @@ +export default function Container({ children }) { + return ( +
+ {children} +
+
+ ); +} diff --git a/src/widgets/glances/custom_tooltip.jsx b/src/widgets/glances/components/custom_tooltip.jsx similarity index 100% rename from src/widgets/glances/custom_tooltip.jsx rename to src/widgets/glances/components/custom_tooltip.jsx diff --git a/src/widgets/glances/components/error.jsx b/src/widgets/glances/components/error.jsx new file mode 100644 index 00000000..6e3b4da0 --- /dev/null +++ b/src/widgets/glances/components/error.jsx @@ -0,0 +1,9 @@ +import { useTranslation } from "next-i18next"; + +export default function Error() { + const { t } = useTranslation(); + + return
+ {t("widget.api_error")} +
; +} diff --git a/src/widgets/glances/cpu.jsx b/src/widgets/glances/cpu.jsx deleted file mode 100644 index daec91e0..00000000 --- a/src/widgets/glances/cpu.jsx +++ /dev/null @@ -1,100 +0,0 @@ -import dynamic from "next/dynamic"; -import { useState, useEffect } from "react"; -import { useTranslation } from "next-i18next"; - -import useWidgetAPI from "utils/proxy/use-widget-api"; - -const Chart = dynamic(() => import("./chart"), { ssr: false }); - -const pointsLimit = 15; - -export default function Component({ service }) { - const { t } = useTranslation(); - - const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); - - const { data, error } = useWidgetAPI(service.widget, 'cpu', { - refreshInterval: 1000, - }); - - const { data: systemData, error: systemError } = useWidgetAPI(service.widget, 'system'); - - useEffect(() => { - if (data) { - setDataPoints((prevDataPoints) => { - const newDataPoints = [...prevDataPoints, { value: data.total }]; - if (newDataPoints.length > pointsLimit) { - newDataPoints.shift(); - } - return newDataPoints; - }); - } - }, [data]); - - if (error) { - return
-
-
- {t("widget.api_error")} -
-
-
; - } - - if (!data) { - return
-
-
- - -
-
-
; - } - - return ( - <> -
- t("common.number", { - value, - style: "unit", - unit: "percent", - maximumFractionDigits: 0, - })} - /> -
-
- {systemData && !systemError && ( - <> - {systemData.linux_distro && ( -
- {systemData.linux_distro} -
- )} - {systemData.os_version && ( -
- {systemData.os_version} -
- )} - {systemData.hostname && ( -
- {systemData.hostname} -
- )} - - )} -
-
- {t("common.number", { - value: data.total, - style: "unit", - unit: "percent", - maximumFractionDigits: 0, - })} {t("resources.used")} -
-
- - ); -} diff --git a/src/widgets/glances/memory.jsx b/src/widgets/glances/memory.jsx deleted file mode 100644 index 0e6002ee..00000000 --- a/src/widgets/glances/memory.jsx +++ /dev/null @@ -1,96 +0,0 @@ -import dynamic from "next/dynamic"; -import { useState, useEffect } from "react"; -import { useTranslation } from "next-i18next"; - -import useWidgetAPI from "utils/proxy/use-widget-api"; - -const ChartDual = dynamic(() => import("./chart_dual"), { ssr: false }); - -const pointsLimit = 15; - -export default function Component({ service }) { - const { t } = useTranslation(); - - const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); - - const { data, error } = useWidgetAPI(service.widget, 'mem', { - refreshInterval: 1000, - }); - - useEffect(() => { - if (data) { - setDataPoints((prevDataPoints) => { - const newDataPoints = [...prevDataPoints, { a: data.used, b: data.free }]; - if (newDataPoints.length > pointsLimit) { - newDataPoints.shift(); - } - return newDataPoints; - }); - } - }, [data]); - - if (error) { - return
-
-
- {t("widget.api_error")} -
-
-
; - } - if (!data) { - return
-
-
- - -
-
-
; - } - - return ( - <> -
- t("common.bytes", { - value, - maximumFractionDigits: 0, - })} - /> -
-
- {data && !error && ( - <> - {data.free && ( -
- {t("common.bytes", { - value: data.free, - maximumFractionDigits: 0, - })} {t("resources.free")} -
- )} - - {data.total && ( -
- {t("common.bytes", { - value: data.total, - maximumFractionDigits: 0, - })} {t("resources.total")} -
- )} - - )} -
-
- {t("common.bytes", { - value: data.used, - maximumFractionDigits: 0, - })} {t("resources.used")} -
-
- - ); -} diff --git a/src/widgets/glances/metrics/cpu.jsx b/src/widgets/glances/metrics/cpu.jsx new file mode 100644 index 00000000..a93abbc7 --- /dev/null +++ b/src/widgets/glances/metrics/cpu.jsx @@ -0,0 +1,91 @@ +import dynamic from "next/dynamic"; +import { useState, useEffect } from "react"; +import { useTranslation } from "next-i18next"; + +import Error from "../components/error"; +import Container from "../components/container"; +import Block from "../components/block"; + +import useWidgetAPI from "utils/proxy/use-widget-api"; + +const Chart = dynamic(() => import("../components/chart"), { ssr: false }); + +const pointsLimit = 15; + +export default function Component({ service }) { + const { t } = useTranslation(); + + const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); + + const { data, error } = useWidgetAPI(service.widget, 'cpu', { + refreshInterval: 1000, + }); + + const { data: systemData, error: systemError } = useWidgetAPI(service.widget, 'system'); + + useEffect(() => { + if (data) { + setDataPoints((prevDataPoints) => { + const newDataPoints = [...prevDataPoints, { value: data.total }]; + if (newDataPoints.length > pointsLimit) { + newDataPoints.shift(); + } + return newDataPoints; + }); + } + }, [data]); + + if (error) { + return ; + } + + if (!data) { + return -; + } + + return ( + + t("common.number", { + value, + style: "unit", + unit: "percent", + maximumFractionDigits: 0, + })} + /> + + {systemData && !systemError && ( + + {systemData.linux_distro && ( +
+ {systemData.linux_distro} +
+ )} + {systemData.os_version && ( +
+ {systemData.os_version} +
+ )} + {systemData.hostname && ( +
+ {systemData.hostname} +
+ )} +
+ )} + + +
+ {t("common.number", { + value: data.total, + style: "unit", + unit: "percent", + maximumFractionDigits: 0, + })} {t("resources.used")} +
+
+
+ ); +} diff --git a/src/widgets/glances/disk.jsx b/src/widgets/glances/metrics/disk.jsx similarity index 50% rename from src/widgets/glances/disk.jsx rename to src/widgets/glances/metrics/disk.jsx index 7ad783ac..dcb1dc71 100644 --- a/src/widgets/glances/disk.jsx +++ b/src/widgets/glances/metrics/disk.jsx @@ -2,9 +2,13 @@ import dynamic from "next/dynamic"; import { useState, useEffect } from "react"; import { useTranslation } from "next-i18next"; +import Error from "../components/error"; +import Container from "../components/container"; +import Block from "../components/block"; + import useWidgetAPI from "utils/proxy/use-widget-api"; -const ChartDual = dynamic(() => import("./chart_dual"), { ssr: false }); +const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); const pointsLimit = 15; @@ -44,70 +48,55 @@ export default function Component({ service }) { }, [dataPoints]); if (error) { - return
-
-
- {t("widget.api_error")} -
-
-
; + return ; } if (!data) { - return
-
-
- - -
-
-
; + return -; } const diskData = data.find((item) => item.disk_name === diskName); if (!diskData) { - return
-
-
; + return -; } const diskRates = calculateRates(dataPoints); const currentRate = diskRates[diskRates.length - 1]; return ( - <> -
+ t("common.bitrate", { - value, - })} - /> -
-
- {currentRate && !error && ( - <> -
- {t("common.bitrate", { - value: currentRate.a, - })} {t("glances.read")} -
-
- {t("common.bitrate", { - value: currentRate.b, - })} {t("glances.write")} -
- - )} -
-
- {t("common.bitrate", { - value: currentRate.a + currentRate.b, - })} -
-
- + dataPoints={ratePoints} + label={[t("glances.read"), t("glances.write")]} + max={diskData.critical} + formatter={(value) => t("common.bitrate", { + value, + })} + /> + + {currentRate && !error && ( + +
+ {t("common.bitrate", { + value: currentRate.a, + })} {t("glances.read")} +
+
+ {t("common.bitrate", { + value: currentRate.b, + })} {t("glances.write")} +
+
+ )} + + +
+ {t("common.bitrate", { + value: currentRate.a + currentRate.b, + })} +
+
+ ); } diff --git a/src/widgets/glances/metrics/memory.jsx b/src/widgets/glances/metrics/memory.jsx new file mode 100644 index 00000000..f9d0cd15 --- /dev/null +++ b/src/widgets/glances/metrics/memory.jsx @@ -0,0 +1,88 @@ +import dynamic from "next/dynamic"; +import { useState, useEffect } from "react"; +import { useTranslation } from "next-i18next"; + +import Error from "../components/error"; +import Container from "../components/container"; +import Block from "../components/block"; + +import useWidgetAPI from "utils/proxy/use-widget-api"; + +const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); + +const pointsLimit = 15; + +export default function Component({ service }) { + const { t } = useTranslation(); + + const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); + + const { data, error } = useWidgetAPI(service.widget, 'mem', { + refreshInterval: 1000, + }); + + useEffect(() => { + if (data) { + setDataPoints((prevDataPoints) => { + const newDataPoints = [...prevDataPoints, { a: data.used, b: data.free }]; + if (newDataPoints.length > pointsLimit) { + newDataPoints.shift(); + } + return newDataPoints; + }); + } + }, [data]); + + if (error) { + return ; + } + + if (!data) { + return -; + } + + return ( + + t("common.bytes", { + value, + maximumFractionDigits: 0, + })} + /> + + {data && !error && ( + + {data.free && ( +
+ {t("common.bytes", { + value: data.free, + maximumFractionDigits: 0, + })} {t("resources.free")} +
+ )} + + {data.total && ( +
+ {t("common.bytes", { + value: data.total, + maximumFractionDigits: 0, + })} {t("resources.total")} +
+ )} +
+ )} + + +
+ {t("common.bytes", { + value: data.used, + maximumFractionDigits: 0, + })} {t("resources.used")} +
+
+
+ ); +} diff --git a/src/widgets/glances/net.jsx b/src/widgets/glances/metrics/net.jsx similarity index 50% rename from src/widgets/glances/net.jsx rename to src/widgets/glances/metrics/net.jsx index a630ae74..15233b42 100644 --- a/src/widgets/glances/net.jsx +++ b/src/widgets/glances/metrics/net.jsx @@ -2,9 +2,13 @@ import dynamic from "next/dynamic"; import { useState, useEffect } from "react"; import { useTranslation } from "next-i18next"; +import Error from "../components/error"; +import Container from "../components/container"; +import Block from "../components/block"; + import useWidgetAPI from "utils/proxy/use-widget-api"; -const ChartDual = dynamic(() => import("./chart_dual"), { ssr: false }); +const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); const pointsLimit = 15; @@ -36,61 +40,53 @@ export default function Component({ service }) { }, [data, interfaceName]); if (error) { - return
-
-
- {t("widget.api_error")} -
-
-
; + return ; } + if (!data) { - return
-
-
- - -
-
-
; + return -; } + const interfaceData = data.find((item) => item[item.key] === interfaceName); if (!interfaceData) { - return
-
-
; + return -; } return ( - <> -
- t("common.byterate", { - value, - maximumFractionDigits: 0, - })} - /> -
-
+ + t("common.byterate", { + value, + maximumFractionDigits: 0, + })} + /> + + {interfaceData && interfaceData.interface_name && ( -
+
{interfaceData.interface_name}
)} - {t("common.bitrate", { - value: interfaceData.tx, - maximumFractionDigits: 0, - })} {t("docker.tx")} -
-
- {t("common.bitrate", { - value: interfaceData.rx, - maximumFractionDigits: 0, - })} {t("docker.rx")} -
-
- + +
+ {t("common.bitrate", { + value: interfaceData.tx, + maximumFractionDigits: 0, + })} {t("docker.tx")} +
+ + + +
+ {t("common.bitrate", { + value: interfaceData.rx, + maximumFractionDigits: 0, + })} {t("docker.rx")} +
+
+ ); } diff --git a/src/widgets/glances/process.jsx b/src/widgets/glances/metrics/process.jsx similarity index 60% rename from src/widgets/glances/process.jsx rename to src/widgets/glances/metrics/process.jsx index 7d9785e6..bf606a75 100644 --- a/src/widgets/glances/process.jsx +++ b/src/widgets/glances/metrics/process.jsx @@ -1,5 +1,9 @@ import { useTranslation } from "next-i18next"; +import Error from "../components/error"; +import Container from "../components/container"; +import Block from "../components/block"; + import useWidgetAPI from "utils/proxy/use-widget-api"; import ResolvedIcon from "components/resolvedicon"; @@ -21,52 +25,42 @@ export default function Component({ service }) { }); if (error) { - return
-
-
- {t("widget.api_error")} -
-
-
; + return ; } if (!data) { - return
-
-
- - -
-
-
; + return -; } data.splice(5); return ( - <> -
+ +
{t("resources.cpu")}
{t("resources.mem")}
-
-
- { data.map((item) =>
+ + + +
+ { data.map((item) =>
-
+
{statusMap[item.status]}
-
{item.name}
-
{item.cpu_percent.toFixed(1)}%
-
{t("common.bytes", { +
{item.name}
+
{item.cpu_percent.toFixed(1)}%
+
{t("common.bytes", { value: item.memory_info[0], maximumFractionDigits: 0, })}
) } -
-
- +
+ + ); } diff --git a/src/widgets/glances/metrics/sensor.jsx b/src/widgets/glances/metrics/sensor.jsx new file mode 100644 index 00000000..9be5666f --- /dev/null +++ b/src/widgets/glances/metrics/sensor.jsx @@ -0,0 +1,88 @@ +import dynamic from "next/dynamic"; +import { useState, useEffect } from "react"; +import { useTranslation } from "next-i18next"; + +import Error from "../components/error"; +import Container from "../components/container"; +import Block from "../components/block"; + +import useWidgetAPI from "utils/proxy/use-widget-api"; + +const Chart = dynamic(() => import("../components/chart"), { ssr: false }); + +const pointsLimit = 15; + +export default function Component({ service }) { + const { t } = useTranslation(); + const { widget } = service; + const [, sensorName] = widget.metric.split(':'); + + const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); + + const { data, error } = useWidgetAPI(service.widget, 'sensors', { + refreshInterval: 1000, + }); + + useEffect(() => { + if (data) { + const sensorData = data.find((item) => item.label === sensorName); + setDataPoints((prevDataPoints) => { + const newDataPoints = [...prevDataPoints, { value: sensorData.value }]; + if (newDataPoints.length > pointsLimit) { + newDataPoints.shift(); + } + return newDataPoints; + }); + } + }, [data, sensorName]); + + if (error) { + return ; + } + + if (!data) { + return -; + } + + const sensorData = data.find((item) => item.label === sensorName); + + if (!sensorData) { + return -; + } + + return ( + + t("common.number", { + value, + })} + /> + + {sensorData && !error && ( + + {sensorData.warning && ( +
+ {sensorData.warning}{sensorData.unit} {t("glances.warn")} +
+ )} + {sensorData.critical && ( +
+ {sensorData.critical} {sensorData.unit} {t("glances.crit")} +
+ )} +
+ )} + + +
+ {t("common.number", { + value: sensorData.value, + })} {sensorData.unit} +
+
+
+ ); +} diff --git a/src/widgets/glances/sensor.jsx b/src/widgets/glances/sensor.jsx deleted file mode 100644 index 32d01eb2..00000000 --- a/src/widgets/glances/sensor.jsx +++ /dev/null @@ -1,99 +0,0 @@ -import dynamic from "next/dynamic"; -import { useState, useEffect } from "react"; -import { useTranslation } from "next-i18next"; - -import useWidgetAPI from "utils/proxy/use-widget-api"; - -const Chart = dynamic(() => import("./chart"), { ssr: false }); - -const pointsLimit = 15; - -export default function Component({ service }) { - const { t } = useTranslation(); - const { widget } = service; - const [, sensorName] = widget.metric.split(':'); - - const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); - - const { data, error } = useWidgetAPI(service.widget, 'sensors', { - refreshInterval: 1000, - }); - - useEffect(() => { - if (data) { - const sensorData = data.find((item) => item.label === sensorName); - setDataPoints((prevDataPoints) => { - const newDataPoints = [...prevDataPoints, { value: sensorData.value }]; - if (newDataPoints.length > pointsLimit) { - newDataPoints.shift(); - } - return newDataPoints; - }); - } - }, [data, sensorName]); - - if (error) { - return
-
-
- {t("widget.api_error")} -
-
-
; - } - - if (!data) { - return
-
-
- - -
-
-
; - } - - const sensorData = data.find((item) => item.label === sensorName); - - if (!sensorData) { - return
-
-
; - } - - return ( - <> -
- t("common.number", { - value, - })} - /> -
-
- {sensorData && !error && ( - <> - {sensorData.warning && ( -
- {sensorData.warning}{sensorData.unit} {t("glances.warn")} -
- )} - {sensorData.critical && ( -
- {sensorData.critical} {sensorData.unit} {t("glances.crit")} -
- )} - - )} -
-
- {t("common.number", { - value: sensorData.value, - })} {sensorData.unit} -
-
- - ); -}