From 42ae1af98700b5b3c1778517acbc8ff34ad2b53e Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Thu, 31 Oct 2024 10:36:09 -0400 Subject: [PATCH 001/142] - Add infrastructure monitor slice --- .../infrastructureMonitorsSlice.js | 405 ++++++++++++++++++ Client/src/store.js | 2 + 2 files changed, 407 insertions(+) create mode 100644 Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js diff --git a/Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js b/Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js new file mode 100644 index 000000000..abcb31adf --- /dev/null +++ b/Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js @@ -0,0 +1,405 @@ +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { jwtDecode } from "jwt-decode"; +import { networkService } from "../../main"; +const initialState = { + isLoading: false, + monitorsSummary: [], + success: null, + msg: null, +}; + +export const createInfrastructureMonitor = createAsyncThunk( + "infrastructureMonitors/createMonitor", + async (data, thunkApi) => { + try { + const { authToken, monitor } = data; + const res = await networkService.createMonitor({ + authToken: authToken, + monitor: monitor, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const checkInfrastructureEndpointResolution = createAsyncThunk( + "infrastructureMonitors/CheckEndpoint", + async (data, thunkApi) => { + try { + const { authToken, monitorURL } = data; + + const res = await networkService.checkEndpointResolution({ + authToken: authToken, + monitorURL: monitorURL, + }) + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +) + +export const getInfrastructureMonitorById = createAsyncThunk( + "infrastructureMonitors/getMonitorById", + async (data, thunkApi) => { + try { + const { authToken, monitorId } = data; + const res = await networkService.getMonitorById({ + authToken: authToken, + monitorId: monitorId, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const getInfrastructureMonitorsByTeamId = createAsyncThunk( + "infrastructureMonitors/getMonitorsByTeamId", + async (token, thunkApi) => { + const user = jwtDecode(token); + try { + const res = await networkService.getMonitorsAndSummaryByTeamId({ + authToken: token, + teamId: user.teamId, + types: ["http", "ping"], + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const updateInfrastructureMonitor = createAsyncThunk( + "infrastructureMonitors/updateMonitor", + async (data, thunkApi) => { + try { + const { authToken, monitor } = data; + const updatedFields = { + name: monitor.name, + description: monitor.description, + interval: monitor.interval, + notifications: monitor.notifications, + }; + const res = await networkService.updateMonitor({ + authToken: authToken, + monitorId: monitor._id, + updatedFields: updatedFields, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const deleteInfrastructureMonitor = createAsyncThunk( + "infrastructureMonitors/deleteMonitor", + async (data, thunkApi) => { + try { + const { authToken, monitor } = data; + const res = await networkService.deleteMonitorById({ + authToken: authToken, + monitorId: monitor._id, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const pauseInfrastructureMonitor = createAsyncThunk( + "infrastructureMonitors/pauseMonitor", + async (data, thunkApi) => { + try { + const { authToken, monitorId } = data; + const res = await networkService.pauseMonitorById({ + authToken: authToken, + monitorId: monitorId, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const deleteInfrastructureMonitorChecksByTeamId = createAsyncThunk( + "infrastructureMonitors/deleteChecksByTeamId", + async (data, thunkApi) => { + try { + const { authToken, teamId } = data; + const res = await networkService.deleteChecksByTeamId({ + authToken: authToken, + teamId: teamId, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +export const deleteAllInfrastructureMonitors = createAsyncThunk( + "infrastructureMonitors/deleteAllMonitors", + async (data, thunkApi) => { + try { + const { authToken } = data; + const res = await networkService.deleteAllMonitors({ + authToken: authToken, + }); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + +const infrastructureMonitorsSlice = createSlice({ + name: "infrastructureMonitors", + initialState, + reducers: { + clearInfrastructureMonitorState: (state) => { + state.isLoading = false; + state.monitorsSummary = []; + state.success = null; + state.msg = null; + }, + }, + extraReducers: (builder) => { + builder + // ***************************************************** + // Monitors by teamId + // ***************************************************** + + .addCase(getInfrastructureMonitorsByTeamId.pending, (state) => { + state.isLoading = true; + }) + .addCase(getInfrastructureMonitorsByTeamId.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.msg; + state.monitorsSummary = action.payload.data; + }) + .addCase(getInfrastructureMonitorsByTeamId.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Getting infrastructure monitors failed"; + }) + + // ***************************************************** + // Create Monitor + // ***************************************************** + .addCase(createInfrastructureMonitor.pending, (state) => { + state.isLoading = true; + }) + .addCase(createInfrastructureMonitor.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(createInfrastructureMonitor.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to create infrastructure monitor"; + }) + // ***************************************************** + // Resolve Endpoint + // ***************************************************** + .addCase(checkEndpointResolution.pending, (state) => { + state.isLoading = true; + }) + .addCase(checkEndpointResolution.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(checkEndpointResolution.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to check endpoint resolution"; + }) + // ***************************************************** + // Get Monitor By Id + // ***************************************************** + .addCase(getInfrastructureMonitorById.pending, (state) => { + state.isLoading = true; + }) + .addCase(getInfrastructureMonitorById.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(getInfrastructureMonitorById.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload ? action.payload.msg : "Failed to get infrastructure monitor"; + }) + // ***************************************************** + // update Monitor + // ***************************************************** + .addCase(updateInfrastructureMonitor.pending, (state) => { + state.isLoading = true; + }) + .addCase(updateInfrastructureMonitor.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(updateInfrastructureMonitor.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to update infrastructure monitor"; + }) + + // ***************************************************** + // Delete Monitor + // ***************************************************** + .addCase(deleteInfrastructureMonitor.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteInfrastructureMonitor.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(deleteInfrastructureMonitor.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to delete infrastructure monitor"; + }) + // ***************************************************** + // Delete Monitor checks by Team ID + // ***************************************************** + .addCase(deleteMonitorChecksByTeamId.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteMonitorChecksByTeamId.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(deleteMonitorChecksByTeamId.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to delete monitor checks"; + }) + // ***************************************************** + // Pause Monitor + // ***************************************************** + .addCase(pauseInfrastructureMonitor.pending, (state) => { + state.isLoading = true; + }) + .addCase(pauseInfrastructureMonitor.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(pauseInfrastructureMonitor.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to pause infrastructure monitor"; + }) + // ***************************************************** + // Delete all Monitors + // ***************************************************** + .addCase(deleteAllInfrastructureMonitors.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteAllInfrastructureMonitors.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(deleteAllInfrastructureMonitors.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload ? action.payload.msg : "Failed to delete all monitors"; + }); + }, +}); + +export const { setInfrastructureMonitors, clearInfrastructureMonitorState } = infrastructureMonitorsSlice.actions; + +export default infrastructureMonitorsSlice.reducer; diff --git a/Client/src/store.js b/Client/src/store.js index 0b4c46ce8..92ddfad00 100644 --- a/Client/src/store.js +++ b/Client/src/store.js @@ -1,6 +1,7 @@ import { configureStore, combineReducers } from "@reduxjs/toolkit"; import uptimeMonitorsReducer from "./Features/UptimeMonitors/uptimeMonitorsSlice"; +import infrastructureMonitorsReducer from "./Features/InfrastructureMonitors/infrastructureMonitorsSlice"; import pageSpeedMonitorReducer from "./Features/PageSpeedMonitor/pageSpeedMonitorSlice"; import authReducer from "./Features/Auth/authSlice"; import uiReducer from "./Features/UI/uiSlice"; @@ -28,6 +29,7 @@ const persistConfig = { const rootReducer = combineReducers({ uptimeMonitors: uptimeMonitorsReducer, + infrastructureMonitors: infrastructureMonitorsReducer, auth: authReducer, pageSpeedMonitors: pageSpeedMonitorReducer, ui: uiReducer, From ffeb4d79914993b0ec6a7c71cf09ad09ec3aaf24 Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Thu, 31 Oct 2024 15:19:57 -0400 Subject: [PATCH 002/142] - Add initial create infrastructure page --- .../infrastructureMonitorsSlice.js | 12 +- .../CreateMonitor/index.jsx | 378 ++++++++++++++++++ 2 files changed, 384 insertions(+), 6 deletions(-) rename Client/src/Features/{InfrastructureMonitors => InfrastructureMonitors}/infrastructureMonitorsSlice.js (96%) create mode 100644 Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx diff --git a/Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js b/Client/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js similarity index 96% rename from Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js rename to Client/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js index abcb31adf..24b3500ac 100644 --- a/Client/src/Features/InfrastructureMonitors /infrastructureMonitorsSlice.js +++ b/Client/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js @@ -277,15 +277,15 @@ const infrastructureMonitorsSlice = createSlice({ // ***************************************************** // Resolve Endpoint // ***************************************************** - .addCase(checkEndpointResolution.pending, (state) => { + .addCase(checkInfrastructureEndpointResolution.pending, (state) => { state.isLoading = true; }) - .addCase(checkEndpointResolution.fulfilled, (state, action) => { + .addCase(checkInfrastructureEndpointResolution.fulfilled, (state, action) => { state.isLoading = false; state.success = action.payload.success; state.msg = action.payload.msg; }) - .addCase(checkEndpointResolution.rejected, (state, action) => { + .addCase(checkInfrastructureEndpointResolution.rejected, (state, action) => { state.isLoading = false; state.success = false; state.msg = action.payload @@ -348,15 +348,15 @@ const infrastructureMonitorsSlice = createSlice({ // ***************************************************** // Delete Monitor checks by Team ID // ***************************************************** - .addCase(deleteMonitorChecksByTeamId.pending, (state) => { + .addCase(deleteInfrastructureMonitorChecksByTeamId.pending, (state) => { state.isLoading = true; }) - .addCase(deleteMonitorChecksByTeamId.fulfilled, (state, action) => { + .addCase(deleteInfrastructureMonitorChecksByTeamId.fulfilled, (state, action) => { state.isLoading = false; state.success = action.payload.success; state.msg = action.payload.msg; }) - .addCase(deleteMonitorChecksByTeamId.rejected, (state, action) => { + .addCase(deleteInfrastructureMonitorChecksByTeamId.rejected, (state, action) => { state.isLoading = false; state.success = false; state.msg = action.payload diff --git a/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx b/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx new file mode 100644 index 000000000..87c4c537c --- /dev/null +++ b/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx @@ -0,0 +1,378 @@ +import { useState } from "react"; +import { Box, Button, ButtonGroup, Stack, Typography } from "@mui/material"; +import LoadingButton from "@mui/lab/LoadingButton"; +import { useSelector, useDispatch } from "react-redux"; +import { monitorValidation } from "../../../Validation/validation"; +import { createUptimeMonitor } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; +import { checkEndpointResolution } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; +import { useNavigate } from "react-router-dom"; +import { useTheme } from "@emotion/react"; +import { createToast } from "../../../Utils/toastUtils"; +import { logger } from "../../../Utils/Logger"; +import { ConfigBox } from "../../Monitors/styled"; +import Radio from "../../../Components/Inputs/Radio"; +import Field from "../../../Components/Inputs/Field"; +import Select from "../../../Components/Inputs/Select"; +import Checkbox from "../../../Components/Inputs/Checkbox"; +import Breadcrumbs from "../../../Components/Breadcrumbs"; + +const CreateInfrastructureMonitor = () => { + const MS_PER_MINUTE = 60000; + const { user, authToken } = useSelector((state) => state.auth); + const monitorState = useSelector((state) => state.infrastructureMonitor); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const theme = useTheme(); + + const idMap = { + "monitor-url": "url", + "monitor-name": "name", + "monitor-checks-http": "type", + "monitor-checks-ping": "type", + "notify-email-default": "notification-email", + }; + + const [infrastructureMonitor, setInfrastructureMonitor] = useState({ + url: "", + name: "", + type: "http", + notifications: [], + interval: 1, + }); + const [https, setHttps] = useState(true); + const [errors, setErrors] = useState({}); + + const handleChange = (event, name) => { + const { value, id } = event.target; + if (!name) name = idMap[id]; + + if (name.includes("notification-")) { + name = name.replace("notification-", ""); + let hasNotif = infrastructureMonitor.notifications.some( + (notification) => notification.type === name + ); + setInfrastructureMonitor((prev) => { + const notifs = [...prev.notifications]; + if (hasNotif) { + return { + ...prev, + notifications: notifs.filter((notif) => notif.type !== name), + }; + } else { + return { + ...prev, + notifications: [ + ...notifs, + name === "email" + ? { type: name, address: value } + : // TODO - phone number + { type: name, phone: value }, + ], + }; + } + }); + } else { + setInfrastructureMonitor((prev) => ({ + ...prev, + [name]: value, + })); + + const { error } = monitorValidation.validate( + { [name]: value }, + { abortEarly: false } + ); + console.log(error); + setErrors((prev) => { + const updatedErrors = { ...prev }; + if (error) updatedErrors[name] = error.details[0].message; + else delete updatedErrors[name]; + return updatedErrors; + }); + } + }; + + const handleCreateInfrastructureMonitor = async (event) => { + event.preventDefault(); + //obj to submit + let form = { + url: + //preprending protocol for url + infrastructureMonitor.type === "http" + ? `http${https ? "s" : ""}://` + infrastructureMonitor.url + : infrastructureMonitor.url, + name: + infrastructureMonitor.name === "" + ? infrastructureMonitor.url + : infrastructureMonitor.name, + type: infrastructureMonitor.type, + interval: infrastructureMonitor.interval * MS_PER_MINUTE, + }; + + const { error } = monitorValidation.validate(form, { + abortEarly: false, + }); + + if (error) { + const newErrors = {}; + error.details.forEach((err) => { + newErrors[err.path[0]] = err.message; + }); + setErrors(newErrors); + createToast({ body: "Error validation data." }); + } else { + if (infrastructureMonitor.type === "http") { + const checkEndpointAction = await dispatch( + checkEndpointResolution({ authToken, monitorURL: form.url }) + ); + if (checkEndpointAction.meta.requestStatus === "rejected") { + createToast({ + body: "The endpoint you entered doesn't resolve. Check the URL again.", + }); + setErrors({ url: "The entered URL is not reachable." }); + return; + } + } + + form = { + ...form, + description: form.name, + teamId: user.teamId, + userId: user._id, + notifications: infrastructureMonitor.notifications, + }; + const action = await dispatch(createUptimeMonitor({ authToken, monitor: form })); + if (action.meta.requestStatus === "fulfilled") { + createToast({ body: "Monitor created successfully!" }); + navigate("/monitors"); + } else { + createToast({ body: "Failed to create monitor." }); + } + } + }; + + //select values + const frequencies = [ + { _id: 1, name: "1 minute" }, + { _id: 2, name: "2 minutes" }, + { _id: 3, name: "3 minutes" }, + { _id: 4, name: "4 minutes" }, + { _id: 5, name: "5 minutes" }, + ]; + + return ( + + + + + + Create your{" "} + + + infrastructure monitor + + + + + General settings + + Here you can select the URL of the host, together with the type of monitor. + + + + + + + + + + Checks to perform + + You can always add or remove checks after adding your site. + + + + + handleChange(event)} + /> + {infrastructureMonitor.type === "http" ? ( + + + + + ) : ( + "" + )} + + handleChange(event)} + /> + {errors["type"] ? ( + + + {errors["type"]} + + + ) : ( + "" + )} + + + + + Incident notifications + + When there is an incident, notify users. + + + + When there is a new incident, + logger.warn("disabled")} + isDisabled={true} + /> + notification.type === "email" + )} + value={user?.email} + onChange={(event) => handleChange(event)} + /> + logger.warn("disabled")} + isDisabled={true} + /> + {infrastructureMonitor.notifications.some( + (notification) => notification.type === "emails" + ) ? ( + + logger.warn("disabled")} + /> + + You can separate multiple emails with a comma + + + ) : ( + "" + )} + + + + + Advanced settings + + + handleChange(event, "interval")} + onChange={(e) => handleChange(e, "interval")} + onBlur={handleBlur} items={frequencies} /> - + /> */} { variant="contained" color="primary" onClick={handleCreateInfrastructureMonitor} - disabled={Object.keys(errors).length !== 0 && true} loading={monitorState?.isLoading} > Create infrastructure monitor diff --git a/Client/src/Validation/error.js b/Client/src/Validation/error.js index a616e13f5..8bd35e48e 100644 --- a/Client/src/Validation/error.js +++ b/Client/src/Validation/error.js @@ -26,6 +26,10 @@ const hasValidationErrors = (form, validation, setErrors) => { ) { newErrors[err.path[0]] = err.message ?? "Validation error"; } + // Handle conditionally usage number required cases + if (!form.cpu || (form.cpu && form.usage_cpu)) { + delete newErrors["usage_cpu"]; + } }); if (Object.keys(newErrors).length > 0) { setErrors(newErrors); diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index 898ff862b..fb0a436c1 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -181,10 +181,14 @@ const infrastractureMonitorValidation = joi.object({ name: joi.string().trim().max(50).allow("").messages({ "string.max": "This field should not exceed the 50 characters limit.", }), - type: joi.string().trim().messages({ "string.empty": "This field is required." }), - usage_cpu: joi.number(), - usage_memory: joi.number(), - usage_disk: joi.number(), + secret: joi.string().trim().messages({ "string.empty": "This field is required." }), + usage_cpu: joi.number().messages({ + "number.base": "CPU threshold must be a number.", + "any.required": "CPU threshold is required.", + }), + cpu:joi.boolean(), + // usage_memory: joi.number(), + // usage_disk: joi.number(), // usage_temperature: joi.number().messages({ // "number.base": "Temperature must be a number.", // }), @@ -194,6 +198,10 @@ const infrastractureMonitorValidation = joi.object({ // usage_swap: joi.number().messages({ // "number.base": "Swap used must be a number.", // }), + interval: joi.number().messages({ + "number.base": "Frequency must be a number.", + "any.required": "Frequency is required.", + }), }); export { From 439dea44236838f24e2971d8ec1e04e5b3c0c628 Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Thu, 7 Nov 2024 15:27:40 -0500 Subject: [PATCH 010/142] - fine toning payload and default item etc --- .../InfrastructureMonitors/CreateMonitor/index.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx b/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx index 1997e3714..fc82dbc68 100644 --- a/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx @@ -23,7 +23,7 @@ const CreateInfrastructureMonitor = () => { url: "", name: "", notifications: [], - interval: 1, + interval: 15, cpu: false, usage_cpu: "", secret: "", @@ -162,9 +162,9 @@ const CreateInfrastructureMonitor = () => { const generatePayload = (form) => { let thresholds = {}; - thresholds.usage_cpu = form.usage_cpu; - thresholds.usage_memory = form.usage_memory; - thresholds.usage_disk = form.usage_disk; + if (form.usage_cpu) thresholds.usage_cpu = form.usage_cpu; + if (form.usage_memory) thresholds.usage_memory = form.usage_memory; + if (form.usage_disk) thresholds.usage_disk = form.usage_disk; delete form.cpu; delete form.memory; @@ -442,7 +442,7 @@ const CreateInfrastructureMonitor = () => {