diff --git a/client/src/Components/Fallback/FallbackBackground.jsx b/client/src/Components/Fallback/FallbackBackground.jsx index 00ecafb4e..fe46f4064 100644 --- a/client/src/Components/Fallback/FallbackBackground.jsx +++ b/client/src/Components/Fallback/FallbackBackground.jsx @@ -1,7 +1,6 @@ import { useTheme } from "@emotion/react"; import Box from "@mui/material/Box"; import Background from "../../assets/Images/background-grid.svg?react"; -import SkeletonDark from "../../assets/Images/create-placeholder-dark.svg?react"; import OutputAnimation from "../../assets/Animations/output.gif"; import DarkmodeOutput from "../../assets/Animations/darkmodeOutput.gif"; import { useSelector } from "react-redux"; @@ -13,7 +12,7 @@ const FallbackBackground = () => { { setIsLoading(true); const updatedFields = { name: monitor.name, + statusWindowSize: monitor.statusWindowSize, + statusWindowThreshold: monitor.statusWindowThreshold, description: monitor.description, interval: monitor.interval, notifications: monitor.notifications, 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 ( + + + + setIsOpen(false)} + confirmationButtonLabel={t("delete")} + onConfirm={handleRemove} + /> + + ); +}; + +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 && ( - setIsOpen(false)} - confirmationButtonLabel={t("delete")} - onConfirm={handleRemove} - /> - )} ); }; diff --git a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx index 227523439..41d2b0a87 100644 --- a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx +++ b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx @@ -1,8 +1,9 @@ import PropTypes from "prop-types"; import { useState, useEffect } from "react"; -import { FormControl, InputLabel, Select, MenuItem, Box } from "@mui/material"; +import { Box } from "@mui/material"; import { useTranslation } from "react-i18next"; import { useTheme } from "@emotion/react"; +import Select from "../../../../../Components/Inputs/Select"; import NetworkStatBoxes from "./NetworkStatBoxes"; import NetworkCharts from "./NetworkCharts"; import MonitorTimeFrameHeader from "../../../../../Components/MonitorTimeFrameHeader"; @@ -63,27 +64,17 @@ const Network = ({ net, checks, isLoading, dateRange, setDateRange }) => { gap={theme.spacing(4)} > {availableInterfaces.length > 0 && ( - setSelectedInterface(e.target.value)} + items={availableInterfaces.map((interfaceName) => ({ + _id: interfaceName, + name: interfaceName, + }))} sx={{ minWidth: 200 }} - > - {t("networkInterface")} - - + /> )} { + const getValueById = (config, id) => { + const item = config.find((config) => config._id === id); + return item ? (item.value ? item.value : item.name) : null; + }; + + const getIdByValue = (config, name) => { + const item = config.find((config) => { + if (config.value) { + return config.value === name; + } else { + return config.name === name; + } + }); + return item ? item._id : null; + }; + + return ( + { - handleFormChange( - "repeat", - getValueById(repeatConfig, event.target.value) - ); - }} - items={repeatConfig} + valueSelect={form.repeat} + configSelection={repeatConfig} + onChange={(value) => handleFormChange("repeat", value)} /> @@ -437,7 +280,7 @@ const CreateMaintenance = () => { }} sx={{}} onChange={(newDate) => { - handleTimeChange("startDate", newDate); + handleFormChange("startDate", newDate); }} error={errors["startDate"]} /> @@ -453,7 +296,7 @@ const CreateMaintenance = () => { > {t("startTime")} - {t("timeZoneInfo")} + {t("timeZoneInfo")} @@ -462,7 +305,7 @@ const CreateMaintenance = () => { label={t("startTime")} value={form.startTime} onChange={(newTime) => { - handleTimeChange("startTime", newTime); + handleFormChange("startTime", newTime); }} slotProps={{ nextIconButton: { sx: { ml: theme.spacing(2) } }, @@ -508,16 +351,11 @@ const CreateMaintenance = () => { error={errors["duration"] ? true : false} helperText={errors["duration"]} /> -