From 238db5bc8f49185af50c3fa3dacfd5a25185bc95 Mon Sep 17 00:00:00 2001 From: Alexander Holliday Date: Tue, 22 Oct 2024 18:21:10 +0800 Subject: [PATCH] Revert "FE - Advanced Settings Page Validation and Error Handling" --- Client/src/Pages/AdvancedSettings/index.jsx | 455 +++++++++--------- .../Maintenance/CreateMaintenance/index.jsx | 105 ++-- Client/src/Validation/error.js | 25 - Client/src/Validation/validation.js | 33 -- 4 files changed, 279 insertions(+), 339 deletions(-) delete mode 100644 Client/src/Validation/error.js diff --git a/Client/src/Pages/AdvancedSettings/index.jsx b/Client/src/Pages/AdvancedSettings/index.jsx index 12016889f..ce1c89250 100644 --- a/Client/src/Pages/AdvancedSettings/index.jsx +++ b/Client/src/Pages/AdvancedSettings/index.jsx @@ -12,47 +12,45 @@ import { useNavigate } from "react-router"; import { getAppSettings, updateAppSettings } from "../../Features/Settings/settingsSlice"; import { useState, useEffect } from "react"; import Select from "../../Components/Inputs/Select"; -import { advancedSettingsValidation } from "../../Validation/validation"; -import { buildErrors, hasValidationErrors } from "../../Validation/error"; const AdvancedSettings = ({ isAdmin }) => { - const navigate = useNavigate(); - useEffect(() => { - if (!isAdmin) { - navigate("/"); - } - }, [navigate, isAdmin]); + const navigate = useNavigate(); - const theme = useTheme(); - const { authToken } = useSelector((state) => state.auth); - const dispatch = useDispatch(); - const settings = useSelector((state) => state.settings); - const [localSettings, setLocalSettings] = useState({ - apiBaseUrl: "", - logLevel: "debug", - systemEmailHost: "", - systemEmailPort: "", - systemEmailAddress: "", - systemEmailPassword: "", - jwtTTL: "", - dbType: "", - redisHost: "", - redisPort: "", - pagespeedApiKey: "", - }); - const [errors, setErrors] = useState({}); + useEffect(() => { + if (!isAdmin) { + navigate("/"); + } + }, [navigate, isAdmin]); - useEffect(() => { - const getSettings = async () => { - const action = await dispatch(getAppSettings({ authToken })); - if (action.payload?.success) { - setLocalSettings(action.payload.data); - } else { - createToast({ body: "Failed to get settings" }); - } - }; - getSettings(); - }, [authToken, dispatch]); + const theme = useTheme(); + const { authToken } = useSelector((state) => state.auth); + const dispatch = useDispatch(); + const settings = useSelector((state) => state.settings); + const [localSettings, setLocalSettings] = useState({ + apiBaseUrl: "", + logLevel: "debug", + systemEmailHost: "", + systemEmailPort: "", + systemEmailAddress: "", + systemEmailPassword: "", + jwtTTL: "", + dbType: "", + redisHost: "", + redisPort: "", + pagespeedApiKey: "", + }); + + useEffect(() => { + const getSettings = async () => { + const action = await dispatch(getAppSettings({ authToken })); + if (action.payload.success) { + setLocalSettings(action.payload.data); + } else { + createToast({ body: "Failed to get settings" }); + } + }; + getSettings(); + }, [authToken, dispatch]); const logItems = [ { _id: 1, name: "none" }, @@ -74,210 +72,189 @@ const AdvancedSettings = ({ isAdmin }) => { setLocalSettings({ ...localSettings, logLevel: newLogLevel }); }; - const handleChange = (event) => { - const { value, id } = event.target; - setLocalSettings({ ...localSettings, [id]: value }); - const { error } = advancedSettingsValidation.validate( - { [id]: value }, - { - abortEarly: false, - } - ); - setErrors((prev) => { - return buildErrors(prev, id, error); - }); - }; + const handleChange = (event) => { + const { value, id } = event.target; + setLocalSettings({ ...localSettings, [id]: value }); + }; - const handleSave = async () => { - if (hasValidationErrors(localSettings, advancedSettingsValidation, setErrors)) - return; - const action = await dispatch( - updateAppSettings({ settings: localSettings, authToken }) - ); - let body = ""; - if (action.payload.success) { - console.log(action.payload.data); - setLocalSettings(action.payload.data); - body = "Settings saved successfully"; - } else { - body = "Failed to save settings"; - } - createToast({ body }); - }; + const handleSave = async () => { + const action = await dispatch( + updateAppSettings({ settings: localSettings, authToken }) + ); + let body = ""; + if (action.payload.success) { + console.log(action.payload.data); + setLocalSettings(action.payload.data); + body = "Settings saved successfully"; + } else { + body = "Failed to save settings"; + } + createToast({ body }); + }; - return ( - - - - - Client settings - - Modify client settings here. - - - - - + + + + + Email settings + + Set your host email settings here. These settings are used for sending + system emails. + + + + + + + + + + + + Server settings + + Modify server settings here. + + + + + + + + + + + + + About + + + BlueWave Uptime v1.0.0 + + Developed by Bluewave Labs. + + + + + + + Save + + + + + ); }; AdvancedSettings.propTypes = { diff --git a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx index d165523f9..4dbf8f747 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx @@ -28,7 +28,6 @@ import { MS_PER_WEEK, } from "../../../Utils/timeUtils"; import { useNavigate, useParams } from "react-router-dom"; -import { buildErrors, hasValidationErrors } from "../../../Validation/error"; const getDurationAndUnit = (durationInMs) => { if (durationInMs % MS_PER_DAY === 0) { @@ -146,36 +145,46 @@ const CreateMaintenance = () => { return; } - const res = await networkService.getMaintenanceWindowById({ - authToken: authToken, - maintenanceWindowId: maintenanceWindowId, - }); - const maintenanceWindow = res.data.data; - const { name, start, end, repeat, monitorId } = maintenanceWindow; - const startTime = dayjs(start); - const endTime = dayjs(end); - const durationInMs = endTime.diff(startTime, "milliseconds").toString(); - const { duration, durationUnit } = getDurationAndUnit(durationInMs); - const monitor = monitors.find((monitor) => monitor._id === monitorId); - setForm({ - ...form, - name, - repeat: REVERSE_REPEAT_LOOKUP[repeat], - startDate: startTime, - startTime, - duration, - durationUnit, - monitors: monitor ? [monitor] : [], - }); - } catch (error) { - createToast({ body: "Failed to fetch data" }); - logger.error("Failed to fetch monitors", error); - } finally { - setIsLoading(false); - } - }; - fetchMonitors(); - }, [authToken, user]); + const res = await networkService.getMaintenanceWindowById({ + authToken: authToken, + maintenanceWindowId: maintenanceWindowId, + }); + const maintenanceWindow = res.data.data; + const { name, start, end, repeat, monitorId } = maintenanceWindow; + const startTime = dayjs(start); + const endTime = dayjs(end); + const durationInMs = endTime.diff(startTime, "milliseconds").toString(); + const { duration, durationUnit } = getDurationAndUnit(durationInMs); + const monitor = monitors.find((monitor) => monitor._id === monitorId); + setForm({ + ...form, + name, + repeat: REVERSE_REPEAT_LOOKUP[repeat], + startDate: startTime, + startTime, + duration, + durationUnit, + monitors: monitor ? [monitor] : [], + }); + } catch (error) { + createToast({ body: "Failed to fetch data" }); + logger.error("Failed to fetch monitors", error); + } finally { + setIsLoading(false); + } + }; + fetchMonitors(); + }, [authToken, user]); + + const buildErrors = (prev, id, error) => { + const updatedErrors = { ...prev }; + if (error) { + updatedErrors[id] = error.details[0].message; + } else { + delete updatedErrors[id]; + } + return updatedErrors; + }; const handleSearch = (value) => { setSearch(value); @@ -214,17 +223,29 @@ const CreateMaintenance = () => { }); }; - const handleSubmit = async () => { - if(hasValidationErrors(form, maintenanceWindowValidation, setErrors)) - return; - // Build timestamp for maintenance window from startDate and startTime - const start = dayjs(form.startDate) - .set("hour", form.startTime.hour()) - .set("minute", form.startTime.minute()); - // Build end timestamp for maintenance window - const MS_MULTIPLIER = MS_LOOKUP[form.durationUnit]; - const durationInMs = form.duration * MS_MULTIPLIER; - const end = start.add(durationInMs); + const handleSubmit = async () => { + const { error } = maintenanceWindowValidation.validate(form, { + abortEarly: false, + }); + + // If errors, return early + if (error) { + const newErrors = {}; + error.details.forEach((err) => { + newErrors[err.path[0]] = err.message; + }); + setErrors(newErrors); + logger.error(error); + return; + } + // Build timestamp for maintenance window from startDate and startTime + const start = dayjs(form.startDate) + .set("hour", form.startTime.hour()) + .set("minute", form.startTime.minute()); + // Build end timestamp for maintenance window + const MS_MULTIPLIER = MS_LOOKUP[form.durationUnit]; + const durationInMs = form.duration * MS_MULTIPLIER; + const end = start.add(durationInMs); // Get repeat value in milliseconds const repeat = REPEAT_LOOKUP[form.repeat]; diff --git a/Client/src/Validation/error.js b/Client/src/Validation/error.js deleted file mode 100644 index e205ce7d1..000000000 --- a/Client/src/Validation/error.js +++ /dev/null @@ -1,25 +0,0 @@ -const buildErrors = (prev, id, error) => { - const updatedErrors = { ...prev }; - if (error) { - updatedErrors[id] = error.details[0].message?? "Validation error"; - } else { - delete updatedErrors[id]; - } - return updatedErrors; -}; - -const hasValidationErrors = (form, validation, setErrors) => { - const { error } = validation.validate(form, { - abortEarly: false, - }); - if (error) { - const newErrors = {}; - error.details.forEach((err) => { - newErrors[err.path[0]] = err.message?? "Validation error"; - }); - setErrors(newErrors); - return true; - } - return false; -}; -export { buildErrors, hasValidationErrors }; diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index a6ec7688c..c620bdf43 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -128,43 +128,10 @@ const maintenanceWindowValidation = joi.object({ monitors: joi.array().min(1), }); -const advancedSettingsValidation = joi.object({ - apiBaseUrl: joi.string().uri({ allowRelative: true }).trim().messages({ - "string.empty": "API base url is required.", - "string.uri": "The URL you provided is not valid.", - }), - logLevel: joi.string().valid("debug", "none", "error", "warn").allow(""), - systemEmailHost: joi.string().allow(''), - systemEmailPort: joi.string().allow(''), - systemEmailAddress: joi - .string().allow(''), - systemEmailPassword: joi.string().allow(''), - jwtTTL: joi - .string() - .trim() - .messages({ - "string.empty": "JWT TTL is required." - }), - dbType: joi.string().trim().messages({ - "string.empty": "DB type is required", - }), - redisHost: joi.string().trim().messages({ - "string.empty": "Redis host is required", - }), - redisPort: joi.string().allow('').custom((value, helpers) => { - if(value && isNaN(parseInt(value))){ - return helpers.message("Redit port must be a number") - } - return value - }), - pagespeedApiKey: joi.string().allow('') -}); - export { credentials, imageValidation, monitorValidation, settingsValidation, maintenanceWindowValidation, - advancedSettingsValidation, };