diff --git a/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx b/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx
index 02f4ae853..1997e3714 100644
--- a/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx
+++ b/Client/src/Pages/InfrastructureMonitors/CreateMonitor/index.jsx
@@ -16,21 +16,40 @@ import Field from "../../../Components/Inputs/Field";
import Select from "../../../Components/Inputs/Select";
import Checkbox from "../../../Components/Inputs/Checkbox";
import Breadcrumbs from "../../../Components/Breadcrumbs";
+import { buildErrors, hasValidationErrors } from "../../../Validation/error";
const CreateInfrastructureMonitor = () => {
+ const [infrastructureMonitor, setInfrastructureMonitor] = useState({
+ url: "",
+ name: "",
+ notifications: [],
+ interval: 1,
+ cpu: false,
+ usage_cpu: "",
+ secret: "",
+ });
+
+ 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 = {
+ "notify-email-default": "notification-email",
+ };
+
+ const [errors, setErrors] = useState({});
+
const CustomAlertStack = ({
checkboxId,
checkboxLabel,
- checkboxValue,
- isChecked,
- onChange,
fieldId,
- fieldValue,
alertUnit,
- }) => {
- console.log("fieldValue")
- console.log(fieldValue)
- return (
+ onChange,
+ onBlur,
+ }) => (
{
{
type="number"
className="field-infrastructure-alert"
id={fieldId}
- value={fieldValue}
+ value={infrastructureMonitor[fieldId]}
+ onBlur={onBlur}
+ onChange={onChange}
+ error={errors[`${fieldId}`]}
+ disabled={!infrastructureMonitor[checkboxId]}
>
{
- );}
+ );
- 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-secret": "secret",
- "notify-email-default": "notification-email",
+ const handleCustomAlertCheckChange = (event) => {
+ const { value, id } = event.target;
+ setInfrastructureMonitor((prev) => {
+ const newState = {
+ [id]: prev[id] == undefined && value == "on" ? true : !prev[id],
+ };
+ return {
+ ...prev,
+ ...newState,
+ [`usage_${id}`]: newState[id] ? prev[`usage_${id}`] : "",
+ };
+ });
+ // Remove the error if unchecked
+ setErrors((prev) => {
+ return buildErrors(prev, [`usage_${id}`]);
+ });
};
- const [infrastructureMonitor, setInfrastructureMonitor] = useState({
- url: "",
- name: "",
- notifications: [],
- interval: 1,
- threshold: {cpu: "", disk: "", memory: ""}
- });
- const [errors, setErrors] = useState({});
-
- const handleChange = (event, name) => {
+ const handleBlur = (event) => {
const { value, id } = event.target;
- if (!name) name = idMap[id];
+ const { error } = infrastractureMonitorValidation.validate(
+ { [id]: value },
+ {
+ abortEarly: false,
+ }
+ );
+ setErrors((prev) => {
+ return buildErrors(prev, id, error);
+ });
+ };
+
+ const handleChange = (event, appendedId) => {
+ event.preventDefault();
+ const { value, id } = event.target;
+ let name = appendedId ?? idMap[id] ?? id;
if (name.includes("notification-")) {
name = name.replace("notification-", "");
@@ -126,67 +157,59 @@ const CreateInfrastructureMonitor = () => {
...prev,
[name]: value,
}));
-
- const { error } = infrastractureMonitorValidation.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 generatePayload = (form) => {
+ let thresholds = {};
+ thresholds.usage_cpu = form.usage_cpu;
+ thresholds.usage_memory = form.usage_memory;
+ thresholds.usage_disk = form.usage_disk;
+
+ delete form.cpu;
+ delete form.memory;
+ delete form.disk;
+
+ delete form.usage_cpu;
+ delete form.usage_memory;
+ delete form.usage_disk;
+ form = {
+ ...form,
+ description: form.name,
+ teamId: user.teamId,
+ userId: user._id,
+ type: "hardware",
+ notifications: infrastructureMonitor.notifications,
+ thresholds,
+ };
+ return form;
+ };
const handleCreateInfrastructureMonitor = async (event) => {
event.preventDefault();
- //obj to submit
let form = {
- url:infrastructureMonitor.url,
+ ...infrastructureMonitor,
name:
infrastructureMonitor.name === ""
? infrastructureMonitor.url
: infrastructureMonitor.name,
interval: infrastructureMonitor.interval * MS_PER_MINUTE,
};
-
- const { error } =infrastractureMonitorValidation.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." });
+ delete form.notifications;
+ if (hasValidationErrors(form, infrastractureMonitorValidation, setErrors)) {
+ return;
} else {
- if (infrastructureMonitor.type === "http") {
- const checkEndpointAction = await dispatch(
- checkInfrastructureEndpointResolution({ 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;
- }
+ const checkEndpointAction = await dispatch(
+ checkInfrastructureEndpointResolution({ 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(
- createInfrastructureMonitor({ authToken, monitor: form })
+ createInfrastructureMonitor({ authToken, monitor: generatePayload(form) })
);
if (action.meta.requestStatus === "fulfilled") {
createToast({ body: "Infrastructure monitor created successfully!" });
@@ -199,12 +222,12 @@ const CreateInfrastructureMonitor = () => {
//select values
const frequencies = [
- { _id: 1, name: "15 seconds" },
- { _id: 2, name: "30 seconds" },
- { _id: 3, name: "1 minute" },
- { _id: 4, name: "2 minutes" },
- { _id: 5, name: "5 minutes" },
- { _id: 6, name: "10 minutes" },
+ { _id: 15, name: "15 seconds" },
+ { _id: 30, name: "30 seconds" },
+ { _id: 60, name: "1 minute" },
+ { _id: 120, name: "2 minutes" },
+ { _id: 300, name: "5 minutes" },
+ { _id: 600, name: "10 minutes" },
];
return (
@@ -252,28 +275,31 @@ const CreateInfrastructureMonitor = () => {
@@ -295,7 +321,8 @@ const CreateInfrastructureMonitor = () => {
(notification) => notification.type === "email"
)}
value={user?.email}
- onChange={(event) => handleChange(event)}
+ onChange={(e) => handleChange(e)}
+ onBlur={handleBlur}
/>
{
isChecked={false}
value=""
onChange={() => logger.warn("disabled")}
+ onBlur={handleBlur}
isDisabled={true}
/>
@@ -312,6 +340,7 @@ const CreateInfrastructureMonitor = () => {
placeholder="name@gmail.com"
value=""
onChange={() => logger.warn("disabled")}
+ onBlur={handleBlur}
/>
You can separate multiple emails with a comma
@@ -330,51 +359,57 @@ const CreateInfrastructureMonitor = () => {
handleChange(event)}
+ fieldValue={infrastructureMonitor.usage_cpu ?? ""}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="%"
/>
- handleChange(event)}
+ fieldValue={infrastructureMonitor.usage_memory??""}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="%"
/>
handleChange(event)}
+ fieldValue={infrastructureMonitor.usage_disk??""}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="%"
- />
+ /> */}
{/* handleChange(event)}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="°C"
/>
handleChange(event)}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="%"
/>
handleChange(event)}
+ checkboxValue={""}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="%"
/> */}
@@ -393,7 +428,8 @@ const CreateInfrastructureMonitor = () => {
checkboxLabel="Retain data for"
checkboxValue={""}
fieldId={"retries_max"}
- onChange={(event) => handleChange(event)}
+ onChange={handleChange}
+ onBlur={handleBlur}
alertUnit="days"
/>
*/}
@@ -404,20 +440,22 @@ const CreateInfrastructureMonitor = () => {
{
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 {