diff --git a/client/src/Pages/Infrastructure/Create/Components/CustomAlertsSection.jsx b/client/src/Pages/Infrastructure/Create/Components/CustomAlertsSection.jsx
new file mode 100644
index 000000000..5a6f5e981
--- /dev/null
+++ b/client/src/Pages/Infrastructure/Create/Components/CustomAlertsSection.jsx
@@ -0,0 +1,87 @@
+import ConfigBox from "../../../../Components/ConfigBox";
+import { Box, Stack, Typography } from "@mui/material";
+import { CustomThreshold } from "../Components/CustomThreshold";
+import { capitalizeFirstLetter } from "../../../../Utils/stringUtils";
+import { useTheme } from "@emotion/react";
+import { useTranslation } from "react-i18next";
+import PropTypes from "prop-types";
+const CustomAlertsSection = ({
+ errors,
+ onChange,
+ infrastructureMonitor,
+ handleCheckboxChange,
+}) => {
+ const theme = useTheme();
+ const { t } = useTranslation();
+
+ const METRICS = ["cpu", "memory", "disk", "temperature"];
+ const METRIC_PREFIX = "usage_";
+ const hasAlertError = (errors) => {
+ return Object.keys(errors).filter((k) => k.startsWith(METRIC_PREFIX)).length > 0;
+ };
+ const getAlertError = (errors) => {
+ const errorKey = Object.keys(errors).find((key) => key.startsWith(METRIC_PREFIX));
+ return errorKey ? errors[errorKey] : null;
+ };
+ return (
+
+
+
+ {t("infrastructureCustomizeAlerts")}
+
+
+ {t("infrastructureAlertNotificationDescription")}
+
+
+
+ {METRICS.map((metric) => {
+ return (
+
+ );
+ })}
+
+ {hasAlertError(errors) && (
+
+ {getAlertError(errors)}
+
+ )}
+
+
+ );
+};
+
+CustomAlertsSection.propTypes = {
+ errors: PropTypes.object.isRequired,
+ onChange: PropTypes.func.isRequired,
+ infrastructureMonitor: PropTypes.object.isRequired,
+ handleCheckboxChange: PropTypes.func.isRequired,
+};
+
+export default CustomAlertsSection;
diff --git a/client/src/Pages/Infrastructure/Create/Components/MonitorActionButtons.jsx b/client/src/Pages/Infrastructure/Create/Components/MonitorActionButtons.jsx
new file mode 100644
index 000000000..becda3e3a
--- /dev/null
+++ b/client/src/Pages/Infrastructure/Create/Components/MonitorActionButtons.jsx
@@ -0,0 +1,78 @@
+import { useState } from "react";
+import { Box, Button } from "@mui/material";
+import { useTheme } from "@emotion/react";
+import { useTranslation } from "react-i18next";
+import PauseCircleOutlineIcon from "@mui/icons-material/PauseCircleOutline";
+import PlayCircleOutlineRoundedIcon from "@mui/icons-material/PlayCircleOutlineRounded";
+import Dialog from "../../../../Components/Dialog";
+import PropTypes from "prop-types";
+
+const MonitorActionButtons = ({ monitor, isBusy, handlePause, handleRemove }) => {
+ const theme = useTheme();
+ const { t } = useTranslation();
+ const [isOpen, setIsOpen] = useState(false);
+
+ return (
+
+
+
+
+ );
+};
+
+MonitorActionButtons.propTypes = {
+ monitor: PropTypes.object.isRequired,
+ isBusy: PropTypes.bool.isRequired,
+ handlePause: PropTypes.func.isRequired,
+ handleRemove: PropTypes.func.isRequired,
+};
+
+export default MonitorActionButtons;
diff --git a/client/src/Pages/Infrastructure/Create/Components/MonitorStatusHeader.jsx b/client/src/Pages/Infrastructure/Create/Components/MonitorStatusHeader.jsx
new file mode 100644
index 000000000..2ed48bf64
--- /dev/null
+++ b/client/src/Pages/Infrastructure/Create/Components/MonitorStatusHeader.jsx
@@ -0,0 +1,73 @@
+import { Box, Stack, Tooltip, Typography } from "@mui/material";
+import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
+import { useTheme } from "@emotion/react";
+import { useTranslation } from "react-i18next";
+import PulseDot from "../../../../Components/Animated/PulseDot";
+import PropTypes from "prop-types";
+const MonitorStatusHeader = ({ monitor, infrastructureMonitor }) => {
+ const theme = useTheme();
+ const { t } = useTranslation();
+ const { statusColor, pagespeedStatusMsg, determineState } = useMonitorUtils();
+ return (
+
+
+
+
+
+
+
+ {infrastructureMonitor.url?.replace(/^https?:\/\//, "") || "..."}
+
+
+ {t("editing")}
+
+
+ );
+};
+
+MonitorStatusHeader.propTypes = {
+ monitor: PropTypes.object.isRequired,
+ infrastructureMonitor: PropTypes.object.isRequired,
+};
+
+export default MonitorStatusHeader;
diff --git a/client/src/Pages/Infrastructure/Create/hooks/useInfrastructureMonitorForm.jsx b/client/src/Pages/Infrastructure/Create/hooks/useInfrastructureMonitorForm.jsx
new file mode 100644
index 000000000..fa8a6ebe9
--- /dev/null
+++ b/client/src/Pages/Infrastructure/Create/hooks/useInfrastructureMonitorForm.jsx
@@ -0,0 +1,90 @@
+import { useState } from "react";
+const useInfrastructureMonitorForm = () => {
+ const [infrastructureMonitor, setInfrastructureMonitor] = useState({
+ url: "",
+ name: "",
+ notifications: [],
+ notify_email: false,
+ interval: 0.25,
+ cpu: false,
+ usage_cpu: "",
+ memory: false,
+ usage_memory: "",
+ disk: false,
+ usage_disk: "",
+ temperature: false,
+ usage_temperature: "",
+ secret: "",
+ });
+
+ const onChangeForm = (name, value) => {
+ setInfrastructureMonitor({
+ ...infrastructureMonitor,
+ [name]: value,
+ });
+ };
+ const handleCheckboxChange = (event) => {
+ setInfrastructureMonitor({
+ ...infrastructureMonitor,
+ [event.target.name]: event.target.checked,
+ });
+ };
+ const initializeInfrastructureMonitorForCreate = (globalSettings) => {
+ const gt = globalSettings?.data?.settings?.globalThresholds || {};
+ setInfrastructureMonitor({
+ url: "",
+ name: "",
+ notifications: [],
+ interval: 0.25,
+ cpu: gt.cpu !== undefined,
+ usage_cpu: gt.cpu !== undefined ? gt.cpu.toString() : "",
+ memory: gt.memory !== undefined,
+ usage_memory: gt.memory !== undefined ? gt.memory.toString() : "",
+ disk: gt.disk !== undefined,
+ usage_disk: gt.disk !== undefined ? gt.disk.toString() : "",
+ temperature: gt.temperature !== undefined,
+ usage_temperature: gt.temperature !== undefined ? gt.temperature.toString() : "",
+ secret: "",
+ });
+ };
+
+ const initializeInfrastructureMonitorForUpdate = (monitor) => {
+ const MS_PER_MINUTE = 60000;
+ const { thresholds = {} } = monitor;
+ setInfrastructureMonitor({
+ url: monitor.url.replace(/^https?:\/\//, ""),
+ name: monitor.name || "",
+ notifications: monitor.notifications || [],
+ interval: monitor.interval / MS_PER_MINUTE,
+ cpu: thresholds.usage_cpu !== undefined,
+ usage_cpu:
+ thresholds.usage_cpu !== undefined ? (thresholds.usage_cpu * 100).toString() : "",
+ memory: thresholds.usage_memory !== undefined,
+ usage_memory:
+ thresholds.usage_memory !== undefined
+ ? (thresholds.usage_memory * 100).toString()
+ : "",
+ disk: thresholds.usage_disk !== undefined,
+ usage_disk:
+ thresholds.usage_disk !== undefined
+ ? (thresholds.usage_disk * 100).toString()
+ : "",
+ temperature: thresholds.usage_temperature !== undefined,
+ usage_temperature:
+ thresholds.usage_temperature !== undefined
+ ? (thresholds.usage_temperature * 100).toString()
+ : "",
+ secret: monitor.secret || "",
+ });
+ };
+ return {
+ infrastructureMonitor,
+ setInfrastructureMonitor,
+ onChangeForm,
+ handleCheckboxChange,
+ initializeInfrastructureMonitorForCreate,
+ initializeInfrastructureMonitorForUpdate,
+ };
+};
+
+export default useInfrastructureMonitorForm;
diff --git a/client/src/Pages/Infrastructure/Create/hooks/useInfrastructureSubmit.jsx b/client/src/Pages/Infrastructure/Create/hooks/useInfrastructureSubmit.jsx
new file mode 100644
index 000000000..da564ae7c
--- /dev/null
+++ b/client/src/Pages/Infrastructure/Create/hooks/useInfrastructureSubmit.jsx
@@ -0,0 +1,80 @@
+import { useCreateMonitor, useUpdateMonitor } from "../../../../Hooks/monitorHooks";
+const useInfrastructureSubmit = () => {
+ const [createMonitor, isCreating] = useCreateMonitor();
+ const [updateMonitor, isUpdating] = useUpdateMonitor();
+ const buildForm = (infrastructureMonitor, https) => {
+ const MS_PER_MINUTE = 60000;
+
+ let form = {
+ url: `http${https ? "s" : ""}://` + infrastructureMonitor.url,
+ name:
+ infrastructureMonitor.name === ""
+ ? infrastructureMonitor.url
+ : infrastructureMonitor.name,
+ interval: infrastructureMonitor.interval * MS_PER_MINUTE,
+ cpu: infrastructureMonitor.cpu,
+ ...(infrastructureMonitor.cpu
+ ? { usage_cpu: infrastructureMonitor.usage_cpu }
+ : {}),
+ memory: infrastructureMonitor.memory,
+ ...(infrastructureMonitor.memory
+ ? { usage_memory: infrastructureMonitor.usage_memory }
+ : {}),
+ disk: infrastructureMonitor.disk,
+ ...(infrastructureMonitor.disk
+ ? { usage_disk: infrastructureMonitor.usage_disk }
+ : {}),
+ temperature: infrastructureMonitor.temperature,
+ ...(infrastructureMonitor.temperature
+ ? { usage_temperature: infrastructureMonitor.usage_temperature }
+ : {}),
+ secret: infrastructureMonitor.secret,
+ };
+ return form;
+ };
+ const submitInfrastructureForm = async (
+ infrastructureMonitor,
+ form,
+ isCreate,
+ monitorId
+ ) => {
+ const {
+ cpu,
+ usage_cpu,
+ memory,
+ usage_memory,
+ disk,
+ usage_disk,
+ temperature,
+ usage_temperature,
+ ...rest
+ } = form;
+
+ const thresholds = {
+ ...(cpu ? { usage_cpu: usage_cpu / 100 } : {}),
+ ...(memory ? { usage_memory: usage_memory / 100 } : {}),
+ ...(disk ? { usage_disk: usage_disk / 100 } : {}),
+ ...(temperature ? { usage_temperature: usage_temperature / 100 } : {}),
+ };
+
+ const finalForm = {
+ ...(isCreate ? {} : { _id: monitorId }),
+ ...rest,
+ description: form.name,
+ type: "hardware",
+ notifications: infrastructureMonitor.notifications,
+ thresholds,
+ };
+ // Handle create or update
+ isCreate
+ ? await createMonitor({ monitor: finalForm, redirect: "/infrastructure" })
+ : await updateMonitor({ monitor: finalForm, redirect: "/infrastructure" });
+ };
+ return {
+ buildForm,
+ submitInfrastructureForm,
+ isCreating,
+ isUpdating,
+ };
+};
+export default useInfrastructureSubmit;
diff --git a/client/src/Pages/Infrastructure/Create/hooks/useValidateInfrastructureForm.jsx b/client/src/Pages/Infrastructure/Create/hooks/useValidateInfrastructureForm.jsx
new file mode 100644
index 000000000..080f441c4
--- /dev/null
+++ b/client/src/Pages/Infrastructure/Create/hooks/useValidateInfrastructureForm.jsx
@@ -0,0 +1,37 @@
+import { useState } from "react";
+import { infrastructureMonitorValidation } from "../../../../Validation/validation";
+import { createToast } from "../../../../Utils/toastUtils";
+const useValidateInfrastructureForm = () => {
+ const [errors, setErrors] = useState({});
+
+ const validateField = (name, value) => {
+ const { error } = infrastructureMonitorValidation.validate(
+ { [name]: value },
+ { abortEarly: false }
+ );
+ setErrors((prev) => ({
+ ...prev,
+ ...(error ? { [name]: error.details[0].message } : { [name]: undefined }),
+ }));
+ };
+
+ const validateForm = (form) => {
+ const { error } = infrastructureMonitorValidation.validate(form, {
+ abortEarly: false,
+ });
+
+ if (error) {
+ const newErrors = {};
+ error.details.forEach((err) => {
+ newErrors[err.path[0]] = err.message;
+ });
+ console.log(newErrors);
+ setErrors(newErrors);
+ createToast({ body: "Please check the form for errors." });
+ return error;
+ }
+ return null;
+ };
+ return { errors, validateField, validateForm };
+};
+export default useValidateInfrastructureForm;
diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx
index ae95cce33..28007c538 100644
--- a/client/src/Pages/Infrastructure/Create/index.jsx
+++ b/client/src/Pages/Infrastructure/Create/index.jsx
@@ -1,40 +1,33 @@
//Components
import Breadcrumbs from "../../../Components/Breadcrumbs";
import ConfigBox from "../../../Components/ConfigBox";
-import Dialog from "../../../Components/Dialog";
import FieldWrapper from "../../../Components/Inputs/FieldWrapper";
import Link from "../../../Components/Link";
-import PauseCircleOutlineIcon from "@mui/icons-material/PauseCircleOutline";
-import PlayCircleOutlineRoundedIcon from "@mui/icons-material/PlayCircleOutlineRounded";
-import PulseDot from "../../../Components/Animated/PulseDot";
import Select from "../../../Components/Inputs/Select";
import TextInput from "../../../Components/Inputs/TextInput";
-import { Box, Stack, Tooltip, Typography, Button, ButtonGroup } from "@mui/material";
-import { CustomThreshold } from "./Components/CustomThreshold";
+import { Box, Stack, Typography, Button, ButtonGroup } from "@mui/material";
import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
-import { createToast } from "../../../Utils/toastUtils";
+import MonitorStatusHeader from "./Components/MonitorStatusHeader";
+import MonitorActionButtons from "./Components/MonitorActionButtons";
+import CustomAlertsSection from "./Components/CustomAlertsSection";
// Utils
import NotificationsConfig from "../../../Components/NotificationConfig";
-import { capitalizeFirstLetter } from "../../../Utils/stringUtils";
-import { infrastructureMonitorValidation } from "../../../Validation/validation";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
-import { useMonitorUtils } from "../../../Hooks/useMonitorUtils";
import { useParams } from "react-router-dom";
-import { useSelector } from "react-redux";
import { useState, useEffect } from "react";
import { useTheme } from "@emotion/react";
import { useTranslation } from "react-i18next";
import {
- useCreateMonitor,
useDeleteMonitor,
useFetchGlobalSettings,
useFetchHardwareMonitorById,
usePauseMonitor,
- useUpdateMonitor,
} from "../../../Hooks/monitorHooks";
+import useInfrastructureMonitorForm from "./hooks/useInfrastructureMonitorForm";
+import useValidateInfrastructureForm from "./hooks/useValidateInfrastructureForm";
+import useInfrastructureSubmit from "./hooks/useInfrastructureSubmit";
const CreateInfrastructureMonitor = () => {
- const { user } = useSelector((state) => state.auth);
const { monitorId } = useParams();
const isCreate = typeof monitorId === "undefined";
@@ -42,39 +35,29 @@ const CreateInfrastructureMonitor = () => {
const { t } = useTranslation();
// State
- const [errors, setErrors] = useState({});
const [https, setHttps] = useState(false);
- const [isOpen, setIsOpen] = useState(false);
const [updateTrigger, setUpdateTrigger] = useState(false);
- const [infrastructureMonitor, setInfrastructureMonitor] = useState({
- url: "",
- name: "",
- notifications: [],
- notify_email: false,
- interval: 0.25,
- cpu: false,
- usage_cpu: "",
- memory: false,
- usage_memory: "",
- disk: false,
- usage_disk: "",
- temperature: false,
- usage_temperature: "",
- secret: "",
- });
// Fetch monitor details if editing
- const { statusColor, pagespeedStatusMsg, determineState } = useMonitorUtils();
const [monitor, isLoading] = useFetchHardwareMonitorById({
monitorId,
updateTrigger,
});
- const [createMonitor, isCreating] = useCreateMonitor();
const [deleteMonitor, isDeleting] = useDeleteMonitor();
const [globalSettings, globalSettingsLoading] = useFetchGlobalSettings();
const [notifications, notificationsAreLoading] = useGetNotificationsByTeamId();
const [pauseMonitor, isPausing] = usePauseMonitor();
- const [updateMonitor, isUpdating] = useUpdateMonitor();
+ const {
+ infrastructureMonitor,
+ setInfrastructureMonitor,
+ onChangeForm,
+ handleCheckboxChange,
+ initializeInfrastructureMonitorForCreate,
+ initializeInfrastructureMonitorForUpdate,
+ } = useInfrastructureMonitorForm();
+ const { errors, validateField, validateForm } = useValidateInfrastructureForm();
+ const { buildForm, submitInfrastructureForm, isCreating, isUpdating } =
+ useInfrastructureSubmit();
const FREQUENCIES = [
{ _id: 0.25, name: t("time.fifteenSeconds") },
@@ -93,157 +76,27 @@ const CreateInfrastructureMonitor = () => {
{ name: "Configure", path: `/infrastructure/configure/${monitorId}` },
]),
];
- const METRICS = ["cpu", "memory", "disk", "temperature"];
- const METRIC_PREFIX = "usage_";
- const MS_PER_MINUTE = 60000;
-
- const hasAlertError = (errors) => {
- return Object.keys(errors).filter((k) => k.startsWith(METRIC_PREFIX)).length > 0;
- };
-
- const getAlertError = (errors) => {
- const errorKey = Object.keys(errors).find((key) => key.startsWith(METRIC_PREFIX));
- return errorKey ? errors[errorKey] : null;
- };
-
// Populate form fields if editing
useEffect(() => {
if (isCreate) {
if (globalSettingsLoading) return;
-
- const gt = globalSettings?.data?.settings?.globalThresholds || {};
-
setHttps(false);
-
- setInfrastructureMonitor({
- url: "",
- name: "",
- notifications: [],
- interval: 0.25,
- cpu: gt.cpu !== undefined,
- usage_cpu: gt.cpu !== undefined ? gt.cpu.toString() : "",
- memory: gt.memory !== undefined,
- usage_memory: gt.memory !== undefined ? gt.memory.toString() : "",
- disk: gt.disk !== undefined,
- usage_disk: gt.disk !== undefined ? gt.disk.toString() : "",
- temperature: gt.temperature !== undefined,
- usage_temperature: gt.temperature !== undefined ? gt.temperature.toString() : "",
- secret: "",
- });
+ initializeInfrastructureMonitorForCreate(globalSettings);
} else if (monitor) {
- const { thresholds = {} } = monitor;
-
setHttps(monitor.url.startsWith("https"));
-
- setInfrastructureMonitor({
- url: monitor.url.replace(/^https?:\/\//, ""),
- name: monitor.name || "",
- notifications: monitor.notifications || [],
- interval: monitor.interval / MS_PER_MINUTE,
- cpu: thresholds.usage_cpu !== undefined,
- usage_cpu:
- thresholds.usage_cpu !== undefined
- ? (thresholds.usage_cpu * 100).toString()
- : "",
- memory: thresholds.usage_memory !== undefined,
- usage_memory:
- thresholds.usage_memory !== undefined
- ? (thresholds.usage_memory * 100).toString()
- : "",
- disk: thresholds.usage_disk !== undefined,
- usage_disk:
- thresholds.usage_disk !== undefined
- ? (thresholds.usage_disk * 100).toString()
- : "",
- temperature: thresholds.usage_temperature !== undefined,
- usage_temperature:
- thresholds.usage_temperature !== undefined
- ? (thresholds.usage_temperature * 100).toString()
- : "",
- secret: monitor.secret || "",
- });
+ initializeInfrastructureMonitorForUpdate(monitor);
}
}, [isCreate, monitor, globalSettings, globalSettingsLoading]);
// Handlers
const onSubmit = async (event) => {
event.preventDefault();
-
- // Build the form
- let form = {
- url: `http${https ? "s" : ""}://` + infrastructureMonitor.url,
- name:
- infrastructureMonitor.name === ""
- ? infrastructureMonitor.url
- : infrastructureMonitor.name,
- interval: infrastructureMonitor.interval * MS_PER_MINUTE,
- cpu: infrastructureMonitor.cpu,
- ...(infrastructureMonitor.cpu
- ? { usage_cpu: infrastructureMonitor.usage_cpu }
- : {}),
- memory: infrastructureMonitor.memory,
- ...(infrastructureMonitor.memory
- ? { usage_memory: infrastructureMonitor.usage_memory }
- : {}),
- disk: infrastructureMonitor.disk,
- ...(infrastructureMonitor.disk
- ? { usage_disk: infrastructureMonitor.usage_disk }
- : {}),
- temperature: infrastructureMonitor.temperature,
- ...(infrastructureMonitor.temperature
- ? { usage_temperature: infrastructureMonitor.usage_temperature }
- : {}),
- secret: infrastructureMonitor.secret,
- };
-
- const { error } = infrastructureMonitorValidation.validate(form, {
- abortEarly: false,
- });
-
+ const form = buildForm(infrastructureMonitor, https);
+ const error = validateForm(form);
if (error) {
- const newErrors = {};
- error.details.forEach((err) => {
- newErrors[err.path[0]] = err.message;
- });
- console.log(newErrors);
- setErrors(newErrors);
- createToast({ body: "Please check the form for errors." });
return;
}
-
- // Build the thresholds for the form
- const {
- cpu,
- usage_cpu,
- memory,
- usage_memory,
- disk,
- usage_disk,
- temperature,
- usage_temperature,
- ...rest
- } = form;
-
- const thresholds = {
- ...(cpu ? { usage_cpu: usage_cpu / 100 } : {}),
- ...(memory ? { usage_memory: usage_memory / 100 } : {}),
- ...(disk ? { usage_disk: usage_disk / 100 } : {}),
- ...(temperature ? { usage_temperature: usage_temperature / 100 } : {}),
- };
-
- form = {
- ...(isCreate ? {} : { _id: monitorId }),
- ...rest,
- description: form.name,
- type: "hardware",
- notifications: infrastructureMonitor.notifications,
- thresholds,
- };
-
- // Handle create or update
- isCreate
- ? await createMonitor({ monitor: form, redirect: "/infrastructure" })
- : await updateMonitor({ monitor: form, redirect: "/infrastructure" });
+ submitInfrastructureForm(infrastructureMonitor, form, isCreate, monitorId);
};
const triggerUpdate = () => {
@@ -252,28 +105,8 @@ const CreateInfrastructureMonitor = () => {
const onChange = (event) => {
const { value, name } = event.target;
- setInfrastructureMonitor({
- ...infrastructureMonitor,
- [name]: value,
- });
-
- const { error } = infrastructureMonitorValidation.validate(
- { [name]: value },
- { abortEarly: false }
- );
- setErrors((prev) => ({
- ...prev,
- ...(error ? { [name]: error.details[0].message } : { [name]: undefined }),
- }));
- };
-
- const handleCheckboxChange = (event) => {
- const { name } = event.target;
- const { checked } = event.target;
- setInfrastructureMonitor({
- ...infrastructureMonitor,
- [name]: checked,
- });
+ onChangeForm(name, value);
+ validateField(name, value);
};
const handlePause = async () => {
@@ -336,105 +169,19 @@ const CreateInfrastructureMonitor = () => {
)}
{!isCreate && (
-
-
-
-
-
-
-
- {infrastructureMonitor.url?.replace(/^https?:\/\//, "") || "..."}
-
-
- {t("editing")}
-
-
+
)}
{!isCreate && (
-
-
-
-
+
)}
@@ -534,58 +281,12 @@ const CreateInfrastructureMonitor = () => {
setNotifications={infrastructureMonitor.notifications}
/>
-
-
-
- {t("infrastructureCustomizeAlerts")}
-
-
- {t("infrastructureAlertNotificationDescription")}
-
-
-
- {METRICS.map((metric) => {
- return (
-
- );
- })}
- {/* Error text */}
- {hasAlertError(errors) && (
-
- {getAlertError(errors)}
-
- )}
-
-
+
{
- {!isCreate && (
-
);
};