diff --git a/Client/src/Components/Charts/AreaChart/index.jsx b/Client/src/Components/Charts/AreaChart/index.jsx
index d05dbb14a..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,
@@ -11,69 +65,15 @@ import { createGradient } from "../Utils/gradientUtils";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
import { useId } 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;
- */
+import { Fragment } from "react";
+
const CustomAreaChart = ({
data,
- dataKey,
+ dataKeys,
xKey,
+ xDomain,
yKey,
+ yDomain,
xTick,
yTick,
strokeColor,
@@ -87,7 +87,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, index) => {
+ const gradientId = `gradient-${uniqueId}-${index}`;
+
+ return (
+
+ {gradient === true &&
+ createGradient({
+ id: gradientId,
+ startColor: gradientStartColor || AREA_COLORS[index],
+ endColor: gradientEndColor,
+ direction: gradientDirection,
+ })}
+
+
+ );
+ })}
{customTooltip ? (
{
fontSize={11}
fontWeight={400}
>
- {`${payload?.value * 100}%`}
+ {`${(payload?.value * 100).toFixed()}%`}
);
};
@@ -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,
+ ]),
+};
diff --git a/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx b/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx
index abbd2e6f6..61070ba7d 100644
--- a/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx
+++ b/Client/src/Pages/Infrastructure/CreateMonitor/index.jsx
@@ -33,12 +33,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();
@@ -75,18 +77,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);
});
};
diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx
index 9fbaae81a..6e8f95d7c 100644
--- a/Client/src/Pages/Infrastructure/Details/index.jsx
+++ b/Client/src/Pages/Infrastructure/Details/index.jsx
@@ -17,6 +17,7 @@ import {
TzTick,
PercentTick,
InfrastructureTooltip,
+ TemperatureTooltip,
} from "../../../Components/Charts/Utils/chartUtils";
import PropTypes from "prop-types";
@@ -204,6 +205,238 @@ const InfrastructureDetails = () => {
(chartContainerHeight - totalChartContainerPadding - totalTypographyPadding) * 0.95;
// end height calculations
+ const buildStatBoxes = (checks) => {
+ let latestCheck = checks[0] ?? null;
+ if (latestCheck === null) return [];
+
+ // Extract values from latest check
+ 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?.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;
+ const platform = latestCheck?.host?.platform ?? null;
+ const osPlatform = os === null && platform === null ? null : `${os} ${platform}`;
+ return [
+ {
+ id: 0,
+ heading: "CPU (Physical)",
+ subHeading: `${physicalCores} cores`,
+ },
+ {
+ id: 1,
+ heading: "CPU (Logical)",
+ subHeading: `${logicalCores} cores`,
+ },
+ {
+ id: 2,
+ heading: "CPU Frequency",
+ subHeading: `${(cpuFrequency / 1000).toFixed(2)} Ghz`,
+ },
+ {
+ id: 3,
+ heading: "Average CPU Temperature",
+ subHeading: `${cpuTemperature.toFixed(2)} C`,
+ },
+ {
+ id: 4,
+ heading: "Memory",
+ subHeading: formatBytes(memoryTotalBytes),
+ },
+ {
+ id: 5,
+ heading: "Disk",
+ subHeading: formatBytes(diskTotalBytes),
+ },
+ { id: 6, heading: "Uptime", subHeading: "100%" },
+ {
+ id: 7,
+ heading: "Status",
+ subHeading: monitor?.status === true ? "Active" : "Inactive",
+ },
+ {
+ id: 8,
+ heading: "OS",
+ subHeading: osPlatform,
+ },
+ ];
+ };
+
+ const buildGaugeBoxConfigs = (checks) => {
+ let latestCheck = checks[0] ?? null;
+ if (latestCheck === null) return [];
+
+ // Extract values from latest check
+ 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: decimalToPercentage(memoryUsagePercent),
+ heading: "Memory Usage",
+ metricOne: "Used",
+ valueOne: formatBytes(memoryUsedBytes),
+ metricTwo: "Total",
+ valueTwo: formatBytes(memoryTotalBytes),
+ },
+ {
+ type: "cpu",
+ value: decimalToPercentage(cpuUsagePercent),
+ heading: "CPU Usage",
+ metricOne: "Cores",
+ valueOne: cpuPhysicalCores ?? 0,
+ metricTwo: "Frequency",
+ valueTwo: `${(cpuFrequency / 1000).toFixed(2)} Ghz`,
+ },
+ ...(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),
+ })),
+ ];
+ };
+
+ const buildTemps = (checks) => {
+ let numCores = 0;
+ if (checks === null) return { temps: [], tempKeys: [] };
+
+ for (const check of checks) {
+ if (check?.cpu?.temperature?.length > numCores) {
+ numCores = check.cpu.temperature.length;
+ 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) {
+ 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,
+ }
+ );
+ });
+ // Slice to remove `createdAt` key
+ return { tempKeys: Object.keys(temps[0]).slice(1), temps };
+ };
+
+ const buildAreaChartConfigs = (checks) => {
+ let latestCheck = checks[0] ?? null;
+ if (latestCheck === null) return [];
+ const reversedChecks = checks.toReversed();
+ const tempData = buildTemps(reversedChecks);
+ return [
+ {
+ type: "memory",
+ data: reversedChecks,
+ 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",
+ data: reversedChecks,
+ 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: [
+ 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: (
+
+ ),
+ },
+ ...(latestCheck?.disk?.map((disk, idx) => ({
+ type: "disk",
+ data: reversedChecks,
+ diskIndex: idx,
+ 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: (
+
+ ),
+ })) || []),
+ ];
+ };
+
// Fetch data
useEffect(() => {
const fetchData = async () => {
@@ -211,102 +444,24 @@ const InfrastructureDetails = () => {
const response = await networkService.getStatsByMonitorId({
authToken: authToken,
monitorId: monitorId,
- sortOrder: "asc",
+ sortOrder: null,
limit: null,
dateRange: dateRange,
numToDisplay: 50,
normalize: false,
});
-
setMonitor(response.data.data);
} catch (error) {
navigate("/not-found", { replace: true });
- logger.error(error);
+ logger.error(error);
}
};
fetchData();
- }, [authToken, monitorId, dateRange]);
+ }, [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",
- },
- {
- type: "cpu",
- dataKey: "cpu.usage_percent",
- heading: "CPU usage",
- strokeColor: theme.palette.success.main,
- yLabel: "CPU Usage",
- },
- ...(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",
- })) || []),
- ];
+ const statBoxConfigs = buildStatBoxes(monitor?.checks ?? []);
+ const gaugeBoxConfigs = buildGaugeBoxConfigs(monitor?.checks ?? []);
+ const areaChartConfigs = buildAreaChartConfigs(monitor?.checks ?? []);
return (
@@ -343,6 +498,7 @@ const InfrastructureDetails = () => {
{statBoxConfigs.map((statBox) => (
@@ -380,41 +536,36 @@ const InfrastructureDetails = () => {
},
}}
>
- {areaChartConfigs.map((config) => (
-
-
- {config.heading}
-
- (
-
- )}
- xTick={}
- yTick={}
- strokeColor={config.strokeColor}
- gradient={true}
- gradientStartColor={config.strokeColor}
- gradientEndColor="#ffffff"
- />
-
- ))}
+ {areaChartConfigs.map((config) => {
+ if (config?.data?.length === 0) {
+ return;
+ }
+
+ return (
+
+
+ {config.heading}
+
+
+
+ );
+ })}
) : (
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/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: () => [],
diff --git a/Server/db/models/Notification.js b/Server/db/models/Notification.js
index 868324cc2..8767880c1 100644
--- a/Server/db/models/Notification.js
+++ b/Server/db/models/Notification.js
@@ -38,9 +38,42 @@ const NotificationSchema = mongoose.Schema(
return this.alertThreshold;
},
},
+ tempAlertThreshold: {
+ type: Number,
+ default: function () {
+ return this.alertThreshold;
+ },
+ },
},
{
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);
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index 10b798753..e22aac1a6 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -205,6 +205,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(),