From 56e1aee5251c10228bf3bea110b596c2cb9dbdf3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 10:48:43 +0800 Subject: [PATCH 01/25] Add x and y domain as optional values to AreaChart --- Client/src/Components/Charts/AreaChart/index.jsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Client/src/Components/Charts/AreaChart/index.jsx b/Client/src/Components/Charts/AreaChart/index.jsx index d05dbb14a..d645779ad 100644 --- a/Client/src/Components/Charts/AreaChart/index.jsx +++ b/Client/src/Components/Charts/AreaChart/index.jsx @@ -46,7 +46,9 @@ import { useId } from "react"; * } * yTick={} * strokeColor="#8884d8" @@ -73,7 +75,9 @@ const CustomAreaChart = ({ data, dataKey, xKey, + xDomain, yKey, + yDomain, xTick, yTick, strokeColor, @@ -97,9 +101,11 @@ const CustomAreaChart = ({ @@ -143,7 +149,9 @@ CustomAreaChart.propTypes = { xTick: PropTypes.object, // Recharts takes an instance of component, so we can't pass the component itself yTick: PropTypes.object, // Recharts takes an instance of component, so we can't pass the component itself xKey: PropTypes.string.isRequired, + xDomain: PropTypes.array, yKey: PropTypes.string.isRequired, + yDomain: PropTypes.array, fillColor: PropTypes.string, strokeColor: PropTypes.string, gradient: PropTypes.bool, From 947adb197b9341024e2b1223f55a7359e0bf9aa9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 10:49:05 +0800 Subject: [PATCH 02/25] format ytick to truncate values --- Client/src/Components/Charts/Utils/chartUtils.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Components/Charts/Utils/chartUtils.jsx b/Client/src/Components/Charts/Utils/chartUtils.jsx index 043203525..546d05cec 100644 --- a/Client/src/Components/Charts/Utils/chartUtils.jsx +++ b/Client/src/Components/Charts/Utils/chartUtils.jsx @@ -62,7 +62,7 @@ export const PercentTick = ({ x, y, payload, index }) => { fontSize={11} fontWeight={400} > - {`${payload?.value * 100}%`} + {`${(payload?.value * 100).toFixed()}%`} ); }; From c8649c8f8722abcfa4f649421d3d0586eb8712d2 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 10:49:16 +0800 Subject: [PATCH 03/25] Add domains to percentage graphs --- Client/src/Pages/Infrastructure/Details/index.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 9fbaae81a..238a15c57 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -221,13 +221,12 @@ const InfrastructureDetails = () => { setMonitor(response.data.data); } catch (error) { navigate("/not-found", { replace: true }); - logger.error(error); + logger.error(error); } }; fetchData(); }, [authToken, monitorId, dateRange]); - const statBoxConfigs = [ { id: 0, @@ -290,6 +289,7 @@ const InfrastructureDetails = () => { heading: "Memory usage", strokeColor: theme.palette.primary.main, yLabel: "Memory Usage", + yDomain: [0, 1], }, { type: "cpu", @@ -297,6 +297,7 @@ const InfrastructureDetails = () => { heading: "CPU usage", strokeColor: theme.palette.success.main, yLabel: "CPU Usage", + yDomain: [0, 1], }, ...(monitor?.checks?.[0]?.disk?.map((disk, idx) => ({ type: "disk", @@ -305,6 +306,7 @@ const InfrastructureDetails = () => { heading: `Disk${idx} usage`, strokeColor: theme.palette.warning.main, yLabel: "Disk Usage", + yDomain: [0, 1], })) || []), ]; @@ -394,6 +396,7 @@ const InfrastructureDetails = () => { dataKey={config.dataKey} xKey="createdAt" yKey={config.dataKey} + yDomain={config.yDomain} customTooltip={({ active, payload, label }) => ( Date: Mon, 25 Nov 2024 11:00:54 +0800 Subject: [PATCH 04/25] udpate db model for correct temp schema --- Server/db/models/HardwareCheck.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Server/db/models/HardwareCheck.js b/Server/db/models/HardwareCheck.js index 527f226b6..ba6fbdf2d 100644 --- a/Server/db/models/HardwareCheck.js +++ b/Server/db/models/HardwareCheck.js @@ -4,7 +4,7 @@ const cpuSchema = mongoose.Schema({ physical_core: { type: Number, default: 0 }, logical_core: { type: Number, default: 0 }, frequency: { type: Number, default: 0 }, - temperature: { type: Number, default: 0 }, + temperature: { type: [Number], default: [] }, free_percent: { type: Number, default: 0 }, usage_percent: { type: Number, default: 0 }, }); @@ -54,6 +54,7 @@ const HardwareCheckSchema = mongoose.Schema( type: hostSchema, default: () => ({}), }, + errors: { type: [errorSchema], default: () => [], From d1d19177bd43dc5c0b66d58960d782c44a2ff2f4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 11:04:18 +0800 Subject: [PATCH 05/25] Add alert threshold for temp --- Server/db/models/Notification.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Server/db/models/Notification.js b/Server/db/models/Notification.js index 868324cc2..895b66362 100644 --- a/Server/db/models/Notification.js +++ b/Server/db/models/Notification.js @@ -38,6 +38,12 @@ const NotificationSchema = mongoose.Schema( return this.alertThreshold; }, }, + tempAlertThreshold: { + type: Number, + default: function () { + return this.alertThreshold; + }, + }, }, { timestamps: true, From 24d5a3852701349975dcc3e4aae1d40d1d5d02f8 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 11:08:13 +0800 Subject: [PATCH 06/25] Add pre save and preupdate functinality to set thresholds on alertThreshold change --- Server/db/models/Notification.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Server/db/models/Notification.js b/Server/db/models/Notification.js index 895b66362..8767880c1 100644 --- a/Server/db/models/Notification.js +++ b/Server/db/models/Notification.js @@ -49,4 +49,31 @@ const NotificationSchema = mongoose.Schema( timestamps: true, } ); + +NotificationSchema.pre("save", function (next) { + if (!this.cpuAlertThreshold || this.isModified("alertThreshold")) { + this.cpuAlertThreshold = this.alertThreshold; + } + if (!this.memoryAlertThreshold || this.isModified("alertThreshold")) { + this.memoryAlertThreshold = this.alertThreshold; + } + if (!this.diskAlertThreshold || this.isModified("alertThreshold")) { + this.diskAlertThreshold = this.alertThreshold; + } + if (!this.tempAlertThreshold || this.isModified("alertThreshold")) { + this.tempAlertThreshold = this.alertThreshold; + } + next(); +}); + +NotificationSchema.pre("findOneAndUpdate", function (next) { + const update = this.getUpdate(); + if (update.alertThreshold) { + update.cpuAlertThreshold = update.alertThreshold; + update.memoryAlertThreshold = update.alertThreshold; + update.diskAlertThreshold = update.alertThreshold; + update.tempAlertThreshold = update.alertThreshold; + } + next(); +}); export default mongoose.model("Notification", NotificationSchema); From 71cde317a7aa37a6d673f7566668f4bba3997233 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 11:20:52 +0800 Subject: [PATCH 07/25] Add temperature threshold to create infrastructure monitor page --- .../Pages/Infrastructure/CreateMonitor/index.jsx | 13 ++++++++----- Client/src/Validation/error.js | 9 +++++++-- Client/src/Validation/validation.js | 7 ++++--- Server/validation/joi.js | 1 + 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx b/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx index bbcb7b05d..1ebbab21e 100644 --- a/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx +++ b/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx @@ -32,12 +32,14 @@ const CreateInfrastructureMonitor = () => { usage_memory: "", disk: false, usage_disk: "", + temperature: false, + usage_temperature: "", secret: "", }); const MS_PER_MINUTE = 60000; const THRESHOLD_FIELD_PREFIX = "usage_"; - const HARDWARE_MONITOR_TYPES = ["cpu", "memory", "disk"]; + const HARDWARE_MONITOR_TYPES = ["cpu", "memory", "disk", "temperature"]; const { user, authToken } = useSelector((state) => state.auth); const monitorState = useSelector((state) => state.infrastructureMonitor); const dispatch = useDispatch(); @@ -74,18 +76,18 @@ const CreateInfrastructureMonitor = () => { }); }; - const handleBlur = (event, appenedID) => { + const handleBlur = (event, appendID) => { event.preventDefault(); const { value, id } = event.target; if (id?.startsWith("notify-email-")) return; const { error } = infrastructureMonitorValidation.validate( - { [id ?? appenedID]: value }, + { [id ?? appendID]: value }, { abortEarly: false, } ); setErrors((prev) => { - return buildErrors(prev, id ?? appenedID, error); + return buildErrors(prev, id ?? appendID, error); }); }; @@ -297,7 +299,8 @@ const CreateInfrastructureMonitor = () => { Customize alerts - Send a notification to user(s) when thresholds exceed a specified percentage. + Send a notification to user(s) when thresholds exceed a specified + percentage. diff --git a/Client/src/Validation/error.js b/Client/src/Validation/error.js index a941e2509..0d1359ad5 100644 --- a/Client/src/Validation/error.js +++ b/Client/src/Validation/error.js @@ -37,8 +37,13 @@ const hasValidationErrors = (form, validation, setErrors) => { if (!form.disk || form.usage_disk) { newErrors["usage_disk"] = null; } + if (!form.temperature || form.usage_temperature) { + newErrors["usage_temperature"] = null; + } }); - if (Object.values(newErrors).some(v=> v)) { + + console.log("newErrors", newErrors); + if (Object.values(newErrors).some((v) => v)) { setErrors(newErrors); return true; } else { @@ -48,4 +53,4 @@ const hasValidationErrors = (form, validation, setErrors) => { } return false; }; -export { buildErrors, hasValidationErrors }; \ No newline at end of file +export { buildErrors, hasValidationErrors }; diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index 7dfbeb246..332ea6aea 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -190,15 +190,16 @@ const infrastructureMonitorValidation = joi.object({ cpu: joi.boolean(), memory: joi.boolean(), disk: joi.boolean(), + temperature: joi.boolean(), usage_memory: joi.number().messages({ "number.base": THRESHOLD_COMMON_BASE_MSG, }), usage_disk: joi.number().messages({ "number.base": THRESHOLD_COMMON_BASE_MSG, }), - // usage_temperature: joi.number().messages({ - // "number.base": "Temperature must be a number.", - // }), + usage_temperature: joi.number().messages({ + "number.base": "Temperature must be a number.", + }), // usage_system: joi.number().messages({ // "number.base": "System load must be a number.", // }), diff --git a/Server/validation/joi.js b/Server/validation/joi.js index bc3967657..3b51e6e97 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -201,6 +201,7 @@ const createMonitorBodyValidation = joi.object({ usage_cpu: joi.number(), usage_memory: joi.number(), usage_disk: joi.number(), + usage_temperature: joi.number(), }), notifications: joi.array().items(joi.object()), secret: joi.string(), From e28aaf4ed7f569f8362fcf92e1b4b9cb0061964d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 11:22:19 +0800 Subject: [PATCH 08/25] add missing dependency to useEffect array --- Client/src/Pages/Infrastructure/Details/index.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 238a15c57..63765c3de 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -217,7 +217,6 @@ const InfrastructureDetails = () => { numToDisplay: 50, normalize: false, }); - setMonitor(response.data.data); } catch (error) { navigate("/not-found", { replace: true }); @@ -225,7 +224,7 @@ const InfrastructureDetails = () => { } }; fetchData(); - }, [authToken, monitorId, dateRange]); + }, [authToken, monitorId, dateRange, navigate]); const statBoxConfigs = [ { From d75b15b890cbc2e39d22e55117ade4b81f196d7f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 12:25:48 +0800 Subject: [PATCH 09/25] Extract building of data into funcitons, add defensinve checks --- .../Pages/Infrastructure/Details/index.jsx | 232 +++++++++++------- 1 file changed, 150 insertions(+), 82 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 63765c3de..204f442ac 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -204,6 +204,152 @@ const InfrastructureDetails = () => { (chartContainerHeight - totalChartContainerPadding - totalTypographyPadding) * 0.95; // end height calculations + const buildStatBoxes = (monitor) => { + let latestCheck = monitor?.checks[0] ?? null; + if (latestCheck === null) return []; + + // Extract values from latest check + const physicalCores = latestCheck?.cpu?.physical_core ?? null; + const logicalCores = latestCheck?.cpu?.logical_core ?? null; + const cpuFrequency = latestCheck?.cpu?.frequency ?? null; + const cpuTemperature = + latestCheck?.cpu?.temperature?.reduce((acc, curr) => acc + curr, 0) / + latestCheck?.cpu?.temperature?.length ?? 0; + const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? null; + const diskTotalBytes = latestCheck?.disk[0]?.total_bytes ?? null; + const os = latestCheck?.host?.os ?? null; + const platform = latestCheck?.host?.platform ?? null; + const osPlatform = os === null && platform === null ? null : `${os} ${platform}`; + + return [ + { + id: 0, + heading: "CPU (Physical)", + subHeading: physicalCores ? `${physicalCores} cores` : null, + }, + { + id: 1, + heading: "CPU (Logical)", + subHeading: logicalCores ? `${logicalCores} cores` : null, + }, + { + id: 2, + heading: "CPU Frequency", + subHeading: cpuFrequency ? `${(cpuFrequency / 1000).toFixed(2)} Ghz` : null, + }, + { + id: 3, + heading: "Average CPU Temperature", + subHeading: cpuTemperature ? `${cpuTemperature.toFixed(2)} C` : null, + }, + { + id: 4, + heading: "Memory", + subHeading: memoryTotalBytes ? formatBytes(memoryTotalBytes) : null, + }, + { + id: 5, + heading: "Disk", + subHeading: diskTotalBytes ? formatBytes(diskTotalBytes) : null, + }, + { id: 6, heading: "Uptime", subHeading: "100%" }, + { + id: 7, + heading: "Status", + subHeading: monitor?.status === true ? "Active" : "Inactive", + }, + { + id: 8, + heading: "OS", + subHeading: osPlatform, + }, + ].filter((box) => box.subHeading !== null); + }; + + const buildGaugeBoxConfigs = (monitor) => { + let latestCheck = monitor?.checks[0] ?? null; + if (latestCheck === null) return []; + + // Extract values from latest check + const memoryUsagePercent = latestCheck?.memory?.usage_percent ?? null; + const memoryUsedBytes = latestCheck?.memory?.used_bytes ?? null; + const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? null; + const cpuUsagePercent = latestCheck?.cpu?.usage_percent ?? null; + const cpuPhysicalCores = latestCheck?.cpu?.physical_core ?? null; + const cpuFrequency = latestCheck?.cpu?.frequency ?? null; + return [ + { + type: "memory", + value: memoryUsagePercent ? decimalToPercentage(memoryUsagePercent) : null, + heading: "Memory Usage", + metricOne: "Used", + valueOne: memoryUsedBytes ? formatBytes(memoryUsedBytes) : null, + metricTwo: "Total", + valueTwo: memoryTotalBytes ? formatBytes(memoryTotalBytes) : null, + }, + { + type: "cpu", + value: cpuUsagePercent ? decimalToPercentage(cpuUsagePercent) : null, + heading: "CPU Usage", + metricOne: "Cores", + valueOne: cpuPhysicalCores ?? 0, + metricTwo: "Frequency", + valueTwo: cpuFrequency ? `${(cpuFrequency / 1000).toFixed(2)} Ghz` : null, + }, + ...(latestCheck?.disk ?? []).map((disk, idx) => ({ + type: "disk", + diskIndex: idx, + value: decimalToPercentage(disk.usage_percent), + heading: `Disk${idx} usage`, + metricOne: "Used", + valueOne: formatBytes(disk.total_bytes - disk.free_bytes), + metricTwo: "Total", + valueTwo: formatBytes(disk.total_bytes), + })), + ].filter( + (box) => box.value !== null && box.valueOne !== null && box.valueTwo !== null + ); + }; + + const buildAreaChartConfigs = (monitor) => { + let latestCheck = monitor?.checks[0] ?? null; + if (latestCheck === null) return []; + const temps = monitor?.checks?.map((check) => + check.cpu.temperature.map((temp, idx) => { + return { [`core${idx + 1}`]: temp }; + }) + ); + console.log(temps); + console.log(latestCheck); + return [ + { + type: "memory", + dataKey: latestCheck?.memory?.usage_percent ? "memory.usage_percent" : null, + heading: "Memory usage", + strokeColor: theme.palette.primary.main, + yLabel: "Memory Usage", + yDomain: [0, 1], + }, + { + type: "cpu", + dataKey: latestCheck?.cpu?.usage_percent ? "cpu.usage_percent" : null, + heading: "CPU usage", + strokeColor: theme.palette.success.main, + yLabel: "CPU Usage", + yDomain: [0, 1], + }, + ...(latestCheck?.disk?.map((disk, idx) => ({ + type: "disk", + diskIndex: idx, + dataKey: `disk[${idx}].usage_percent`, + heading: `Disk${idx} usage`, + strokeColor: theme.palette.warning.main, + yLabel: "Disk Usage", + yDomain: [0, 1], + })) || []), + ].filter((box) => box.dataKey !== null); + }; + // Fetch data useEffect(() => { const fetchData = async () => { @@ -226,88 +372,9 @@ const InfrastructureDetails = () => { fetchData(); }, [authToken, monitorId, dateRange, navigate]); - const statBoxConfigs = [ - { - id: 0, - heading: "CPU", - subHeading: `${monitor?.checks[0]?.cpu?.physical_core ?? 0} cores`, - }, - { - id: 1, - heading: "Memory", - subHeading: formatBytes(monitor?.checks[0]?.memory?.total_bytes), - }, - { - id: 2, - heading: "Disk", - subHeading: formatBytes(monitor?.checks[0]?.disk[0]?.total_bytes), - }, - { id: 3, heading: "Uptime", subHeading: "100%" }, - { - id: 4, - heading: "Status", - subHeading: monitor?.status === true ? "Active" : "Inactive", - }, - ]; - - const gaugeBoxConfigs = [ - { - type: "memory", - value: decimalToPercentage(monitor?.checks[0]?.memory?.usage_percent), - heading: "Memory Usage", - metricOne: "Used", - valueOne: formatBytes(monitor?.checks[0]?.memory?.used_bytes), - metricTwo: "Total", - valueTwo: formatBytes(monitor?.checks[0]?.memory?.total_bytes), - }, - { - type: "cpu", - value: decimalToPercentage(monitor?.checks[0]?.cpu?.usage_percent), - heading: "CPU Usage", - metricOne: "Cores", - valueOne: monitor?.checks[0]?.cpu?.physical_core ?? 0, - metricTwo: "Frequency", - valueTwo: `${(monitor?.checks[0]?.cpu?.frequency ?? 0 / 1000).toFixed(2)} Ghz`, - }, - ...(monitor?.checks?.[0]?.disk ?? []).map((disk, idx) => ({ - type: "disk", - diskIndex: idx, - value: decimalToPercentage(disk.usage_percent), - heading: `Disk${idx} usage`, - metricOne: "Used", - valueOne: formatBytes(disk.total_bytes - disk.free_bytes), - metricTwo: "Total", - valueTwo: formatBytes(disk.total_bytes), - })), - ]; - - const areaChartConfigs = [ - { - type: "memory", - dataKey: "memory.usage_percent", - heading: "Memory usage", - strokeColor: theme.palette.primary.main, - yLabel: "Memory Usage", - yDomain: [0, 1], - }, - { - type: "cpu", - dataKey: "cpu.usage_percent", - heading: "CPU usage", - strokeColor: theme.palette.success.main, - yLabel: "CPU Usage", - yDomain: [0, 1], - }, - ...(monitor?.checks?.[0]?.disk?.map((disk, idx) => ({ - type: "disk", - diskIndex: idx, - dataKey: `disk[${idx}].usage_percent`, - heading: `Disk${idx} usage`, - strokeColor: theme.palette.warning.main, - yLabel: "Disk Usage", - yDomain: [0, 1], - })) || []), - ]; + const statBoxConfigs = buildStatBoxes(monitor); + const gaugeBoxConfigs = buildGaugeBoxConfigs(monitor); + const areaChartConfigs = buildAreaChartConfigs(monitor); return ( @@ -344,6 +411,7 @@ const InfrastructureDetails = () => { {statBoxConfigs.map((statBox) => ( From 8db24e901601a5072bd5ec7806f30ca5f52d948d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 13:00:28 +0800 Subject: [PATCH 10/25] refactor AreaChart to take an array of data keys --- .../src/Components/Charts/AreaChart/index.jsx | 20 +++++++++++-------- .../Pages/Infrastructure/Details/index.jsx | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Client/src/Components/Charts/AreaChart/index.jsx b/Client/src/Components/Charts/AreaChart/index.jsx index d645779ad..e3c231ebc 100644 --- a/Client/src/Components/Charts/AreaChart/index.jsx +++ b/Client/src/Components/Charts/AreaChart/index.jsx @@ -45,6 +45,7 @@ import { useId } from "react"; * return ( * - + {dataKeys.map((dataKey) => ( + + ))} {customTooltip ? ( { Date: Mon, 25 Nov 2024 16:14:18 +0800 Subject: [PATCH 11/25] Add temp tooltip component --- .../Components/Charts/Utils/chartUtils.jsx | 89 ++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/Client/src/Components/Charts/Utils/chartUtils.jsx b/Client/src/Components/Charts/Utils/chartUtils.jsx index 546d05cec..004f9a227 100644 --- a/Client/src/Components/Charts/Utils/chartUtils.jsx +++ b/Client/src/Components/Charts/Utils/chartUtils.jsx @@ -165,7 +165,6 @@ export const InfrastructureTooltip = ({ ? `${yLabel} ${getFormattedPercentage(payload[0].payload[hardwareType][yIdx][metric])}` : `${yLabel} ${getFormattedPercentage(payload[0].payload[hardwareType][metric])}`} - {/* Display original value */} @@ -188,3 +187,91 @@ InfrastructureTooltip.propTypes = { yLabel: PropTypes.string, dotColor: PropTypes.string, }; + +export const TemperatureTooltip = ({ active, payload, label, keys, dotColor }) => { + const uiTimezone = useSelector((state) => state.ui.timezone); + const theme = useTheme(); + const formatCoreKey = (key) => { + return key.replace(/^core(\d+)$/, "Core $1"); + }; + if (active && payload && payload.length) { + return ( + + + {formatDateWithTz(label, "ddd, MMMM D, YYYY, h:mm A", uiTimezone)} + + + + {keys.map((key) => { + return ( + + + + + + {`${formatCoreKey(key)}: ${payload[0].payload[key]} °C`} + + + + + ); + })} + + + ); + } + return null; +}; + +TemperatureTooltip.propTypes = { + active: PropTypes.bool, + keys: PropTypes.array, + payload: PropTypes.array, + label: PropTypes.oneOfType([ + PropTypes.instanceOf(Date), + PropTypes.string, + PropTypes.number, + ]), +}; From 70ff4c31fbcb01d81e526b5584b26bfbb2c1c57f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 16:14:37 +0800 Subject: [PATCH 12/25] refactor area char to take an array of areas and data keys --- .../src/Components/Charts/AreaChart/index.jsx | 91 +++++++++++++++---- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/Client/src/Components/Charts/AreaChart/index.jsx b/Client/src/Components/Charts/AreaChart/index.jsx index e3c231ebc..d99ab6eb4 100644 --- a/Client/src/Components/Charts/AreaChart/index.jsx +++ b/Client/src/Components/Charts/AreaChart/index.jsx @@ -11,6 +11,7 @@ import { createGradient } from "../Utils/gradientUtils"; import PropTypes from "prop-types"; import { useTheme } from "@mui/material"; import { useId } from "react"; +import { Fragment } from "react"; /** * CustomAreaChart component for rendering an area chart with optional gradient and custom ticks. * @@ -92,7 +93,49 @@ const CustomAreaChart = ({ }) => { const theme = useTheme(); const uniqueId = useId(); - const gradientId = `gradient-${uniqueId}`; + + const AREA_COLORS = [ + // Blues + "#3182bd", // Deep blue + "#6baed6", // Medium blue + "#9ecae1", // Light blue + + // Greens + "#74c476", // Soft green + "#a1d99b", // Light green + "#c7e9c0", // Pale green + + // Oranges + "#fdae6b", // Warm orange + "#fdd0a2", // Light orange + "#feedde", // Pale orange + + // Purples + "#9467bd", // Lavender + "#a55194", // Deep magenta + "#c994c7", // Soft magenta + + // Reds + "#ff9896", // Soft red + "#de2d26", // Deep red + "#fc9272", // Medium red + + // Cyans/Teals + "#17becf", // Cyan + "#7fcdbb", // Teal + "#a1dab4", // Light teal + + // Yellows + "#fec44f", // Mustard + "#fee391", // Light yellow + "#ffffd4", // Pale yellow + + // Additional colors + "#e377c2", // Soft pink + "#bcbd22", // Olive + "#2ca02c", // Vibrant green + ]; + return ( - {gradient === true && - createGradient({ - id: gradientId, - startColor: gradientStartColor, - endColor: gradientEndColor, - direction: gradientDirection, - })} + - {dataKeys.map((dataKey) => ( - - ))} + {dataKeys.map((dataKey, index) => { + const gradientId = `gradient-${uniqueId}-${index}`; + + return ( + + {gradient === true && + createGradient({ + id: gradientId, + startColor: gradientStartColor || AREA_COLORS[index], + endColor: gradientEndColor, + direction: gradientDirection, + })} + + + ); + })} {customTooltip ? ( Date: Mon, 25 Nov 2024 16:14:56 +0800 Subject: [PATCH 13/25] Add temp to details page --- .../Pages/Infrastructure/Details/index.jsx | 186 ++++++++++++------ 1 file changed, 127 insertions(+), 59 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index d90b54ba6..ccff1388d 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -17,8 +17,10 @@ import { TzTick, PercentTick, InfrastructureTooltip, + TemperatureTooltip, } from "../../../Components/Charts/Utils/chartUtils"; import PropTypes from "prop-types"; +import Monitors from "../../Monitors/Home"; const BASE_BOX_PADDING_VERTICAL = 4; const BASE_BOX_PADDING_HORIZONTAL = 8; @@ -205,52 +207,51 @@ const InfrastructureDetails = () => { // end height calculations const buildStatBoxes = (monitor) => { - let latestCheck = monitor?.checks[0] ?? null; + let latestCheck = monitor?.checks[monitor?.checks.length - 1] ?? null; if (latestCheck === null) return []; // Extract values from latest check - const physicalCores = latestCheck?.cpu?.physical_core ?? null; - const logicalCores = latestCheck?.cpu?.logical_core ?? null; - const cpuFrequency = latestCheck?.cpu?.frequency ?? null; + const physicalCores = latestCheck?.cpu?.physical_core ?? 0; + const logicalCores = latestCheck?.cpu?.logical_core ?? 0; + const cpuFrequency = latestCheck?.cpu?.frequency ?? 0; const cpuTemperature = latestCheck?.cpu?.temperature?.reduce((acc, curr) => acc + curr, 0) / latestCheck?.cpu?.temperature?.length ?? 0; - const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? null; - const diskTotalBytes = latestCheck?.disk[0]?.total_bytes ?? null; + const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? 0; + const diskTotalBytes = latestCheck?.disk[0]?.total_bytes ?? 0; const os = latestCheck?.host?.os ?? null; const platform = latestCheck?.host?.platform ?? null; const osPlatform = os === null && platform === null ? null : `${os} ${platform}`; - return [ { id: 0, heading: "CPU (Physical)", - subHeading: physicalCores ? `${physicalCores} cores` : null, + subHeading: `${physicalCores} cores`, }, { id: 1, heading: "CPU (Logical)", - subHeading: logicalCores ? `${logicalCores} cores` : null, + subHeading: `${logicalCores} cores`, }, { id: 2, heading: "CPU Frequency", - subHeading: cpuFrequency ? `${(cpuFrequency / 1000).toFixed(2)} Ghz` : null, + subHeading: `${(cpuFrequency / 1000).toFixed(2)} Ghz`, }, { id: 3, heading: "Average CPU Temperature", - subHeading: cpuTemperature ? `${cpuTemperature.toFixed(2)} C` : null, + subHeading: `${cpuTemperature.toFixed(2)} C`, }, { id: 4, heading: "Memory", - subHeading: memoryTotalBytes ? formatBytes(memoryTotalBytes) : null, + subHeading: formatBytes(memoryTotalBytes), }, { id: 5, heading: "Disk", - subHeading: diskTotalBytes ? formatBytes(diskTotalBytes) : null, + subHeading: formatBytes(diskTotalBytes), }, { id: 6, heading: "Uptime", subHeading: "100%" }, { @@ -263,38 +264,38 @@ const InfrastructureDetails = () => { heading: "OS", subHeading: osPlatform, }, - ].filter((box) => box.subHeading !== null); + ]; }; const buildGaugeBoxConfigs = (monitor) => { - let latestCheck = monitor?.checks[0] ?? null; + let latestCheck = monitor?.checks[monitor?.checks.length - 1] ?? null; if (latestCheck === null) return []; // Extract values from latest check - const memoryUsagePercent = latestCheck?.memory?.usage_percent ?? null; - const memoryUsedBytes = latestCheck?.memory?.used_bytes ?? null; - const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? null; - const cpuUsagePercent = latestCheck?.cpu?.usage_percent ?? null; - const cpuPhysicalCores = latestCheck?.cpu?.physical_core ?? null; - const cpuFrequency = latestCheck?.cpu?.frequency ?? null; + const memoryUsagePercent = latestCheck?.memory?.usage_percent ?? 0; + const memoryUsedBytes = latestCheck?.memory?.used_bytes ?? 0; + const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? 0; + const cpuUsagePercent = latestCheck?.cpu?.usage_percent ?? 0; + const cpuPhysicalCores = latestCheck?.cpu?.physical_core ?? 0; + const cpuFrequency = latestCheck?.cpu?.frequency ?? 0; return [ { type: "memory", - value: memoryUsagePercent ? decimalToPercentage(memoryUsagePercent) : null, + value: decimalToPercentage(memoryUsagePercent), heading: "Memory Usage", metricOne: "Used", - valueOne: memoryUsedBytes ? formatBytes(memoryUsedBytes) : null, + valueOne: formatBytes(memoryUsedBytes), metricTwo: "Total", - valueTwo: memoryTotalBytes ? formatBytes(memoryTotalBytes) : null, + valueTwo: formatBytes(memoryTotalBytes), }, { type: "cpu", - value: cpuUsagePercent ? decimalToPercentage(cpuUsagePercent) : null, + value: decimalToPercentage(cpuUsagePercent), heading: "CPU Usage", metricOne: "Cores", valueOne: cpuPhysicalCores ?? 0, metricTwo: "Frequency", - valueTwo: cpuFrequency ? `${(cpuFrequency / 1000).toFixed(2)} Ghz` : null, + valueTwo: `${(cpuFrequency / 1000).toFixed(2)} Ghz`, }, ...(latestCheck?.disk ?? []).map((disk, idx) => ({ type: "disk", @@ -306,48 +307,127 @@ const InfrastructureDetails = () => { metricTwo: "Total", valueTwo: formatBytes(disk.total_bytes), })), - ].filter( - (box) => box.value !== null && box.valueOne !== null && box.valueTwo !== null - ); + ]; + }; + + const buildTemps = (monitor) => { + let numCores = 0; + const checks = monitor?.checks ?? null; + if (checks === null) return []; + for (const check of checks) { + if (check.cpu.temperature.length > numCores) { + numCores = check.cpu.temperature.length; + break; + } + } + + if (numCores === 0) return []; + + const temps = monitor?.checks?.map((check) => { + if (check.cpu.temperature.length > numCores) { + numCores = check.cpu.temperature.length; + } + + // If there's no data, set the temperature to 0 + if (check.cpu.temperature.length === 0) { + check.cpu.temperature = Array(numCores).fill(0); + } + + return check.cpu.temperature.reduce( + (acc, cur, idx) => { + acc[`core${idx + 1}`] = cur; + return acc; + }, + { + createdAt: check.createdAt, + } + ); + }); + return { tempKeys: Object.keys(temps[0]).slice(1), temps }; }; const buildAreaChartConfigs = (monitor) => { - let latestCheck = monitor?.checks[0] ?? null; + let latestCheck = monitor?.checks[monitor?.checks.length - 1] ?? null; if (latestCheck === null) return []; - const temps = monitor?.checks?.map((check) => - check.cpu.temperature.map((temp, idx) => { - return { [`core${idx + 1}`]: temp }; - }) - ); - console.log(temps); - console.log(latestCheck); + const tempData = buildTemps(monitor); return [ { type: "memory", - dataKey: latestCheck?.memory?.usage_percent ? "memory.usage_percent" : null, + data: monitor?.checks ?? [], + dataKeys: ["memory.usage_percent"], heading: "Memory usage", strokeColor: theme.palette.primary.main, + gradientStartColor: theme.palette.primary.main, yLabel: "Memory Usage", yDomain: [0, 1], + yTick: , + xTick: , + toolTip: ( + + ), }, { type: "cpu", - dataKey: latestCheck?.cpu?.usage_percent ? "cpu.usage_percent" : null, + data: monitor?.checks ?? [], + dataKeys: ["cpu.usage_percent"], heading: "CPU usage", strokeColor: theme.palette.success.main, + gradientStartColor: theme.palette.success.main, yLabel: "CPU Usage", yDomain: [0, 1], + yTick: , + xTick: , + toolTip: ( + + ), + }, + { + type: "temperature", + data: tempData.temps, + dataKeys: tempData.tempKeys, + strokeColor: theme.palette.error.main, + gradientStartColor: theme.palette.error.main, + heading: "CPU Temperature", + yLabel: "Temperature", + xTick: , + yDomain: [0, 200], + toolTip: ( + + ), }, ...(latestCheck?.disk?.map((disk, idx) => ({ type: "disk", + data: monitor?.checks ?? [], diskIndex: idx, - dataKey: `disk[${idx}].usage_percent`, + dataKeys: [`disk[${idx}].usage_percent`], heading: `Disk${idx} usage`, strokeColor: theme.palette.warning.main, + gradientStartColor: theme.palette.warning.main, yLabel: "Disk Usage", yDomain: [0, 1], + yTick: , + xTick: , + toolTip: ( + + ), })) || []), - ].filter((box) => box.dataKey !== null); + ]; }; // Fetch data @@ -459,28 +539,16 @@ const InfrastructureDetails = () => { ( - - )} - xTick={} - yTick={} + customTooltip={config.toolTip} + xTick={config.xTick} + yTick={config.yTick} strokeColor={config.strokeColor} gradient={true} - gradientStartColor={config.strokeColor} + gradientStartColor={config.gradientStartColor} gradientEndColor="#ffffff" /> From bdbf31ce3c9b797f3ac78767ffc5579771795a66 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 16:24:10 +0800 Subject: [PATCH 14/25] update jsdocs --- .../src/Components/Charts/AreaChart/index.jsx | 116 +++++++++--------- 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/Client/src/Components/Charts/AreaChart/index.jsx b/Client/src/Components/Charts/AreaChart/index.jsx index d99ab6eb4..5e239996b 100644 --- a/Client/src/Components/Charts/AreaChart/index.jsx +++ b/Client/src/Components/Charts/AreaChart/index.jsx @@ -1,3 +1,57 @@ +/** + * CustomAreaChart component for rendering an area chart with optional gradient and custom ticks. + * + * @param {Object} props - The properties object. + * @param {Array} props.data - The data array for the chart. + * @param {Array} props.dataKeys - An array of data keys to be plotted as separate areas. + * @param {string} props.xKey - The key for the x-axis data. + * @param {string} [props.yKey] - The key for the y-axis data (optional). + * @param {Object} [props.xTick] - Custom tick component for the x-axis. + * @param {Object} [props.yTick] - Custom tick component for the y-axis. + * @param {string} [props.strokeColor] - The base stroke color for the areas. + * If not provided, uses a predefined color palette. + * @param {string} [props.fillColor] - The base fill color for the areas. + * @param {boolean} [props.gradient=false] - Whether to apply a gradient fill to the areas. + * @param {string} [props.gradientDirection="vertical"] - The direction of the gradient. + * @param {string} [props.gradientStartColor] - The start color of the gradient. + * Defaults to the area's stroke color if not provided. + * @param {string} [props.gradientEndColor] - The end color of the gradient. + * @param {Object} [props.customTooltip] - Custom tooltip component for the chart. + * @param {string|number} [props.height="100%"] - Height of the chart container. + * + * @returns {JSX.Element} The rendered area chart component. + * + * @example + * // Single series chart + * + * + * @example + * // Multi-series chart with custom tooltip + * } + * yTick={} + * gradient={true} + * customTooltip={({ active, payload, label }) => ( + * + * )} + * /> + */ + import { AreaChart, Area, @@ -12,67 +66,7 @@ import PropTypes from "prop-types"; import { useTheme } from "@mui/material"; import { useId } from "react"; import { Fragment } from "react"; -/** - * CustomAreaChart component for rendering an area chart with optional gradient and custom ticks. - * - * @param {Object} props - The properties object. - * @param {Array} props.data - The data array for the chart. - * @param {string} props.xKey - The key for the x-axis data. - * @param {string} props.yKey - The key for the y-axis data. - * @param {Object} [props.xTick] - Custom tick component for the x-axis. - * @param {Object} [props.yTick] - Custom tick component for the y-axis. - * @param {string} [props.strokeColor] - The stroke color for the area. - * @param {string} [props.fillColor] - The fill color for the area. - * @param {boolean} [props.gradient=false] - Whether to apply a gradient fill. - * @param {string} [props.gradientDirection="vertical"] - The direction of the gradient. - * @param {string} [props.gradientStartColor] - The start color of the gradient. - * @param {string} [props.gradientEndColor] - The end color of the gradient. - * @param {Object} [props.customTooltip] - Custom tooltip component. - * @returns {JSX.Element} The rendered area chart component. - * - * @example - * // Example usage of CustomAreaChart - * import React from 'react'; - * import CustomAreaChart from './CustomAreaChart'; - * import { TzTick, PercentTick, InfrastructureTooltip } from './chartUtils'; - * - * const data = [ - * { createdAt: '2023-01-01T00:00:00Z', cpu: { usage_percent: 0.5 } }, - * { createdAt: '2023-01-01T01:00:00Z', cpu: { usage_percent: 0.6 } }, - * // more data points... - * ]; - * - * const MyChartComponent = () => { - * return ( - * } - * yTick={} - * strokeColor="#8884d8" - * fillColor="#8884d8" - * gradient={true} - * gradientStartColor="#8884d8" - * gradientEndColor="#82ca9d" - * customTooltip={({ active, payload, label }) => ( - * - * )} - * /> - * ); - * }; - * - * export default MyChartComponent; - */ + const CustomAreaChart = ({ data, dataKeys, From 0b3df9afce29e4fe73ef962d4ac0ed9f6fdbe144 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 25 Nov 2024 16:27:32 +0800 Subject: [PATCH 15/25] fix 0/0 error for avg cpu temp --- Client/src/Pages/Infrastructure/Details/index.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index ccff1388d..3899ad9d2 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -215,8 +215,10 @@ const InfrastructureDetails = () => { const logicalCores = latestCheck?.cpu?.logical_core ?? 0; const cpuFrequency = latestCheck?.cpu?.frequency ?? 0; const cpuTemperature = - latestCheck?.cpu?.temperature?.reduce((acc, curr) => acc + curr, 0) / - latestCheck?.cpu?.temperature?.length ?? 0; + latestCheck?.cpu?.temperature?.length > 0 + ? latestCheck.cpu.temperature.reduce((acc, curr) => acc + curr, 0) / + latestCheck.cpu.temperature.length + : 0; const memoryTotalBytes = latestCheck?.memory?.total_bytes ?? 0; const diskTotalBytes = latestCheck?.disk[0]?.total_bytes ?? 0; const os = latestCheck?.host?.os ?? null; From bb2f2450fd7d1ca1f4e0db8579229eae3f4bde43 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 26 Nov 2024 09:34:47 +0800 Subject: [PATCH 16/25] fix sort order, checks need to be queried in desc order due to the way that works. --- Client/src/Pages/Infrastructure/Details/index.jsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 3899ad9d2..d3f10651f 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -207,7 +207,8 @@ const InfrastructureDetails = () => { // end height calculations const buildStatBoxes = (monitor) => { - let latestCheck = monitor?.checks[monitor?.checks.length - 1] ?? null; + let latestCheck = monitor?.checks[0] ?? null; + console.log(latestCheck); if (latestCheck === null) return []; // Extract values from latest check @@ -270,7 +271,7 @@ const InfrastructureDetails = () => { }; const buildGaugeBoxConfigs = (monitor) => { - let latestCheck = monitor?.checks[monitor?.checks.length - 1] ?? null; + let latestCheck = monitor?.checks[0] ?? null; if (latestCheck === null) return []; // Extract values from latest check @@ -349,13 +350,13 @@ const InfrastructureDetails = () => { }; const buildAreaChartConfigs = (monitor) => { - let latestCheck = monitor?.checks[monitor?.checks.length - 1] ?? null; + let latestCheck = monitor?.checks[0] ?? null; if (latestCheck === null) return []; const tempData = buildTemps(monitor); return [ { type: "memory", - data: monitor?.checks ?? [], + data: monitor?.checks?.reverse() ?? [], dataKeys: ["memory.usage_percent"], heading: "Memory usage", strokeColor: theme.palette.primary.main, @@ -374,7 +375,7 @@ const InfrastructureDetails = () => { }, { type: "cpu", - data: monitor?.checks ?? [], + data: monitor?.checks?.reverse() ?? [], dataKeys: ["cpu.usage_percent"], heading: "CPU usage", strokeColor: theme.palette.success.main, @@ -410,7 +411,7 @@ const InfrastructureDetails = () => { }, ...(latestCheck?.disk?.map((disk, idx) => ({ type: "disk", - data: monitor?.checks ?? [], + data: monitor?.checks?.reverse() ?? [], diskIndex: idx, dataKeys: [`disk[${idx}].usage_percent`], heading: `Disk${idx} usage`, @@ -439,7 +440,7 @@ const InfrastructureDetails = () => { const response = await networkService.getStatsByMonitorId({ authToken: authToken, monitorId: monitorId, - sortOrder: "asc", + sortOrder: null, limit: null, dateRange: dateRange, numToDisplay: 50, From c9f454854c7ff052a943498ef198eb1b631a1507 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 26 Nov 2024 09:46:20 +0800 Subject: [PATCH 17/25] use non mutating array .toReversed() instead of reversed() --- .../Pages/Infrastructure/Details/index.jsx | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index d3f10651f..801a0e672 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -206,9 +206,8 @@ const InfrastructureDetails = () => { (chartContainerHeight - totalChartContainerPadding - totalTypographyPadding) * 0.95; // end height calculations - const buildStatBoxes = (monitor) => { - let latestCheck = monitor?.checks[0] ?? null; - console.log(latestCheck); + const buildStatBoxes = (checks) => { + let latestCheck = checks[0] ?? null; if (latestCheck === null) return []; // Extract values from latest check @@ -270,8 +269,8 @@ const InfrastructureDetails = () => { ]; }; - const buildGaugeBoxConfigs = (monitor) => { - let latestCheck = monitor?.checks[0] ?? null; + const buildGaugeBoxConfigs = (checks) => { + let latestCheck = checks[0] ?? null; if (latestCheck === null) return []; // Extract values from latest check @@ -313,9 +312,8 @@ const InfrastructureDetails = () => { ]; }; - const buildTemps = (monitor) => { + const buildTemps = (checks) => { let numCores = 0; - const checks = monitor?.checks ?? null; if (checks === null) return []; for (const check of checks) { if (check.cpu.temperature.length > numCores) { @@ -346,17 +344,19 @@ const InfrastructureDetails = () => { } ); }); + // Slice to remove `createdAt` key return { tempKeys: Object.keys(temps[0]).slice(1), temps }; }; - const buildAreaChartConfigs = (monitor) => { - let latestCheck = monitor?.checks[0] ?? null; + const buildAreaChartConfigs = (checks) => { + let latestCheck = checks[0] ?? null; if (latestCheck === null) return []; - const tempData = buildTemps(monitor); + const reversedChecks = checks.toReversed(); + const tempData = buildTemps(reversedChecks); return [ { type: "memory", - data: monitor?.checks?.reverse() ?? [], + data: reversedChecks, dataKeys: ["memory.usage_percent"], heading: "Memory usage", strokeColor: theme.palette.primary.main, @@ -375,7 +375,7 @@ const InfrastructureDetails = () => { }, { type: "cpu", - data: monitor?.checks?.reverse() ?? [], + data: reversedChecks, dataKeys: ["cpu.usage_percent"], heading: "CPU usage", strokeColor: theme.palette.success.main, @@ -411,7 +411,7 @@ const InfrastructureDetails = () => { }, ...(latestCheck?.disk?.map((disk, idx) => ({ type: "disk", - data: monitor?.checks?.reverse() ?? [], + data: reversedChecks, diskIndex: idx, dataKeys: [`disk[${idx}].usage_percent`], heading: `Disk${idx} usage`, @@ -455,9 +455,9 @@ const InfrastructureDetails = () => { fetchData(); }, [authToken, monitorId, dateRange, navigate]); - const statBoxConfigs = buildStatBoxes(monitor); - const gaugeBoxConfigs = buildGaugeBoxConfigs(monitor); - const areaChartConfigs = buildAreaChartConfigs(monitor); + const statBoxConfigs = buildStatBoxes(monitor?.checks ?? []); + const gaugeBoxConfigs = buildGaugeBoxConfigs(monitor?.checks ?? []); + const areaChartConfigs = buildAreaChartConfigs(monitor?.checks ?? []); return ( From 0b85a4761321363b7c9dcea9089512fad8f7c1eb Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 26 Nov 2024 09:48:35 +0800 Subject: [PATCH 18/25] buildTemps uses correct array --- Client/src/Pages/Infrastructure/Details/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 801a0e672..21245b719 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -324,7 +324,7 @@ const InfrastructureDetails = () => { if (numCores === 0) return []; - const temps = monitor?.checks?.map((check) => { + const temps = checks.map((check) => { if (check.cpu.temperature.length > numCores) { numCores = check.cpu.temperature.length; } From 7fb51e5801b2b9e49d2097d762ab633a71bc33b5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 26 Nov 2024 14:54:32 +0800 Subject: [PATCH 19/25] safe access of temp data, don't render charts without data --- .../Pages/Infrastructure/Details/index.jsx | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 21245b719..6e8f95d7c 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -20,7 +20,6 @@ import { TemperatureTooltip, } from "../../../Components/Charts/Utils/chartUtils"; import PropTypes from "prop-types"; -import Monitors from "../../Monitors/Home"; const BASE_BOX_PADDING_VERTICAL = 4; const BASE_BOX_PADDING_HORIZONTAL = 8; @@ -314,15 +313,15 @@ const InfrastructureDetails = () => { const buildTemps = (checks) => { let numCores = 0; - if (checks === null) return []; + if (checks === null) return { temps: [], tempKeys: [] }; + for (const check of checks) { - if (check.cpu.temperature.length > numCores) { + if (check?.cpu?.temperature?.length > numCores) { numCores = check.cpu.temperature.length; break; } } - - if (numCores === 0) return []; + if (numCores === 0) return { temps: [], tempKeys: [] }; const temps = checks.map((check) => { if (check.cpu.temperature.length > numCores) { @@ -401,7 +400,12 @@ const InfrastructureDetails = () => { heading: "CPU Temperature", yLabel: "Temperature", xTick: , - yDomain: [0, 200], + yDomain: [ + Math.min(...tempData.temps.flatMap((t) => tempData.tempKeys.map((k) => t[k]))) * + 0.9, + Math.max(...tempData.temps.flatMap((t) => tempData.tempKeys.map((k) => t[k]))) * + 1.1, + ], toolTip: ( { }, }} > - {areaChartConfigs.map((config) => ( - - - {config.heading} - - - - ))} + {areaChartConfigs.map((config) => { + if (config?.data?.length === 0) { + return; + } + + return ( + + + {config.heading} + + + + ); + })} ) : ( From ce0a99e8e2c509ea4882570e720d64155b82fbd7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 14:32:06 +0000 Subject: [PATCH 20/25] Update dependency @vitejs/plugin-react to v4.3.4 --- Client/package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index bcd5567ef..9c3fae4b1 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -2409,15 +2409,15 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz", - "integrity": "sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-transform-react-jsx-self": "^7.24.7", - "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, @@ -2425,7 +2425,7 @@ "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "node_modules/acorn": { From a9f3aeae55e56b513aa7b9af64fc9ecc5fa650ca Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 14:32:13 +0000 Subject: [PATCH 21/25] Update dependency mongoose to v8.8.3 --- Server/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Server/package-lock.json b/Server/package-lock.json index 9fdd415c4..ddb07fa0f 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -4524,9 +4524,9 @@ } }, "node_modules/mongoose": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.2.tgz", - "integrity": "sha512-jCTSqDANfRzk909v4YoZQi7jlGRB2MTvgG+spVBc/BA4tOs1oWJr//V6yYujqNq9UybpOtsSfBqxI0dSOEFJHQ==", + "version": "8.8.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.3.tgz", + "integrity": "sha512-/I4n/DcXqXyIiLRfAmUIiTjj3vXfeISke8dt4U4Y8Wfm074Wa6sXnQrXN49NFOFf2mM1kUdOXryoBvkuCnr+Qw==", "license": "MIT", "dependencies": { "bson": "^6.7.0", From 5c7d19dcbf65a30b0726543f4962cde985f1d9c1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 16:00:38 +0000 Subject: [PATCH 22/25] Update dependency prettier to v3.4.1 --- Client/package-lock.json | 6 +++--- Server/package-lock.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index bcd5567ef..b19c917d1 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -5251,9 +5251,9 @@ } }, "node_modules/prettier": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.0.tgz", - "integrity": "sha512-/OXNZcLyWkfo13ofOW5M7SLh+k5pnIs07owXK2teFpnfaOEcycnSy7HQxldaVX1ZP/7Q8oO1eDuQJNwbomQq5Q==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, "license": "MIT", "bin": { diff --git a/Server/package-lock.json b/Server/package-lock.json index 9fdd415c4..9918766b6 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -5671,9 +5671,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" From 87615e68bbb6f57487dd011deb0ee9de6fc3cafb Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 27 Nov 2024 10:14:10 +0800 Subject: [PATCH 23/25] update title and favicon --- Client/index.html | 33 +++++++++++----------------- Client/public/bluewave_favicon.ico | Bin 4286 -> 0 bytes Client/public/checkmate_favicon.svg | 4 ++++ 3 files changed, 17 insertions(+), 20 deletions(-) delete mode 100644 Client/public/bluewave_favicon.ico create mode 100644 Client/public/checkmate_favicon.svg diff --git a/Client/index.html b/Client/index.html index 8186ba31c..2d13bd25d 100644 --- a/Client/index.html +++ b/Client/index.html @@ -1,23 +1,16 @@ - - - - - BlueWave Uptime - - -
- - - + + + + + Checkmate + + + +
+ + + + \ No newline at end of file diff --git a/Client/public/bluewave_favicon.ico b/Client/public/bluewave_favicon.ico deleted file mode 100644 index 487946975b025af198ebb1094af4bdf62c0ca5f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmeHL+e;Kt7@z)v>}D5w5Q;Dgi!360@j-&1h@uE6@fsPo^PRry&ud^e3m7thfNq-^4D|z+DnV^LWc#9+m8-ic z=AM!7G{@3pAUwx15$JdTDSy$}JUH+z)eC=pCVc1D!&kKdO6_)NPs(8_gB-^k=!8_X zjQCDPu=fk^vvdXe%PUZ7Hbbsh3x8cEfoUkZ8*MQ-&aV-QfzHIc@IB3@qL7U zBF#OP{He`_9E;&A7q?P87wmV%1Nn4Dv^JT~)@pkU?TK8zCVI?h_@%4twU7^{Uy1k_ z`tg?g3if^D{2OgI_&d{`RJ_6+FY`-zsNOBG@eM!E4W64}Oy}LXe$ub;`WEz-bI_kw z!gzI^^#7T2ZA$%I8%+Of3~T0K*97p@3FC98Q5OqCoo$rc8$%k39X`t+jq=uCzYqS~ z+0Y)Jf;sS==eF^temI|FwSMa_`d4bVQSN&=D{N0$osJoPr2Yv@%3ln#zmww!+V4Qj zNsKLi*=pKnsFw?Ir#dj?dQ3YH7^YPx&4A&^%bHDavxtBrY( zPo~p;%(VA~_*bs&f&QX~a-|sFBMW$)a-DIc8+LxMI;ppurJ9u*U87tzD0Eh{^V(%p n1KBx1{@nf@ + + + From 82a514f637c9bbfb54151c075e7e1e52f5c34bef Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 27 Nov 2024 10:37:11 +0800 Subject: [PATCH 24/25] add 0 data for temps for consistent empty data handling --- .../Pages/Infrastructure/Details/index.jsx | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 6e8f95d7c..06fb1296a 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -312,7 +312,7 @@ const InfrastructureDetails = () => { }; const buildTemps = (checks) => { - let numCores = 0; + let numCores = 1; if (checks === null) return { temps: [], tempKeys: [] }; for (const check of checks) { @@ -321,19 +321,16 @@ const InfrastructureDetails = () => { break; } } - if (numCores === 0) return { temps: [], tempKeys: [] }; - const temps = checks.map((check) => { - if (check.cpu.temperature.length > numCores) { - numCores = check.cpu.temperature.length; - } - // If there's no data, set the temperature to 0 - if (check.cpu.temperature.length === 0) { + if ( + check?.cpu?.temperature?.length === 0 || + check?.cpu?.temperature === undefined || + check?.cpu?.temperature === null + ) { check.cpu.temperature = Array(numCores).fill(0); } - - return check.cpu.temperature.reduce( + const res = check?.cpu?.temperature?.reduce( (acc, cur, idx) => { acc[`core${idx + 1}`] = cur; return acc; @@ -342,9 +339,16 @@ const InfrastructureDetails = () => { createdAt: check.createdAt, } ); + return res; }); - // Slice to remove `createdAt` key - return { tempKeys: Object.keys(temps[0]).slice(1), temps }; + if (temps.length === 0 || !temps[0]) { + return { temps: [], tempKeys: [] }; + } + + return { + tempKeys: Object.keys(temps[0] || {}).filter((key) => key !== "createdAt"), + temps, + }; }; const buildAreaChartConfigs = (checks) => { @@ -401,10 +405,13 @@ const InfrastructureDetails = () => { yLabel: "Temperature", xTick: , yDomain: [ - Math.min(...tempData.temps.flatMap((t) => tempData.tempKeys.map((k) => t[k]))) * - 0.9, - Math.max(...tempData.temps.flatMap((t) => tempData.tempKeys.map((k) => t[k]))) * - 1.1, + 0, + Math.max( + Math.max( + ...tempData.temps.flatMap((t) => tempData.tempKeys.map((k) => t[k])) + ) * 1.1, + 200 + ), ], toolTip: ( { }} > {areaChartConfigs.map((config) => { - if (config?.data?.length === 0) { - return; - } - return ( Date: Wed, 27 Nov 2024 16:53:56 +0000 Subject: [PATCH 25/25] Update material-ui monorepo --- Client/package-lock.json | 94 ++++++++++++++++++++-------------------- Client/package.json | 6 +-- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index 55e849eb2..80aa209c1 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -11,9 +11,9 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", - "@mui/icons-material": "6.1.8", - "@mui/lab": "6.0.0-beta.16", - "@mui/material": "6.1.8", + "@mui/icons-material": "6.1.9", + "@mui/lab": "6.0.0-beta.17", + "@mui/material": "6.1.9", "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.22.3", "@mui/x-date-pickers": "7.22.3", @@ -1078,15 +1078,15 @@ "license": "MIT" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.62", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.62.tgz", - "integrity": "sha512-TzJLCNlrMkSU4bTCdTT+TVUiGx4sjZLhH673UV6YN+rNNP8wJpkWfRSvjDB5HcbH2T0lUamnz643ZnV+8IiMjw==", + "version": "5.0.0-beta.63", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.63.tgz", + "integrity": "sha512-W6aIqKP9X8VUX0KhSnYWo2+5C7MnKV1IhYVd517L/apvfkVq5KaTdlnxSBVwnaWt46whayVgQ/9KXwUVCXp6+w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", "@floating-ui/react-dom": "^2.1.1", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.8", + "@mui/utils": "^6.1.9", "@popperjs/core": "^2.11.8", "clsx": "^2.1.1", "prop-types": "^15.8.1" @@ -1110,9 +1110,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.8.tgz", - "integrity": "sha512-TGAvzwUg9hybDacwfIGFjI2bXYXrIqky+vMfaeay8rvT56/PNAlvIDUJ54kpT5KRc9AWAihOvtDI7/LJOThOmQ==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.9.tgz", + "integrity": "sha512-TWqj7b1w5cmSz4H/uf+y2AHxAH4ldPR7D2bz0XVyn60GCAo/zRbRPx7cF8gTs/i7CiYeHzV6dtat0VpMwOtolw==", "license": "MIT", "funding": { "type": "opencollective", @@ -1120,9 +1120,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.8.tgz", - "integrity": "sha512-6frsXcf1TcJKWevWwRup6V4L8lzI33cbHcAjT83YLgKw0vYRZKY0kjMI9fhrJZdRWXgFFgKKvEv3GjoxbqFF7A==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.9.tgz", + "integrity": "sha512-AzlhIT51rdjkZ/EcUV2dbhNkNSUHIqCnNoUxodpiTw8buyAUBd+qnxg5OBSuPpun/ZEdSSB8Q7Uyh6zqjiMsEQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0" @@ -1135,7 +1135,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.1.8", + "@mui/material": "^6.1.9", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -1146,16 +1146,16 @@ } }, "node_modules/@mui/lab": { - "version": "6.0.0-beta.16", - "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.16.tgz", - "integrity": "sha512-YFeKREMMCiUhp4dGXd6Y/7N3BLepys9bM6xi4aF0WTZOvfl1ksDXPzuXPGiiiIuMgQFJeyN5iUnS1iPu3wH+kQ==", + "version": "6.0.0-beta.17", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.17.tgz", + "integrity": "sha512-Ls1pIuYi5D9wq9mUwncky6CWokd6CCqQDCxXbm0TP0e7ksU5DcCPUZXBmTWQgbkldLu14aUXbJHyts63L0rycQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/base": "5.0.0-beta.62", - "@mui/system": "^6.1.8", + "@mui/base": "5.0.0-beta.63", + "@mui/system": "^6.1.9", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.8", + "@mui/utils": "^6.1.9", "clsx": "^2.1.1", "prop-types": "^15.8.1" }, @@ -1169,8 +1169,8 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material": "^6.1.8", - "@mui/material-pigment-css": "^6.1.8", + "@mui/material": "^6.1.9", + "@mui/material-pigment-css": "^6.1.9", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1191,16 +1191,16 @@ } }, "node_modules/@mui/material": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.8.tgz", - "integrity": "sha512-QZdQFnXct+7NXIzHgT3qt+sQiO7HYGZU2vymP9Xl9tUMXEOA/S1mZMMb7+WGZrk5TzNlU/kP/85K0da5V1jXoQ==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.9.tgz", + "integrity": "sha512-NwqIN0bdsgzSbZd5JFcC+2ez0XW/XNs8uiV2PDHrqQ4qf/FEasFJG1z6g8JbCN0YlTrHZekVb17X0Fv0qcYJfQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.1.8", - "@mui/system": "^6.1.8", + "@mui/core-downloads-tracker": "^6.1.9", + "@mui/system": "^6.1.9", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.8", + "@mui/utils": "^6.1.9", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", @@ -1219,7 +1219,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.1.8", + "@mui/material-pigment-css": "^6.1.9", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1240,13 +1240,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.8.tgz", - "integrity": "sha512-TuKl7msynCNCVvhX3c0ef1sF0Qb3VHcPs8XOGB/8bdOGBr/ynmIG1yTMjZeiFQXk8yN9fzK/FDEKMFxILNn3wg==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.9.tgz", + "integrity": "sha512-7aum/O1RquBYhfwL/7egDyl9GqJgPM6hoJDFFBbhF6Sgv9yI9v4w3ArKUkuVvR0CtVj4NXRVMKEioh1bjUzvuA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.1.8", + "@mui/utils": "^6.1.9", "prop-types": "^15.8.1" }, "engines": { @@ -1267,14 +1267,14 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.8.tgz", - "integrity": "sha512-ZvEoT0U2nPLSLI+B4by4cVjaZnPT2f20f4JUPkyHdwLv65ZzuoHiTlwyhqX1Ch63p8bcJzKTHQVGisEoMK6PGA==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.9.tgz", + "integrity": "sha512-xynSLlJRxHLzSfQaiDjkaTx8LiFb9ByVa7aOdwFnTxGWFMY1F+mkXwAUY4jDDE+MAxkWxlzzQE0wOohnsxhdQg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@emotion/cache": "^11.13.1", - "@emotion/serialize": "^1.3.2", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", "@emotion/sheet": "^1.4.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1301,16 +1301,16 @@ } }, "node_modules/@mui/system": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.8.tgz", - "integrity": "sha512-i1kLfQoWxzFpXTBQIuPoA3xKnAnP3en4I2T8xIolovSolGQX5k8vGjw1JaydQS40td++cFsgCdEU458HDNTGUA==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.9.tgz", + "integrity": "sha512-8x+RucnNp21gfFYsklCaZf0COXbv3+v0lrVuXONxvPEkESi2rwLlOi8UPJfcz6LxZOAX3v3oQ7qw18vnpgueRg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.1.8", - "@mui/styled-engine": "^6.1.8", + "@mui/private-theming": "^6.1.9", + "@mui/styled-engine": "^6.1.9", "@mui/types": "^7.2.19", - "@mui/utils": "^6.1.8", + "@mui/utils": "^6.1.9", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1355,9 +1355,9 @@ } }, "node_modules/@mui/utils": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.8.tgz", - "integrity": "sha512-O2DWb1kz8hiANVcR7Z4gOB3SvPPsSQGUmStpyBDzde6dJIfBzgV9PbEQOBZd3EBsd1pB+Uv1z5LAJAbymmawrA==", + "version": "6.1.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.9.tgz", + "integrity": "sha512-N7uzBp7p2or+xanXn3aH2OTINC6F/Ru/U8h6amhRZEev8bJhKN86rIDIoxZZ902tj+09LXtH83iLxFMjMHyqNA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", diff --git a/Client/package.json b/Client/package.json index c2ea33996..795dd8d87 100644 --- a/Client/package.json +++ b/Client/package.json @@ -14,9 +14,9 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", - "@mui/icons-material": "6.1.8", - "@mui/lab": "6.0.0-beta.16", - "@mui/material": "6.1.8", + "@mui/icons-material": "6.1.9", + "@mui/lab": "6.0.0-beta.17", + "@mui/material": "6.1.9", "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.22.3", "@mui/x-date-pickers": "7.22.3",