From cb7f596b0db4b5b8fc7632450072cbd7ca551b9e Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Tue, 10 Dec 2024 11:21:59 -0500 Subject: [PATCH 01/40] - Remove the login landing page - Remove the back button as it is not needed anymore - Adjust layout due to the removal of backbutton and remove the propTypes requirement for onBack function --- Client/src/Pages/Auth/Login.jsx | 121 +------------------------------- 1 file changed, 3 insertions(+), 118 deletions(-) diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index 6329835ef..c75f38951 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -19,99 +19,6 @@ import { logger } from "../../Utils/Logger"; import "./index.css"; const DEMO = import.meta.env.VITE_APP_DEMO; -/** - * Displays the initial landing page. - * - * @param {Object} props - * @param {Function} props.onContinue - Callback function to handle "Continue with Email" button click. - * @returns {JSX.Element} - */ -const LandingPage = ({ onContinue }) => { - const theme = useTheme(); - - return ( - <> - - - Log In - We are pleased to see you again! - - - - - - - By continuing, you agree to our{" "} - { - window.open( - "https://bluewavelabs.ca/terms-of-service-open-source", - "_blank", - "noreferrer" - ); - }} - sx={{ - "&:hover": { - color: theme.palette.text.tertiary, - }, - }} - > - Terms of Service - {" "} - and{" "} - { - window.open( - "https://bluewavelabs.ca/privacy-policy-open-source", - "_blank", - "noreferrer" - ); - }} - sx={{ - "&:hover": { - color: theme.palette.text.tertiary, - }, - }} - > - Privacy Policy. - - - - - - ); -}; - -LandingPage.propTypes = { - onContinue: PropTypes.func.isRequired, -}; - /** * Renders the first step of the login process. * @@ -168,26 +75,8 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => { /> - - - - - - ); -}; - -StepOne.propTypes = { - form: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - onSubmit: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, -}; - -/** - * Renders the second step of the login process, including a password input field. - * - * @param {Object} props - * @param {Object} props.form - Form state object. - * @param {Object} props.errors - Object containing form validation errors. - * @param {Function} props.onSubmit - Callback function to handle form submission. - * @param {Function} props.onChange - Callback function to handle form input changes. - * @param {Function} props.onBack - Callback function to handle "Back" button click. - * @returns {JSX.Element} - */ -const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { - const theme = useTheme(); - const navigate = useNavigate(); - const inputRef = useRef(null); - const authState = useSelector((state) => state.auth); - - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - }, []); - - const handleNavigate = () => { - if (form.email !== "" && !errors.email) { - sessionStorage.setItem("email", form.email); - } - navigate("/forgot-password"); - }; - - return ( - <> - - - Log In - Enter your password - - - } - /> - - - - Continue - - - - - - Forgot password? - - - Reset password - - - - - ); -}; - -StepTwo.propTypes = { - form: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - onSubmit: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onBack: PropTypes.func.isRequired, -}; - -const Login = () => { - const dispatch = useDispatch(); - const navigate = useNavigate(); - const theme = useTheme(); - - const authState = useSelector((state) => state.auth); - const { authToken } = authState; - - const idMap = { - "login-email-input": "email", - "login-password-input": "password", - }; - - const [form, setForm] = useState({ - email: DEMO !== undefined ? "uptimedemo@demo.com" : "", - password: DEMO !== undefined ? "Demouser1!" : "", - }); - const [errors, setErrors] = useState({}); - const [step, setStep] = useState(0); - - useEffect(() => { - if (authToken) { - navigate("/monitors"); - return; - } - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - }, [authToken, navigate]); - - const handleChange = (event) => { - const { value, id } = event.target; - const name = idMap[id]; - setForm((prev) => ({ - ...prev, - [name]: value, - })); - - const { error } = credentials.validate({ [name]: value }, { abortEarly: false }); - - setErrors((prev) => { - const prevErrors = { ...prev }; - if (error) prevErrors[name] = error.details[0].message; - else delete prevErrors[name]; - return prevErrors; - }); - }; - - const handleSubmit = async (event) => { - event.preventDefault(); - - if (step === 0) { - const { error } = credentials.validate( - { email: form.email }, - { abortEarly: false } - ); - if (error) { - setErrors((prev) => ({ ...prev, email: error.details[0].message })); - createToast({ body: error.details[0].message }); - } else { - setStep(1); - } - } else if (step === 1) { - const { error } = credentials.validate(form, { abortEarly: false }); - - if (error) { - // validation errors - const newErrors = {}; - error.details.forEach((err) => { - newErrors[err.path[0]] = err.message; - }); - setErrors(newErrors); - createToast({ - body: - error.details && error.details.length > 0 - ? error.details[0].message - : "Error validating data.", - }); - } else { - const action = await dispatch(login(form)); - if (action.payload.success) { - navigate("/monitors"); - createToast({ - body: "Welcome back! You're successfully logged in.", - }); - } else { - if (action.payload) { - if (action.payload.msg === "Incorrect password") - setErrors({ - password: "The password you provided does not match our records", - }); - // dispatch errors - createToast({ - body: action.payload.msg, - }); - } else { - // unknown errors - createToast({ - body: "Unknown error.", - }); - } - } - } - } - }; - - return ( - - - - - - - BlueWave Uptime - - .MuiStack-root": { - border: 1, - borderRadius: theme.spacing(5), - borderColor: theme.palette.border.light, - backgroundColor: theme.palette.background.main, - padding: { - xs: theme.spacing(12), - sm: theme.spacing(20), - }, - }, - }} - > - {step === 0 ? ( - - ) : ( - step === 1 && ( - setStep(0)} - /> - ) - )} - - - ); -}; - -export default Login; diff --git a/Client/src/Pages/Auth/Login/Components/EmailStep.jsx b/Client/src/Pages/Auth/Login/Components/EmailStep.jsx new file mode 100644 index 000000000..f78193186 --- /dev/null +++ b/Client/src/Pages/Auth/Login/Components/EmailStep.jsx @@ -0,0 +1,95 @@ +import { useRef, useEffect } from "react"; +import { Box, Button, Stack, Typography } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import TextInput from "../../../../Components/Inputs/TextInput"; +import PropTypes from "prop-types"; + +/** + * Renders the email step of the login process which includes an email field. + * + * @param {Object} props + * @param {Object} props.form - Form state object. + * @param {Object} props.errors - Object containing form validation errors. + * @param {Function} props.onSubmit - Callback function to handle form submission. + * @param {Function} props.onChange - Callback function to handle form input changes. + * @param {Function} props.onBack - Callback function to handle "Back" button click. + * @returns {JSX.Element} + */ +const EmailStep = ({ form, errors, onSubmit, onChange }) => { + const theme = useTheme(); + const inputRef = useRef(null); + + useEffect(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, []); + + return ( + <> + + + Log In + Enter your email address + + + (e.target.value = e.target.value.toLowerCase())} + onChange={onChange} + error={errors.email ? true : false} + helperText={errors.email} + ref={inputRef} + /> + + + + + + + ); +}; + +EmailStep.propTypes = { + form: PropTypes.object.isRequired, + errors: PropTypes.object.isRequired, + onSubmit: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, +}; + +export default EmailStep; \ No newline at end of file diff --git a/Client/src/Pages/Auth/Login/Components/PasswordStep.jsx b/Client/src/Pages/Auth/Login/Components/PasswordStep.jsx new file mode 100644 index 000000000..34df4959d --- /dev/null +++ b/Client/src/Pages/Auth/Login/Components/PasswordStep.jsx @@ -0,0 +1,159 @@ +import { useRef, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { Box, Button, Stack, Typography } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import LoadingButton from "@mui/lab/LoadingButton"; +import { useSelector } from "react-redux"; +import TextInput from "../../../../Components/Inputs/TextInput"; +import { PasswordEndAdornment } from "../../../../Components/Inputs/TextInput/Adornments"; +import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; +import PropTypes from "prop-types"; + +/** + * Renders the password step of the login process, including a password input field. + * + * @param {Object} props + * @param {Object} props.form - Form state object. + * @param {Object} props.errors - Object containing form validation errors. + * @param {Function} props.onSubmit - Callback function to handle form submission. + * @param {Function} props.onChange - Callback function to handle form input changes. + * @param {Function} props.onBack - Callback function to handle "Back" button click. + * @returns {JSX.Element} + */ +const PasswordStep = ({ form, errors, onSubmit, onChange, onBack }) => { + const theme = useTheme(); + const navigate = useNavigate(); + const inputRef = useRef(null); + const authState = useSelector((state) => state.auth); + + useEffect(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, []); + + const handleNavigate = () => { + if (form.email !== "" && !errors.email) { + sessionStorage.setItem("email", form.email); + } + navigate("/forgot-password"); + }; + + return ( + <> + + + Log In + Enter your password + + + } + /> + + + + Continue + + + + + + Forgot password? + + + Reset password + + + + + ); +}; + +PasswordStep.propTypes = { + form: PropTypes.object.isRequired, + errors: PropTypes.object.isRequired, + onSubmit: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + onBack: PropTypes.func.isRequired, +}; + +export default PasswordStep \ No newline at end of file diff --git a/Client/src/Pages/Auth/Login/Login.jsx b/Client/src/Pages/Auth/Login/Login.jsx new file mode 100644 index 000000000..1b3a420ea --- /dev/null +++ b/Client/src/Pages/Auth/Login/Login.jsx @@ -0,0 +1,213 @@ +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { Box, Stack, Typography } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import { credentials } from "../../../Validation/validation"; +import { login } from "../../../Features/Auth/authSlice"; +import { useDispatch, useSelector } from "react-redux"; +import { createToast } from "../../../Utils/toastUtils"; +import { networkService } from "../../../main"; +import Background from "../../../assets/Images/background-grid.svg?react"; +import Logo from "../../../assets/icons/bwu-icon.svg?react"; +import { logger } from "../../../Utils/Logger"; +import "../index.css"; +import EmailStep from "./Components/EmailStep"; +import PasswordStep from "./Components/PasswordStep"; + +const DEMO = import.meta.env.VITE_APP_DEMO; + +/** + * Displays the login page. + */ + +const Login = () => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const theme = useTheme(); + + const authState = useSelector((state) => state.auth); + const { authToken } = authState; + + const idMap = { + "login-email-input": "email", + "login-password-input": "password", + }; + + const [form, setForm] = useState({ + email: DEMO !== undefined ? "uptimedemo@demo.com" : "", + password: DEMO !== undefined ? "Demouser1!" : "", + }); + const [errors, setErrors] = useState({}); + const [step, setStep] = useState(0); + + useEffect(() => { + if (authToken) { + navigate("/monitors"); + return; + } + networkService + .doesSuperAdminExist() + .then((response) => { + if (response.data.data === false) { + navigate("/register"); + } + }) + .catch((error) => { + logger.error(error); + }); + }, [authToken, navigate]); + + const handleChange = (event) => { + const { value, id } = event.target; + const name = idMap[id]; + setForm((prev) => ({ + ...prev, + [name]: value, + })); + + const { error } = credentials.validate({ [name]: value }, { abortEarly: false }); + + setErrors((prev) => { + const prevErrors = { ...prev }; + if (error) prevErrors[name] = error.details[0].message; + else delete prevErrors[name]; + return prevErrors; + }); + }; + + const handleSubmit = async (event) => { + event.preventDefault(); + + if (step === 0) { + const { error } = credentials.validate( + { email: form.email }, + { abortEarly: false } + ); + if (error) { + setErrors((prev) => ({ ...prev, email: error.details[0].message })); + createToast({ body: error.details[0].message }); + } else { + setStep(1); + } + } else if (step === 1) { + const { error } = credentials.validate(form, { abortEarly: false }); + + if (error) { + // validation errors + const newErrors = {}; + error.details.forEach((err) => { + newErrors[err.path[0]] = err.message; + }); + setErrors(newErrors); + createToast({ + body: + error.details && error.details.length > 0 + ? error.details[0].message + : "Error validating data.", + }); + } else { + const action = await dispatch(login(form)); + if (action.payload.success) { + navigate("/monitors"); + createToast({ + body: "Welcome back! You're successfully logged in.", + }); + } else { + if (action.payload) { + if (action.payload.msg === "Incorrect password") + setErrors({ + password: "The password you provided does not match our records", + }); + // dispatch errors + createToast({ + body: action.payload.msg, + }); + } else { + // unknown errors + createToast({ + body: "Unknown error.", + }); + } + } + } + } + }; + + return ( + + + + + + + BlueWave Uptime + + .MuiStack-root": { + border: 1, + borderRadius: theme.spacing(5), + borderColor: theme.palette.border.light, + backgroundColor: theme.palette.background.main, + padding: { + xs: theme.spacing(12), + sm: theme.spacing(20), + }, + }, + }} + > + {step === 0 ? ( + + ) : ( + step === 1 && ( + setStep(0)} + /> + ) + )} + + + ); +}; + +export default Login; From e30b64bed3f73f579e8eaf2353008c11b23dd599 Mon Sep 17 00:00:00 2001 From: Shalini M Date: Mon, 16 Dec 2024 17:08:27 +0530 Subject: [PATCH 08/40] Changed the avatar color to checkmate blue color --- Client/src/Components/Avatar/index.jsx | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Client/src/Components/Avatar/index.jsx b/Client/src/Components/Avatar/index.jsx index 3760c04b8..18bb6be47 100644 --- a/Client/src/Components/Avatar/index.jsx +++ b/Client/src/Components/Avatar/index.jsx @@ -9,19 +9,8 @@ import { useEffect, useState } from "react"; * @returns {string} */ const stringToColor = (string) => { - let hash = 0; - let i; - for (i = 0; i < string.length; i += 1) { - hash = string.charCodeAt(i) + ((hash << 5) - hash); - } - let color = "#"; - for (i = 0; i < 3; i += 1) { - const value = (hash >> (i * 8)) & 0xff; - color += `00${value.toString(16)}`.slice(-2); - } - - return color; + return "#156EEF"; }; /** From 69ef798f603154597d70b0a11d6827edf192e260 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 16 Dec 2024 16:57:03 +0000 Subject: [PATCH 09/40] chore(deps): update dependency @types/react to v18.3.17 --- Client/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index dfc221fc4..603e30ae0 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -2372,9 +2372,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.16", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz", - "integrity": "sha512-oh8AMIC4Y2ciKufU8hnKgs+ufgbA/dhPTACaZPM86AbwX9QwnFtSoPWEeRUj8fge+v6kFt78BXcDhAU1SrrAsw==", + "version": "18.3.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.17.tgz", + "integrity": "sha512-opAQ5no6LqJNo9TqnxBKsgnkIYHozW9KSTlFVoSUJYh1Fl/sswkEoqIugRSm7tbh6pABtYjGAjW+GOS23j8qbw==", "license": "MIT", "dependencies": { "@types/prop-types": "*", From dd5527931de30b6b9326f825c08baa3d079db2dd Mon Sep 17 00:00:00 2001 From: Anand Roy Date: Mon, 16 Dec 2024 18:59:29 +0000 Subject: [PATCH 10/40] modified radio button visibility --- Client/src/Components/Inputs/Radio/index.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Client/src/Components/Inputs/Radio/index.jsx b/Client/src/Components/Inputs/Radio/index.jsx index 7a700e2b7..6291485f0 100644 --- a/Client/src/Components/Inputs/Radio/index.jsx +++ b/Client/src/Components/Inputs/Radio/index.jsx @@ -42,6 +42,9 @@ const Radio = (props) => { width: 16, height: 16, boxShadow: `inset 0 0 0 1px ${theme.palette.secondary.main}`, + "&:not(.Mui-checked)": { + boxShadow: `inset 0 0 0 1px ${theme.palette.text.primary}70`, // Use theme text color for the outline + }, mt: theme.spacing(0.5), }} /> From 0022d839dfefcd58b43d8f995f89f2dd3d891b19 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 16 Dec 2024 23:54:02 +0000 Subject: [PATCH 11/40] fix(deps): update dependency mongoose to v8.9.1 --- Server/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Server/package-lock.json b/Server/package-lock.json index cb4ee1836..3f57f737a 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -4489,9 +4489,9 @@ } }, "node_modules/mongoose": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.0.tgz", - "integrity": "sha512-b58zY3PLNBcoz6ZXFckr0leJcVVBMAOBvD+7Bj2ZjghAwntXmNnqwlDixTKQU3UYoQIGTv+AQx/0ThsvaeVrCA==", + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.1.tgz", + "integrity": "sha512-whM6lWMdeKlUm4d2LSLS/q6cWtTp13lUrL5hy2YTsQdTSN+dsAu8HLdLUQOEgtBE59qp4IqLrjSXCSETbxhkQQ==", "license": "MIT", "dependencies": { "bson": "^6.10.1", From 0aa46aa2c29d4fb323baebbaeb3032ee1b7e3639 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Dec 2024 17:55:45 -0800 Subject: [PATCH 12/40] fix empty view message --- Client/src/Pages/Infrastructure/Details/empty.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Client/src/Pages/Infrastructure/Details/empty.jsx b/Client/src/Pages/Infrastructure/Details/empty.jsx index 4a311233f..ad3ed2505 100644 --- a/Client/src/Pages/Infrastructure/Details/empty.jsx +++ b/Client/src/Pages/Infrastructure/Details/empty.jsx @@ -21,8 +21,7 @@ const Empty = ({ styles }) => { textAlign="center" color={theme.palette.text.secondary} > - Hang tight! When we receive data, we'll show it here. Please check back in a few - minutes. + Hang tight! Data is loading From d94ba5c5240b637277caa764a428e6e04b6cb1f1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Dec 2024 17:58:58 -0800 Subject: [PATCH 13/40] update dockeringore --- .dockerignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index e6b9c067d..fdfa00585 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,3 @@ Client/node_modules/ Server/node_modules/ -*.env \ No newline at end of file +Server/*.env \ No newline at end of file From df11a457f1f830f2c8c96a808b94440c401d884b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 16 Dec 2024 18:20:41 -0800 Subject: [PATCH 14/40] 401 -> 403 --- Server/controllers/authController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 1fba9c92f..fb48796df 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -284,7 +284,7 @@ const editUser = async (req, res, next) => { // If not a match, throw a 401 if (!match) { const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD); - error.status = 401; + error.status = 403; next(error); return; } From 2d27eed9ba7ebc57b12b5d026240bfc0d7fb448f Mon Sep 17 00:00:00 2001 From: Shalini Date: Tue, 17 Dec 2024 10:38:20 +0530 Subject: [PATCH 15/40] Used theme for the avatar BG instead of hard coding --- Client/src/Components/Avatar/index.jsx | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Client/src/Components/Avatar/index.jsx b/Client/src/Components/Avatar/index.jsx index 18bb6be47..39e8a3f42 100644 --- a/Client/src/Components/Avatar/index.jsx +++ b/Client/src/Components/Avatar/index.jsx @@ -2,17 +2,7 @@ import { Avatar as MuiAvatar } from "@mui/material"; import PropTypes from "prop-types"; import { useSelector } from "react-redux"; import { useEffect, useState } from "react"; - -/** - * Generates a color based on the input string. - * @param {string} string - The input string to generate the color from. - * @returns {string} - */ -const stringToColor = (string) => { - - return "#156EEF"; -}; - +import { useTheme } from "@emotion/react"; /** * @component * @param {Object} props @@ -27,6 +17,7 @@ const stringToColor = (string) => { const Avatar = ({ src, small, sx }) => { const { user } = useSelector((state) => state.auth); + const theme = useTheme(); const style = small ? { width: 32, height: 32 } : { width: 64, height: 64 }; const border = small ? 1 : 3; @@ -46,7 +37,7 @@ const Avatar = ({ src, small, sx }) => { fontSize: small ? "16px" : "22px", color: "white", fontWeight: 400, - backgroundColor: stringToColor(`${user?.firstName} ${user?.lastName}`), + backgroundColor: theme.palette.primary.main, // Same BG color as checkmate BG in sidebar display: "inline-flex", "&::before": { content: `""`, @@ -63,7 +54,7 @@ const Avatar = ({ src, small, sx }) => { }} > {user.firstName?.charAt(0)} - {user.lastName?.charAt(0)} + {user.lastName?.charAt(0) || ''} ); }; From a9ed2158e9a2f18783423b3a0821393b45923e3d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 15:28:45 +0000 Subject: [PATCH 16/40] fix(deps): update material-ui monorepo --- Client/package-lock.json | 116 +++++++++++++++++++-------------------- Client/package.json | 6 +- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index 603e30ae0..8090e52b1 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -11,9 +11,9 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", - "@mui/icons-material": "6.2.0", - "@mui/lab": "6.0.0-beta.19", - "@mui/material": "6.2.0", + "@mui/icons-material": "6.2.1", + "@mui/lab": "6.0.0-beta.20", + "@mui/material": "6.2.1", "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.23.2", "@mui/x-date-pickers": "7.23.2", @@ -1071,15 +1071,15 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.66", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.66.tgz", - "integrity": "sha512-1SzcNbtIms0o/Dx+599B6QbvR5qUMBUjwc2Gs47h1HsF7RcEFXxqaq7zrWkIWbvGctIIPx0j330oGx/SkF+UmA==", + "version": "5.0.0-beta.67", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.67.tgz", + "integrity": "sha512-pwjibXqBrSw1Z1fZEIhWJnMJHSvh3BLz0pZcrX/x01B/BVf6QUbFlGVV/k8KCsZ9sPzln1l8bBJ+ynIIE9LtjA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", "@floating-ui/react-dom": "^2.1.1", - "@mui/types": "^7.2.19", - "@mui/utils": "^6.2.0", + "@mui/types": "^7.2.20", + "@mui/utils": "^6.2.1", "@popperjs/core": "^2.11.8", "clsx": "^2.1.1", "prop-types": "^15.8.1" @@ -1103,9 +1103,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.2.0.tgz", - "integrity": "sha512-Nn5PSkUqbDrvezpiiiYZiAbX4SFEiy3CbikUL6pWOXEUsq+L1j50OOyyUIHpaX2Hr+5V5UxTh+fPeC4nsGNhdw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.2.1.tgz", + "integrity": "sha512-U/8vS1+1XiHBnnRRESSG1gvr6JDHdPjrpnW6KEebkAQWBn6wrpbSF/XSZ8/vJIRXH5NyDmMHi4Ro5Q70//JKhA==", "license": "MIT", "funding": { "type": "opencollective", @@ -1113,9 +1113,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.2.0.tgz", - "integrity": "sha512-WR1EEhGOSvxAsoTSzWZBlrWFjul8wziDrII4rC3PvMBHhBYBqEc2n/0aamfFbwkH5EiYb96aqc6kYY6tB310Sw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.2.1.tgz", + "integrity": "sha512-bP0XtW+t5KFL+wjfQp2UctN/8CuWqF1qaxbYuCAsJhL+AzproM8gGOh2n8sNBcrjbVckzDNqaXqxdpn+OmoWug==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0" @@ -1128,7 +1128,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.2.0", + "@mui/material": "^6.2.1", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -1139,16 +1139,16 @@ } }, "node_modules/@mui/lab": { - "version": "6.0.0-beta.19", - "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.19.tgz", - "integrity": "sha512-t7iub8kjpLdA5uDGwGnNRjtGc1vYEUnDwSROjKrnYqjOlCQhBajFa8uoQtaST6jE/VEk6cxpDMnN5MalC6YpCg==", + "version": "6.0.0-beta.20", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.20.tgz", + "integrity": "sha512-Sg3aTrSSsfXcSHwKhnZbXmz7kUZzvXww3vO4p8U/DbMVSGJxll1GRpKNQkFLpZy2y7ZBTgKaZTbPYw4Q6UKrsA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/base": "5.0.0-beta.66", - "@mui/system": "^6.2.0", - "@mui/types": "^7.2.19", - "@mui/utils": "^6.2.0", + "@mui/base": "5.0.0-beta.67", + "@mui/system": "^6.2.1", + "@mui/types": "^7.2.20", + "@mui/utils": "^6.2.1", "clsx": "^2.1.1", "prop-types": "^15.8.1" }, @@ -1162,8 +1162,8 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material": "^6.2.0", - "@mui/material-pigment-css": "^6.2.0", + "@mui/material": "^6.2.1", + "@mui/material-pigment-css": "^6.2.1", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1184,18 +1184,18 @@ } }, "node_modules/@mui/material": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.2.0.tgz", - "integrity": "sha512-7FXXUPIyYzP02a7GvqwJ7ocmdP+FkvLvmy/uxG1TDmTlsr8nEClQp75uxiVznJqAY/jJy4d+Rj/fNWNxwidrYQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.2.1.tgz", + "integrity": "sha512-7VlKGsRKsy1bOSOPaSNgpkzaL+0C7iWAVKd2KYyAvhR9fTLJtiAMpq+KuzgEh1so2mtvQERN0tZVIceWMiIesw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.2.0", - "@mui/system": "^6.2.0", - "@mui/types": "^7.2.19", - "@mui/utils": "^6.2.0", + "@mui/core-downloads-tracker": "^6.2.1", + "@mui/system": "^6.2.1", + "@mui/types": "^7.2.20", + "@mui/utils": "^6.2.1", "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.11", + "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", @@ -1212,7 +1212,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.2.0", + "@mui/material-pigment-css": "^6.2.1", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1239,13 +1239,13 @@ "license": "MIT" }, "node_modules/@mui/private-theming": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.2.0.tgz", - "integrity": "sha512-lYd2MrVddhentF1d/cMXKnwlDjr/shbO3A2eGq22PCYUoZaqtAGZMc0U86KnJ/Sh5YzNYePqTOaaowAN8Qea8A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.2.1.tgz", + "integrity": "sha512-u1y0gpcfrRRxCcIdVeU5eIvkinA82Q8ft178WUNYuoFQrsOrXdlBdZlRVi+eYuUFp1iXI55Cud7sMZZtETix5Q==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.2.0", + "@mui/utils": "^6.2.1", "prop-types": "^15.8.1" }, "engines": { @@ -1266,9 +1266,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.2.0.tgz", - "integrity": "sha512-rV4YCu6kcCjMnHFXU/tQcL6XfYVfFVR8n3ZVNGnk2rpXnt/ctOPJsF+eUQuhkHciueLVKpI06+umr1FxWWhVmQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.2.1.tgz", + "integrity": "sha512-6R3OgYw6zgCZWFYYMfxDqpGfJA78mUTOIlUDmmJlr60ogVNCrM87X0pqx5TbZ2OwUyxlJxN9qFgRr+J9H6cOBg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", @@ -1300,16 +1300,16 @@ } }, "node_modules/@mui/system": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.2.0.tgz", - "integrity": "sha512-DCeqev9Cd4f4pm3O1lqSGW/DIHHBG6ZpqMX9iIAvN4asYv+pPWv2/lKov9kWk5XThhxFnGSv93SRNE1kNRRg5Q==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.2.1.tgz", + "integrity": "sha512-0lc8CbBP4WAAF+SmGMFJI9bpIyQvW3zvwIDzLsb26FIB/4Z0pO7qGe8mkAl0RM63Vb37899qxnThhHKgAAdy6w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.2.0", - "@mui/styled-engine": "^6.2.0", - "@mui/types": "^7.2.19", - "@mui/utils": "^6.2.0", + "@mui/private-theming": "^6.2.1", + "@mui/styled-engine": "^6.2.1", + "@mui/types": "^7.2.20", + "@mui/utils": "^6.2.1", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1340,9 +1340,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.19", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", - "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", + "version": "7.2.20", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.20.tgz", + "integrity": "sha512-straFHD7L8v05l/N5vcWk+y7eL9JF0C2mtph/y4BPm3gn2Eh61dDwDB65pa8DLss3WJfDXYC7Kx5yjP0EmXpgw==", "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1354,13 +1354,13 @@ } }, "node_modules/@mui/utils": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.2.0.tgz", - "integrity": "sha512-77CaFJi+OIi2SjbPwCis8z5DXvE0dfx9hBz5FguZHt1VYFlWEPCWTHcMsQCahSErnfik5ebLsYK8+D+nsjGVfw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.2.1.tgz", + "integrity": "sha512-ubLqGIMhKUH2TF/Um+wRzYXgAooQw35th+DPemGrTpgrZHpOgcnUDIDbwsk1e8iQiuJ3mV/ErTtcQrecmlj5cg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/types": "^7.2.19", + "@mui/types": "^7.2.20", "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -2392,11 +2392,11 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", - "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", "license": "MIT", - "dependencies": { + "peerDependencies": { "@types/react": "*" } }, diff --git a/Client/package.json b/Client/package.json index b1a8409cf..882ecfd38 100644 --- a/Client/package.json +++ b/Client/package.json @@ -14,9 +14,9 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", - "@mui/icons-material": "6.2.0", - "@mui/lab": "6.0.0-beta.19", - "@mui/material": "6.2.0", + "@mui/icons-material": "6.2.1", + "@mui/lab": "6.0.0-beta.20", + "@mui/material": "6.2.1", "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.23.2", "@mui/x-date-pickers": "7.23.2", From a42e280e490d3ba78e1682db17bdc3b3148c6c2d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 10:02:56 -0800 Subject: [PATCH 17/40] update comments --- Server/controllers/authController.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index fb48796df..b7e4a7808 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -281,7 +281,8 @@ const editUser = async (req, res, next) => { const user = await req.db.getUserByEmail(email); // Compare passwords const match = await user.comparePassword(req.body.password); - // If not a match, throw a 401 + // If not a match, throw a 403 + // 403 instead of 401 to avoid triggering axios interceptor if (!match) { const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD); error.status = 403; From a507e1282e833c480a2b15ebbe0f70d949b1a279 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:10:28 -0800 Subject: [PATCH 18/40] Fix links in login page --- Client/src/Pages/Auth/Login/Login.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Client/src/Pages/Auth/Login/Login.jsx b/Client/src/Pages/Auth/Login/Login.jsx index 1b3a420ea..c1687a0ec 100644 --- a/Client/src/Pages/Auth/Login/Login.jsx +++ b/Client/src/Pages/Auth/Login/Login.jsx @@ -11,8 +11,8 @@ import Background from "../../../assets/Images/background-grid.svg?react"; import Logo from "../../../assets/icons/bwu-icon.svg?react"; import { logger } from "../../../Utils/Logger"; import "../index.css"; -import EmailStep from "./Components/EmailStep"; -import PasswordStep from "./Components/PasswordStep"; +import EmailStep from "./Components/EmailStep"; +import PasswordStep from "./Components/PasswordStep"; const DEMO = import.meta.env.VITE_APP_DEMO; @@ -42,7 +42,7 @@ const Login = () => { useEffect(() => { if (authToken) { - navigate("/monitors"); + navigate("/uptime"); return; } networkService @@ -108,7 +108,7 @@ const Login = () => { } else { const action = await dispatch(login(form)); if (action.payload.success) { - navigate("/monitors"); + navigate("/uptime"); createToast({ body: "Welcome back! You're successfully logged in.", }); From 1f823fc672cadc2d8cac5b05981204b29477670f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:10:40 -0800 Subject: [PATCH 19/40] remove old login page --- Client/src/Pages/Auth/Login.jsx | 562 -------------------------------- 1 file changed, 562 deletions(-) delete mode 100644 Client/src/Pages/Auth/Login.jsx diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx deleted file mode 100644 index a7554a7c1..000000000 --- a/Client/src/Pages/Auth/Login.jsx +++ /dev/null @@ -1,562 +0,0 @@ -import { useState, useEffect, useRef } from "react"; -import { useNavigate } from "react-router-dom"; -import { Box, Button, Stack, Typography } from "@mui/material"; -import { useTheme } from "@emotion/react"; -import { credentials } from "../../Validation/validation"; -import { login } from "../../Features/Auth/authSlice"; -import LoadingButton from "@mui/lab/LoadingButton"; -import { useDispatch, useSelector } from "react-redux"; -import { createToast } from "../../Utils/toastUtils"; -import { networkService } from "../../main"; -import TextInput from "../../Components/Inputs/TextInput"; -import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments"; -import Background from "../../assets/Images/background-grid.svg?react"; -import Logo from "../../assets/icons/bwu-icon.svg?react"; -import Mail from "../../assets/icons/mail.svg?react"; -import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; -import PropTypes from "prop-types"; -import { logger } from "../../Utils/Logger"; -import "./index.css"; -const DEMO = import.meta.env.VITE_APP_DEMO; - -/** - * Displays the initial landing page. - * - * @param {Object} props - * @param {Function} props.onContinue - Callback function to handle "Continue with Email" button click. - * @returns {JSX.Element} - */ -const LandingPage = ({ onContinue }) => { - const theme = useTheme(); - - return ( - <> - - - Log In - We are pleased to see you again! - - - - - - - By continuing, you agree to our{" "} - { - window.open( - "https://bluewavelabs.ca/terms-of-service-open-source", - "_blank", - "noreferrer" - ); - }} - sx={{ - "&:hover": { - color: theme.palette.text.tertiary, - }, - }} - > - Terms of Service - {" "} - and{" "} - { - window.open( - "https://bluewavelabs.ca/privacy-policy-open-source", - "_blank", - "noreferrer" - ); - }} - sx={{ - "&:hover": { - color: theme.palette.text.tertiary, - }, - }} - > - Privacy Policy. - - - - - - ); -}; - -LandingPage.propTypes = { - onContinue: PropTypes.func.isRequired, -}; - -/** - * Renders the first step of the login process. - * - * @param {Object} props - * @param {Object} props.form - Form state object. - * @param {Object} props.errors - Object containing form validation errors. - * @param {Function} props.onSubmit - Callback function to handle form submission. - * @param {Function} props.onChange - Callback function to handle form input changes. - * @param {Function} props.onBack - Callback function to handle "Back" button click. - * @returns {JSX.Element} - */ -const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => { - const theme = useTheme(); - const inputRef = useRef(null); - - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - }, []); - - return ( - <> - - - Log In - Enter your email address - - - (e.target.value = e.target.value.toLowerCase())} - onChange={onChange} - error={errors.email ? true : false} - helperText={errors.email} - ref={inputRef} - /> - - - - - - - - ); -}; - -StepOne.propTypes = { - form: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - onSubmit: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onBack: PropTypes.func.isRequired, -}; - -/** - * Renders the second step of the login process, including a password input field. - * - * @param {Object} props - * @param {Object} props.form - Form state object. - * @param {Object} props.errors - Object containing form validation errors. - * @param {Function} props.onSubmit - Callback function to handle form submission. - * @param {Function} props.onChange - Callback function to handle form input changes. - * @param {Function} props.onBack - Callback function to handle "Back" button click. - * @returns {JSX.Element} - */ -const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { - const theme = useTheme(); - const navigate = useNavigate(); - const inputRef = useRef(null); - const authState = useSelector((state) => state.auth); - - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - }, []); - - const handleNavigate = () => { - if (form.email !== "" && !errors.email) { - sessionStorage.setItem("email", form.email); - } - navigate("/forgot-password"); - }; - - return ( - <> - - - Log In - Enter your password - - - } - /> - - - - Continue - - - - - - Forgot password? - - - Reset password - - - - - ); -}; - -StepTwo.propTypes = { - form: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - onSubmit: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onBack: PropTypes.func.isRequired, -}; - -const Login = () => { - const dispatch = useDispatch(); - const navigate = useNavigate(); - const theme = useTheme(); - - const authState = useSelector((state) => state.auth); - const { authToken } = authState; - - const idMap = { - "login-email-input": "email", - "login-password-input": "password", - }; - - const [form, setForm] = useState({ - email: DEMO !== undefined ? "uptimedemo@demo.com" : "", - password: DEMO !== undefined ? "Demouser1!" : "", - }); - const [errors, setErrors] = useState({}); - const [step, setStep] = useState(0); - - useEffect(() => { - if (authToken) { - navigate("/uptime"); - return; - } - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - }, [authToken, navigate]); - - const handleChange = (event) => { - const { value, id } = event.target; - const name = idMap[id]; - setForm((prev) => ({ - ...prev, - [name]: value, - })); - - const { error } = credentials.validate({ [name]: value }, { abortEarly: false }); - - setErrors((prev) => { - const prevErrors = { ...prev }; - if (error) prevErrors[name] = error.details[0].message; - else delete prevErrors[name]; - return prevErrors; - }); - }; - - const handleSubmit = async (event) => { - event.preventDefault(); - - if (step === 1) { - const { error } = credentials.validate( - { email: form.email }, - { abortEarly: false } - ); - if (error) { - setErrors((prev) => ({ ...prev, email: error.details[0].message })); - createToast({ body: error.details[0].message }); - } else { - setStep(2); - } - } else if (step === 2) { - const { error } = credentials.validate(form, { abortEarly: false }); - - if (error) { - // validation errors - const newErrors = {}; - error.details.forEach((err) => { - newErrors[err.path[0]] = err.message; - }); - setErrors(newErrors); - createToast({ - body: - error.details && error.details.length > 0 - ? error.details[0].message - : "Error validating data.", - }); - } else { - const action = await dispatch(login(form)); - if (action.payload.success) { - navigate("/uptime"); - createToast({ - body: "Welcome back! You're successfully logged in.", - }); - } else { - if (action.payload) { - if (action.payload.msg === "Incorrect password") - setErrors({ - password: "The password you provided does not match our records", - }); - // dispatch errors - createToast({ - body: action.payload.msg, - }); - } else { - // unknown errors - createToast({ - body: "Unknown error.", - }); - } - } - } - } - }; - - return ( - - - - - - - BlueWave Uptime - - .MuiStack-root": { - border: 1, - borderRadius: theme.spacing(5), - borderColor: theme.palette.border.light, - backgroundColor: theme.palette.background.main, - padding: { - xs: theme.spacing(12), - sm: theme.spacing(20), - }, - }, - }} - > - {step === 0 ? ( - setStep(1)} /> - ) : step === 1 ? ( - setStep(0)} - /> - ) : ( - step === 2 && ( - setStep(1)} - /> - ) - )} - - - ); -}; - -export default Login; From f631fb16ac44416e41466af3005663e93b7ffc44 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:39:55 -0800 Subject: [PATCH 20/40] fix login import --- Client/src/Routes/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 5fc764b6a..784b44609 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -3,7 +3,7 @@ import HomeLayout from "../Components/Layouts/HomeLayout"; import { Infrastructure } from "../Pages/Infrastructure"; import InfrastructureDetails from "../Pages/Infrastructure/Details"; import NotFound from "../Pages/NotFound"; -import Login from "../Pages/Auth/Login"; +import Login from "../Pages/Auth/Login/Login"; import Register from "../Pages/Auth/Register/Register"; import Account from "../Pages/Account"; import Monitors from "../Pages/Uptime/Home"; From 1e6b3394832ef04b1fd904a22a1217c364bf527e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:50:55 -0800 Subject: [PATCH 21/40] Add empty message to BasicTable component --- Client/src/Components/BasicTable/index.jsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index e519a079f..9f9a5b9da 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -115,7 +115,7 @@ TablePaginationActions.propTypes = { * @param {boolean} [props.paginated=false] - Flag to enable pagination. * @param {boolean} [props.reversed=false] - Flag to enable reverse order. * @param {number} props.rowsPerPage- Number of rows per page (table). - * + * @param {string} props.emptyMessage - Message to display when there is no data. * @example * const data = { * cols: [ @@ -149,7 +149,7 @@ TablePaginationActions.propTypes = { * */ -const BasicTable = ({ data, paginated, reversed, table }) => { +const BasicTable = ({ data, paginated, reversed, table, emptyMessage = "No data" }) => { const DEFAULT_ROWS_PER_PAGE = 5; const theme = useTheme(); const dispatch = useDispatch(); @@ -228,6 +228,16 @@ const BasicTable = ({ data, paginated, reversed, table }) => { ); })} + {displayData.length === 0 && ( + + + {emptyMessage} + + + )} @@ -317,6 +327,7 @@ BasicTable.propTypes = { reversed: PropTypes.bool, rowPerPage: PropTypes.number, table: PropTypes.string, + emptyMessage: PropTypes.string, }; export default BasicTable; From f880c2623c24d2ed9ece9370cfd31eb382d9d1c5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:51:03 -0800 Subject: [PATCH 22/40] Supply empty message to basic table --- .../TabPanels/Account/TeamPanel.jsx | 84 ++----------------- 1 file changed, 5 insertions(+), 79 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 209dbeaed..bbc6c4305 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -64,7 +64,7 @@ const TeamPanel = () => { }; fetchTeam(); - }, [user]); + }, [authToken]); useEffect(() => { let team = members; @@ -81,8 +81,6 @@ const TeamPanel = () => { { id: 1, name: "NAME" }, { id: 2, name: "EMAIL" }, { id: 3, name: "ROLE" }, - // FEATURE STILL TO BE IMPLEMENTED - // { id: 4, name: "ACTION" }, ], rows: team?.map((member, idx) => { const roles = member.role.map((role) => roleMap[role]).join(","); @@ -104,45 +102,19 @@ const TeamPanel = () => { }, { id: idx + 1, data: member.email }, { - // TODO - Add select dropdown id: idx + 2, data: roles, }, - // FEATURE STILL TO BE IMPLEMENTED - // { - // // TODO - Add delete onClick - // id: idx + 3, - // data: ( - // - // - // - // ), - // }, ], }; }), }; setTableData(data); - }, [members, filter]); + }, [filter, members, roleMap, theme]); useEffect(() => { setIsDisabled(Object.keys(errors).length !== 0 || toInvite.email === ""); }, [errors, toInvite.email]); - - // RENAME ORGANIZATION - // const toggleEdit = () => { - // setOrgStates((prev) => ({ ...prev, isEdit: !prev.isEdit })); - // }; - // const handleRename = () => {}; - - // INVITE MEMBER const [isOpen, setIsOpen] = useState(false); const handleChange = (event) => { @@ -226,58 +198,11 @@ const TeamPanel = () => { }, }} > - {/* FEATURE STILL TO BE IMPLEMENTED */} - {/* - - Organization name - - - - setOrgStates((prev) => ({ - ...prev, - name: event.target.value, - })) - } - disabled={!orgStates.isEdit} - sx={{ - color: theme.palette.otherColors.bluishGray, - "& .Mui-disabled": { - WebkitTextFillColor: "initial !important", - }, - "& .Mui-disabled fieldset": { - borderColor: "transparent !important", - }, - }} - inputProps={{ - sx: { textAlign: "end", padding: theme.spacing(4) }, - }} - /> - - - - - )} + About diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 784b44609..7d444f2ab 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -19,7 +19,6 @@ import SetNewPassword from "../Pages/Auth/SetNewPassword"; import NewPasswordConfirmed from "../Pages/Auth/NewPasswordConfirmed"; import ProtectedRoute from "../Components/ProtectedRoute"; import Details from "../Pages/Uptime/Details"; -import AdvancedSettings from "../Pages/AdvancedSettings"; import Maintenance from "../Pages/Maintenance"; import Configure from "../Pages/Uptime/Configure"; import PageSpeed from "../Pages/PageSpeed"; @@ -114,10 +113,6 @@ const Routes = () => { path="settings" element={} /> - } - /> } From 3cc7cf8deaeafbd771699dd7225d405f642c00ba Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 18 Dec 2024 13:33:35 +0000 Subject: [PATCH 24/40] fix(deps): update dependency bullmq to v5.34.3 --- Server/package-lock.json | 8 ++++---- Server/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Server/package-lock.json b/Server/package-lock.json index 3f57f737a..9c1315867 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "axios": "^1.7.2", "bcrypt": "^5.1.1", - "bullmq": "5.34.2", + "bullmq": "5.34.3", "cors": "^2.8.5", "dockerode": "4.0.2", "dotenv": "^16.4.5", @@ -1223,9 +1223,9 @@ } }, "node_modules/bullmq": { - "version": "5.34.2", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.2.tgz", - "integrity": "sha512-eUzeCswrKbQDE1WY8h4ZTBtynOzCU5qx9felFdYOmIJrsy0warDahHKUiCZ6dUCs6ZxYMGtcaciIMcAf1L54yw==", + "version": "5.34.3", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.3.tgz", + "integrity": "sha512-S8/V11w7p6jYAGvv+00skLza/4inTOupWPe0uCD8mZSUiYKzvmW4/YEB+KVjZI2CC2oD3KJ3t7/KkUd31MxMig==", "license": "MIT", "dependencies": { "cron-parser": "^4.6.0", diff --git a/Server/package.json b/Server/package.json index 93d4d6be8..c480aea4c 100644 --- a/Server/package.json +++ b/Server/package.json @@ -14,7 +14,7 @@ "dependencies": { "axios": "^1.7.2", "bcrypt": "^5.1.1", - "bullmq": "5.34.2", + "bullmq": "5.34.3", "cors": "^2.8.5", "dockerode": "4.0.2", "dotenv": "^16.4.5", From 6e29e37241f20a3704f00df363bb06d14bd777b0 Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Wed, 18 Dec 2024 10:42:41 -0500 Subject: [PATCH 25/40] - Add divider for setting --- Client/src/Pages/Settings/styled.jsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Client/src/Pages/Settings/styled.jsx b/Client/src/Pages/Settings/styled.jsx index 269706a27..aeefdaebb 100644 --- a/Client/src/Pages/Settings/styled.jsx +++ b/Client/src/Pages/Settings/styled.jsx @@ -5,19 +5,27 @@ export const ConfigBox = styled(Stack)(({ theme }) => ({ flexDirection: "row", justifyContent: "space-between", gap: theme.spacing(20), - paddingTop: theme.spacing(12), - paddingInline: theme.spacing(15), - paddingBottom: theme.spacing(25), backgroundColor: theme.palette.background.main, border: 1, borderStyle: "solid", borderColor: theme.palette.border.light, borderRadius: theme.spacing(2), + "& > *": { + paddingTop: theme.spacing(12), + paddingBottom: theme.spacing(18), + }, "& > div:first-of-type": { flex: 0.7, + borderRight: 1, + borderRightStyle: "solid", + borderRightColor: theme.palette.border.light, + paddingRight: theme.spacing(15), + paddingLeft: theme.spacing(15), }, "& > div:last-of-type": { flex: 1, + paddingRight: theme.spacing(20), + paddingLeft: theme.spacing(18), }, "& h1, & h2": { color: theme.palette.text.secondary, From 7f7423aed830ab9bdff0587e15841023d1c36d01 Mon Sep 17 00:00:00 2001 From: Anand Roy Date: Wed, 18 Dec 2024 17:46:44 +0000 Subject: [PATCH 26/40] reset password link added --- .../Pages/Auth/Login/Components/EmailStep.jsx | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Client/src/Pages/Auth/Login/Components/EmailStep.jsx b/Client/src/Pages/Auth/Login/Components/EmailStep.jsx index f78193186..08ae51c4f 100644 --- a/Client/src/Pages/Auth/Login/Components/EmailStep.jsx +++ b/Client/src/Pages/Auth/Login/Components/EmailStep.jsx @@ -1,8 +1,9 @@ -import { useRef, useEffect } from "react"; +import { useRef, useEffect } from "react"; import { Box, Button, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; import TextInput from "../../../../Components/Inputs/TextInput"; import PropTypes from "prop-types"; +import { useNavigate } from "react-router"; /** * Renders the email step of the login process which includes an email field. @@ -18,6 +19,7 @@ import PropTypes from "prop-types"; const EmailStep = ({ form, errors, onSubmit, onChange }) => { const theme = useTheme(); const inputRef = useRef(null); + const navigate = useNavigate(); useEffect(() => { if (inputRef.current) { @@ -25,11 +27,19 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => { } }, []); + const handleNavigate = () => { + if (form.email !== "" && !errors.email) { + sessionStorage.setItem("email", form.email); + } + navigate("/forgot-password"); + }; + return ( <> Log In @@ -80,6 +90,32 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => { + + + Forgot password? + + + Reset password + + ); @@ -92,4 +128,4 @@ EmailStep.propTypes = { onChange: PropTypes.func.isRequired, }; -export default EmailStep; \ No newline at end of file +export default EmailStep; From bd5bc2617c031c78909cc5165b643f32aa52c4ec Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 18 Dec 2024 12:19:21 -0800 Subject: [PATCH 27/40] Add a config box component --- Client/src/Components/ConfigBox/index.jsx | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Client/src/Components/ConfigBox/index.jsx diff --git a/Client/src/Components/ConfigBox/index.jsx b/Client/src/Components/ConfigBox/index.jsx new file mode 100644 index 000000000..7650dd47f --- /dev/null +++ b/Client/src/Components/ConfigBox/index.jsx @@ -0,0 +1,38 @@ +import { Stack, styled } from "@mui/material"; + +const ConfigBox = styled(Stack)(({ theme }) => ({ + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + gap: theme.spacing(20), + backgroundColor: theme.palette.background.main, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + borderRadius: theme.spacing(2), + "& > *": { + paddingTop: theme.spacing(12), + paddingBottom: theme.spacing(18), + }, + "& > div:first-of-type": { + flex: 0.7, + borderRight: 1, + borderRightStyle: "solid", + borderRightColor: theme.palette.border.light, + paddingRight: theme.spacing(15), + paddingLeft: theme.spacing(15), + }, + "& > div:last-of-type": { + flex: 1, + paddingRight: theme.spacing(20), + paddingLeft: theme.spacing(18), + }, + "& h1, & h2": { + color: theme.palette.text.secondary, + }, + "& p": { + color: theme.palette.text.tertiary, + }, +})); + +export default ConfigBox; From c47ec6ce8bb6925ea6f29965f41066a2cf757541 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 18 Dec 2024 12:20:09 -0800 Subject: [PATCH 28/40] refactor create maintenance to use new ConfigBox --- .../Maintenance/CreateMaintenance/index.jsx | 232 ++++++++---------- .../Maintenance/CreateMaintenance/styled.jsx | 25 -- 2 files changed, 99 insertions(+), 158 deletions(-) delete mode 100644 Client/src/Pages/Maintenance/CreateMaintenance/styled.jsx diff --git a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx index f41603330..c832d463a 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx @@ -2,7 +2,7 @@ import { Box, Button, Stack, Typography } from "@mui/material"; import { useSelector } from "react-redux"; import { useTheme } from "@emotion/react"; import { useEffect, useState } from "react"; -import { ConfigBox } from "./styled"; +import ConfigBox from "../../../Components/ConfigBox"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; @@ -321,18 +321,27 @@ const CreateMaintenance = () => { Your pings won't be sent during this time frame - - - General Settings - - + + + + General Settings + + + + { + handleFormChange("name", event.target.value); + }} + error={errors["name"] ? true : false} + helperText={errors["name"]} + />