Enhancement: Add configurable refresh interval and max points for glances services (#2363)

---------

Co-authored-by: Quentin de Grandmaison <quentin.degrandmaison@7speaking.com>
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
nioKi 2023-11-22 21:35:54 +01:00 committed by GitHub
parent e98b5e2233
commit c2729e302d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 120 additions and 63 deletions

View File

@ -336,48 +336,87 @@ export function cleanServiceGroups(groups) {
if (cleanedService.widget) { if (cleanedService.widget) {
// whitelisted set of keys to pass to the frontend // whitelisted set of keys to pass to the frontend
// alphabetical, grouped by widget(s)
const { const {
type, // all widgets // all widgets
fields, fields,
hideErrors, hideErrors,
server, // docker widget type,
container,
currency, // coinmarketcap widget // azuredevops
symbols,
slugs,
defaultinterval,
site, // unifi widget
namespace, // kubernetes widget
app,
podSelector,
wan, // opnsense widget, pfsense widget
enableBlocks, // emby/jellyfin
enableNowPlaying,
volume, // diskstation widget,
enableQueue, // sonarr/radarr
node, // Proxmox
snapshotHost, // kopia
snapshotPath,
userEmail, // azuredevops
repositoryId, repositoryId,
metric, // glances userEmail,
chart, // glances
stream, // mjpeg // calendar
fit,
method, // openmediavault widget
mappings, // customapi widget
refreshInterval,
integrations, // calendar widget
firstDayInWeek, firstDayInWeek,
view, integrations,
maxEvents, maxEvents,
src, // iframe widget view,
classes,
referrerPolicy, // coinmarketcap
allowPolicy, currency,
defaultinterval,
slugs,
symbols,
// customapi
mappings,
// diskstation
volume,
// docker
container,
server,
// emby, jellyfin
enableBlocks,
enableNowPlaying,
// glances
chart,
metric,
pointsLimit,
// glances, customapi, iframe
refreshInterval,
// iframe
allowFullscreen, allowFullscreen,
loadingStrategy, allowPolicy,
allowScrolling, allowScrolling,
classes,
loadingStrategy,
referrerPolicy,
src,
// kopia
snapshotHost,
snapshotPath,
// kubernetes
app,
namespace,
podSelector,
// mjpeg
fit,
stream,
// openmediavault
method,
// opnsense, pfsense
wan,
// proxmox
node,
// sonarr, radarr
enableQueue,
// unifi
site,
} = cleanedService.widget; } = cleanedService.widget;
let fieldsList = fields; let fieldsList = fields;
@ -459,6 +498,8 @@ export function cleanServiceGroups(groups) {
} else { } else {
cleanedService.widget.chart = true; cleanedService.widget.chart = true;
} }
if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval;
if (pointsLimit) cleanedService.widget.pointsLimit = pointsLimit;
} }
if (type === "mjpeg") { if (type === "mjpeg") {
if (stream) cleanedService.widget.stream = stream; if (stream) cleanedService.widget.stream = stream;

View File

@ -10,17 +10,18 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const Chart = dynamic(() => import("../components/chart"), { ssr: false }); const Chart = dynamic(() => import("../components/chart"), { ssr: false });
const pointsLimit = 15; const defaultPointsLimit = 15;
const defaultInterval = 1000;
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget;
const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit));
const { data, error } = useWidgetAPI(service.widget, "cpu", { const { data, error } = useWidgetAPI(service.widget, "cpu", {
refreshInterval: 1000, refreshInterval: Math.max(defaultInterval, refreshInterval),
}); });
const { data: systemData, error: systemError } = useWidgetAPI(service.widget, "system"); const { data: systemData, error: systemError } = useWidgetAPI(service.widget, "system");
@ -35,7 +36,7 @@ export default function Component({ service }) {
return newDataPoints; return newDataPoints;
}); });
} }
}, [data]); }, [data, pointsLimit]);
if (error) { if (error) {
return ( return (

View File

@ -10,12 +10,13 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false });
const pointsLimit = 15; const defaultPointsLimit = 15;
const defaultInterval = 1000;
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget;
const [, diskName] = widget.metric.split(":"); const [, diskName] = widget.metric.split(":");
const [dataPoints, setDataPoints] = useState( const [dataPoints, setDataPoints] = useState(
@ -24,7 +25,7 @@ export default function Component({ service }) {
const [ratePoints, setRatePoints] = useState(new Array(pointsLimit).fill({ a: 0, b: 0 }, 0, pointsLimit)); const [ratePoints, setRatePoints] = useState(new Array(pointsLimit).fill({ a: 0, b: 0 }, 0, pointsLimit));
const { data, error } = useWidgetAPI(service.widget, "diskio", { const { data, error } = useWidgetAPI(service.widget, "diskio", {
refreshInterval: 1000, refreshInterval: Math.max(defaultInterval, refreshInterval),
}); });
const calculateRates = (d) => const calculateRates = (d) =>
@ -45,7 +46,7 @@ export default function Component({ service }) {
return newDataPoints; return newDataPoints;
}); });
} }
}, [data, diskName]); }, [data, diskName, pointsLimit]);
useEffect(() => { useEffect(() => {
setRatePoints(calculateRates(dataPoints)); setRatePoints(calculateRates(dataPoints));

View File

@ -6,14 +6,16 @@ import Block from "../components/block";
import useWidgetAPI from "utils/proxy/use-widget-api"; import useWidgetAPI from "utils/proxy/use-widget-api";
const defaultInterval = 1000;
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval } = widget;
const [, fsName] = widget.metric.split("fs:"); const [, fsName] = widget.metric.split("fs:");
const { data, error } = useWidgetAPI(widget, "fs", { const { data, error } = useWidgetAPI(widget, "fs", {
refreshInterval: 1000, refreshInterval: Math.max(defaultInterval, refreshInterval),
}); });
if (error) { if (error) {

View File

@ -10,18 +10,19 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false });
const pointsLimit = 15; const defaultPointsLimit = 15;
const defaultInterval = 1000;
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget;
const [, gpuName] = widget.metric.split(":"); const [, gpuName] = widget.metric.split(":");
const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ a: 0, b: 0 }, 0, pointsLimit)); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ a: 0, b: 0 }, 0, pointsLimit));
const { data, error } = useWidgetAPI(widget, "gpu", { const { data, error } = useWidgetAPI(widget, "gpu", {
refreshInterval: 1000, refreshInterval: Math.max(defaultInterval, refreshInterval),
}); });
useEffect(() => { useEffect(() => {
@ -39,7 +40,7 @@ export default function Component({ service }) {
}); });
} }
} }
}, [data, gpuName]); }, [data, gpuName, pointsLimit]);
if (error) { if (error) {
return ( return (

View File

@ -69,16 +69,19 @@ function Mem({ quicklookData, className = "" }) {
); );
} }
const defaultInterval = 1000;
const defaultSystemInterval = 30000; // This data (OS, hostname, distribution) is usually super stable.
export default function Component({ service }) { export default function Component({ service }) {
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval } = widget;
const { data: quicklookData, errorL: quicklookError } = useWidgetAPI(service.widget, "quicklook", { const { data: quicklookData, errorL: quicklookError } = useWidgetAPI(service.widget, "quicklook", {
refreshInterval: 1000, refreshInterval,
}); });
const { data: systemData, errorL: systemError } = useWidgetAPI(service.widget, "system", { const { data: systemData, errorL: systemError } = useWidgetAPI(service.widget, "system", {
refreshInterval: 30000, refreshInterval: defaultSystemInterval,
}); });
if (quicklookError) { if (quicklookError) {

View File

@ -10,17 +10,19 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false });
const pointsLimit = 15; const defaultPointsLimit = 15;
const defaultInterval = (isChart) => (isChart ? 1000 : 5000);
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart } = widget;
const { refreshInterval = defaultInterval(chart), pointsLimit = defaultPointsLimit } = widget;
const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit));
const { data, error } = useWidgetAPI(service.widget, "mem", { const { data, error } = useWidgetAPI(service.widget, "mem", {
refreshInterval: chart ? 1000 : 5000, refreshInterval: Math.max(defaultInterval(chart), refreshInterval),
}); });
useEffect(() => { useEffect(() => {
@ -33,7 +35,7 @@ export default function Component({ service }) {
return newDataPoints; return newDataPoints;
}); });
} }
}, [data]); }, [data, pointsLimit]);
if (error) { if (error) {
return ( return (

View File

@ -10,18 +10,21 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false }); const ChartDual = dynamic(() => import("../components/chart_dual"), { ssr: false });
const pointsLimit = 15; const defaultPointsLimit = 15;
const defaultInterval = (isChart) => (isChart ? 1000 : 5000);
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart, metric } = widget; const { chart, metric } = widget;
const { refreshInterval = defaultInterval(chart), pointsLimit = defaultPointsLimit } = widget;
const [, interfaceName] = metric.split(":"); const [, interfaceName] = metric.split(":");
const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit));
const { data, error } = useWidgetAPI(widget, "network", { const { data, error } = useWidgetAPI(widget, "network", {
refreshInterval: chart ? 1000 : 5000, refreshInterval: Math.max(defaultInterval(chart), refreshInterval),
}); });
useEffect(() => { useEffect(() => {
@ -44,7 +47,7 @@ export default function Component({ service }) {
}); });
} }
} }
}, [data, interfaceName]); }, [data, interfaceName, pointsLimit]);
if (error) { if (error) {
return ( return (

View File

@ -17,13 +17,15 @@ const statusMap = {
X: <ResolvedIcon icon="mdi-rhombus-outline" width={32} height={32} />, // dead X: <ResolvedIcon icon="mdi-rhombus-outline" width={32} height={32} />, // dead
}; };
const defaultInterval = 1000;
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval } = widget;
const { data, error } = useWidgetAPI(service.widget, "processlist", { const { data, error } = useWidgetAPI(service.widget, "processlist", {
refreshInterval: 1000, refreshInterval: Math.max(defaultInterval, refreshInterval),
}); });
if (error) { if (error) {

View File

@ -10,18 +10,19 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const Chart = dynamic(() => import("../components/chart"), { ssr: false }); const Chart = dynamic(() => import("../components/chart"), { ssr: false });
const pointsLimit = 15; const defaultPointsLimit = 15;
const defaultInterval = 1000;
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { chart } = widget; const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget;
const [, sensorName] = widget.metric.split(":"); const [, sensorName] = widget.metric.split(":");
const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit));
const { data, error } = useWidgetAPI(service.widget, "sensors", { const { data, error } = useWidgetAPI(service.widget, "sensors", {
refreshInterval: 1000, refreshInterval: Math.max(defaultInterval, refreshInterval),
}); });
useEffect(() => { useEffect(() => {
@ -35,7 +36,7 @@ export default function Component({ service }) {
return newDataPoints; return newDataPoints;
}); });
} }
}, [data, sensorName]); }, [data, sensorName, pointsLimit]);
if (error) { if (error) {
return ( return (