From 23097b740662d5e2b3b0d5e167ceac6f900d61ce Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:43:13 -0800 Subject: [PATCH] Enhancement: resources network widget (#4327) --- docs/installation/k8s.md | 3 +- docs/widgets/info/resources.md | 3 +- src/components/widgets/resources/network.jsx | 47 +++++++++++++++++++ .../widgets/resources/resources.jsx | 2 + src/components/widgets/widget/resource.jsx | 7 ++- src/pages/api/widgets/resources.js | 28 ++++++++++- 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/components/widgets/resources/network.jsx diff --git a/docs/installation/k8s.md b/docs/installation/k8s.md index 6805139b65c..24be2c341fc 100644 --- a/docs/installation/k8s.md +++ b/docs/installation/k8s.md @@ -175,6 +175,7 @@ data: expanded: true cpu: true memory: true + network: default - search: provider: duckduckgo target: _blank @@ -370,7 +371,7 @@ prevent unnecessary re-renders on page loads and window / tab focusing. The procedure for enabling sticky sessions depends on your Ingress controller. Below is an example using Traefik as the Ingress controller. -``` +```yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: diff --git a/docs/widgets/info/resources.md b/docs/widgets/info/resources.md index 19323dc30c9..7fcf9c5cdf3 100644 --- a/docs/widgets/info/resources.md +++ b/docs/widgets/info/resources.md @@ -24,9 +24,10 @@ _Note: unfortunately, the package used for getting CPU temp ([systeminformation] tempmin: 0 # optional, minimum cpu temp tempmax: 100 # optional, maximum cpu temp uptime: true - units: imperial # only used by cpu temp + units: imperial # only used by cpu temp, options: 'imperial' or 'metric' refresh: 3000 # optional, in ms diskUnits: bytes # optional, bytes (default) or bbytes. Only applies to disk + network: true # optional, uses 'default' if true or specify a network interface name ``` You can also pass a `label` option, which allows you to group resources under named sections, diff --git a/src/components/widgets/resources/network.jsx b/src/components/widgets/resources/network.jsx new file mode 100644 index 00000000000..5b5cc004360 --- /dev/null +++ b/src/components/widgets/resources/network.jsx @@ -0,0 +1,47 @@ +import useSWR from "swr"; +import { FaNetworkWired } from "react-icons/fa"; +import { useTranslation } from "next-i18next"; + +import Resource from "../widget/resource"; +import Error from "../widget/error"; + +export default function Network({ options, refresh = 1500 }) { + const { t } = useTranslation(); + // eslint-disable-next-line no-param-reassign + if (options.network === true) options.network = "default"; + + const { data, error } = useSWR(`/api/widgets/resources?type=network&interfaceName=${options.network}`, { + refreshInterval: refresh, + }); + + if (error || data?.error) { + return ; + } + + if (!data || !data.network) { + return ( + + ); + } + + return ( + + ); +} diff --git a/src/components/widgets/resources/resources.jsx b/src/components/widgets/resources/resources.jsx index 634e0ff5330..db26caa78ee 100644 --- a/src/components/widgets/resources/resources.jsx +++ b/src/components/widgets/resources/resources.jsx @@ -6,6 +6,7 @@ import Cpu from "./cpu"; import Memory from "./memory"; import CpuTemp from "./cputemp"; import Uptime from "./uptime"; +import Network from "./network"; export default function Resources({ options }) { const { expanded, units, diskUnits, tempmin, tempmax } = options; @@ -23,6 +24,7 @@ export default function Resources({ options }) { )) : options.disk && } + {options.network && } {options.cputemp && ( )} diff --git a/src/components/widgets/widget/resource.jsx b/src/components/widgets/widget/resource.jsx index 8c9759284f0..b1f737407b6 100644 --- a/src/components/widgets/widget/resource.jsx +++ b/src/components/widgets/widget/resource.jsx @@ -10,6 +10,7 @@ export default function Resource({ percentage, expanded = false, additionalClassNames = "", + wide = false, }) { const Icon = icon; @@ -18,7 +19,11 @@ export default function Resource({ className={`flex-none flex flex-row items-center mr-3 py-1.5 information-widget-resource ${additionalClassNames}`} > -
+
{value}
{label}
diff --git a/src/pages/api/widgets/resources.js b/src/pages/api/widgets/resources.js index 66449bff0c1..fa7cc7663bd 100644 --- a/src/pages/api/widgets/resources.js +++ b/src/pages/api/widgets/resources.js @@ -7,7 +7,7 @@ const logger = createLogger("resources"); const si = require("systeminformation"); export default async function handler(req, res) { - const { type, target } = req.query; + const { type, target, interfaceName = "default" } = req.query; if (type === "cpu") { const load = await si.currentLoad(); @@ -57,6 +57,32 @@ export default async function handler(req, res) { }); } + if (type === "network") { + let networkData = await si.networkStats(); + let interfaceDefault; + logger.debug("networkData:", JSON.stringify(networkData)); + if (interfaceName && interfaceName !== "default") { + networkData = networkData.filter((network) => network.iface === interfaceName)[0]; + if (!networkData) { + return res.status(404).json({ + error: "Interface not found", + }); + } + } else { + interfaceDefault = await si.networkInterfaceDefault(); + networkData = networkData.filter((network) => network.iface === interfaceDefault)[0]; + if (!networkData) { + return res.status(404).json({ + error: "Default interface not found", + }); + } + } + return res.status(200).json({ + network: networkData, + interface: interfaceName !== "default" ? interfaceName : interfaceDefault, + }); + } + return res.status(400).json({ error: "invalid type", });