From 4b2973e308b352f5783f12fbdd135661cf2a8afd Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 09:39:45 -0700 Subject: [PATCH 001/101] Add team schema --- Server/models/Team.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Server/models/Team.js diff --git a/Server/models/Team.js b/Server/models/Team.js new file mode 100644 index 000000000..33c81f10b --- /dev/null +++ b/Server/models/Team.js @@ -0,0 +1,12 @@ +const mongoose = require("mongoose"); + +const TeamSchema = mongoose.Schema({ + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + immutable: true, + }, + timestamps: true, +}); + +module.exports = mongoose.model("Team", TeamSchema); From ef02bd8078c433f7e62c699b32b44ec06c01b0b4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 09:46:23 -0700 Subject: [PATCH 002/101] Check for superadmin as opposed to admin --- Server/controllers/authController.js | 8 ++++---- Server/db/mongo/MongoDB.js | 6 +++--- Server/models/user.js | 2 +- Server/routes/authRoute.js | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 6fbcdb669..7c053ae56 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -293,13 +293,13 @@ const inviteVerifyController = async (req, res, next) => { * @returns {Promise} */ -const checkAdminController = async (req, res) => { +const checkSuperadminController = async (req, res) => { try { - const adminExists = await req.db.checkAdmin(req, res); + const superAdminExists = await req.db.checkSuperadmin(req, res); return res.status(200).json({ success: true, msg: successMessages.AUTH_ADMIN_EXISTS, - data: adminExists, + data: superAdminExists, }); } catch (error) { error.service = SERVICE_NAME; @@ -508,7 +508,7 @@ module.exports = { userEditController, inviteController, inviteVerifyController, - checkAdminController, + checkSuperadminController, recoveryRequestController, validateRecoveryTokenController, resetPasswordController, diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 9c1005c32..8c1d97351 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -15,9 +15,9 @@ const connect = async () => { } }; -const checkAdmin = async (req, res) => { +const checkSuperadmin = async (req, res) => { try { - const admin = await UserModel.findOne({ role: "admin" }); + const admin = await UserModel.findOne({ role: "superadmin" }); if (admin !== null) { return true; } @@ -141,7 +141,7 @@ module.exports = { requestRecoveryToken, validateRecoveryToken, resetPassword, - checkAdmin, + checkSuperadmin, getAllMonitors, getMonitorStatsById, getMonitorById, diff --git a/Server/models/user.js b/Server/models/user.js index 977cabc15..73567798c 100644 --- a/Server/models/user.js +++ b/Server/models/user.js @@ -38,7 +38,7 @@ const UserSchema = mongoose.Schema( role: { type: [String], default: "user", - enum: ["user", "admin"], + enum: ["user", "admin", "superadmin"], }, }, { diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 201807121..589c0f1ac 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -14,7 +14,7 @@ const { recoveryRequestController, validateRecoveryTokenController, resetPasswordController, - checkAdminController, + checkSuperadminController, getAllUsersController, deleteUserController, inviteController, @@ -30,7 +30,7 @@ router.put( verifyJWT, userEditController ); -router.get("/users/admin", checkAdminController); +router.get("/users/superadmin", checkSuperadminController); router.get("/users", verifyJWT, verifyAdmin, getAllUsersController); router.delete( "/user/:userId", From 4c2cc6fb2cbe8dbd63bb1203caf2d2415d295db1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 10:00:34 -0700 Subject: [PATCH 003/101] First user is superadmin instead of admin --- Client/src/HOC/withAdminCheck.jsx | 4 ++-- Client/src/Pages/Auth/Login.jsx | 2 +- Client/src/Pages/Auth/Register/Register.jsx | 23 ++++++++++++++------- Client/src/Utils/NetworkService.js | 4 ++-- Server/validation/joi.js | 11 ++++++---- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Client/src/HOC/withAdminCheck.jsx b/Client/src/HOC/withAdminCheck.jsx index 30a767f36..097f224e9 100644 --- a/Client/src/HOC/withAdminCheck.jsx +++ b/Client/src/HOC/withAdminCheck.jsx @@ -10,7 +10,7 @@ const withAdminCheck = (WrappedComponent) => { useEffect(() => { networkService - .doesAdminExist() + .doesSuperAdminExist() .then((response) => { if (response.data.data === true) { navigate("/login"); @@ -20,7 +20,7 @@ const withAdminCheck = (WrappedComponent) => { logger.error(error); }); }, [navigate]); - return ; + return ; }; const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || "Component"; diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index b962fbb9a..30b7f8f8a 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -301,7 +301,7 @@ const Login = () => { return; } networkService - .doesAdminExist() + .doesSuperAdminExist() .then((response) => { if (response.data.data === false) { navigate("/register"); diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 4680c1821..4dd8fad24 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -23,11 +23,11 @@ import { logger } from "../../../Utils/Logger"; * Displays the initial landing page. * * @param {Object} props - * @param {boolean} props.isAdmin - Whether the user is creating and admin account + * @param {boolean} props.isSuperAdmin - Whether the user is creating and admin account * @param {Function} props.onContinue - Callback function to handle "Continue with Email" button click. * @returns {JSX.Element} */ -const LandingPage = ({ isAdmin, onSignup }) => { +const LandingPage = ({ isSuperAdmin, onSignup }) => { const theme = useTheme(); return ( @@ -40,7 +40,8 @@ const LandingPage = ({ isAdmin, onSignup }) => { Sign Up - Create your {isAdmin ? "admin " : ""}account to get started. + Create your {isSuperAdmin ? "Super admin " : ""}account to get + started. @@ -93,7 +94,7 @@ const LandingPage = ({ isAdmin, onSignup }) => { }; LandingPage.propTypes = { - isAdmin: PropTypes.bool, + isSuperAdmin: PropTypes.bool, onSignup: PropTypes.func, }; @@ -422,7 +423,7 @@ StepThree.propTypes = { onBack: PropTypes.func, }; -const Register = ({ isAdmin }) => { +const Register = ({ isSuperAdmin }) => { const dispatch = useDispatch(); const navigate = useNavigate(); const { token } = useParams(); @@ -525,7 +526,10 @@ const Register = ({ isAdmin }) => { const handleStepThree = async (e) => { e.preventDefault(); - let registerForm = { ...form, role: isAdmin ? ["admin"] : form.role }; + let registerForm = { + ...form, + role: isSuperAdmin ? ["superadmin"] : form.role, + }; let error = validateForm(registerForm, { context: { password: form.password }, }); @@ -616,7 +620,10 @@ const Register = ({ isAdmin }) => { }} > {step === 0 ? ( - setStep(1)} /> + setStep(1)} + /> ) : step === 1 ? ( { ); }; Register.propTypes = { - isAdmin: PropTypes.bool, + isSuperAdmin: PropTypes.bool, }; export default Register; diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index de4508cff..97071a7aa 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -293,8 +293,8 @@ class NetworkService { * @returns {Promise} The response from the axios GET request. * */ - async doesAdminExist() { - return this.axiosInstance.get("/auth/users/admin"); + async doesSuperAdminExist() { + return this.axiosInstance.get("/auth/users/superadmin"); } /** diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 4f8042e12..3a9b7e1a1 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -5,8 +5,11 @@ const joi = require("joi"); //**************************************** const roleValidatior = (role) => (value, helpers) => { - if (!value.includes(role)) { - throw new joi.ValidationError(`You do not have ${role} authorization`); + const hasRole = roles.some((role) => value.includes(role)); + if (!hasRole) { + throw new Joi.ValidationError( + `You do not have the required authorization. Required roles: ${roles.join(", ")}` + ); } return value; }; @@ -66,7 +69,7 @@ const registerValidation = joi.object({ profileImage: joi.any(), role: joi .array() - .items(joi.string().valid("admin", "user")) + .items(joi.string().valid("superadmin", "admin", "user")) .min(1) .required(), }); @@ -123,7 +126,7 @@ const deleteUserParamValidation = joi.object({ }); const inviteRoleValidation = joi.object({ - roles: joi.custom(roleValidatior("admin")).required(), + roles: joi.custom(roleValidatior(["admin", "superadmin"])).required(), }); const inviteBodyValidation = joi.object({ From a6f5c96f93bdb2d68eb313dac8105d5d101e06c1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 10:23:05 -0700 Subject: [PATCH 004/101] Create team on superadmin create --- Server/db/mongo/modules/userModule.js | 13 +++++++++++++ Server/models/Team.js | 18 +++++++++++------- Server/models/user.js | 5 +++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Server/db/mongo/modules/userModule.js b/Server/db/mongo/modules/userModule.js index 3dacfd943..bc2f83958 100644 --- a/Server/db/mongo/modules/userModule.js +++ b/Server/db/mongo/modules/userModule.js @@ -1,4 +1,5 @@ const UserModel = require("../../../models/user"); +const TeamModel = require("../../../models/Team"); const { errorMessages } = require("../../../utils/messages"); const { GenerateAvatarImage } = require("../../../utils/imageProcessing"); @@ -27,7 +28,19 @@ const insertUser = async (req, res) => { const avatar = await GenerateAvatarImage(req.file); userData.avatarImage = avatar; } + + let teamId; + // Is user superadmin? If so, create team + if (userData.role.includes("superadmin")) { + const team = new TeamModel({ + email: userData.email, + }); + teamId = team._id; + await team.save(); + } + const newUser = new UserModel(userData); + newUser.teamId = teamId; await newUser.save(); return await UserModel.findOne({ _id: newUser._id }) .select("-password") diff --git a/Server/models/Team.js b/Server/models/Team.js index 33c81f10b..25e1f9b22 100644 --- a/Server/models/Team.js +++ b/Server/models/Team.js @@ -1,12 +1,16 @@ const mongoose = require("mongoose"); -const TeamSchema = mongoose.Schema({ - userId: { - type: mongoose.Schema.Types.ObjectId, - ref: "User", - immutable: true, +const TeamSchema = mongoose.Schema( + { + email: { + type: String, + required: true, + unique: true, + }, }, - timestamps: true, -}); + { + timestamps: true, + } +); module.exports = mongoose.model("Team", TeamSchema); diff --git a/Server/models/user.js b/Server/models/user.js index 73567798c..a6045547d 100644 --- a/Server/models/user.js +++ b/Server/models/user.js @@ -40,6 +40,11 @@ const UserSchema = mongoose.Schema( default: "user", enum: ["user", "admin", "superadmin"], }, + teamId: { + type: mongoose.Schema.Types.ObjectId, + ref: "Team", + immutable: true, + }, }, { timestamps: true, From d5f7aadadc52b69192c9c47261baedd7ab2deb1a Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Mon, 26 Aug 2024 14:45:31 -0400 Subject: [PATCH 005/101] =?UTF-8?q?=EF=BF=BD=20colors=20rebranded?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/index.css | 84 ++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 58 deletions(-) diff --git a/Client/src/index.css b/Client/src/index.css index d513ac9a1..77ac4c1c5 100644 --- a/Client/src/index.css +++ b/Client/src/index.css @@ -7,19 +7,38 @@ :root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; font-weight: 400; - - /* color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; */ - font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Generalized Stylings */ + --theme-main: #1570ef; - --env-var-font-familt-1: "Roboto", "Helvetica", "Arial", sans-serif; + --primary-color: #1c2130; + --secondary-color: #344054; + --secondary-color-light: #475467; + --secondary-color-light-accent: #838c99; + + --primary-bg: #ffffff; + --primary-bg-accent: #f9fafb; + --secondary-bg: #fcfcfd; + + --border-color: #eaecf0; + + /* OTHER COLORS */ + --success-color: #17b26a; + --success-color-light: #d4f4e1; + --success-bg: #ecfdf3; + --error-color: #f04438; + --error-color-light: #fbd1d1; + --error-bg: #f9eced; + --warning-color: #fdb022; + --warning-color-light: #fffcf5; + --warning-bg: #ffecbc; + --unresolved-color: #4e5ba6; + --unresolved-color-light: #e2eaf7; + --unresolved-bg: #f2f4f7; --env-var-color-0: #fff; --env-var-color-1: #1c2130; @@ -99,48 +118,12 @@ 0px 3px 3px -3px rgba(16, 24, 40, 0.03); } -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - body { margin: 0; min-width: 320px; height: 100%; } -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} - -button:hover { - border-color: #646cff; -} - -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - .MuiInputBase-root.Mui-disabled input { cursor: not-allowed; } @@ -165,7 +148,7 @@ button:focus-visible { } body .MuiSkeleton-root { - background-color: var(--env-var-color-15); + background-color: #f2f4f7; } @keyframes ripple { @@ -178,18 +161,3 @@ body .MuiSkeleton-root { transform: scale(2); } } - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - - a:hover { - color: #747bff; - } - - button { - background-color: #f9f9f9; - } -} From c39eab49bd0639f98d24651fac3da4eeac8610dd Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 13:29:11 -0700 Subject: [PATCH 006/101] Add teams to a user when they are created --- Client/src/Pages/Account/index.jsx | 8 ++++++-- Client/src/Pages/Auth/Register/Register.jsx | 9 +++++---- Client/src/Validation/validation.js | 1 + Server/controllers/authController.js | 3 ++- Server/db/mongo/modules/inviteModule.js | 1 + Server/db/mongo/modules/userModule.js | 2 ++ Server/models/InviteToken.js | 6 ++++++ Server/validation/joi.js | 4 +++- 8 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Client/src/Pages/Account/index.jsx b/Client/src/Pages/Account/index.jsx index 2fed926b8..e731d231a 100644 --- a/Client/src/Pages/Account/index.jsx +++ b/Client/src/Pages/Account/index.jsx @@ -25,7 +25,11 @@ const Account = ({ open = "profile" }) => { let tabList = ["Profile", "Password", "Team"]; const { user } = useSelector((state) => state.auth); - if (!user.role.includes("admin")) tabList = ["Profile", "Password"]; + const requiredRoles = ["superadmin", "admin"]; + const hideTeams = !requiredRoles.some((role) => user.role.includes(role)); + if (hideTeams) { + tabList = ["Profile", "Password"]; + } return ( { - {user.role.includes("admin") && } + {!hideTeams && } ); diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 4dd8fad24..39a5fdafd 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -444,24 +444,26 @@ const Register = ({ isSuperAdmin }) => { password: "", confirm: "", role: [], + teamId: "", }); const [errors, setErrors] = useState({}); const [step, setStep] = useState(0); useEffect(() => { const fetchInvite = async () => { + console.log("FETCHING"); if (token !== undefined) { try { const res = await networkService.verifyInvitationToken(token); - const { role, email } = res.data.data; - setForm({ ...form, email, role }); + const { role, email, teamId } = res.data.data; + setForm({ ...form, email, role, teamId }); } catch (error) { logger.error(error); } } }; fetchInvite(); - }, [token, form]); + }, []); /** * Validates the form data against the validation schema. @@ -494,7 +496,6 @@ const Register = ({ isSuperAdmin }) => { const handleStepOne = async (e) => { e.preventDefault(); - let error = validateForm({ firstName: form.firstName, lastName: form.lastName, diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index 35d47d6b1..c326e8ee9 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -76,6 +76,7 @@ const credentials = joi.object({ return value; }), role: joi.array(), + teamId: joi.string().allow("").optional(), }); const monitorValidation = joi.object({ diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 7c053ae56..720dcd08c 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -226,7 +226,8 @@ const inviteController = async (req, res, next) => { try { // Only admins can invite const token = getTokenFromHeaders(req.headers); - const { role, firstname } = jwt.decode(token); + const { role, firstname, teamId } = jwt.decode(token); + req.body.teamId = teamId; try { await inviteRoleValidation.validateAsync({ roles: role }); await inviteBodyValidation.validateAsync(req.body); diff --git a/Server/db/mongo/modules/inviteModule.js b/Server/db/mongo/modules/inviteModule.js index b4404c615..73e883930 100644 --- a/Server/db/mongo/modules/inviteModule.js +++ b/Server/db/mongo/modules/inviteModule.js @@ -8,6 +8,7 @@ const requestInviteToken = async (req, res) => { let inviteToken = new InviteToken({ email: req.body.email, role: req.body.role, + teamId: req.body.teamId, token: crypto.randomBytes(32).toString("hex"), }); await inviteToken.save(); diff --git a/Server/db/mongo/modules/userModule.js b/Server/db/mongo/modules/userModule.js index bc2f83958..2df13ddc7 100644 --- a/Server/db/mongo/modules/userModule.js +++ b/Server/db/mongo/modules/userModule.js @@ -37,6 +37,8 @@ const insertUser = async (req, res) => { }); teamId = team._id; await team.save(); + } else { + teamId = userData.teamId; } const newUser = new UserModel(userData); diff --git a/Server/models/InviteToken.js b/Server/models/InviteToken.js index 10515dadb..5fbd4fc73 100644 --- a/Server/models/InviteToken.js +++ b/Server/models/InviteToken.js @@ -7,6 +7,12 @@ const InviteTokenSchema = mongoose.Schema( required: true, unique: true, }, + teamId: { + type: mongoose.Schema.Types.ObjectId, + ref: "Team", + immutable: true, + required: true, + }, role: { type: Array, required: true, diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 3a9b7e1a1..14654e1ae 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -5,7 +5,7 @@ const joi = require("joi"); //**************************************** const roleValidatior = (role) => (value, helpers) => { - const hasRole = roles.some((role) => value.includes(role)); + const hasRole = role.some((role) => value.includes(role)); if (!hasRole) { throw new Joi.ValidationError( `You do not have the required authorization. Required roles: ${roles.join(", ")}` @@ -72,6 +72,7 @@ const registerValidation = joi.object({ .items(joi.string().valid("superadmin", "admin", "user")) .min(1) .required(), + teamId: joi.string().allow("").required(), }); const editUserParamValidation = joi.object({ @@ -135,6 +136,7 @@ const inviteBodyValidation = joi.object({ "string.email": "Must be a valid email address", }), role: joi.array().required(), + teamId: joi.string().required(), }); const inviteVerifciationBodyValidation = joi.object({ From 64ca926a85038842b37f29ae4c501d6a1de58cf6 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Mon, 26 Aug 2024 17:22:21 -0400 Subject: [PATCH 007/101] =?UTF-8?q?=EF=BF=BD=EF=B8=8F=EF=BF=BD=EF=B8=8F?= =?UTF-8?q?=EF=BF=BD=20Updated=20color=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/App.css | 28 ----------- Client/src/Components/BasicTable/index.css | 35 ++++++------- Client/src/Components/Breadcrumbs/index.css | 4 +- .../src/Components/Charts/BarChart/index.css | 4 +- .../Charts/MonitorDetails60MinChart/index.jsx | 6 +-- .../Charts/MonitorDetailsAreaChart/index.css | 6 +-- .../Charts/ResponseTimeChart/index.jsx | 4 +- .../Charts/Statistics/Statistic.jsx | 35 ------------- .../Charts/Statistics/statistic.css | 31 ------------ Client/src/Components/Check/check.css | 10 ++-- Client/src/Components/Fallback/index.css | 2 +- .../src/Components/Inputs/Checkbox/index.css | 4 +- Client/src/Components/Inputs/Field/index.css | 14 +++--- Client/src/Components/Inputs/Image/index.css | 4 +- Client/src/Components/Inputs/Select/index.css | 12 ++--- Client/src/Components/ProgressBars/index.css | 10 ++-- Client/src/Components/RadioButton/index.css | 2 +- Client/src/Components/Sidebar/index.css | 20 ++++---- .../TabPanels/Account/TeamPanel.jsx | 2 +- .../TooltipWithTail/TooltipWithTail.jsx | 45 ----------------- .../TooltipWithTail/tooltipWithTail.css | 49 ------------------- Client/src/Layouts/HomeLayout/index.css | 8 +-- Client/src/Pages/Account/index.css | 9 ++-- Client/src/Pages/Auth/index.css | 10 ++-- Client/src/Pages/Incidents/index.css | 10 ++-- Client/src/Pages/Integrations/index.css | 6 +-- Client/src/Pages/Maintenance/index.css | 4 +- Client/src/Pages/Monitors/Configure/index.css | 16 +++--- Client/src/Pages/Monitors/Configure/index.jsx | 4 +- .../Pages/Monitors/CreateMonitor/index.css | 14 +++--- Client/src/Pages/Monitors/index.css | 20 ++++---- Client/src/Pages/Monitors/index.jsx | 4 +- Client/src/Pages/NotFound/index.css | 2 +- .../src/Pages/PageSpeed/Configure/index.css | 10 ++-- .../src/Pages/PageSpeed/Configure/index.jsx | 4 +- .../Pages/PageSpeed/CreatePageSpeed/index.css | 8 +-- Client/src/Pages/PageSpeed/Details/index.css | 10 ++-- Client/src/Pages/PageSpeed/Details/index.jsx | 2 +- Client/src/Pages/PageSpeed/index.css | 8 +-- Client/src/Pages/PageSpeed/index.jsx | 6 ++- Client/src/Pages/Settings/index.css | 6 +-- Client/src/index.css | 2 + 42 files changed, 155 insertions(+), 335 deletions(-) delete mode 100644 Client/src/Components/Charts/Statistics/Statistic.jsx delete mode 100644 Client/src/Components/Charts/Statistics/statistic.css delete mode 100644 Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx delete mode 100644 Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css diff --git a/Client/src/App.css b/Client/src/App.css index 0d669ffa5..bf3d4ea92 100644 --- a/Client/src/App.css +++ b/Client/src/App.css @@ -1,31 +1,3 @@ -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - .card { padding: 2em; } diff --git a/Client/src/Components/BasicTable/index.css b/Client/src/Components/BasicTable/index.css index 208604021..69562d661 100644 --- a/Client/src/Components/BasicTable/index.css +++ b/Client/src/Components/BasicTable/index.css @@ -17,7 +17,7 @@ .MuiPaper-root:has(table.MuiTable-root) { box-shadow: none; - border: solid 1px var(--env-var-color-16); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); } .MuiTable-root @@ -28,7 +28,7 @@ } .MuiTable-root .MuiTableHead-root, .MuiTable-root .MuiTableRow-root:hover { - background-color: var(--env-var-color-13); + background-color: var(--primary-bg-accent); } .MuiTable-root .MuiTableHead-root .MuiTableCell-root, .MuiTable-root .MuiTableBody-root .MuiTableCell-root { @@ -37,7 +37,7 @@ .MuiTable-root .MuiTableHead-root .MuiTableCell-root { padding: var(--env-var-spacing-1) var(--env-var-spacing-2); font-weight: 500; - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .MuiTable-root .MuiTableHead-root span { display: inline-block; @@ -52,7 +52,7 @@ height: 20px; } .MuiTable-root .MuiTableBody-root .MuiTableCell-root { - color: var(--env-var-color-5); + color: var(--secondary-color); padding: 6px var(--env-var-spacing-2); } .MuiTable-root .MuiTableBody-root .MuiTableRow-root { @@ -61,7 +61,8 @@ .MuiPaper-root + .MuiPagination-root { margin-top: 24px; - border: solid 1px var(--env-var-color-16); + background-color: var(--primary-bg); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); padding: var(--env-var-spacing-1-plus) var(--env-var-spacing-2); } @@ -74,7 +75,7 @@ li:not(:first-child):not(:last-child) button { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); font-weight: 500; } .MuiPaper-root + .MuiPagination-root ul li:first-child { @@ -85,7 +86,7 @@ } .MuiPaper-root + .MuiPagination-root ul li:first-child button, .MuiPaper-root + .MuiPagination-root ul li:last-child button { - border: solid 1px var(--env-var-color-16); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); } .MuiPaper-root + .MuiPagination-root ul li:first-child button { @@ -108,20 +109,20 @@ margin-right: 15px; } .MuiPaper-root + .MuiPagination-root .MuiPaginationItem-root.Mui-selected { - background-color: var(--env-var-color-15); + background-color: var(--primary-bg-fill); } .MuiPaper-root + .MuiPagination-root div.MuiPaginationItem-root { user-select: none; } .MuiTablePagination-root p { - color: var(--env-var-color-2); + color: var(--secondary-color-light); font-weight: 500; font-size: var(--env-var-font-size-small-plus); } .MuiTablePagination-root button, .MuiTablePagination-root .MuiSelect-select { - border: solid 1px #ebebeb; + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); } .MuiTablePagination-root .MuiTablePagination-select.MuiSelect-select { @@ -138,7 +139,7 @@ height: 22px; } .MuiTablePagination-root svg path { - stroke: var(--env-var-color-2); + stroke: var(--secondary-color-light); stroke-width: 1.3; } .MuiTablePagination-root .MuiSelect-icon { @@ -152,13 +153,13 @@ opacity: 0.4; } .MuiTablePagination-root button:not(.Mui-disabled):hover { - background-color: #f4f4f4; - border-color: #f4f4f4; + background-color: var(--primary-bg-fill); + border-color: var(--primary-bg-fill); } .pagination-dropdown.MuiPaper-root { box-shadow: var(--env-var-shadow-1); - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); } .pagination-dropdown ul { @@ -168,13 +169,13 @@ .pagination-dropdown li, body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-2); + color: var(--secondary-color-light); padding: 4px; } .pagination-dropdown li.Mui-selected, .pagination-dropdown li.Mui-selected.Mui-focusVisible, .pagination-dropdown li.Mui-selected:hover { - background-color: #f4f4f4; + background-color: var(--primary-bg-fill); } body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) { font-size: var(--env-var-font-size-small-plus); @@ -182,7 +183,7 @@ body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) { .monitors .MuiTable-root .MuiTableHead-root .MuiTableCell-root { text-transform: uppercase; - color: var(--env-var-color-5); + color: var(--secondary-color); opacity: 0.8; font-size: var(--env-var-font-size-small-plus); font-weight: 400; diff --git a/Client/src/Components/Breadcrumbs/index.css b/Client/src/Components/Breadcrumbs/index.css index b7d190de1..1d1454b3d 100644 --- a/Client/src/Components/Breadcrumbs/index.css +++ b/Client/src/Components/Breadcrumbs/index.css @@ -7,12 +7,12 @@ } .MuiBreadcrumbs-root .MuiBreadcrumbs-li a { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-2); + color: var(--secondary-color-light); opacity: 0.8; font-weight: 400; } .MuiBreadcrumbs-root .MuiBreadcrumbs-li:hover a { - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child):hover a { opacity: 1; diff --git a/Client/src/Components/Charts/BarChart/index.css b/Client/src/Components/Charts/BarChart/index.css index e386aef1c..ed22f8bd7 100644 --- a/Client/src/Components/Charts/BarChart/index.css +++ b/Client/src/Components/Charts/BarChart/index.css @@ -9,11 +9,11 @@ .bar-tooltip .MuiTooltip-tooltip p { font-size: var(--env-var-font-size-small-plus); - color: var(--env-var-color-2); + color: var(--secondary-color-light); font-weight: 500; } .bar-tooltip .MuiTooltip-tooltip span { font-size: var(--env-var-font-size-small); - color: var(--env-var-color-2); + color: var(--secondary-color-light); font-weight: 600; } diff --git a/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx b/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx index f7fc0d3d8..dbb45f109 100644 --- a/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx +++ b/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx @@ -9,9 +9,9 @@ const MonitorDetails60MinChart = ({ data }) => { }; const color = { - true: "var(--env-var-color-23)", - false: "var(--env-var-color-24)", - undefined: "var(--env-var-color-33)", + true: "var(--success-color)", + false: "var(--error-color)", + undefined: "var(--unresolved-color)", }; return ( { key={`cell-${index}`} fill={ check.status === true - ? "var(--env-var-color-23)" - : "var(--env-var-color-24)" + ? "var(--success-color)" + : "var(--error-color)" } /> ))} diff --git a/Client/src/Components/Charts/Statistics/Statistic.jsx b/Client/src/Components/Charts/Statistics/Statistic.jsx deleted file mode 100644 index 99ad2066f..000000000 --- a/Client/src/Components/Charts/Statistics/Statistic.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react"; -import "./statistic.css"; -import PropTypes from "prop-types"; -import { useTheme } from "@mui/material"; - -/** - * @component - * @param {Object} props - * @param {string} props.title - The title text for the statistic (required) - * @param {string} props.value - The numerical or textual value for the statistic (required) - * @returns {JSX.Element} - Renders the statistic component - */ -const Statistic = ({ title, value }) => { - const theme = useTheme(); - - const fontLookup = { - default: theme.font.default.font, - }; - - const fontFamily = fontLookup["default"]; - - return ( -
-
{title}
-
{value}
-
- ); -}; - -Statistic.propTypes = { - title: PropTypes.string.isRequired, - value: PropTypes.string.isRequired, -}; - -export default Statistic; diff --git a/Client/src/Components/Charts/Statistics/statistic.css b/Client/src/Components/Charts/Statistics/statistic.css deleted file mode 100644 index a8834199d..000000000 --- a/Client/src/Components/Charts/Statistics/statistic.css +++ /dev/null @@ -1,31 +0,0 @@ -:root { - --stats-spacing-general-0: 5px 10px; - --color-border-0: #eaecf0; - --border-radius-0: 4px; - --font-size-0: 1rem; - --font-size-1: 13px; - --font-color-0: #344054; - --margin-bottom-0: 10px; -} - -.statistic-tile { - margin: var(--stats-spacing-general-0); - padding: var(--stats-spacing-general-0); - border: 1px solid var(--color-border-0); - border-radius: var(--border-radius-0); - - width: 180px; -} - -.statistic-tile-title { - font-size: var(--font-size-0); - color: var(--font-color-0); - margin-bottom: var(--margin-bottom-0); -} - -.statistic-tile-value { - font-size: var(--font-size-1); - color: var(--font-color-0); - font-weight: 700; - margin-bottom: var(--margin-bottom-0); -} diff --git a/Client/src/Components/Check/check.css b/Client/src/Components/Check/check.css index f1432d2bc..8d9bbc24e 100644 --- a/Client/src/Components/Check/check.css +++ b/Client/src/Components/Check/check.css @@ -1,17 +1,17 @@ .check > span.MuiTypography-root { font-size: var(--env-var-font-size-small-plus); - color: var(--env-var-color-2); + color: var(--secondary-color-light); opacity: 0.8; } .check-error span.MuiTypography-root { - color: var(--env-var-color-24); + color: var(--error-color); } .check-error svg > path { - fill: var(--env-var-color-19); + fill: var(--error-color); } .check-success span.MuiTypography-root { - color: var(--env-var-color-17); + color: var(--success-color); } .check-success svg > path { - fill: var(--env-var-color-23); + fill: var(--success-color); } diff --git a/Client/src/Components/Fallback/index.css b/Client/src/Components/Fallback/index.css index 226c7bc47..ea1925ff5 100644 --- a/Client/src/Components/Fallback/index.css +++ b/Client/src/Components/Fallback/index.css @@ -9,7 +9,7 @@ } [class*="fallback__"] .check span.MuiTypography-root, [class*="fallback__"] h1.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } [class*="fallback__"] button.MuiButtonBase-root, [class*="fallback__"] .check { diff --git a/Client/src/Components/Inputs/Checkbox/index.css b/Client/src/Components/Inputs/Checkbox/index.css index 0d2285955..130be8853 100644 --- a/Client/src/Components/Inputs/Checkbox/index.css +++ b/Client/src/Components/Inputs/Checkbox/index.css @@ -2,11 +2,11 @@ border-radius: var(--env-var-radius-1); } .checkbox-wrapper:not(:has(.Mui-disabled)):hover { - background-color: var(--env-var-color-15); + background-color: var(--unresolved-bg); } .checkbox-wrapper span.MuiTypography-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .checkbox-wrapper .MuiButtonBase-root { margin-right: var(--env-var-spacing-1); diff --git a/Client/src/Components/Inputs/Field/index.css b/Client/src/Components/Inputs/Field/index.css index 3e2435694..8c86f9e30 100644 --- a/Client/src/Components/Inputs/Field/index.css +++ b/Client/src/Components/Inputs/Field/index.css @@ -12,13 +12,13 @@ .field h5.MuiTypography-root, .field input, .field textarea { - color: var(--env-var-color-5); + color: var(--secondary-color); } .field h3.MuiTypography-root { font-weight: 500; } .field h3.MuiTypography-root span.field-required { - color: var(--env-var-color-19); + color: var(--error-color); margin-left: 2px; } .field h3.MuiTypography-root span.field-optional { @@ -53,7 +53,7 @@ margin-right: 5px; } .field .MuiInputBase-root .MuiInputAdornment-root .MuiButtonBase-root:hover { - border-color: var(--env-var-color-29); + border-color: var(--border-color-dark); } .field input { height: 100%; @@ -63,20 +63,20 @@ padding: var(--env-var-spacing-1-minus); } .field .MuiOutlinedInput-root fieldset { - border-color: var(--env-var-color-29); + border-color: var(--border-color-dark); border-radius: var(--env-var-radius-1); } .field:not(:has(.Mui-disabled)):not(:has(.input-error)) .MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus)) fieldset { - border-color: var(--env-var-color-29); + border-color: var(--border-color-dark); } .field .input-error { - color: var(--env-var-color-24); + color: var(--error-color); opacity: 0.8; } .field:has(.input-error) .MuiOutlinedInput-root fieldset { - border-color: var(--env-var-color-19); + border-color: var(--error-color); } .register-page .field .MuiOutlinedInput-root fieldset, diff --git a/Client/src/Components/Inputs/Image/index.css b/Client/src/Components/Inputs/Image/index.css index 96a730bf0..4c427c9de 100644 --- a/Client/src/Components/Inputs/Image/index.css +++ b/Client/src/Components/Inputs/Image/index.css @@ -2,7 +2,7 @@ .image-field-wrapper p.MuiTypography-root, .image-field-wrapper + p.MuiTypography-root, .MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root { - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root { font-weight: 600; @@ -24,6 +24,6 @@ font-size: var(--env-var-font-size-small-plus); } .image-field-wrapper h2.MuiTypography-root span { - color: var(--env-var-color-3); + color: var(--theme-main); font-weight: 500; } diff --git a/Client/src/Components/Inputs/Select/index.css b/Client/src/Components/Inputs/Select/index.css index be1a92503..a760010bf 100644 --- a/Client/src/Components/Inputs/Select/index.css +++ b/Client/src/Components/Inputs/Select/index.css @@ -13,21 +13,21 @@ .MuiMenu-List .MuiMenuItem-root, .select-wrapper h3.MuiTypography-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); } .select-wrapper h3.MuiTypography-root { font-weight: 500; } .MuiInputBase-root:has(> .MuiSelect-select) fieldset { - border-color: var(--env-var-color-29); + border-color: var(--border-color-dark); } .MuiInputBase-root:not(.Mui-focused):has(> .MuiSelect-select):hover fieldset { - border-color: var(--env-var-color-29); + border-color: var(--border-color-dark); } .select-dropdown.MuiPaper-root { box-shadow: var(--env-var-shadow-1); - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); } .select-dropdown .MuiList-root { @@ -35,12 +35,12 @@ } .select-dropdown li { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); padding: 5px 8px; border-radius: var(--env-var-radius-1); } .select-dropdown li.Mui-selected, .select-dropdown li.Mui-selected.Mui-focusVisible, .select-dropdown li.Mui-selected:hover { - background-color: #f4f4f4; + background-color: var(--primary-bg-fill); } diff --git a/Client/src/Components/ProgressBars/index.css b/Client/src/Components/ProgressBars/index.css index 5ba1939da..214a409a8 100644 --- a/Client/src/Components/ProgressBars/index.css +++ b/Client/src/Components/ProgressBars/index.css @@ -4,7 +4,7 @@ } .progress-bar-container h2.MuiTypography-root, .progress-bar-container p.MuiTypography-root { - color: var(--env-var-color-2); + color: var(--secondary-color-light); font-size: var(--env-var-font-size-medium); } .progress-bar-container p.MuiTypography-root { @@ -17,16 +17,16 @@ padding-left: 2px; } .progress-bar-container:has(p.input-error){ - border-color: var(--env-var-color-19); - background-color: var(--env-var-color-21); + border-color: var(--error-color); + background-color: var(--error-bg); padding: 8px var(--env-var-spacing-1-plus); } .progress-bar-container p.input-error{ - color: var(--env-var-color-24); + color: var(--error-color); opacity: 0.8; } .progress-bar-container:has(p.input-error)>.MuiStack-root>svg{ - fill: var(--env-var-color-24); + fill: var(--error-color); width: 20px; height: 20px; } diff --git a/Client/src/Components/RadioButton/index.css b/Client/src/Components/RadioButton/index.css index 353bbdf55..3f6fba7bb 100644 --- a/Client/src/Components/RadioButton/index.css +++ b/Client/src/Components/RadioButton/index.css @@ -6,7 +6,7 @@ } .create-monitor-form .custom-radio-button.MuiFormControlLabel-root:hover, .configure-monitor .custom-radio-button.MuiFormControlLabel-root:hover { - background-color: var(--env-var-color-15); + background-color: var(--unresolved-bg); } .custom-radio-button.MuiFormControlLabel-root .MuiButtonBase-root { diff --git a/Client/src/Components/Sidebar/index.css b/Client/src/Components/Sidebar/index.css index 4c253c781..0996b3f71 100644 --- a/Client/src/Components/Sidebar/index.css +++ b/Client/src/Components/Sidebar/index.css @@ -1,7 +1,7 @@ aside .selected-path, .sidebar-popup .selected-path, aside .MuiListItemButton-root:hover { - background-color: var(--env-var-color-13); + background-color: var(--primary-bg-accent); } aside .MuiList-root svg { width: 20px; @@ -9,7 +9,7 @@ aside .MuiList-root svg { opacity: 0.9; } aside .MuiList-root svg path { - stroke: var(--env-var-color-2); + stroke: var(--secondary-color-light); } aside span.MuiTypography-root { font-size: var(--env-var-font-size-medium); @@ -29,7 +29,7 @@ aside .MuiListSubheader-root { aside span.MuiTypography-root, aside p.MuiTypography-root, aside .MuiListSubheader-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } aside p.MuiTypography-root { font-size: var(--env-var-font-size-small); @@ -48,7 +48,7 @@ aside .MuiCollapse-wrapperInner .MuiList-root > .MuiListItemButton-root { position: relative; } aside .MuiDivider-root { - border-color: var(--env-var-color-6); + border-color: var(--border-color); } aside .MuiCollapse-wrapperInner @@ -60,7 +60,7 @@ aside top: 0; height: 100%; width: 100%; - border-left: solid 1px var(--env-var-color-5); + border-left: solid 1px var(--secondary-color); opacity: 0.2; } aside @@ -90,13 +90,13 @@ aside .MuiCollapse-wrapperInner .MuiList-root > .selected-path.MuiListItemButton-root::after { - background-color: var(--env-var-color-2); + background-color: var(--secondary-color-light); transform: scale(1.2); } .sidebar-popup .MuiPaper-root { box-shadow: var(--env-var-shadow-1); - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); gap: 1px; } @@ -106,12 +106,12 @@ aside } .sidebar-popup li.MuiButtonBase-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); padding: 5px 8px; border-radius: var(--env-var-radius-1); } .sidebar-popup li.MuiButtonBase-root:hover { - background-color: var(--env-var-color-13); + background-color: var(--primary-bg-accent); } .sidebar-popup li.MuiButtonBase-root:has(.MuiBox-root):hover { background-color: white; @@ -121,7 +121,7 @@ aside } .sidebar-popup .MuiModal-root p.MuiTypography-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .sidebar-popup svg { width: 16px; diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index a0393977d..cac7adc62 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -90,7 +90,7 @@ const TeamPanel = () => { > {member.firstName + " " + member.lastName} - + Created {new Date(member.createdAt).toLocaleDateString()} diff --git a/Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx b/Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx deleted file mode 100644 index 1b1fb8b4d..000000000 --- a/Client/src/Components/Tooltips/TooltipWithTail/TooltipWithTail.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import "./tooltipWithTail.css"; -import React from "react"; -import { styled } from "@mui/material/styles"; -import Tooltip, { tooltipClasses } from "@mui/material/Tooltip"; -import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; - -const CustomizedTooltip = styled( - ({ className, placement, arrow, ...props }) => ( - - ) -)(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: "black", - }, - [`& .${tooltipClasses.arrow}`]: { - color: "black", - }, -})); - -function TooltipWithTail({ placement, arrow = false, title, text }) { - return ( -
- - {title &&
{title}
} -
{text}
- - } - className="tooltip-holder" - > - -
-
- ); -} - -export default TooltipWithTail; diff --git a/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css b/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css deleted file mode 100644 index 3efe67643..000000000 --- a/Client/src/Components/Tooltips/TooltipWithTail/tooltipWithTail.css +++ /dev/null @@ -1,49 +0,0 @@ -:root { - --env-var-color-1: #101828; - --env-var-color-2: #475467; - --env-var-color-3: #1570ef; - - --env-var-color-4: #d0d5dd; - --env-var-color-5: #344054; - --env-var-color-6: #eaecf0; - --env-var-color-7: #7f56d9; - --env-var-color-8: #fff; - --env-var-color-9: #f2f2f2; - --env-var-color-10: #175cd3; - - --env-var-radius-1: 4px; - --env-var-radius-2: 8px; - - --env-var-width-1: 100vw; - --env-var-width-2: 360px; - - --env-var-height-1: 100vh; - - --env-var-spacing-1: 12px; - --env-var-spacing-2: 24px; - --env-var-spacing-3: 32px; - --env-var-spacing-4: 40px; - - --env-var-font-size-small: 11px; - --env-var-font-size-medium: 13px; - --env-var-font-size-medium-plus: 14px; - --env-var-font-size-large: 16px; - --env-var-font-size-xlarge: 30px; - - --env-var-img-width-1: 20px; - - --env-var-default-1: 24px; - --env-var-default-2: 40px; -} - -.tooltip-title { - font-size: var(--env-var-font-size-medium); - font-weight: bold; - margin: 5px; -} - -.tooltip-description { - font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-4); - margin: 5px; -} diff --git a/Client/src/Layouts/HomeLayout/index.css b/Client/src/Layouts/HomeLayout/index.css index e85a6362b..75a1925f3 100644 --- a/Client/src/Layouts/HomeLayout/index.css +++ b/Client/src/Layouts/HomeLayout/index.css @@ -1,5 +1,5 @@ #root:has(.home-layout) { - background-color: var(--env-var-color-30); + background-color: var(--secondary-bg); } .home-layout { @@ -20,7 +20,7 @@ height: calc(100vh - var(--env-var-spacing-2) * 2); max-width: var(--env-var-side-bar-width); - border: 1px solid var(--env-var-color-6); + border: 1px solid var(--border-color); border-radius: var(--env-var-radius-1); background-color: var(--env-var-color-8); @@ -33,10 +33,10 @@ } .home-layout > div:has(> [class*="fallback__"]) { - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); border-style: dashed; - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); overflow: hidden; position: relative; } diff --git a/Client/src/Pages/Account/index.css b/Client/src/Pages/Account/index.css index 594b7b839..82d5fc991 100644 --- a/Client/src/Pages/Account/index.css +++ b/Client/src/Pages/Account/index.css @@ -10,7 +10,7 @@ .account p.MuiTypography-root, .account input, .account .MuiSelect-select { - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .account h1.MuiTypography-root { font-weight: 600; @@ -21,7 +21,7 @@ } .account .MuiDivider-root, .account .MuiButtonGroup-root button { - border-color: var(--env-var-color-16); + border-color: var(--border-color); } .account button:not(.MuiIconButton-root) { height: 34px; @@ -43,8 +43,9 @@ top: 100%; } -.account .MuiTable-root .MuiTableBody-root .MuiTableCell-root { - color: var(--env-var-color-25); +.account .MuiTable-root .MuiTableBody-root .MuiTableCell-root, +.account .MuiTable-root p + p { + color: var(--secondary-color-light-accent); } .account .MuiTableBody-root .MuiTableCell-root { padding: var(--env-var-spacing-1-plus) var(--env-var-spacing-2); diff --git a/Client/src/Pages/Auth/index.css b/Client/src/Pages/Auth/index.css index 979ae191c..bf95174a8 100644 --- a/Client/src/Pages/Auth/index.css +++ b/Client/src/Pages/Auth/index.css @@ -5,7 +5,7 @@ .auth h1 { font-size: var(--env-var-font-size-xlarge); font-weight: 600; - color: var(--env-var-color-3); + color: var(--theme-main); } .auth button:not(.MuiIconButton-root), .auth p, @@ -14,15 +14,15 @@ font-size: var(--env-var-font-size-medium-plus); } .auth p { - color: var(--env-var-color-2-light); + color: var(--secondary-color-light-accent); } .auth .field h3.MuiTypography-root, .auth .field input { - color: var(--env-var-color-5); + color: var(--secondary-color); } .auth p + span { - color: var(--env-var-color-3); + color: var(--theme-main); opacity: 0.8; cursor: pointer; transition: opacity 300ms ease-in; @@ -34,7 +34,7 @@ transition: all 200ms; } .auth p > span:not(.email-sent-to):hover { - color: var(--env-var-color-2); + color: var(--secondary-color-light); text-underline-offset: 4px; } .auth p + span:hover { diff --git a/Client/src/Pages/Incidents/index.css b/Client/src/Pages/Incidents/index.css index 286552d22..b434d5e63 100644 --- a/Client/src/Pages/Incidents/index.css +++ b/Client/src/Pages/Incidents/index.css @@ -1,6 +1,6 @@ .incidents h1.MuiTypography-root, .incidents p.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .incidents h1.MuiTypography-root { font-size: var(--env-var-font-size-large); @@ -12,14 +12,14 @@ } .incidents button.MuiButtonBase-root { height: 34px; - border-color: var(--env-var-color-16); + border-color: var(--border-color); } .incidents .MuiPagination-root { - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); } .incidents > .MuiBox-root { - background-color: var(--env-var-color-8); - border: solid 1px var(--env-var-color-6); + background-color: var(--primary-bg); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); padding: 60px; } diff --git a/Client/src/Pages/Integrations/index.css b/Client/src/Pages/Integrations/index.css index c05b44212..1258b69af 100644 --- a/Client/src/Pages/Integrations/index.css +++ b/Client/src/Pages/Integrations/index.css @@ -1,6 +1,6 @@ .integrations h1.MuiTypography-root, .integrations p.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .integrations h1.MuiTypography-root { font-size: var(--env-var-font-size-large); @@ -14,7 +14,7 @@ } .integrations .MuiGrid-item > .MuiStack-root { - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); } diff --git a/Client/src/Pages/Maintenance/index.css b/Client/src/Pages/Maintenance/index.css index f26a48767..46ba8b0fa 100644 --- a/Client/src/Pages/Maintenance/index.css +++ b/Client/src/Pages/Maintenance/index.css @@ -13,7 +13,7 @@ } .maintenance-title { - color: var(--env-var-color-2); + color: var(--secondary-color-light); font-size: 16px; font-weight: bold; margin-top: 40px; @@ -22,7 +22,7 @@ .checklist-item { font-size: 13px; - color: var(--env-var-color-2); + color: var(--secondary-color-light); display: flex; margin-bottom: 10px; } diff --git a/Client/src/Pages/Monitors/Configure/index.css b/Client/src/Pages/Monitors/Configure/index.css index ec140887c..1f46d12d3 100644 --- a/Client/src/Pages/Monitors/Configure/index.css +++ b/Client/src/Pages/Monitors/Configure/index.css @@ -1,6 +1,6 @@ .configure-monitor h1.MuiTypography-root { font-size: var(--env-var-font-size-large-plus); - color: var(--env-var-color-1); + color: var(--primary-color); font-weight: 600; } .configure-monitor h2.MuiTypography-root { @@ -10,10 +10,10 @@ .configure-monitor h2.MuiTypography-root, .configure-monitor .config-box p.MuiTypography-root, .configure-monitor .MuiSelect-select { - color: var(--env-var-color-5); + color: var(--secondary-color); } .configure-monitor .MuiModal-root h2.MuiTypography-root { - color: var(--env-var-color-1); + color: var(--primary-color); } .configure-monitor p.MuiTypography-root, .configure-monitor .MuiSelect-select { @@ -33,9 +33,9 @@ height: var(--env-var-height-2); } .configure-monitor .config-box { - border: 1px solid var(--env-var-color-16); + border: 1px solid var(--border-color); border-radius: var(--env-var-radius-1); - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); } .configure-monitor .config-box > .MuiBox-root, .configure-monitor .config-box > .MuiStack-root { @@ -45,7 +45,7 @@ } .configure-monitor .config-box > *:first-child { flex: 0.7; - border-right: solid 1px var(--env-var-color-16); + border-right: solid 1px var(--border-color); } .configure-monitor .MuiStack-root:has(span.MuiTypography-root.input-error) { position: relative; @@ -55,7 +55,7 @@ top: 100%; } .configure-monitor .MuiInputBase-root:has(> .Mui-disabled) { - background-color: var(--env-var-color-13); + background-color: var(--primary-bg-accent); } .MuiInputBase-root:has(#monitor-interval) { @@ -69,7 +69,7 @@ align-items: center; } .MuiInputBase-root:not(.Mui-focused):has(#monitor-interval):hover fieldset { - border-color: var(--env-var-color-29); + border-color: var(--border-color-dark); } body:has(.configure-monitor) .select-dropdown .MuiMenuItem-root, diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx index bd2a26df0..25d2698cd 100644 --- a/Client/src/Pages/Monitors/Configure/index.jsx +++ b/Client/src/Pages/Monitors/Configure/index.jsx @@ -249,8 +249,8 @@ const Configure = () => { lineHeight={theme.gap.large} sx={{ color: monitor?.status - ? "var(--env-var-color-17)" - : "var(--env-var-color-24)", + ? "var(--success-color)" + : "var(--error-color)", }} > Your site is {monitor?.status ? "up" : "down"}. diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.css b/Client/src/Pages/Monitors/CreateMonitor/index.css index 2a1b5a2a6..3e5571675 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.css +++ b/Client/src/Pages/Monitors/CreateMonitor/index.css @@ -1,6 +1,6 @@ .create-monitor h1.MuiTypography-root { font-size: var(--env-var-font-size-large-plus); - color: var(--env-var-color-1); + color: var(--primary-color); font-weight: 500; } .create-monitor h2.MuiTypography-root { @@ -12,11 +12,11 @@ font-size: var(--env-var-font-size-medium); } .create-monitor h2.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .create-monitor h6.MuiTypography-root, .create-monitor p.MuiTypography-root { - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .create-monitor h6.MuiTypography-root, .create-monitor .MuiBox-root .field + p.MuiTypography-root { @@ -30,7 +30,7 @@ position: relative; } .create-monitor .error-container p.MuiTypography-root.input-error { - color: var(--env-var-color-24); + color: var(--error-color); opacity: 0.8; position: absolute; top: 0; @@ -44,9 +44,9 @@ } .create-monitor .config-box { flex-direction: row; - border: 1px solid var(--env-var-color-16); + border: 1px solid var(--border-color); border-radius: var(--env-var-radius-1); - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); } .create-monitor .config-box > .MuiBox-root, .create-monitor .config-box > .MuiStack-root { @@ -56,7 +56,7 @@ } .create-monitor .config-box > *:first-child { flex: 0.7; - border-right: solid 1px var(--env-var-color-16); + border-right: solid 1px var(--border-color); } .create-monitor .MuiStack-root .MuiButtonGroup-root button { diff --git a/Client/src/Pages/Monitors/index.css b/Client/src/Pages/Monitors/index.css index 71eb2c755..e0c111036 100644 --- a/Client/src/Pages/Monitors/index.css +++ b/Client/src/Pages/Monitors/index.css @@ -1,16 +1,16 @@ .monitors h1.MuiTypography-root { font-size: var(--env-var-font-size-large-plus); - color: var(--env-var-color-1); + color: var(--primary-color); font-weight: 500; } .monitors h2.MuiTypography-root { font-size: var(--env-var-font-size-large); - color: var(--env-var-color-5); + color: var(--secondary-color); font-weight: 500; } .monitors p.MuiTypography-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); } .monitors h1.MuiTypography-root + p.MuiTypography-root { font-size: var(--env-var-font-size-medium-plus); @@ -28,19 +28,19 @@ padding: 5px; min-width: 25px; min-height: 25px; - background-color: var(--env-var-color-15); - border: 1px solid var(--env-var-color-6); + background-color: var(--unresolved-bg); + border: 1px solid var(--border-color); border-radius: 50%; font-size: var(--env-var-font-size-medium); font-weight: 500; - color: var(--env-var-color-1); + color: var(--primary-color); margin-left: 10px; line-height: 0.8; } body:has(.monitors) .actions-menu .MuiPaper-root { box-shadow: var(--env-var-shadow-1); - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); gap: 1px; } @@ -50,14 +50,14 @@ body:has(.monitors) .actions-menu .MuiList-root { } body:has(.monitors) .actions-menu li.MuiButtonBase-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); padding: 5px 8px; border-radius: var(--env-var-radius-1); } body:has(.monitors) .actions-menu li.MuiButtonBase-root:last-of-type { - color: var(--env-var-color-26); + color: var(--error-color); } body:has(.monitors) .actions-menu .MuiModal-root p.MuiTypography-root { font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-2); + color: var(--secondary-color-light); } diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index b935231d6..44101b332 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -448,8 +448,8 @@ const Monitors = () => { percentage: 100, percentageColor: monitor.status === true - ? "var(--env-var-color-17)" - : "var(--env-var-color-19)", + ? "var(--success-color)" + : "var(--error-color)", status: monitor.status === true ? "up" : "down", }; diff --git a/Client/src/Pages/NotFound/index.css b/Client/src/Pages/NotFound/index.css index 621172386..3d7c48aae 100644 --- a/Client/src/Pages/NotFound/index.css +++ b/Client/src/Pages/NotFound/index.css @@ -11,5 +11,5 @@ } .not-found-page h1, .not-found-page p { - color: var(--env-var-color-5); + color: var(--secondary-color); } diff --git a/Client/src/Pages/PageSpeed/Configure/index.css b/Client/src/Pages/PageSpeed/Configure/index.css index 408e2d639..140d37887 100644 --- a/Client/src/Pages/PageSpeed/Configure/index.css +++ b/Client/src/Pages/PageSpeed/Configure/index.css @@ -1,6 +1,6 @@ .configure-pagespeed form > .MuiStack-root:nth-child(2) { - background-color: var(--env-var-color-8); - border: solid 1px var(--env-var-color-6); + background-color: var(--primary-bg); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); padding: var(--env-var-font-size-large-plus) var(--env-var-font-size-xlarge); } @@ -9,14 +9,14 @@ } .configure-pagespeed h1.MuiTypography-root, .configure-pagespeed h2.MuiTypography-root { - color: var(--env-var-color-1); + color: var(--primary-color); } .configure-pagespeed span.MuiTypography-root { font-size: var(--env-var-font-size-small-plus); } .configure-pagespeed p.MuiTypography-root, .configure-pagespeed h3.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .configure-pagespeed h1.MuiTypography-root, .configure-pagespeed h3.MuiTypography-root, @@ -39,7 +39,7 @@ margin-bottom: 1px; } .configure-pagespeed .MuiInputBase-root:has(> .Mui-disabled) { - background-color: var(--env-var-color-13); + background-color: var(--primary-bg-accent); } /* to be removed */ .configure-pagespeed .section-disabled { diff --git a/Client/src/Pages/PageSpeed/Configure/index.jsx b/Client/src/Pages/PageSpeed/Configure/index.jsx index 83484de7e..21fc32fed 100644 --- a/Client/src/Pages/PageSpeed/Configure/index.jsx +++ b/Client/src/Pages/PageSpeed/Configure/index.jsx @@ -187,8 +187,8 @@ const PageSpeedConfigure = () => { component="span" sx={{ color: monitor?.status - ? "var(--env-var-color-17)" - : "var(--env-var-color-24)", + ? "var(--success-color)" + : "var(--error-color)", }} > Your pagespeed monitor is {monitor?.status ? "live" : "down"}. diff --git a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css index 42ca0ffa8..f0581565f 100644 --- a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css +++ b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css @@ -1,16 +1,16 @@ .create-page-speed form > .MuiStack-root:not(:last-of-type) { - background-color: var(--env-var-color-8); - border: solid 1px var(--env-var-color-6); + background-color: var(--primary-bg); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); padding: var(--env-var-font-size-large-plus) var(--env-var-font-size-xlarge); } .create-page-speed h1.MuiTypography-root { font-size: 22px; - color: var(--env-var-color-1); + color: var(--primary-bg); } .create-page-speed p.MuiTypography-root, .create-page-speed h3.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .create-page-speed h1.MuiTypography-root, .create-page-speed h3.MuiTypography-root { diff --git a/Client/src/Pages/PageSpeed/Details/index.css b/Client/src/Pages/PageSpeed/Details/index.css index 357177c78..147c1d7d9 100644 --- a/Client/src/Pages/PageSpeed/Details/index.css +++ b/Client/src/Pages/PageSpeed/Details/index.css @@ -1,6 +1,6 @@ .page-speed-details h1 { font-size: var(--env-var-font-size-large-plus); - color: var(--env-var-color-1); + color: var(--primary-color); } .page-speed-details h2, .page-speed-details h6 { @@ -18,10 +18,10 @@ .page-speed-details h2, .page-speed-details h4, .page-speed-details p { - color: var(--env-var-color-5); + color: var(--secondary-color); } .page-speed-details h6 { - color: var(--env-var-color-3); + color: var(--theme-main); line-height: 22px; } .page-speed-details h1, @@ -36,9 +36,9 @@ .page-speed-details .stat-box, .page-speed-details > .MuiStack-root:last-child, .page-speed-details > .MuiBox-root:nth-last-child(3) { - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); min-width: 200px; } .page-speed-details .stat-box { diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 2e5cc12a7..ba24c88df 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -342,7 +342,7 @@ const PageSpeedDetails = () => {
Your pagespeed monitor is live. diff --git a/Client/src/Pages/PageSpeed/index.css b/Client/src/Pages/PageSpeed/index.css index b910c1645..904aa4e0f 100644 --- a/Client/src/Pages/PageSpeed/index.css +++ b/Client/src/Pages/PageSpeed/index.css @@ -1,10 +1,10 @@ .page-speed h1.MuiTypography-root, .page-speed span.MuiTypography-root, .page-speed p.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .page-speed h2.MuiTypography-root { - color: var(--env-var-color-3); + color: var(--theme-main); line-height: 1.1; } .page-speed h1.MuiTypography-root, @@ -20,9 +20,9 @@ font-size: var(--env-var-font-size-small-plus); } .page-speed .MuiGrid-item > .MuiStack-root { - border: solid 1px var(--env-var-color-6); + border: solid 1px var(--border-color); border-radius: var(--env-var-radius-1); - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); } .page-speed .label { padding: 7px; diff --git a/Client/src/Pages/PageSpeed/index.jsx b/Client/src/Pages/PageSpeed/index.jsx index 368ae2062..dc327ad5f 100644 --- a/Client/src/Pages/PageSpeed/index.jsx +++ b/Client/src/Pages/PageSpeed/index.jsx @@ -22,7 +22,11 @@ const Card = ({ data }) => { item lg={6} flexGrow={1} - sx={{ "&:hover > .MuiStack-root": { backgroundColor: "#f9fafb" } }} + sx={{ + "&:hover > .MuiStack-root": { + backgroundColor: "var(--primary-bg-accent)", + }, + }} > Date: Mon, 26 Aug 2024 17:23:26 -0400 Subject: [PATCH 008/101] =?UTF-8?q?=EF=BF=BD=20Removed=20old=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/index.css | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/Client/src/index.css b/Client/src/index.css index 21c252f54..717b3c16c 100644 --- a/Client/src/index.css +++ b/Client/src/index.css @@ -42,45 +42,7 @@ --unresolved-color-light: #e2eaf7; --unresolved-bg: #f2f4f7; - --env-var-color-0: #fff; - --env-var-color-1: #1c2130; - --env-var-color-2: #475467; - --env-var-color-2-light: #838c99; - --env-var-color-3: #1570ef; - - --env-var-color-4: #d0d5dd; - --env-var-color-5: #344054; - --env-var-color-6: #eaecf0; - --env-var-color-7: #7f56d9; - --env-var-color-8: #fff; - --env-var-color-9: #f2f2f2; - --env-var-color-10: #175cd3; - --env-var-color-11: #5d6b98; - --env-var-color-12: #182230; - --env-var-color-13: #f9fafb; - --env-var-color-14: #98a2b3; - --env-var-color-15: #f2f4f7; - --env-var-color-16: #ebebeb; - --env-var-color-17: #079455; - --env-var-color-18: #ffc301; - --env-var-color-19: #f04438; - --env-var-color-20: #ecfdf3; - --env-var-color-21: hsla(0, 100%, 52%, 0.06); - --env-var-color-22: #4e5ba6; - --env-var-color-23: #17b26a; - --env-var-color-24: #d92d20; - --env-var-color-25: #667085; - --env-var-color-26: #ff1818; - - --env-var-color-27: #fecf60; - --lighter-env-var-color-27: rgba(254, 207, 96, 0.1); - --env-var-color-28: #f79009; - --env-var-color-29: #d0d5dd; - --env-var-color-30: #fcfcfd; - --env-var-color-31: #1a1919; - --env-var-color-32: #f5f5f5; - --env-var-color-33: rgba(83, 83, 83, 0.1); - + /* */ --env-var-radius-1: 4px; --env-var-radius-2: 8px; From 20b2b089a42877e61d78bf979f2f61d42ec1662c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 15:21:06 -0700 Subject: [PATCH 009/101] Removed awaits for emails, added redirect if invite verify fails --- Client/src/Pages/Auth/Register/Register.jsx | 3 +- Server/controllers/authController.js | 46 ++++++++++++++------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 39a5fdafd..4423189af 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -451,14 +451,13 @@ const Register = ({ isSuperAdmin }) => { useEffect(() => { const fetchInvite = async () => { - console.log("FETCHING"); if (token !== undefined) { try { const res = await networkService.verifyInvitationToken(token); const { role, email, teamId } = res.data.data; setForm({ ...form, email, role, teamId }); } catch (error) { - logger.error(error); + navigate("/register", { replace: true }); } } }; diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 720dcd08c..955d590e7 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -90,12 +90,20 @@ const registerController = async (req, res, next) => { const token = issueToken(userForToken); - await req.emailService.buildAndSendEmail( - "welcomeEmailTemplate", - { name: newUser.firstName }, - newUser.email, - "Welcome to Uptime Monitor" - ); + req.emailService + .buildAndSendEmail( + "welcomeEmailTemplate", + { name: newUser.firstName }, + newUser.email, + "Welcome to Uptime Monitor" + ) + .catch((error) => { + logger.error("Error sending welcome email", { + service: SERVICE_NAME, + error: error.message, + }); + }); + return res.status(200).json({ success: true, msg: successMessages.AUTH_CREATE_USER, @@ -241,15 +249,22 @@ const inviteController = async (req, res, next) => { } const inviteToken = await req.db.requestInviteToken(req, res); - await req.emailService.buildAndSendEmail( - "employeeActivationTemplate", - { - name: firstname, - link: `${process.env.CLIENT_HOST}/register/${inviteToken.token}`, - }, - req.body.email, - "Welcome to Uptime Monitor" - ); + req.emailService + .buildAndSendEmail( + "employeeActivationTemplate", + { + name: firstname, + link: `${process.env.CLIENT_HOST}/register/${inviteToken.token}`, + }, + req.body.email, + "Welcome to Uptime Monitor" + ) + .catch((error) => { + logger.error("Error sending invite email", { + service: SERVICE_NAME, + error: error.message, + }); + }); return res .status(200) @@ -275,7 +290,6 @@ const inviteVerifyController = async (req, res, next) => { try { const invite = await req.db.getInviteToken(req, res); - res .status(200) .json({ status: "success", msg: "Invite verified", data: invite }); From 32101b4c2f40f43bcf43dfeab8a3f179739305aa Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 15:27:05 -0700 Subject: [PATCH 010/101] Initialize User model to creat index --- Server/models/user.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Server/models/user.js b/Server/models/user.js index 977cabc15..e05e74037 100644 --- a/Server/models/user.js +++ b/Server/models/user.js @@ -70,4 +70,10 @@ UserSchema.methods.comparePassword = async function (submittedPassword) { return res; }; +const User = mongoose.model("User", UserSchema); + +User.init().then(() => { + console.log("User model initialized"); +}); + module.exports = mongoose.model("User", UserSchema); From 48bd6ec95a8e1591783996b1b51bf8f947ec55ef Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 15:34:50 -0700 Subject: [PATCH 011/101] Updated verifyAdmin middleware --- Server/middleware/verifyAdmin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/middleware/verifyAdmin.js b/Server/middleware/verifyAdmin.js index 7ef123451..94f529d35 100644 --- a/Server/middleware/verifyAdmin.js +++ b/Server/middleware/verifyAdmin.js @@ -42,7 +42,7 @@ const verifyAdmin = (req, res, next) => { .json({ success: false, msg: errorMessages.INVALID_AUTH_TOKEN }); } - if (decoded.role.includes("admin") === false) { + if (decoded.role.includes("superadmin") === false) { logger.error(errorMessages.INVALID_AUTH_TOKEN, { service: SERVICE_NAME, }); From bad0039757e1118b63ce4f79db619851cfa9bd5a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 15:36:53 -0700 Subject: [PATCH 012/101] renamed verifyAdmin to verifySuperAdmin --- Server/middleware/{verifyAdmin.js => verifySuperAdmin.js} | 4 ++-- Server/routes/authRoute.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename Server/middleware/{verifyAdmin.js => verifySuperAdmin.js} (94%) diff --git a/Server/middleware/verifyAdmin.js b/Server/middleware/verifySuperAdmin.js similarity index 94% rename from Server/middleware/verifyAdmin.js rename to Server/middleware/verifySuperAdmin.js index 94f529d35..82401b3b7 100644 --- a/Server/middleware/verifyAdmin.js +++ b/Server/middleware/verifySuperAdmin.js @@ -11,7 +11,7 @@ const { errorMessages } = require("../utils/messages"); * @param {express.NextFunction} next * @returns {express.Response} */ -const verifyAdmin = (req, res, next) => { +const verifySuperAdmin = (req, res, next) => { const token = req.headers["authorization"]; // Make sure a token is provided if (!token) { @@ -54,4 +54,4 @@ const verifyAdmin = (req, res, next) => { }); }; -module.exports = { verifyAdmin }; +module.exports = { verifySuperAdmin }; diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 589c0f1ac..e78dd5e52 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -1,6 +1,6 @@ const router = require("express").Router(); const { verifyJWT } = require("../middleware/verifyJWT"); -const { verifyAdmin } = require("../middleware/verifyAdmin"); +const { verifySuperAdmin } = require("../middleware/verifySuperAdmin"); const { verifyOwnership } = require("../middleware/verifyOwnership"); const multer = require("multer"); const upload = multer(); @@ -31,7 +31,7 @@ router.put( userEditController ); router.get("/users/superadmin", checkSuperadminController); -router.get("/users", verifyJWT, verifyAdmin, getAllUsersController); +router.get("/users", verifyJWT, verifySuperAdmin, getAllUsersController); router.delete( "/user/:userId", verifyJWT, From e72212a467926f6b7e55143a127f2384633a49d1 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Mon, 26 Aug 2024 19:54:48 -0400 Subject: [PATCH 013/101] Reconfigured theme colors --- Client/src/Utils/Theme.js | 45 +++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/Client/src/Utils/Theme.js b/Client/src/Utils/Theme.js index c4faa2d1f..7b6535bfa 100644 --- a/Client/src/Utils/Theme.js +++ b/Client/src/Utils/Theme.js @@ -6,13 +6,6 @@ const secondaryMain = "#475467"; const tertiaryMain = "#475467"; const tertiaryLinkHover = "#eff8ff"; -// Label Colors -const labelOrange = "#F79009"; -const labelGray = "#475467"; -const labelPurple = "#6941C6"; -const labelGreen = "#067647"; -const labelRed = "#F04438"; - // Section colors const sectionBorder = "#D0D5DD"; const sectionBg = "#F8F9F8"; @@ -39,6 +32,25 @@ const fontFamilyDefault = const theme = createTheme({ typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, palette: { + common: { main: "#1570ef" }, + text: { + primary: "#1c2130", + secondary: "#344054", + tertiary: "#475467", + accent: "#838c99", + }, + background: { + primary: "#FFFFFF", + secondary: "#FCFCFD", + fill: "#F4F4F4", + accent: "#f9fafb", + }, + border: { light: "#eaecf0", dark: "#d0d5dd" }, + success: { main: "#17b26a", light: "#d4f4e1", bg: "#ecfdf3" }, + error: { main: "#f04438", light: "#fbd1d1", bg: "#f9eced" }, + warning: { main: "#fdb022", light: "#fffcf5", bg: "#ffecbc" }, + unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, + other: {}, primary: { main: primaryMain, }, @@ -49,21 +61,6 @@ const theme = createTheme({ main: tertiaryMain, linkHover: tertiaryLinkHover, }, - labelOrange: { - color: labelOrange, - }, - labelGray: { - color: labelGray, - }, - labelPurple: { - color: labelPurple, - }, - labelGreen: { - color: labelGreen, - }, - labelRed: { - color: labelRed, - }, section: { borderColor: sectionBorder, bgColor: sectionBg, @@ -85,10 +82,6 @@ const theme = createTheme({ borderThick: 2, boxShadow: shadow, }, - content: { - pX: "80px", - pY: "40px", - }, gap: { xs: "4px", small: "8px", From 3e63a3266954fa4eb77dd47d5754935ced7cd67e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 16:57:30 -0700 Subject: [PATCH 014/101] Renamed variable --- Server/db/mongo/MongoDB.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 8c1d97351..d6440ca12 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -17,8 +17,8 @@ const connect = async () => { const checkSuperadmin = async (req, res) => { try { - const admin = await UserModel.findOne({ role: "superadmin" }); - if (admin !== null) { + const superAdmin = await UserModel.findOne({ role: "superadmin" }); + if (superAdmin !== null) { return true; } return false; From 98f56248eb94e86b5290b42b6257e4dd9614352b Mon Sep 17 00:00:00 2001 From: M M Date: Mon, 26 Aug 2024 17:16:29 -0700 Subject: [PATCH 015/101] Update all areas where it says friendly name to display name. --- .../Maintenance/CreateMaintenanceWindow/index.jsx | 14 +++++++------- Client/src/Pages/Monitors/Configure/index.jsx | 2 +- Client/src/Pages/Monitors/CreateMonitor/index.jsx | 2 +- Client/src/Pages/PageSpeed/Configure/index.jsx | 2 +- .../src/Pages/PageSpeed/CreatePageSpeed/index.jsx | 2 +- Client/src/Validation/validation.js | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index 9110b7a96..f97578d5a 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -62,7 +62,7 @@ const CreateNewMaintenanceWindow = () => { startTime: dayjs(), duration: "60", unit: "minutes", - friendlyName: "", + displayName: "", AddMonitors: "", }); const [errors, setErrors] = useState({}); @@ -82,7 +82,7 @@ const CreateNewMaintenanceWindow = () => { startTime: values.startTime.format("HH:mm"), duration: values.duration, unit: values.unit, - friendlyName: values.friendlyName, + displayName: values.displayName, addMonitors: values.AddMonitors, }; @@ -178,14 +178,14 @@ const CreateNewMaintenanceWindow = () => { ), }, { - title: "Friendly name", + title: "Display name", component: ( handleChange(e, "friendlyName")} - error={errors.friendlyName} + value={values.displayName} + onChange={(e) => handleChange(e, "displayName")} + error={errors.displayName} /> ), }, diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx index bd2a26df0..ebf6e3279 100644 --- a/Client/src/Pages/Monitors/Configure/index.jsx +++ b/Client/src/Pages/Monitors/Configure/index.jsx @@ -314,7 +314,7 @@ const Configure = () => { { { - Monitor friendly name + Monitor display name { Create pagespeed monitor - Monitor friendly name + Monitor display name Date: Mon, 26 Aug 2024 17:43:56 -0700 Subject: [PATCH 016/101] refactor invite to its own route and controller --- .../TabPanels/Account/TeamPanel.jsx | 9 +- Client/src/Utils/NetworkService.js | 4 +- Server/controllers/authController.js | 6 +- Server/controllers/inviteController.js | 96 +++++++++++++++++++ Server/db/mongo/modules/inviteModule.js | 40 ++++++-- Server/db/mongo/modules/userModule.js | 19 ++-- Server/index.js | 2 + Server/routes/authRoute.js | 5 - Server/routes/inviteRoute.js | 11 +++ Server/validation/joi.js | 4 +- 10 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 Server/controllers/inviteController.js create mode 100644 Server/routes/inviteRoute.js diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index a0393977d..aa218e721 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -32,6 +32,12 @@ import Select from "../../Inputs/Select"; */ const TeamPanel = () => { + const roleMap = { + superadmin: "Super admin", + admin: "Admin", + user: "Team member", + }; + const theme = useTheme(); const { authToken, user } = useSelector((state) => state.auth); @@ -78,6 +84,7 @@ const TeamPanel = () => { // { id: 4, name: "ACTION" }, ], rows: team?.map((member, idx) => { + const roles = member.role.map((role) => roleMap[role]).join(","); return { id: member._id, data: [ @@ -100,7 +107,7 @@ const TeamPanel = () => { { // TODO - Add select dropdown id: idx + 2, - data: member.role.includes("admin") ? "Administrator" : "Member", + data: roles, }, // FEATURE STILL TO BE IMPLEMENTED // { diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 97071a7aa..cd46469b4 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -327,7 +327,7 @@ class NetworkService { */ async requestInvitationToken(authToken, email, role) { return this.axiosInstance.post( - `/auth/invite`, + `/invite`, { email, role }, { headers: { Authorization: `Bearer ${authToken}` }, @@ -346,7 +346,7 @@ class NetworkService { * */ async verifyInvitationToken(token) { - return this.axiosInstance.post(`/auth/invite/verify`, { + return this.axiosInstance.post(`/invite/verify`, { token, }); } diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 955d590e7..03f7f1b66 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -1,6 +1,6 @@ const express = require("express"); const { - registerValidation, + registrationBodyValidation, loginValidation, editUserParamValidation, editUserBodyValidation, @@ -50,7 +50,7 @@ const getTokenFromHeaders = (headers) => { const registerController = async (req, res, next) => { // joi validation try { - await registerValidation.validateAsync(req.body); + await registrationBodyValidation.validateAsync(req.body); } catch (error) { error.status = 422; error.service = SERVICE_NAME; @@ -78,7 +78,7 @@ const registerController = async (req, res, next) => { // Create a new user try { - const newUser = await req.db.insertUser(req, res); + const newUser = await req.db.insertUser({ ...req.body }, req.file); logger.info(successMessages.AUTH_CREATE_USER, { service: SERVICE_NAME, userId: newUser._id, diff --git a/Server/controllers/inviteController.js b/Server/controllers/inviteController.js new file mode 100644 index 000000000..e685d0eef --- /dev/null +++ b/Server/controllers/inviteController.js @@ -0,0 +1,96 @@ +const { + inviteRoleValidation, + inviteBodyValidation, + inviteVerifciationBodyValidation, +} = require("../validation/joi"); +const logger = require("../utils/logger"); +require("dotenv").config(); +const { errorMessages, successMessages } = require("../utils/messages"); +var jwt = require("jsonwebtoken"); +const SERVICE_NAME = "inviteController"; + +const getTokenFromHeaders = (headers) => { + const authorizationHeader = headers.authorization; + if (!authorizationHeader) throw new Error("No auth headers"); + + const parts = authorizationHeader.split(" "); + if (parts.length !== 2 || parts[0] !== "Bearer") + throw new Error("Invalid auth headers"); + + return parts[1]; +}; + +const inviteController = async (req, res, next) => { + try { + // Only admins can invite + const token = getTokenFromHeaders(req.headers); + const { role, firstname, teamId } = jwt.decode(token); + req.body.teamId = teamId; + try { + await inviteRoleValidation.validateAsync({ roles: role }); + await inviteBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = + error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + + const inviteToken = await req.db.requestInviteToken({ ...req.body }); + req.emailService + .buildAndSendEmail( + "employeeActivationTemplate", + { + name: firstname, + link: `${process.env.CLIENT_HOST}/register/${inviteToken.token}`, + }, + req.body.email, + "Welcome to Uptime Monitor" + ) + .catch((error) => { + logger.error("Error sending invite email", { + service: SERVICE_NAME, + error: error.message, + }); + }); + + return res + .status(200) + .json({ success: true, msg: "Invite sent", data: inviteToken }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + +const inviteVerifyController = async (req, res, next) => { + try { + await inviteVerifciationBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = + error.details?.[0]?.message || error.message || "Validation Error"; + next(error); + return; + } + + try { + const invite = await req.db.getInviteToken(req.body.token); + res + .status(200) + .json({ status: "success", msg: "Invite verified", data: invite }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + +module.exports = { + inviteController, + inviteVerifyController, +}; diff --git a/Server/db/mongo/modules/inviteModule.js b/Server/db/mongo/modules/inviteModule.js index 73e883930..975f6f1e8 100644 --- a/Server/db/mongo/modules/inviteModule.js +++ b/Server/db/mongo/modules/inviteModule.js @@ -2,15 +2,25 @@ const InviteToken = require("../../../models/InviteToken"); const crypto = require("crypto"); const { errorMessages } = require("../../../utils/messages"); -const requestInviteToken = async (req, res) => { +/** + * Request an invite token for a user. + * + * This function deletes any existing invite tokens for the user's email, + * generates a new token, saves it, and then returns the new token. + * + * @param {Object} userData - The user data. + * @param {string} userData.email - The user's email. + * @param {mongoose.Schema.Types.ObjectId} userData.teamId - The ID of the team. + * @param {Array} userData.role - The user's role(s). + * @param {Date} [userData.expiry=Date.now] - The expiry date of the token. Defaults to the current date and time. + * @returns {Promise} The invite token. + * @throws {Error} If there is an error. + */ +const requestInviteToken = async (userData) => { try { - await InviteToken.deleteMany({ email: req.body.email }); - let inviteToken = new InviteToken({ - email: req.body.email, - role: req.body.role, - teamId: req.body.teamId, - token: crypto.randomBytes(32).toString("hex"), - }); + await InviteToken.deleteMany({ email: userData.email }); + userData.token = crypto.randomBytes(32).toString("hex"); + let inviteToken = new InviteToken(userData); await inviteToken.save(); return inviteToken; } catch (error) { @@ -18,10 +28,20 @@ const requestInviteToken = async (req, res) => { } }; -const getInviteToken = async (req, res) => { +/** + * Retrieves and deletes an invite token. + * + * This function searches for an invite token in the database and deletes it. + * If the invite token is not found, it throws an error. + * + * @param {string} token - The invite token to search for. + * @returns {Promise} The invite token data. + * @throws {Error} If the invite token is not found or there is another error. + */ +const getInviteToken = async (token) => { try { const invite = await InviteToken.findOneAndDelete({ - token: req.body.token, + token, }); if (invite === null) { throw new Error(errorMessages.AUTH_INVITE_NOT_FOUND); diff --git a/Server/db/mongo/modules/userModule.js b/Server/db/mongo/modules/userModule.js index 2df13ddc7..d29c1889b 100644 --- a/Server/db/mongo/modules/userModule.js +++ b/Server/db/mongo/modules/userModule.js @@ -14,35 +14,30 @@ const { ParseBoolean } = require("../../../utils/utils"); * @returns {Promise} * @throws {Error} */ -const insertUser = async (req, res) => { +const insertUser = async (userData, imageFile) => { try { - const userData = { ...req.body }; - if (req.file) { + if (imageFile) { // 1. Save the full size image userData.profileImage = { - data: req.file.buffer, - contentType: req.file.mimetype, + data: imageFile.buffer, + contentType: imageFile.mimetype, }; // 2. Get the avatar sized image - const avatar = await GenerateAvatarImage(req.file); + const avatar = await GenerateAvatarImage(imageFile); userData.avatarImage = avatar; } - let teamId; - // Is user superadmin? If so, create team + // Handle creating team if superadmin if (userData.role.includes("superadmin")) { const team = new TeamModel({ email: userData.email, }); - teamId = team._id; + userData.teamId = team._id; await team.save(); - } else { - teamId = userData.teamId; } const newUser = new UserModel(userData); - newUser.teamId = teamId; await newUser.save(); return await UserModel.findOne({ _id: newUser._id }) .select("-password") diff --git a/Server/index.js b/Server/index.js index 9a5f1797f..846b11e3d 100644 --- a/Server/index.js +++ b/Server/index.js @@ -7,6 +7,7 @@ const { verifyJWT } = require("./middleware/verifyJWT"); const { handleErrors } = require("./middleware/handleErrors"); const { errorMessages } = require("./utils/messages"); const authRouter = require("./routes/authRoute"); +const inviteRouter = require("./routes/inviteRoute"); const monitorRouter = require("./routes/monitorRoute"); const checkRouter = require("./routes/checkRoute"); const alertRouter = require("./routes/alertRoute"); @@ -71,6 +72,7 @@ const startApp = async () => { //routes app.use("/api/v1/auth", authRouter); + app.use("/api/v1/invite", inviteRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); app.use("/api/v1/alerts", verifyJWT, alertRouter); diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index e78dd5e52..ddecd8d39 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -17,8 +17,6 @@ const { checkSuperadminController, getAllUsersController, deleteUserController, - inviteController, - inviteVerifyController, } = require("../controllers/authController"); //Auth routes @@ -39,9 +37,6 @@ router.delete( deleteUserController ); -router.post("/invite", verifyJWT, inviteController); -router.post("/invite/verify", inviteVerifyController); - //Recovery routes router.post("/recovery/request", recoveryRequestController); router.post("/recovery/validate", validateRecoveryTokenController); diff --git a/Server/routes/inviteRoute.js b/Server/routes/inviteRoute.js new file mode 100644 index 000000000..05df2f51f --- /dev/null +++ b/Server/routes/inviteRoute.js @@ -0,0 +1,11 @@ +const router = require("express").Router(); +const { verifyJWT } = require("../middleware/verifyJWT"); +const { + inviteController, + inviteVerifyController, +} = require("../controllers/inviteController"); + +router.post("/", verifyJWT, inviteController); +router.post("/verify", inviteVerifyController); + +module.exports = router; diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 14654e1ae..a9bcb9683 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -39,7 +39,7 @@ const loginValidation = joi.object({ ), }); -const registerValidation = joi.object({ +const registrationBodyValidation = joi.object({ firstName: joi .string() .required() @@ -336,7 +336,7 @@ const getMaintenanceWindowsByMonitorIdParamValidation = joi.object({ module.exports = { roleValidatior, loginValidation, - registerValidation, + registrationBodyValidation, recoveryValidation, recoveryTokenValidation, newPasswordValidation, From ce542879e708244596c5b7c9c2998901d0bffe43 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 17:46:56 -0700 Subject: [PATCH 017/101] Add invite object for clarity --- Client/src/Pages/Auth/Register/Register.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 4423189af..8163201ae 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -454,7 +454,8 @@ const Register = ({ isSuperAdmin }) => { if (token !== undefined) { try { const res = await networkService.verifyInvitationToken(token); - const { role, email, teamId } = res.data.data; + const invite = res.data.data; + const { role, email, teamId } = invite; setForm({ ...form, email, role, teamId }); } catch (error) { navigate("/register", { replace: true }); From a02f547b2cf422195f8857de2df4c257e40bca0a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 19:15:01 -0700 Subject: [PATCH 018/101] Add teamID to monitor model --- Server/models/Monitor.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Server/models/Monitor.js b/Server/models/Monitor.js index 7d4bd17d2..525f4e4eb 100644 --- a/Server/models/Monitor.js +++ b/Server/models/Monitor.js @@ -6,6 +6,13 @@ const MonitorSchema = mongoose.Schema( type: mongoose.Schema.Types.ObjectId, ref: "User", immutable: true, + required: true, + }, + teamId: { + type: mongoose.Schema.Types.ObjectId, + ref: "Team", + immutable: true, + required: true, }, name: { type: String, From e658b4759a9ed99d312dfe4ecab76c46480b4427 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 19:25:19 -0700 Subject: [PATCH 019/101] Add teamID to monitor on creation --- Client/src/Pages/Monitors/CreateMonitor/index.jsx | 2 ++ Server/db/mongo/modules/monitorModule.js | 2 +- Server/validation/joi.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.jsx b/Client/src/Pages/Monitors/CreateMonitor/index.jsx index 28493080a..21233a264 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/Monitors/CreateMonitor/index.jsx @@ -118,9 +118,11 @@ const CreateMonitor = () => { form = { ...form, description: form.name, + teamId: user.teamId, userId: user._id, notifications: monitor.notifications, }; + console.log(form); const action = await dispatch( createUptimeMonitor({ authToken, monitor: form }) ); diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index 9778b6224..612b71a89 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -364,10 +364,10 @@ const getMonitorsByUserId = async (req, res) => { */ const createMonitor = async (req, res) => { try { + console.log(req.body); const monitor = new Monitor({ ...req.body }); // Remove notifications fom monitor as they aren't needed here monitor.notifications = undefined; - monitor.userId = req.user._id; await monitor.save(); return monitor; } catch (error) { diff --git a/Server/validation/joi.js b/Server/validation/joi.js index a9bcb9683..24e7f7b76 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -180,6 +180,7 @@ const getMonitorsByUserIdQueryValidation = joi.object({ const createMonitorBodyValidation = joi.object({ _id: joi.string(), userId: joi.string().required(), + teamId: joi.string().required(), name: joi.string().required(), description: joi.string().required(), type: joi.string().required(), From 465c1f9f9eef3a401a7980b827d8fc0e7514d480 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 26 Aug 2024 19:38:24 -0700 Subject: [PATCH 020/101] Refactor getMonitorByUserID to getMonitorByTeamID --- .../UptimeMonitors/uptimeMonitorsSlice.js | 4 ++-- Client/src/Utils/NetworkService.js | 6 +++--- Server/controllers/monitorController.js | 18 +++++++++--------- Server/db/mongo/MongoDB.js | 4 ++-- Server/db/mongo/modules/monitorModule.js | 8 ++++---- Server/routes/monitorRoute.js | 2 +- Server/validation/joi.js | 10 +++++----- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 9ab7d385b..dc9fa3c20 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -33,9 +33,9 @@ export const getUptimeMonitorsByUserId = createAsyncThunk( async (token, thunkApi) => { const user = jwtDecode(token); try { - const res = await networkService.getMonitorsByUserId( + const res = await networkService.getMonitorsByTeamId( token, - user._id, + user.teamId, 25, ["http", "ping"], null, diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index cd46469b4..1901f6654 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -52,9 +52,9 @@ class NetworkService { * @param {boolean} [normalize] - Whether to normalize the retrieved monitors. * @returns {Promise} The response from the axios GET request. */ - async getMonitorsByUserId( + async getMonitorsByTeamId( authToken, - userId, + teamId, limit, types, status, @@ -74,7 +74,7 @@ class NetworkService { if (normalize) params.append("normalize", normalize); return this.axiosInstance.get( - `/monitors/user/${userId}?${params.toString()}`, + `/monitors/team/${teamId}?${params.toString()}`, { headers: { Authorization: `Bearer ${authToken}`, diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index 37aff6c96..c3fe37955 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -1,10 +1,10 @@ const { getMonitorByIdParamValidation, getMonitorByIdQueryValidation, - getMonitorsByUserIdValidation, + getMonitorsByTeamIdValidation, createMonitorBodyValidation, editMonitorBodyValidation, - getMonitorsByUserIdQueryValidation, + getMonitorsByTeamIdQueryValidation, } = require("../validation/joi"); const sslChecker = require("ssl-checker"); @@ -149,10 +149,10 @@ const getMonitorById = async (req, res, next) => { * @returns {Promise} * @throws {Error} */ -const getMonitorsByUserId = async (req, res, next) => { +const getMonitorsByTeamId = async (req, res, next) => { try { - await getMonitorsByUserIdValidation.validateAsync(req.params); - await getMonitorsByUserIdQueryValidation.validateAsync(req.query); + await getMonitorsByTeamIdValidation.validateAsync(req.params); + await getMonitorsByTeamIdQueryValidation.validateAsync(req.query); } catch (error) { error.status = 422; error.service = SERVICE_NAME; @@ -163,12 +163,12 @@ const getMonitorsByUserId = async (req, res, next) => { } try { - const userId = req.params.userId; - const monitors = await req.db.getMonitorsByUserId(req, res); + const teamId = req.params.teamId; + const monitors = await req.db.getMonitorsByTeamId(req, res); return res.json({ success: true, - msg: successMessages.MONITOR_GET_BY_USER_ID(userId), + msg: successMessages.MONITOR_GET_BY_USER_ID(teamId), data: monitors, }); } catch (error) { @@ -342,7 +342,7 @@ module.exports = { getMonitorStatsById, getMonitorCertificate, getMonitorById, - getMonitorsByUserId, + getMonitorsByTeamId, createMonitor, deleteMonitor, deleteAllMonitors, diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index d6440ca12..05dfa35c5 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -66,7 +66,7 @@ const { getAllMonitors, getMonitorStatsById, getMonitorById, - getMonitorsByUserId, + getMonitorsByTeamId, createMonitor, deleteMonitor, deleteAllMonitors, @@ -145,7 +145,7 @@ module.exports = { getAllMonitors, getMonitorStatsById, getMonitorById, - getMonitorsByUserId, + getMonitorsByTeamId, createMonitor, deleteMonitor, deleteAllMonitors, diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index 612b71a89..6e3bba66c 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -287,17 +287,17 @@ const getMonitorById = async (monitorId) => { }; /** - * Get monitors by UserID + * Get monitors by TeamID * @async * @param {Express.Request} req * @param {Express.Response} res * @returns {Promise>} * @throws {Error} */ -const getMonitorsByUserId = async (req, res) => { +const getMonitorsByTeamId = async (req, res) => { try { let { limit, type, status, sortOrder, normalize } = req.query || {}; - const monitorQuery = { userId: req.params.userId }; + const monitorQuery = { teamId: req.params.teamId }; if (type !== undefined) { const types = Array.isArray(type) ? type : [type]; @@ -453,7 +453,7 @@ module.exports = { getAllMonitors, getMonitorStatsById, getMonitorById, - getMonitorsByUserId, + getMonitorsByTeamId, createMonitor, deleteMonitor, deleteAllMonitors, diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index 847b2b25d..facbf47ed 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -7,7 +7,7 @@ router.get("/", monitorController.getAllMonitors); router.get("/stats/:monitorId", monitorController.getMonitorStatsById); router.get("/certificate/:monitorId", monitorController.getMonitorCertificate); router.get("/:monitorId", monitorController.getMonitorById); -router.get("/user/:userId", monitorController.getMonitorsByUserId); +router.get("/team/:teamId", monitorController.getMonitorsByTeamId); router.post("/", monitorController.createMonitor); router.delete( diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 24e7f7b76..a97574548 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -160,11 +160,11 @@ const getMonitorByIdQueryValidation = joi.object({ normalize: joi.boolean(), }); -const getMonitorsByUserIdValidation = joi.object({ - userId: joi.string().required(), +const getMonitorsByTeamIdValidation = joi.object({ + teamId: joi.string().required(), }); -const getMonitorsByUserIdQueryValidation = joi.object({ +const getMonitorsByTeamIdQueryValidation = joi.object({ status: joi.boolean(), sortOrder: joi.string().valid("asc", "desc"), limit: joi.number(), @@ -347,8 +347,8 @@ module.exports = { createMonitorBodyValidation, getMonitorByIdParamValidation, getMonitorByIdQueryValidation, - getMonitorsByUserIdValidation, - getMonitorsByUserIdQueryValidation, + getMonitorsByTeamIdValidation, + getMonitorsByTeamIdQueryValidation, editMonitorBodyValidation, editUserParamValidation, editUserBodyValidation, From 3fbd986bbe060753880da4567710576858bdd17c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 27 Aug 2024 09:13:48 -0700 Subject: [PATCH 021/101] Update admin to superadmin in sidebar --- Client/src/Components/Sidebar/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Client/src/Components/Sidebar/index.jsx b/Client/src/Components/Sidebar/index.jsx index ae6507b69..de35e400e 100644 --- a/Client/src/Components/Sidebar/index.jsx +++ b/Client/src/Components/Sidebar/index.jsx @@ -289,7 +289,7 @@ function Sidebar() { if ( child.name === "Team" && authState.user?.role && - !authState.user.role.includes("admin") + !authState.user.role.includes("superadmin") ) { return null; } @@ -349,7 +349,7 @@ function Sidebar() { if ( child.name === "Team" && authState.user?.role && - !authState.user.role.includes("admin") + !authState.user.role.includes("superadmin") ) { return null; } From 8b27bc2ab27013587eacfb70d8750b8f8206a7b2 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Tue, 27 Aug 2024 12:18:25 -0400 Subject: [PATCH 022/101] Refactored components styling 1/? --- Client/src/Components/Alert/index.jsx | 24 +++--- Client/src/Components/BasicTable/index.css | 56 +----------- Client/src/Components/BasicTable/index.jsx | 85 ++++++++++++++++--- Client/src/Components/Breadcrumbs/index.css | 11 +-- Client/src/Components/Breadcrumbs/index.jsx | 29 +++++-- Client/src/Components/Button/index.jsx | 1 + Client/src/Components/ButtonSpinner/index.jsx | 3 +- .../src/Components/Charts/BarChart/index.css | 19 ----- .../src/Components/Charts/BarChart/index.jsx | 53 ++++++++---- .../Charts/MonitorDetails60MinChart/index.jsx | 11 ++- .../Charts/MonitorDetailsAreaChart/index.css | 19 ----- .../Charts/MonitorDetailsAreaChart/index.jsx | 37 ++++++-- .../Charts/ResponseTimeChart/index.css | 7 -- .../Charts/ResponseTimeChart/index.jsx | 13 ++- .../TabPanels/Account/PasswordPanel.jsx | 2 +- Client/src/Layouts/HomeLayout/index.css | 2 +- .../Details/PaginationTable/index.jsx | 44 ++++++++-- Client/src/Pages/Monitors/Details/index.css | 14 +-- Client/src/Pages/Monitors/index.jsx | 14 ++- Client/src/Utils/Theme.js | 31 +++++-- 20 files changed, 278 insertions(+), 197 deletions(-) diff --git a/Client/src/Components/Alert/index.jsx b/Client/src/Components/Alert/index.jsx index 61c3b6bc3..cd9dcc18e 100644 --- a/Client/src/Components/Alert/index.jsx +++ b/Client/src/Components/Alert/index.jsx @@ -32,7 +32,7 @@ const icons = { const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => { const theme = useTheme(); - const { bg, border, color } = theme.alert[variant]; + const { text, light, border } = theme.palette[variant]; const icon = icons[variant]; return ( @@ -41,23 +41,25 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => { justifyContent="flex-start" alignItems={hasIcon ? "" : "center"} className="alert row-stack" - gap={theme.gap.ml} + gap={theme.spacing(8)} sx={{ - padding: hasIcon ? theme.gap.ml : `${theme.gap.small} ${theme.gap.ml}`, - backgroundColor: bg, + padding: hasIcon + ? theme.spacing(8) + : `${theme.spacing(4)} ${theme.spacing(8)}`, + backgroundColor: light, border: `solid 1px ${border}`, - borderRadius: `${theme.shape.borderRadius}px`, + borderRadius: theme.shape.borderRadius, }} > - {hasIcon && {icon}} + {hasIcon && {icon}} {title && ( - + {title} )} {body && ( - + {body} )} @@ -69,7 +71,7 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => { sx={{ fontWeight: "600", width: "fit-content", - mt: theme.gap.small, + mt: theme.spacing(4), padding: 0, minWidth: 0, "&:hover": { @@ -95,10 +97,6 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => { "&:focus": { outline: "none", }, - "& .MuiTouchRipple-root": { - pointerEvents: "none", - display: "none", - }, }} > { return ( <> - + - + {data.cols.map((col) => ( - {col.name} + + {col.name} + ))} @@ -215,12 +232,24 @@ const BasicTable = ({ data, paginated, reversed, table }) => { {row.data.map((cell) => { - return {cell.data}; + return ( + + {cell.data} + + ); })} ); @@ -233,9 +262,14 @@ const BasicTable = ({ data, paginated, reversed, table }) => { direction="row" alignItems="center" justifyContent="space-between" - px={theme.gap.small} + px={theme.spacing(4)} + sx={{ + "& p": { + color: theme.palette.text.tertiary, + }, + }} > - + Showing {getRange()} of {data.rows.length} monitor(s) { keepMounted: true, PaperProps: { className: "pagination-dropdown", + sx: { + border: 1, + borderColor: theme.palette.border.light, + borderRadius: theme.shape.borderRadius, + boxShadow: theme.shape.boxShadow, + "& li": { + p: theme.spacing(2), + color: theme.palette.text.tertiary, + }, + "& li.Mui-selected, & li.Mui-selected.Mui-focusVisible, & li.Mui-selected:hover": + { + backgroundColor: theme.palette.background.fill, + }, + }, }, transformOrigin: { vertical: "bottom", horizontal: "left" }, anchorOrigin: { vertical: "top", horizontal: "left" }, @@ -268,19 +316,32 @@ const BasicTable = ({ data, paginated, reversed, table }) => { inputProps: { id: "pagination-dropdown" }, IconComponent: SelectorVertical, sx: { - ml: theme.gap.small, - mr: theme.gap.large, - minWidth: theme.gap.xl, + ml: theme.spacing(4), + mr: theme.spacing(12), + minWidth: theme.spacing(20), textAlign: "left", "&.Mui-focused > div": { - backgroundColor: theme.palette.otherColors.white, + backgroundColor: theme.palette.background.main, }, }, }, }} sx={{ - mt: theme.gap.medium, - color: theme.palette.otherColors.bluishGray, + mt: theme.spacing(6), + color: theme.palette.text.secondary, + "& button, & .MuiSelect-select": { + border: 1, + borderColor: theme.palette.border.light, + borderRadius: theme.shape.borderRadius, + }, + "& svg path": { + stroke: theme.palette.text.tertiary, + strokeWidth: 1.3, + }, + "& button:not(.Mui-disabled):hover": { + backgroundColor: theme.palette.background.fill, + borderColor: theme.palette.background.fill, + }, }} /> diff --git a/Client/src/Components/Breadcrumbs/index.css b/Client/src/Components/Breadcrumbs/index.css index 1d1454b3d..a425946e8 100644 --- a/Client/src/Components/Breadcrumbs/index.css +++ b/Client/src/Components/Breadcrumbs/index.css @@ -1,5 +1,5 @@ .MuiBreadcrumbs-root { - height: 36px; + height: 34px; } .MuiBreadcrumbs-root svg { width: 16px; @@ -7,17 +7,8 @@ } .MuiBreadcrumbs-root .MuiBreadcrumbs-li a { font-size: var(--env-var-font-size-medium); - color: var(--secondary-color-light); - opacity: 0.8; font-weight: 400; } -.MuiBreadcrumbs-root .MuiBreadcrumbs-li:hover a { - color: var(--secondary-color-light); -} -.MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child):hover a { - opacity: 1; - background-color: #e3e3e3; -} .MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child) { cursor: pointer; } diff --git a/Client/src/Components/Breadcrumbs/index.jsx b/Client/src/Components/Breadcrumbs/index.jsx index 506263fce..c54b4c4a6 100644 --- a/Client/src/Components/Breadcrumbs/index.jsx +++ b/Client/src/Components/Breadcrumbs/index.jsx @@ -25,23 +25,36 @@ const Breadcrumbs = ({ list }) => { } aria-label="breadcrumb" - p={theme.gap.small} + px={theme.spacing(2)} + py={theme.spacing(3.5)} width="fit-content" - backgroundColor={theme.palette.otherColors.fillGray} - borderRadius={`${theme.shape.borderRadius}px`} + backgroundColor={theme.palette.background.fill} + borderRadius={theme.shape.borderRadius} lineHeight="18px" + sx={{ + "& .MuiBreadcrumbs-li:not(:last-of-type):hover a": { + backgroundColor: "#e3e3e3", + opacity: 1, + }, + }} > {list.map((item, index) => { return ( navigate(item.path)} + sx={{ + opacity: 0.8, + textTransform: "capitalize", + "&, &:hover": { + color: theme.palette.text.tertiary, + }, + }} > {item.name} diff --git a/Client/src/Components/Button/index.jsx b/Client/src/Components/Button/index.jsx index 485973498..4c59f8b47 100644 --- a/Client/src/Components/Button/index.jsx +++ b/Client/src/Components/Button/index.jsx @@ -77,6 +77,7 @@ const Button = ({ fontWeight: 400, boxShadow: "none", textTransform: "none", + borderRadius: "4px", "&:focus": { outline: "none", }, diff --git a/Client/src/Components/ButtonSpinner/index.jsx b/Client/src/Components/ButtonSpinner/index.jsx index 62cfae477..8c6d1deb8 100644 --- a/Client/src/Components/ButtonSpinner/index.jsx +++ b/Client/src/Components/ButtonSpinner/index.jsx @@ -74,12 +74,13 @@ const ButtonSpinner = ({ sx={{ boxShadow: "none", textTransform: "none", + borderRadius: "4px", "&:focus": { outline: "none", }, "&:hover": { boxShadow: "none", - transition: "none" + transition: "none", }, ...sx, }} diff --git a/Client/src/Components/Charts/BarChart/index.css b/Client/src/Components/Charts/BarChart/index.css index ed22f8bd7..e69de29bb 100644 --- a/Client/src/Components/Charts/BarChart/index.css +++ b/Client/src/Components/Charts/BarChart/index.css @@ -1,19 +0,0 @@ -.bar-tooltip .MuiTooltip-tooltip { - background-color: white; - border: solid 1px black; - box-shadow: var(--env-var-shadow-1); - border: solid 1px var(--env-var-color-6); - border-radius: var(--env-var-radius-1); - padding: 4px 8px; -} - -.bar-tooltip .MuiTooltip-tooltip p { - font-size: var(--env-var-font-size-small-plus); - color: var(--secondary-color-light); - font-weight: 500; -} -.bar-tooltip .MuiTooltip-tooltip span { - font-size: var(--env-var-font-size-small); - color: var(--secondary-color-light); - font-weight: 600; -} diff --git a/Client/src/Components/Charts/BarChart/index.jsx b/Client/src/Components/Charts/BarChart/index.jsx index 9238374c2..54a9524af 100644 --- a/Client/src/Components/Charts/BarChart/index.jsx +++ b/Client/src/Components/Charts/BarChart/index.jsx @@ -26,7 +26,7 @@ const BarChart = ({ checks = [] }) => { event.stopPropagation()} @@ -39,11 +39,11 @@ const BarChart = ({ checks = [] }) => { ) : ( @@ -53,15 +53,15 @@ const BarChart = ({ checks = [] }) => { {formatDate(new Date(check.createdAt), { year: undefined })} - + @@ -69,8 +69,8 @@ const BarChart = ({ checks = [] }) => { display="inline-flex" direction="row" justifyContent="space-between" - ml={theme.gap.xs} - gap={theme.gap.large} + ml={theme.spacing(2)} + gap={theme.spacing(12)} > Response Time @@ -99,6 +99,27 @@ const BarChart = ({ checks = [] }) => { }, }, ], + sx: { + "& .MuiTooltip-tooltip": { + backgroundColor: theme.palette.background.main, + border: 1, + borderColor: theme.palette.border.dark, + borderRadius: theme.shape.borderRadius, + boxShadow: theme.shape.boxShadow, + px: theme.spacing(4), + py: theme.spacing(2), + }, + "& .MuiTooltip-tooltip p": { + fontSize: 12, + color: theme.palette.text.tertiary, + fontWeight: 500, + }, + "& .MuiTooltip-tooltip span": { + fontSize: 11, + color: theme.palette.text.tertiary, + fontWeight: 600, + }, + }, }, }} > @@ -107,10 +128,10 @@ const BarChart = ({ checks = [] }) => { width="9px" height="100%" backgroundColor={ - check.status ? theme.label.up.bgColor : theme.label.down.bgColor + check.status ? theme.palette.success.bg : theme.palette.error.bg } sx={{ - borderRadius: "3px", + borderRadius: theme.spacing(1.5), "&:hover > .MuiBox-root": { filter: "brightness(0.8)", }, @@ -123,11 +144,11 @@ const BarChart = ({ checks = [] }) => { height={`${animate ? check.responseTime : 0}%`} backgroundColor={ check.status - ? theme.label.up.dotColor - : theme.label.down.dotColor + ? theme.palette.success.main + : theme.palette.error.text } sx={{ - borderRadius: "3px", + borderRadius: theme.spacing(1.5), transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)", }} /> diff --git a/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx b/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx index dbb45f109..57cb344e7 100644 --- a/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx +++ b/Client/src/Components/Charts/MonitorDetails60MinChart/index.jsx @@ -1,17 +1,20 @@ import { BarChart, Bar, Cell, ReferenceLine, Label } from "recharts"; import PropTypes from "prop-types"; +import { useTheme } from "@emotion/react"; const MonitorDetails60MinChart = ({ data }) => { + const theme = useTheme(); + const labelStyle = { fontSize: "10px", - fill: "#475467", + fill: theme.palette.text.tertiary, }; const color = { - true: "var(--success-color)", - false: "var(--error-color)", - undefined: "var(--unresolved-color)", + true: theme.palette.success.main, + false: theme.palette.error.text, + undefined: theme.palette.unresolved.main, }; return ( { + const theme = useTheme(); + if (active && payload && payload.length) { return ( -
-

+ + {new Date(label).toLocaleDateString("en-US", { weekday: "short", // Mon month: "long", // July @@ -18,10 +37,18 @@ const CustomToolTip = ({ active, payload, label }) => { minute: "2-digit", // 15 hour12: true, // AM/PM format })} -

-

Response Time (ms): {payload[0].payload.originalResponseTime}

{" "} + + + Response Time (ms): {payload[0].payload.originalResponseTime} + {" "} {/* Display original value */} -
+
); } return null; diff --git a/Client/src/Components/Charts/ResponseTimeChart/index.css b/Client/src/Components/Charts/ResponseTimeChart/index.css index 86b7a1d1b..e69de29bb 100644 --- a/Client/src/Components/Charts/ResponseTimeChart/index.css +++ b/Client/src/Components/Charts/ResponseTimeChart/index.css @@ -1,7 +0,0 @@ -.chart-container { - display: flex; - justify-content: space-around; - align-items: flex-end; - height: 50px; - width: 300px; -} diff --git a/Client/src/Components/Charts/ResponseTimeChart/index.jsx b/Client/src/Components/Charts/ResponseTimeChart/index.jsx index 3c57daf1a..fd6c0f41e 100644 --- a/Client/src/Components/Charts/ResponseTimeChart/index.jsx +++ b/Client/src/Components/Charts/ResponseTimeChart/index.jsx @@ -1,10 +1,17 @@ -import "./index.css"; import PropTypes from "prop-types"; +import { Stack } from "@mui/material"; import { BarChart, Bar, ResponsiveContainer, Cell } from "recharts"; +import "./index.css"; const ResponseTimeChart = ({ checks = [] }) => { return ( -
+ { -
+
); }; diff --git a/Client/src/Components/TabPanels/Account/PasswordPanel.jsx b/Client/src/Components/TabPanels/Account/PasswordPanel.jsx index 602816e6c..f921aa1ed 100644 --- a/Client/src/Components/TabPanels/Account/PasswordPanel.jsx +++ b/Client/src/Components/TabPanels/Account/PasswordPanel.jsx @@ -1,7 +1,7 @@ import TabPanel from "@mui/lab/TabPanel"; import React, { useState } from "react"; import { useTheme } from "@emotion/react"; -import { Box, Divider, Stack, Typography } from "@mui/material"; +import { Box, Stack, Typography } from "@mui/material"; import ButtonSpinner from "../../ButtonSpinner"; import Field from "../../Inputs/Field"; import { credentials } from "../../../Validation/validation"; diff --git a/Client/src/Layouts/HomeLayout/index.css b/Client/src/Layouts/HomeLayout/index.css index 75a1925f3..c5407eda6 100644 --- a/Client/src/Layouts/HomeLayout/index.css +++ b/Client/src/Layouts/HomeLayout/index.css @@ -22,7 +22,7 @@ border: 1px solid var(--border-color); border-radius: var(--env-var-radius-1); - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); padding: var(--env-var-spacing-1) 0; } diff --git a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx index ad8248ab0..e484b01ae 100644 --- a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx +++ b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx @@ -18,8 +18,10 @@ import { StatusLabel } from "../../../../Components/Label"; import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded"; import { logger } from "../../../../Utils/Logger"; +import { useTheme } from "@emotion/react"; const PaginationTable = ({ monitorId, dateRange }) => { + const theme = useTheme(); const { authToken } = useSelector((state) => state.auth); const [checks, setChecks] = useState([]); const [checksCount, setChecksCount] = useState(0); @@ -78,6 +80,19 @@ const PaginationTable = ({ monitorId, dateRange }) => { page={paginationController.page + 1} //0-indexed onChange={handlePageChange} shape="rounded" + sx={{ + backgroundColor: theme.palette.background.main, + border: 1, + borderColor: theme.palette.border.light, + "& button": { + color: theme.palette.text.tertiary, + borderRadius: theme.shape.borderRadius, + }, + "& li:first-of-type button, & li:last-of-type button": { + border: 1, + borderColor: theme.palette.border.light, + }, + }} renderItem={(item) => ( { pointerEvents: "none", display: "none", }, + "&.Mui-selected, &.Mui-selected:hover": { + backgroundColor: theme.palette.background.fill, + }, }} /> )} @@ -102,13 +120,29 @@ const PaginationTable = ({ monitorId, dateRange }) => { return ( <> - +
- + - Status - Date & Time - Message + + Status + + + Date & Time + + + Message + diff --git a/Client/src/Pages/Monitors/Details/index.css b/Client/src/Pages/Monitors/Details/index.css index 127b7377a..0ebad73e3 100644 --- a/Client/src/Pages/Monitors/Details/index.css +++ b/Client/src/Pages/Monitors/Details/index.css @@ -1,6 +1,6 @@ .monitor-details h1.MuiTypography-root { font-size: var(--env-var-font-size-large-plus); - color: var(--env-var-color-1); + color: var(--primary-color); font-weight: 600; } .monitor-details h2.MuiTypography-root { @@ -11,10 +11,10 @@ } .monitor-details h2.MuiTypography-root, .monitor-details h4.MuiTypography-root { - color: var(--env-var-color-5); + color: var(--secondary-color); } .monitor-details h6.MuiTypography-root { - color: var(--env-var-color-3); + color: var(--theme-main); } .monitor-details button.MuiButtonBase-root, .monitor-details h4.MuiTypography-root { @@ -29,7 +29,7 @@ font-size: var(--env-var-font-size-small-plus); } .monitor-details p.MuiTypography-root { - color: var(--env-var-color-2); + color: var(--secondary-color-light); } .monitor-details .stat-box { @@ -38,7 +38,7 @@ border: solid 1px; border-radius: var(--env-var-radius-1); padding: var(--env-var-spacing-1) 16px; - background-color: var(--env-var-color-8); + background-color: var(--primary-bg); } .monitor-details h6.MuiTypography-root { font-size: var(--env-var-font-size-medium-plus); @@ -46,10 +46,10 @@ .monitor-details h6.MuiTypography-root span.MuiTypography-root { font-style: italic; font-size: var(--env-var-font-size-medium); - color: var(--env-var-color-5); + color: var(--secondary-color); opacity: 0.7; } .monitor-details button.MuiButtonBase-root, .monitor-details .stat-box { - border-color: var(--env-var-color-16); + border-color: var(--border-color); } diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index 44101b332..b1f4c05c1 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -309,11 +309,11 @@ const StatusBox = ({ title, value }) => { position="relative" flex={1} border={1} - borderColor={theme.palette.otherColors.graishWhite} - borderRadius={`${theme.shape.borderRadius}px`} - backgroundColor={theme.palette.otherColors.white} - px={theme.gap.large} - py={theme.gap.ml} + borderColor={theme.palette.border.light} + borderRadius={theme.shape.borderRadius} + backgroundColor={theme.palette.background.main} + px={theme.spacing(12)} + py={theme.spacing(8)} overflow="hidden" sx={{ "&:hover": { @@ -447,9 +447,7 @@ const Monitors = () => { title: monitor.name, percentage: 100, percentageColor: - monitor.status === true - ? "var(--success-color)" - : "var(--error-color)", + monitor.status === true ? "var(--success-color)" : "var(--error-color)", status: monitor.status === true ? "up" : "down", }; diff --git a/Client/src/Utils/Theme.js b/Client/src/Utils/Theme.js index 7b6535bfa..3a8282dd0 100644 --- a/Client/src/Utils/Theme.js +++ b/Client/src/Utils/Theme.js @@ -40,15 +40,34 @@ const theme = createTheme({ accent: "#838c99", }, background: { - primary: "#FFFFFF", - secondary: "#FCFCFD", + main: "#FFFFFF", + alt: "#FCFCFD", fill: "#F4F4F4", accent: "#f9fafb", }, border: { light: "#eaecf0", dark: "#d0d5dd" }, + info: { + text: "#475467", + main: "#475467", + bg: "#ffffff", + light: "#ffffff", + border: "#D0D5DD", + }, success: { main: "#17b26a", light: "#d4f4e1", bg: "#ecfdf3" }, - error: { main: "#f04438", light: "#fbd1d1", bg: "#f9eced" }, - warning: { main: "#fdb022", light: "#fffcf5", bg: "#ffecbc" }, + error: { + text: "#f04438", + main: "#d32f2f", + light: "#fbd1d1", + bg: "#f9eced", + border: "#f04438", + }, + warning: { + text: "#DC6803", + main: "#fdb022", + light: "#fffcf5", + bg: "#ffecbc", + border: "#fec84b", + }, unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, other: {}, primary: { @@ -77,8 +96,10 @@ const theme = createTheme({ fillGray: otherColorsFillGray, }, }, + spacing: 2, + components: {}, shape: { - borderRadius: 4, + borderRadius: 2, borderThick: 2, boxShadow: shadow, }, From 5bd13a572e9e45afcb3a20132967110ed1060237 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 27 Aug 2024 10:39:55 -0700 Subject: [PATCH 023/101] Add middleware for verifying roles, use middleware on appropriate routs --- Server/middleware/isAllowed.js | 53 ++++++++++++++++++++++++++++++++++ Server/routes/authRoute.js | 9 ++++-- Server/routes/inviteRoute.js | 15 ++++++++-- Server/routes/monitorRoute.js | 21 ++++++++++---- Server/utils/messages.js | 3 ++ 5 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 Server/middleware/isAllowed.js diff --git a/Server/middleware/isAllowed.js b/Server/middleware/isAllowed.js new file mode 100644 index 000000000..fefb26099 --- /dev/null +++ b/Server/middleware/isAllowed.js @@ -0,0 +1,53 @@ +const jwt = require("jsonwebtoken"); +const TOKEN_PREFIX = "Bearer "; +const SERVICE_NAME = "allowedRoles"; +const { errorMessages } = require("../utils/messages"); + +const isAllowed = (allowedRoles) => { + return (req, res, next) => { + const token = req.headers["authorization"]; + + // If no token is pressent, return an error + if (!token) { + const error = new Error(errorMessages.NO_AUTH_TOKEN); + error.status = 401; + error.service = SERVICE_NAME; + next(error); + return; + } + + // If the token is improperly formatted, return an error + if (!token.startsWith(TOKEN_PREFIX)) { + const error = new Error(errorMessages.INVALID_AUTH_TOKEN); + error.status = 400; + error.service = SERVICE_NAME; + next(error); + return; + } + // Parse the token + try { + const parsedToken = token.slice(TOKEN_PREFIX.length, token.length); + var decoded = jwt.verify(parsedToken, process.env.JWT_SECRET); + const userRoles = decoded.role; + + // Check if the user has the required role + if (userRoles.some((role) => allowedRoles.includes(role))) { + next(); + return; + } else { + const error = new Error(errorMessages.INSUFFICIENT_PERMISSIONS); + error.status = 401; + error.service = SERVICE_NAME; + next(error); + return; + } + } catch (error) { + error.status = 401; + error.service = SERVICE_NAME; + next(error); + return; + } + }; +}; + +module.exports = { isAllowed }; diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index ddecd8d39..743a55c19 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -1,7 +1,7 @@ const router = require("express").Router(); const { verifyJWT } = require("../middleware/verifyJWT"); -const { verifySuperAdmin } = require("../middleware/verifySuperAdmin"); const { verifyOwnership } = require("../middleware/verifyOwnership"); +const { isAllowed } = require("../middleware/isAllowed"); const multer = require("multer"); const upload = multer(); const User = require("../models/user"); @@ -29,7 +29,12 @@ router.put( userEditController ); router.get("/users/superadmin", checkSuperadminController); -router.get("/users", verifyJWT, verifySuperAdmin, getAllUsersController); +router.get( + "/users", + verifyJWT, + isAllowed(["admin", "superadmin"]), + getAllUsersController +); router.delete( "/user/:userId", verifyJWT, diff --git a/Server/routes/inviteRoute.js b/Server/routes/inviteRoute.js index 05df2f51f..54e74b0fa 100644 --- a/Server/routes/inviteRoute.js +++ b/Server/routes/inviteRoute.js @@ -1,11 +1,22 @@ const router = require("express").Router(); const { verifyJWT } = require("../middleware/verifyJWT"); +const { isAllowed } = require("../middleware/isAllowed"); + const { inviteController, inviteVerifyController, } = require("../controllers/inviteController"); -router.post("/", verifyJWT, inviteController); -router.post("/verify", inviteVerifyController); +router.post( + "/", + isAllowed(["admin", "superadmin"]), + verifyJWT, + inviteController +); +router.post( + "/verify", + isAllowed(["admin", "superadmin"]), + inviteVerifyController +); module.exports = router; diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index facbf47ed..e08c43b7d 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -1,7 +1,6 @@ const router = require("express").Router(); const monitorController = require("../controllers/monitorController"); -const { verifyOwnership } = require("../middleware/verifyOwnership"); -const Monitor = require("../models/Monitor"); +const { isAllowed } = require("../middleware/isAllowed"); router.get("/", monitorController.getAllMonitors); router.get("/stats/:monitorId", monitorController.getMonitorStatsById); @@ -9,17 +8,27 @@ router.get("/certificate/:monitorId", monitorController.getMonitorCertificate); router.get("/:monitorId", monitorController.getMonitorById); router.get("/team/:teamId", monitorController.getMonitorsByTeamId); -router.post("/", monitorController.createMonitor); +router.post( + "/", + isAllowed(["admin", "superadmin"]), + monitorController.createMonitor +); + router.delete( "/:monitorId", - verifyOwnership(Monitor, "monitorId"), + isAllowed(["admin", "superadmin"]), monitorController.deleteMonitor ); + router.put( "/:monitorId", - verifyOwnership(Monitor, "monitorId"), + isAllowed(["admin", "superadmin"]), monitorController.editMonitor ); -router.delete("/all", monitorController.deleteAllMonitors); +router.delete( + "/all", + isAllowed(["superadmin"]), + monitorController.deleteAllMonitors +); module.exports = router; diff --git a/Server/utils/messages.js b/Server/utils/messages.js index 55f0fa7e9..7375fe448 100644 --- a/Server/utils/messages.js +++ b/Server/utils/messages.js @@ -17,6 +17,9 @@ const errorMessages = { VERIFY_OWNER_NOT_FOUND: "Document not found", VERIFY_OWNER_UNAUTHORIZED: "Unauthorized access", + //Permissions Middleware + INSUFFICIENT_PERMISSIONS: "Insufficient permissions", + //DB Errors DB_USER_EXISTS: "User already exists", DB_USER_NOT_FOUND: "User not found", From efe508f93614ff0f3def503fe257ea3ad70c5c91 Mon Sep 17 00:00:00 2001 From: Alexander Holliday Date: Tue, 27 Aug 2024 10:48:30 -0700 Subject: [PATCH 024/101] Update index.jsx --- Client/src/Pages/Monitors/Configure/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx index ebf6e3279..6df2f1be2 100644 --- a/Client/src/Pages/Monitors/Configure/index.jsx +++ b/Client/src/Pages/Monitors/Configure/index.jsx @@ -314,7 +314,7 @@ const Configure = () => { Date: Tue, 27 Aug 2024 12:07:30 -0700 Subject: [PATCH 025/101] Rename thunks to reflect teamId vs userId --- .../PageSpeedMonitor/pageSpeedMonitorSlice.js | 12 ++++++------ .../Features/UptimeMonitors/uptimeMonitorsSlice.js | 10 +++++----- Client/src/Pages/Incidents/index.jsx | 2 +- Client/src/Pages/Monitors/Configure/index.jsx | 4 ++-- Client/src/Pages/Monitors/index.jsx | 6 +++--- Client/src/Pages/PageSpeed/Configure/index.jsx | 4 ++-- Client/src/Pages/PageSpeed/index.jsx | 4 ++-- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js index 22e2b3324..5679de108 100644 --- a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js +++ b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js @@ -28,12 +28,12 @@ export const createPageSpeed = createAsyncThunk( } ); -export const getPageSpeedByUserId = createAsyncThunk( - "pageSpeedMonitors/getPageSpeedByUserId", +export const getPageSpeedByTeamId = createAsyncThunk( + "pageSpeedMonitors/getPageSpeedByTeamId", async (token, thunkApi) => { const user = jwtDecode(token); try { - const res = await networkService.getMonitorsByUserId( + const res = await networkService.getMonitorsByTeamId( token, user._id, 25, @@ -127,15 +127,15 @@ const pageSpeedMonitorSlice = createSlice({ // Monitors by userId // ***************************************************** - .addCase(getPageSpeedByUserId.pending, (state) => { + .addCase(getPageSpeedByTeamId.pending, (state) => { state.isLoading = true; }) - .addCase(getPageSpeedByUserId.fulfilled, (state, action) => { + .addCase(getPageSpeedByTeamId.fulfilled, (state, action) => { state.isLoading = false; state.success = action.payload.msg; state.monitors = action.payload.data; }) - .addCase(getPageSpeedByUserId.rejected, (state, action) => { + .addCase(getPageSpeedByTeamId.rejected, (state, action) => { state.isLoading = false; state.success = false; state.msg = action.payload diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index dc9fa3c20..237d9d3dc 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -28,8 +28,8 @@ export const createUptimeMonitor = createAsyncThunk( } ); -export const getUptimeMonitorsByUserId = createAsyncThunk( - "montiors/getMonitorsByUserId", +export const getUptimeMonitorsByTeamId = createAsyncThunk( + "montiors/getMonitorsByTeamId", async (token, thunkApi) => { const user = jwtDecode(token); try { @@ -126,15 +126,15 @@ const uptimeMonitorsSlice = createSlice({ // Monitors by userId // ***************************************************** - .addCase(getUptimeMonitorsByUserId.pending, (state) => { + .addCase(getUptimeMonitorsByTeamId.pending, (state) => { state.isLoading = true; }) - .addCase(getUptimeMonitorsByUserId.fulfilled, (state, action) => { + .addCase(getUptimeMonitorsByTeamId.fulfilled, (state, action) => { state.isLoading = false; state.success = action.payload.msg; state.monitors = action.payload.data; }) - .addCase(getUptimeMonitorsByUserId.rejected, (state, action) => { + .addCase(getUptimeMonitorsByTeamId.rejected, (state, action) => { state.isLoading = false; state.success = false; state.msg = action.payload diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 34768f7f9..d660be270 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -48,7 +48,7 @@ const Incidents = () => { useEffect(() => { const fetchMonitors = async () => { setLoading(true); - const res = await networkService.getMonitorsByUserId( + const res = await networkService.getMonitorsByTeamId( authState.authToken, authState.user._id, 1, diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx index bd2a26df0..bfb93a1de 100644 --- a/Client/src/Pages/Monitors/Configure/index.jsx +++ b/Client/src/Pages/Monitors/Configure/index.jsx @@ -8,7 +8,7 @@ import { createToast } from "../../../Utils/toastUtils"; import { logger } from "../../../Utils/Logger"; import { updateUptimeMonitor, - getUptimeMonitorsByUserId, + getUptimeMonitorsByTeamId, deleteUptimeMonitor, } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; import Button from "../../../Components/Button"; @@ -177,7 +177,7 @@ const Configure = () => { ); if (action.meta.requestStatus === "fulfilled") { createToast({ body: "Monitor updated successfully!" }); - dispatch(getUptimeMonitorsByUserId(authToken)); + dispatch(getUptimeMonitorsByTeamId(authToken)); } else { createToast({ body: "Failed to update monitor." }); } diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index 9eef7ec3a..8f2b93531 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import { useSelector, useDispatch } from "react-redux"; import { deleteUptimeMonitor, - getUptimeMonitorsByUserId, + getUptimeMonitorsByTeamId, } from "../../Features/UptimeMonitors/uptimeMonitorsSlice"; import { useNavigate } from "react-router-dom"; import Button from "../../Components/Button"; @@ -44,7 +44,7 @@ const ActionsMenu = ({ monitor }) => { ); if (action.meta.requestStatus === "fulfilled") { setIsOpen(false); // close modal - dispatch(getUptimeMonitorsByUserId(authState.authToken)); + dispatch(getUptimeMonitorsByTeamId(authState.authToken)); createToast({ body: "Monitor deleted successfully." }); } else { createToast({ body: "Failed to delete monitor." }); @@ -269,7 +269,7 @@ const Monitors = () => { const dispatch = useDispatch({}); useEffect(() => { - dispatch(getUptimeMonitorsByUserId(authState.authToken)); + dispatch(getUptimeMonitorsByTeamId(authState.authToken)); }, [authState.authToken, dispatch]); const up = monitorState.monitors.reduce((acc, cur) => { diff --git a/Client/src/Pages/PageSpeed/Configure/index.jsx b/Client/src/Pages/PageSpeed/Configure/index.jsx index 83484de7e..bb51c0703 100644 --- a/Client/src/Pages/PageSpeed/Configure/index.jsx +++ b/Client/src/Pages/PageSpeed/Configure/index.jsx @@ -5,7 +5,7 @@ import { useDispatch, useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router"; import { deletePageSpeed, - getPageSpeedByUserId, + getPageSpeedByTeamId, updatePageSpeed, } from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice"; import { monitorValidation } from "../../../Validation/validation"; @@ -127,7 +127,7 @@ const PageSpeedConfigure = () => { ); if (action.meta.requestStatus === "fulfilled") { createToast({ body: "Monitor updated successfully!" }); - dispatch(getPageSpeedByUserId(authToken)); + dispatch(getPageSpeedByTeamId(authToken)); } else { createToast({ body: "Failed to update monitor." }); } diff --git a/Client/src/Pages/PageSpeed/index.jsx b/Client/src/Pages/PageSpeed/index.jsx index 368ae2062..399597b13 100644 --- a/Client/src/Pages/PageSpeed/index.jsx +++ b/Client/src/Pages/PageSpeed/index.jsx @@ -4,7 +4,7 @@ import { useTheme } from "@emotion/react"; import { formatDate, formatDurationRounded } from "../../Utils/timeUtils"; import { StatusLabel } from "../../Components/Label"; import { useDispatch, useSelector } from "react-redux"; -import { getPageSpeedByUserId } from "../../Features/PageSpeedMonitor/pageSpeedMonitorSlice"; +import { getPageSpeedByTeamId } from "../../Features/PageSpeedMonitor/pageSpeedMonitorSlice"; import PageSpeedIcon from "../../assets/icons/page-speed.svg?react"; import Fallback from "../../Components/Fallback"; import "./index.css"; @@ -133,7 +133,7 @@ const PageSpeed = () => { (state) => state.pageSpeedMonitors ); useEffect(() => { - dispatch(getPageSpeedByUserId(authToken)); + dispatch(getPageSpeedByTeamId(authToken)); }, [authToken, dispatch]); // will show skeletons only on initial load From eedc6bbed608fbf4988050f223476a31c76ba5fb Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 27 Aug 2024 12:22:32 -0700 Subject: [PATCH 026/101] Refactor getChecksByUserId to getChecksByTeamId --- Client/src/Pages/Incidents/IncidentTable/index.jsx | 4 ++-- Client/src/Pages/Incidents/index.jsx | 4 ++-- Client/src/Utils/NetworkService.js | 6 +++--- Server/controllers/checkController.js | 14 +++++++------- Server/db/mongo/MongoDB.js | 4 ++-- Server/db/mongo/modules/checkModule.js | 8 ++++---- Server/routes/checkRoute.js | 8 ++------ Server/validation/joi.js | 10 +++++----- 8 files changed, 27 insertions(+), 31 deletions(-) diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index 7a77208f8..ae633c4dd 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -46,9 +46,9 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { try { let res; if (selectedMonitor === "0") { - res = await networkService.getChecksByUser( + res = await networkService.getChecksByTeam( authToken, - user._id, + user.teamId, "desc", null, null, diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index d660be270..46c7d51cf 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -50,14 +50,14 @@ const Incidents = () => { setLoading(true); const res = await networkService.getMonitorsByTeamId( authState.authToken, - authState.user._id, + authState.user.teamId, 1, null, null, null, null ); - + console.log(res); // Reduce to a lookup object for 0(1) lookup if (res.data && res.data.data.length > 0) { const monitorLookup = res.data.data.reduce((acc, monitor) => { diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 1901f6654..c375fade4 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -409,9 +409,9 @@ class NetworkService { * @returns {Promise} The response from the axios GET request. * */ - async getChecksByUser( + async getChecksByTeam( authToken, - userId, + teamId, sortOrder, limit, dateRange, @@ -427,7 +427,7 @@ class NetworkService { if (page) params.append("page", page); if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); return this.axiosInstance.get( - `/checks/user/${userId}?${params.toString()}`, + `/checks/team/${teamId}?${params.toString()}`, { headers: { Authorization: `Bearer ${authToken}` }, } diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index 957eeed4e..f553dabcb 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -3,8 +3,8 @@ const { createCheckBodyValidation, getChecksParamValidation, getChecksQueryValidation, - getUserChecksParamValidation, - getUserChecksQueryValidation, + getTeamChecksParamValidation, + getTeamChecksQueryValidation, deleteChecksParamValidation, } = require("../validation/joi"); const { successMessages } = require("../utils/messages"); @@ -62,10 +62,10 @@ const getChecks = async (req, res, next) => { } }; -const getUserChecks = async (req, res, next) => { +const getTeamChecks = async (req, res, next) => { try { - await getUserChecksParamValidation.validateAsync(req.params); - await getUserChecksQueryValidation.validateAsync(req.query); + await getTeamChecksParamValidation.validateAsync(req.params); + await getTeamChecksQueryValidation.validateAsync(req.query); } catch (error) { error.status = 422; error.service = SERVICE_NAME; @@ -75,7 +75,7 @@ const getUserChecks = async (req, res, next) => { return; } try { - const checkData = await req.db.getUserChecks(req); + const checkData = await req.db.getTeamChecks(req); return res.status(200).json({ success: true, msg: successMessages.CHECK_GET, @@ -115,6 +115,6 @@ const deleteChecks = async (req, res, next) => { module.exports = { createCheck, getChecks, - getUserChecks, + getTeamChecks, deleteChecks, }; diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 05dfa35c5..1b675e7e5 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -92,7 +92,7 @@ const { createCheck, getChecksCount, getChecks, - getUserChecks, + getTeamChecks, deleteChecks, } = require("./modules/checkModule"); @@ -153,7 +153,7 @@ module.exports = { createCheck, getChecksCount, getChecks, - getUserChecks, + getTeamChecks, deleteChecks, createAlert, getAlertsByUserId, diff --git a/Server/db/mongo/modules/checkModule.js b/Server/db/mongo/modules/checkModule.js index 782e5f64d..56a40d2ad 100644 --- a/Server/db/mongo/modules/checkModule.js +++ b/Server/db/mongo/modules/checkModule.js @@ -116,12 +116,12 @@ const getChecks = async (req) => { } }; -const getUserChecks = async (req) => { - const { userId } = req.params; +const getTeamChecks = async (req) => { + const { teamId } = req.params; let { sortOrder, limit, dateRange, filter, page, rowsPerPage } = req.query; // Get monitorIDs - const userMonitors = await Monitor.find({ userId: userId }); + const userMonitors = await Monitor.find({ teamId: teamId }); const monitorIds = userMonitors.map((monitor) => monitor._id); //Build check query @@ -189,6 +189,6 @@ module.exports = { createCheck, getChecksCount, getChecks, - getUserChecks, + getTeamChecks, deleteChecks, }; diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index 4bba24e79..562b91263 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -9,13 +9,9 @@ router.post( checkController.createCheck ); -router.get( - "/:monitorId", - verifyOwnership(Monitor, "monitorId"), - checkController.getChecks -); +router.get("/:monitorId", checkController.getChecks); -router.get("/user/:userId", checkController.getUserChecks); +router.get("/team/:teamId", checkController.getTeamChecks); router.delete( "/:monitorId", diff --git a/Server/validation/joi.js b/Server/validation/joi.js index a97574548..714eff5cf 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -271,11 +271,11 @@ const getChecksQueryValidation = joi.object({ rowsPerPage: joi.number(), }); -const getUserChecksParamValidation = joi.object({ - userId: joi.string().required(), +const getTeamChecksParamValidation = joi.object({ + teamId: joi.string().required(), }); -const getUserChecksQueryValidation = joi.object({ +const getTeamChecksQueryValidation = joi.object({ sortOrder: joi.string().valid("asc", "desc"), limit: joi.number(), dateRange: joi.string().valid("day", "week", "month"), @@ -364,8 +364,8 @@ module.exports = { createCheckBodyValidation, getChecksParamValidation, getChecksQueryValidation, - getUserChecksParamValidation, - getUserChecksQueryValidation, + getTeamChecksParamValidation, + getTeamChecksQueryValidation, deleteChecksParamValidation, deleteUserParamValidation, getPageSpeedCheckParamValidation, From cd6f55a9c99a05eed4edbf76857a8b2ce218af19 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 27 Aug 2024 12:54:44 -0700 Subject: [PATCH 027/101] Conditionally render some components based on admin status --- Client/src/App.jsx | 10 +++- Client/src/Components/Fallback/index.jsx | 19 +++--- Client/src/HOC/withAdminProp.jsx | 20 +++++++ Client/src/Pages/Monitors/Details/index.jsx | 53 +++++++++-------- Client/src/Pages/Monitors/index.jsx | 65 ++++++++++++--------- Client/src/Pages/PageSpeed/index.jsx | 6 +- 6 files changed, 110 insertions(+), 63 deletions(-) create mode 100644 Client/src/HOC/withAdminProp.jsx diff --git a/Client/src/App.jsx b/Client/src/App.jsx index 12db9dab9..f8a2f72f5 100644 --- a/Client/src/App.jsx +++ b/Client/src/App.jsx @@ -21,6 +21,7 @@ import ProtectedRoute from "./Components/ProtectedRoute"; import Details from "./Pages/Monitors/Details"; import Maintenance from "./Pages/Maintenance"; import withAdminCheck from "./HOC/withAdminCheck"; +import withAdminProp from "./HOC/withAdminProp"; import Configure from "./Pages/Monitors/Configure"; import PageSpeed from "./Pages/PageSpeed"; import CreatePageSpeed from "./Pages/PageSpeed/CreatePageSpeed"; @@ -30,6 +31,9 @@ import PageSpeedConfigure from "./Pages/PageSpeed/Configure"; function App() { const AdminCheckedRegister = withAdminCheck(Register); + const MonitorsWithAdminProp = withAdminProp(Monitors); + const DetailsWithAdminProp = withAdminProp(Details); + return ( <> @@ -37,11 +41,11 @@ function App() { } + element={} /> } + element={} /> } + element={} /> { +const Fallback = ({ title, checks, link = "/", isAdmin }) => { const theme = useTheme(); const navigate = useNavigate(); @@ -36,7 +36,7 @@ const Fallback = ({ title, checks, link = "/" }) => { /> - A {title} is used to: + A {title} monitor is used to: {checks.map((check, index) => ( { /> ))} -
- - + + .MuiTableCell-root": { + color: theme.palette.text.secondary, + }, + }} + > Monitor Name Status Date & Time diff --git a/Client/src/Pages/Incidents/index.css b/Client/src/Pages/Incidents/index.css index b434d5e63..73c7b93e0 100644 --- a/Client/src/Pages/Incidents/index.css +++ b/Client/src/Pages/Incidents/index.css @@ -1,7 +1,3 @@ -.incidents h1.MuiTypography-root, -.incidents p.MuiTypography-root { - color: var(--secondary-color); -} .incidents h1.MuiTypography-root { font-size: var(--env-var-font-size-large); font-weight: 600; @@ -12,19 +8,4 @@ } .incidents button.MuiButtonBase-root { height: 34px; - border-color: var(--border-color); -} -.incidents .MuiPagination-root { - background-color: var(--primary-bg); -} -.incidents > .MuiBox-root { - background-color: var(--primary-bg); - border: solid 1px var(--border-color); - border-radius: var(--env-var-radius-1); - padding: 60px; -} - -/* remove later */ -.incidents .MuiSelect-select { - padding: 0 10px; } diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 5e1cffcb0..cd0216f9e 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -78,13 +78,17 @@ const Incidents = () => { }; return ( - + {loading ? ( ) : ( <> - - + + Incidents for { items={frequencies} /> - +
diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 510eeeaaf..75e8fb174 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -78,7 +78,11 @@ const Incidents = () => { }; return ( - + {loading ? ( ) : ( diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.jsx b/Client/src/Pages/Monitors/CreateMonitor/index.jsx index 3de96ad5c..bc0f55ed3 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/Monitors/CreateMonitor/index.jsx @@ -237,6 +237,10 @@ const CreateMonitor = () => { onClick={() => setHttps(true)} sx={{ backgroundColor: https && theme.palette.background.fill, + borderColor: theme.palette.border.dark, + "&:hover": { + borderColor: theme.palette.border.dark, + }, }} />
@@ -134,13 +135,28 @@ const PaginationTable = ({ monitorId, dateRange }) => { }} > - + Status - + Date & Time - + Message @@ -151,17 +167,31 @@ const PaginationTable = ({ monitorId, dateRange }) => { return ( - + - + {new Date(check.createdAt).toLocaleString()} - {check.statusCode} + + {check.statusCode} + ); })} diff --git a/Client/src/Pages/Monitors/Home/StatusBox.jsx b/Client/src/Pages/Monitors/Home/StatusBox.jsx index e28d09d6c..a7c56d75a 100644 --- a/Client/src/Pages/Monitors/Home/StatusBox.jsx +++ b/Client/src/Pages/Monitors/Home/StatusBox.jsx @@ -8,7 +8,12 @@ import ClockSnooze from "../../../assets/icons/clock-snooze.svg?react"; const StatusBox = ({ title, value }) => { const theme = useTheme(); - let sharedStyles = { position: "absolute", right: 8, opacity: 0.5 }; + let sharedStyles = { + position: "absolute", + right: 8, + opacity: 0.5, + "& svg path": { stroke: theme.palette.other.icon }, + }; let color; let icon; @@ -48,7 +53,7 @@ const StatusBox = ({ title, value }) => { overflow="hidden" sx={{ "&:hover": { - backgroundColor: "#f9fafb", + backgroundColor: theme.palette.background.accent, }, "&:after": { position: "absolute", diff --git a/Client/src/Pages/Monitors/Home/actionsMenu.jsx b/Client/src/Pages/Monitors/Home/actionsMenu.jsx index 11da8cbdf..d6e9da2ee 100644 --- a/Client/src/Pages/Monitors/Home/actionsMenu.jsx +++ b/Client/src/Pages/Monitors/Home/actionsMenu.jsx @@ -77,6 +77,9 @@ const ActionsMenu = ({ monitor, isAdmin }) => { "&:focus": { outline: "none", }, + "& svg path": { + stroke: theme.palette.other.icon, + }, }} > @@ -94,6 +97,7 @@ const ActionsMenu = ({ monitor, isAdmin }) => { borderColor: theme.palette.border.light, borderRadius: theme.shape.borderRadius, boxShadow: theme.shape.boxShadow, + backgroundColor: theme.palette.background.main, "& ul": { p: theme.spacing(2.5), minWidth: "100px", diff --git a/Client/src/Pages/Monitors/Home/index.jsx b/Client/src/Pages/Monitors/Home/index.jsx index f98ede024..8d7edbcc1 100644 --- a/Client/src/Pages/Monitors/Home/index.jsx +++ b/Client/src/Pages/Monitors/Home/index.jsx @@ -145,7 +145,7 @@ const Monitors = ({ isAdmin }) => { color={theme.palette.text.primary} border={1} borderColor={theme.palette.border.light} - backgroundColor={theme.palette.unresolved.bg} + backgroundColor={theme.palette.background.accent} > {monitorState.monitors.length} diff --git a/Client/src/Pages/Monitors/Home/monitorData.jsx b/Client/src/Pages/Monitors/Home/monitorData.jsx index ae3cc4e30..c82a1fa95 100644 --- a/Client/src/Pages/Monitors/Home/monitorData.jsx +++ b/Client/src/Pages/Monitors/Home/monitorData.jsx @@ -4,6 +4,7 @@ import BarChart from "../../../Components/Charts/BarChart"; import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded"; import { StatusLabel } from "../../../Components/Label"; import { Box } from "@mui/material"; +import { useTheme } from "@emotion/react"; const data = { cols: [ @@ -27,13 +28,17 @@ const data = { }; export const buildData = (monitors, isAdmin, navigate) => { + const theme = useTheme(); + data.rows = monitors.map((monitor, idx) => { const params = { url: monitor.url, title: monitor.name, percentage: 100, percentageColor: - monitor.status === true ? "var(--success-color)" : "var(--error-color)", + monitor.status === true + ? theme.palette.success.main + : theme.palette.error.text, status: monitor.status === true ? "up" : "down", }; diff --git a/Client/src/Utils/Theme.js b/Client/src/Utils/Theme.js index 4f8ede4d0..0122847ce 100644 --- a/Client/src/Utils/Theme.js +++ b/Client/src/Utils/Theme.js @@ -53,7 +53,10 @@ const theme = createTheme({ border: "#fec84b", }, unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, - other: {}, + other: { + icon: "#667085", + line: "#d6d9dd" + }, primary: { main: "#1570EF", }, @@ -73,4 +76,72 @@ const theme = createTheme({ }, }); +export const darkTheme = createTheme({ + typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, + palette: { + common: { main: "#1570ef" }, + text: { + primary: "#fafafa", + secondary: "#e6e6e6", + tertiary: "#a1a1aa", + accent: "#e6e6e6", + }, + background: { + main: "#151518", + alt: "#09090b", + fill: "#2e2e2e", + accent: "#18181a", + }, + border: { light: "#27272a", dark: "#2c2c2c" }, + info: { + text: "#475467", + main: "#475467", + bg: "#ffffff", + light: "#ffffff", + border: "#D0D5DD", + }, + success: { + text: "#079455", + main: "#45bb7a", + light: "#93d5aa", + bg: "#27272a", + }, + error: { + text: "#f04438", + main: "#d32f2f", + light: "#f04438", + bg: "#27272a", + border: "#f04438", + }, + warning: { + text: "#DC6803", + main: "#e88c30", + light: "#fffcf5", + bg: "#ffecbc", + border: "#fec84b", + }, + unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, + other: { + icon: "#e6e6e6", + line: "#27272a" + }, + primary: { + main: "#1570ef", + }, + secondary: { + main: "#e6e6e6", + }, + tertiary: { + main: "#e6e6e6", + }, + }, + spacing: 2, + components: {}, + shape: { + borderRadius: 2, + borderThick: 2, + boxShadow: shadow, + }, +}); + export default theme; diff --git a/Client/src/assets/icons/dots-vertical.svg b/Client/src/assets/icons/dots-vertical.svg new file mode 100644 index 000000000..e720066c4 --- /dev/null +++ b/Client/src/assets/icons/dots-vertical.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Client/src/main.jsx b/Client/src/main.jsx index 00cec7d14..d592f9137 100644 --- a/Client/src/main.jsx +++ b/Client/src/main.jsx @@ -3,8 +3,6 @@ import ReactDOM from "react-dom/client"; import App from "./App.jsx"; import "./index.css"; import { BrowserRouter as Router, HashRouter } from "react-router-dom"; -import theme from "./Utils/Theme.js"; -import { ThemeProvider } from "@mui/material"; import { Provider } from "react-redux"; import { persistor, store } from "./store"; import { PersistGate } from "redux-persist/integration/react"; @@ -13,11 +11,9 @@ export const networkService = new NetworkService(store); ReactDOM.createRoot(document.getElementById("root")).render( - - - - - + + + ); From d4ed7f3f7a8dfb26b5d4fb6985b85a316cd4b5c5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 28 Aug 2024 20:07:22 -0700 Subject: [PATCH 052/101] Add thunks for getting single monitor and pausing/resuming single monitor --- .../UptimeMonitors/uptimeMonitorsSlice.js | 77 ++++++++++++++++++- Client/src/Pages/Monitors/Configure/index.jsx | 37 ++++++--- Client/src/Utils/NetworkService.js | 39 ++++++++++ Server/controllers/monitorController.js | 2 +- 4 files changed, 143 insertions(+), 12 deletions(-) diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 237d9d3dc..0fd70c6b6 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -28,6 +28,26 @@ export const createUptimeMonitor = createAsyncThunk( } ); +export const getUptimeMonitorById = createAsyncThunk( + "monitors/getMonitorById", + async (data, thunkApi) => { + try { + const { authToken, monitorId } = data; + const res = await networkService.getMonitorByid(authToken, monitorId); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + export const getUptimeMonitorsByTeamId = createAsyncThunk( "montiors/getMonitorsByTeamId", async (token, thunkApi) => { @@ -109,6 +129,26 @@ export const deleteUptimeMonitor = createAsyncThunk( } ); +export const pauseUptimeMonitor = createAsyncThunk( + "monitors/pauseMonitor", + async (data, thunkApi) => { + try { + const { authToken, monitor } = data; + const res = await networkService.pauseMonitorById(authToken, monitor._id); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + const uptimeMonitorsSlice = createSlice({ name: "uptimeMonitors", initialState, @@ -160,7 +200,24 @@ const uptimeMonitorsSlice = createSlice({ ? action.payload.msg : "Failed to create uptime monitor"; }) - + // ***************************************************** + // Get Monitor By Id + // ***************************************************** + .addCase(getUptimeMonitorById.pending, (state) => { + state.isLoading = true; + }) + .addCase(getUptimeMonitorById.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(getUptimeMonitorById.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to pause uptime monitor"; + }) // ***************************************************** // update Monitor // ***************************************************** @@ -197,6 +254,24 @@ const uptimeMonitorsSlice = createSlice({ state.msg = action.payload ? action.payload.msg : "Failed to delete uptime monitor"; + }) + // ***************************************************** + // Pause Monitor + // ***************************************************** + .addCase(pauseUptimeMonitor.pending, (state) => { + state.isLoading = true; + }) + .addCase(pauseUptimeMonitor.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(pauseUptimeMonitor.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to pause uptime monitor"; }); }, }); diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx index 7a86d50ce..a548ef56f 100644 --- a/Client/src/Pages/Monitors/Configure/index.jsx +++ b/Client/src/Pages/Monitors/Configure/index.jsx @@ -8,6 +8,7 @@ import { createToast } from "../../../Utils/toastUtils"; import { logger } from "../../../Utils/Logger"; import { updateUptimeMonitor, + getUptimeMonitorById, getUptimeMonitorsByTeamId, deleteUptimeMonitor, } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; @@ -19,6 +20,7 @@ import Checkbox from "../../../Components/Inputs/Checkbox"; import Breadcrumbs from "../../../Components/Breadcrumbs"; import PulseDot from "../../../Components/Animated/PulseDot"; import "./index.css"; +import { networkService } from "../../../main"; /** * Parses a URL string and returns a URL object. @@ -92,7 +94,6 @@ const Configure = () => { const theme = useTheme(); const dispatch = useDispatch(); const { user, authToken } = useSelector((state) => state.auth); - const { monitors } = useSelector((state) => state.uptimeMonitors); const [monitor, setMonitor] = useState({}); const [errors, setErrors] = useState({}); const { monitorId } = useParams(); @@ -106,15 +107,25 @@ const Configure = () => { }; useEffect(() => { - const data = monitors.find((monitor) => monitor._id === monitorId); - if (!data) { - logger.error("Error fetching monitor of id: " + monitorId); - navigate("/not-found", { replace: true }); - } - setMonitor({ - ...data, - }); - }, [monitorId, authToken, monitors, navigate]); + const fetchMonitor = async () => { + try { + const action = await dispatch( + getUptimeMonitorById({ authToken, monitorId }) + ); + + if (getUptimeMonitorById.fulfilled.match(action)) { + const monitor = action.payload.data; + setMonitor(monitor); + } else if (getUptimeMonitorById.rejected.match(action)) { + throw new Error(action.error.message); + } + } catch (error) { + logger.error("Error fetching monitor of id: " + monitorId); + navigate("/not-found", { replace: true }); + } + }; + fetchMonitor(); + }, [monitorId, authToken, navigate]); const handleChange = (event, name) => { let { value, id } = event.target; @@ -170,6 +181,11 @@ const Configure = () => { } }; + const handlePause = async () => { + try { + } catch (error) {} + }; + const handleSubmit = async (event) => { event.preventDefault(); const action = await dispatch( @@ -276,6 +292,7 @@ const Configure = () => { mr: theme.gap.xs, }, }} + onClick={handlePause} />
- - .MuiTableCell-root": { - color: theme.palette.text.secondary, - }, - }} - > + + Monitor Name Status Date & Time diff --git a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx index a6be7a27f..703eebd51 100644 --- a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx +++ b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx @@ -80,19 +80,6 @@ const PaginationTable = ({ monitorId, dateRange }) => { page={paginationController.page + 1} //0-indexed onChange={handlePageChange} shape="rounded" - sx={{ - backgroundColor: theme.palette.background.main, - border: 1, - borderColor: theme.palette.border.light, - "& button": { - color: theme.palette.text.tertiary, - borderRadius: theme.shape.borderRadius, - }, - "& li:first-of-type button, & li:last-of-type button": { - border: 1, - borderColor: theme.palette.border.light, - }, - }} renderItem={(item) => ( { next: ArrowForwardRoundedIcon, }} {...item} - sx={{ - "&:focus": { - outline: "none", - }, - "& .MuiTouchRipple-root": { - pointerEvents: "none", - display: "none", - }, - "&.Mui-selected, &.Mui-selected:hover": { - backgroundColor: theme.palette.background.fill, - }, - }} /> )} /> @@ -120,45 +95,13 @@ const PaginationTable = ({ monitorId, dateRange }) => { return ( <> - +
- + - - Status - - - Date & Time - - - Message - + Status + Date & Time + Message @@ -167,31 +110,17 @@ const PaginationTable = ({ monitorId, dateRange }) => { return ( - + - + {new Date(check.createdAt).toLocaleString()} - - {check.statusCode} - + {check.statusCode} ); })} diff --git a/Client/src/Pages/Monitors/Home/actionsMenu.jsx b/Client/src/Pages/Monitors/Home/actionsMenu.jsx index d6e9da2ee..75274ba49 100644 --- a/Client/src/Pages/Monitors/Home/actionsMenu.jsx +++ b/Client/src/Pages/Monitors/Home/actionsMenu.jsx @@ -93,11 +93,6 @@ const ActionsMenu = ({ monitor, isAdmin }) => { slotProps={{ paper: { sx: { - border: 1, - borderColor: theme.palette.border.light, - borderRadius: theme.shape.borderRadius, - boxShadow: theme.shape.boxShadow, - backgroundColor: theme.palette.background.main, "& ul": { p: theme.spacing(2.5), minWidth: "100px", diff --git a/Client/src/Utils/Theme.js b/Client/src/Utils/Theme.js index 0122847ce..2da17339a 100644 --- a/Client/src/Utils/Theme.js +++ b/Client/src/Utils/Theme.js @@ -55,7 +55,7 @@ const theme = createTheme({ unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, other: { icon: "#667085", - line: "#d6d9dd" + line: "#d6d9dd", }, primary: { main: "#1570EF", @@ -68,7 +68,59 @@ const theme = createTheme({ }, }, spacing: 2, - components: {}, + components: { + MuiButtonBase: { + defaultProps: { + disableRipple: true, + }, + }, + MuiPaper: { + styleOverrides: { + root: { + marginTop: 4, + border: 1, + borderStyle: "solid", + borderColor: "#eaecf0", + borderRadius: 4, + boxShadow: shadow, + backgroundColor: "#FFFFFF", + }, + }, + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: "#eaecf0", + }, + }, + }, + MuiTableHead: { + styleOverrides: { + root: { + backgroundColor: "#f9fafb", + }, + }, + }, + MuiPagination: { + styleOverrides: { + root: { + backgroundColor: "#FFFFFF", + border: 1, + borderStyle: "solid", + borderColor: "#eaecf0", + "& button": { + color: "#475467", + borderRadius: 4, + }, + "& li:first-of-type button, & li:last-of-type button": { + border: 1, + borderStyle: "solid", + borderColor: "#eaecf0", + }, + }, + }, + }, + }, shape: { borderRadius: 2, borderThick: 2, @@ -123,7 +175,7 @@ export const darkTheme = createTheme({ unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, other: { icon: "#e6e6e6", - line: "#27272a" + line: "#27272a", }, primary: { main: "#1570ef", @@ -136,7 +188,59 @@ export const darkTheme = createTheme({ }, }, spacing: 2, - components: {}, + components: { + MuiButtonBase: { + defaultProps: { + disableRipple: true, + }, + }, + MuiPaper: { + styleOverrides: { + root: { + marginTop: 4, + border: 1, + borderStyle: "solid", + borderColor: "#27272a", + borderRadius: 4, + boxShadow: shadow, + backgroundColor: "#151518", + }, + }, + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: "#27272a", + }, + }, + }, + MuiTableHead: { + styleOverrides: { + root: { + backgroundColor: "#18181a", + }, + }, + }, + MuiPagination: { + styleOverrides: { + root: { + backgroundColor: "#151518", + border: 1, + borderStyle: "solid", + borderColor: "#27272a", + "& button": { + color: "#a1a1aa", + borderRadius: 4, + }, + "& li:first-of-type button, & li:last-of-type button": { + border: 1, + borderStyle: "solid", + borderColor: "#27272a", + }, + }, + }, + }, + }, shape: { borderRadius: 2, borderThick: 2, diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js new file mode 100644 index 000000000..aeb762bc0 --- /dev/null +++ b/Client/src/Utils/Theme/darkTheme.js @@ -0,0 +1,141 @@ +import { createTheme } from "@mui/material"; + +const text = { + primary: "#fafafa", + secondary: "#e6e6e6", + tertiary: "#a1a1aa", + accent: "#e6e6e6", +}; +const background = { + main: "#151518", + alt: "#09090b", + fill: "#2e2e2e", + accent: "#18181a", +}; +const border = { light: "#27272a", dark: "#2c2c2c" }; + +const fontFamilyDefault = + '"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif'; +const shadow = + "0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)"; + +const darkTheme = createTheme({ + typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, + palette: { + common: { main: "#1570ef" }, + text: text, + background: background, + border: border, + info: { + text: "#475467", + main: "#475467", + bg: "#ffffff", + light: "#ffffff", + border: "#D0D5DD", + }, + success: { + text: "#079455", + main: "#45bb7a", + light: "#93d5aa", + bg: "#27272a", + }, + error: { + text: "#f04438", + main: "#d32f2f", + light: "#f04438", + bg: "#27272a", + border: "#f04438", + }, + warning: { + text: "#DC6803", + main: "#e88c30", + light: "#fffcf5", + bg: "#ffecbc", + border: "#fec84b", + }, + unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, + other: { + icon: "#e6e6e6", + line: "#27272a", + }, + primary: { + main: "#1570ef", + }, + secondary: { + main: "#e6e6e6", + }, + tertiary: { + main: "#e6e6e6", + }, + }, + spacing: 2, + components: { + MuiButtonBase: { + defaultProps: { + disableRipple: true, + }, + }, + MuiPaper: { + styleOverrides: { + root: { + marginTop: 4, + border: 1, + borderStyle: "solid", + borderColor: border.light, + borderRadius: 4, + boxShadow: shadow, + backgroundColor: background.main, + }, + }, + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: border.light, + }, + }, + }, + MuiTableHead: { + styleOverrides: { + root: { + backgroundColor: background.accent, + }, + }, + }, + MuiPagination: { + styleOverrides: { + root: { + backgroundColor: background.main, + border: 1, + borderStyle: "solid", + borderColor: border.light, + "& button": { + color: text.tertiary, + borderRadius: 4, + }, + "& li:first-of-type button, & li:last-of-type button": { + border: 1, + borderStyle: "solid", + borderColor: border.light, + }, + }, + }, + }, + MuiPaginationItem: { + styleOverrides: { + root: { + "&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": { + backgroundColor: background.fill, + }, + }, + }, + }, + }, + shape: { + borderRadius: 2, + borderThick: 2, + boxShadow: shadow, + }, +}); + +export default darkTheme; diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js new file mode 100644 index 000000000..28ef2b925 --- /dev/null +++ b/Client/src/Utils/Theme/lightTheme.js @@ -0,0 +1,141 @@ +import { createTheme } from "@mui/material"; + +const text = { + primary: "#1c2130", + secondary: "#344054", + tertiary: "#475467", + accent: "#838c99", +}; +const background = { + main: "#FFFFFF", + alt: "#FCFCFD", + fill: "#F4F4F4", + accent: "#f9fafb", +}; +const border = { light: "#eaecf0", dark: "#d0d5dd" }; + +const fontFamilyDefault = + '"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif'; +const shadow = + "0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)"; + +const lightTheme = createTheme({ + typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, + palette: { + common: { main: "#1570ef" }, + text: text, + background: background, + border: border, + info: { + text: "#475467", + main: "#475467", + bg: "#ffffff", + light: "#ffffff", + border: "#D0D5DD", + }, + success: { + text: "#079455", + main: "#17b26a", + light: "#d4f4e1", + bg: "#ecfdf3", + }, + error: { + text: "#f04438", + main: "#d32f2f", + light: "#fbd1d1", + bg: "#f9eced", + border: "#f04438", + }, + warning: { + text: "#DC6803", + main: "#fdb022", + light: "#fffcf5", + bg: "#ffecbc", + border: "#fec84b", + }, + unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, + other: { + icon: "#667085", + line: "#d6d9dd", + }, + primary: { + main: "#1570EF", + }, + secondary: { + main: "#475467", + }, + tertiary: { + main: "#475467", + }, + }, + spacing: 2, + components: { + MuiButtonBase: { + defaultProps: { + disableRipple: true, + }, + }, + MuiPaper: { + styleOverrides: { + root: { + marginTop: 4, + border: 1, + borderStyle: "solid", + borderColor: border.light, + borderRadius: 4, + boxShadow: shadow, + backgroundColor: background.main, + }, + }, + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: border.light, + }, + }, + }, + MuiTableHead: { + styleOverrides: { + root: { + backgroundColor: background.accent, + }, + }, + }, + MuiPagination: { + styleOverrides: { + root: { + backgroundColor: background.main, + border: 1, + borderStyle: "solid", + borderColor: border.light, + "& button": { + color: text.tertiary, + borderRadius: 4, + }, + "& li:first-of-type button, & li:last-of-type button": { + border: 1, + borderStyle: "solid", + borderColor: border.light, + }, + }, + }, + }, + MuiPaginationItem: { + styleOverrides: { + root: { + "&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": { + backgroundColor: background.fill, + }, + }, + }, + }, + }, + shape: { + borderRadius: 2, + borderThick: 2, + boxShadow: shadow, + }, +}); + +export default lightTheme; From 4352b3690d6365759643a4a2a9cae2eb98352e95 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Thu, 29 Aug 2024 20:42:12 -0400 Subject: [PATCH 061/101] Refactored sx styling to theme file style overrides --- Client/src/Components/Avatar/index.jsx | 1 + Client/src/Components/BasicTable/index.css | 11 ---- Client/src/Components/BasicTable/index.jsx | 12 +--- Client/src/Components/Breadcrumbs/index.jsx | 2 +- Client/src/Components/Fallback/index.jsx | 14 +++-- Client/src/Components/Inputs/Select/index.css | 5 -- Client/src/Components/Inputs/Select/index.jsx | 19 +----- Client/src/Components/Sidebar/index.jsx | 62 +++++-------------- Client/src/Layouts/HomeLayout/index.css | 2 +- Client/src/Pages/Monitors/Home/index.css | 3 - Client/src/Utils/Theme/darkTheme.js | 30 +++++++++ Client/src/Utils/Theme/lightTheme.js | 30 +++++++++ 12 files changed, 90 insertions(+), 101 deletions(-) diff --git a/Client/src/Components/Avatar/index.jsx b/Client/src/Components/Avatar/index.jsx index 2a9f70a08..975f27a32 100644 --- a/Client/src/Components/Avatar/index.jsx +++ b/Client/src/Components/Avatar/index.jsx @@ -57,6 +57,7 @@ const Avatar = ({ src, small, sx }) => { } sx={{ fontSize: small ? "16px" : "22px", + color: "white", fontWeight: 400, backgroundColor: stringToColor(`${user?.firstName} ${user?.lastName}`), display: "inline-flex", diff --git a/Client/src/Components/BasicTable/index.css b/Client/src/Components/BasicTable/index.css index c345abf7c..5defa124d 100644 --- a/Client/src/Components/BasicTable/index.css +++ b/Client/src/Components/BasicTable/index.css @@ -120,17 +120,6 @@ opacity: 0.4; } -.pagination-dropdown ul { - padding: 4px; - min-width: 100px; -} -.pagination-dropdown li { - font-size: var(--env-var-font-size-medium); -} -body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) { - font-size: var(--env-var-font-size-small-plus); -} - .monitors .MuiTable-root .MuiTableHead-root .MuiTableCell-root { text-transform: uppercase; opacity: 0.8; diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index 3b1d93b3d..e2de29ae1 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -272,7 +272,7 @@ const BasicTable = ({ data, paginated, reversed, table }) => { }, }} > - + Showing {getRange()} of {data.rows.length} monitor(s) { sx: { mt: 0, mb: theme.spacing(2), - "& li": { - p: theme.spacing(2), - color: theme.palette.text.tertiary, - }, - "& li.Mui-selected, & li.Mui-selected.Mui-focusVisible, & li.Mui-selected:hover": - { - backgroundColor: theme.palette.background.fill, - }, }, }, transformOrigin: { vertical: "bottom", horizontal: "left" }, anchorOrigin: { vertical: "top", horizontal: "left" }, - sx: { mt: "-4px" }, + sx: { mt: theme.spacing(-2) }, }, inputProps: { id: "pagination-dropdown" }, IconComponent: SelectorVertical, diff --git a/Client/src/Components/Breadcrumbs/index.jsx b/Client/src/Components/Breadcrumbs/index.jsx index c54b4c4a6..f2ca2089f 100644 --- a/Client/src/Components/Breadcrumbs/index.jsx +++ b/Client/src/Components/Breadcrumbs/index.jsx @@ -33,7 +33,7 @@ const Breadcrumbs = ({ list }) => { lineHeight="18px" sx={{ "& .MuiBreadcrumbs-li:not(:last-of-type):hover a": { - backgroundColor: "#e3e3e3", + backgroundColor: theme.palette.other.fill, opacity: 1, }, }} diff --git a/Client/src/Components/Fallback/index.jsx b/Client/src/Components/Fallback/index.jsx index 79c14584d..22ac837b0 100644 --- a/Client/src/Components/Fallback/index.jsx +++ b/Client/src/Components/Fallback/index.jsx @@ -2,7 +2,7 @@ import PropTypes from "prop-types"; import { useTheme } from "@emotion/react"; import { Box, Stack, Typography } from "@mui/material"; import Skeleton from "../../assets/Images/create-placeholder.svg?react"; -import background from "../../assets/Images/background_pattern_decorative.png"; +import Background from "../../assets/Images/background-grid.svg?react"; import Button from "../Button"; import Check from "../Check/Check"; import { useNavigate } from "react-router-dom"; @@ -32,12 +32,18 @@ const Fallback = ({ title, checks, link = "/", isAdmin }) => { + sx={{ + "& svg g g:last-of-type path": { + stroke: theme.palette.border.light, + }, + }} + > + + A {title} is used to: diff --git a/Client/src/Components/Inputs/Select/index.css b/Client/src/Components/Inputs/Select/index.css index be46ad109..329cdd7d2 100644 --- a/Client/src/Components/Inputs/Select/index.css +++ b/Client/src/Components/Inputs/Select/index.css @@ -5,8 +5,3 @@ align-items: center; line-height: 1; } -.select-wrapper .MuiInputBase-root:has(> .MuiSelect-select), -.MuiMenu-List .MuiMenuItem-root, -.select-wrapper h3.MuiTypography-root { - font-size: var(--env-var-font-size-medium); -} diff --git a/Client/src/Components/Inputs/Select/index.jsx b/Client/src/Components/Inputs/Select/index.jsx index 46969d7c1..b7146f27a 100644 --- a/Client/src/Components/Inputs/Select/index.jsx +++ b/Client/src/Components/Inputs/Select/index.jsx @@ -77,26 +77,9 @@ const Select = ({ onChange={onChange} displayEmpty inputProps={{ id: id }} - MenuProps={{ - MenuListProps: { - sx: { - p: 0, - "& li": { - color: theme.palette.text.secondary, - fontSize: 13, - px: theme.spacing(4), - py: theme.spacing(2.5), - borderRadius: theme.shape.borderRadius, - }, - "& li.Mui-selected, & li.Mui-selected.Mui-focusVisible, & li.Mui-selected:hover": - { - backgroundColor: theme.palette.background.fill, - }, - }, - }, - }} IconComponent={KeyboardArrowDownIcon} sx={{ + fontSize: 13, minWidth: "125px", "& fieldset": { borderRadius: theme.shape.borderRadius, diff --git a/Client/src/Components/Sidebar/index.jsx b/Client/src/Components/Sidebar/index.jsx index 2730441b6..2988efb54 100644 --- a/Client/src/Components/Sidebar/index.jsx +++ b/Client/src/Components/Sidebar/index.jsx @@ -305,31 +305,12 @@ function Sidebar() { slotProps={{ paper: { sx: { - border: 1, - borderColor: theme.palette.border.light, - borderRadius: theme.shape.borderRadius, - boxShadow: theme.shape.boxShadow, - backgroundColor: theme.palette.background.main, + mt: theme.spacing(-2), ml: theme.spacing(1), }, }, }} - MenuListProps={{ - sx: { - p: 3, - minWidth: "100px", - "& li": { - color: theme.palette.text.secondary, - fontSize: 13, - px: theme.spacing(4), - py: theme.spacing(2.5), - borderRadius: theme.shape.borderRadius, - }, - "& li:hover": { - backgroundColor: theme.palette.background.accent, - }, - }, - }} + MenuListProps={{ sx: { px: 1, py: 2 } }} sx={{ ml: theme.spacing(8), "& .selected-path": { @@ -360,9 +341,13 @@ function Sidebar() { }} sx={{ gap: theme.spacing(4), - borderRadius: theme.shape.borderRadius, - pl: theme.spacing(4), - mb: "1px", + opacity: 0.9, + "& svg": { + "& path": { + stroke: theme.palette.other.icon, + strokeWidth: 1.1, + }, + }, }} > {child.icon} @@ -460,9 +445,7 @@ function Sidebar() { ) )} - + {/* other */} ))} - + )} - {collapsed && ( - - )} + {collapsed && } dispatch(setMode("light"))}>Light dispatch(setMode("dark"))}>Dark + Date: Thu, 29 Aug 2024 20:47:19 -0400 Subject: [PATCH 062/101] Added icon button default padding and background --- Client/src/Utils/Theme/darkTheme.js | 10 ++++++++++ Client/src/Utils/Theme/lightTheme.js | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index 3599e4c53..d9d25893c 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -80,6 +80,16 @@ const darkTheme = createTheme({ disableRipple: true, }, }, + MuiIconButton: { + styleOverrides: { + root: { + padding: 4, + "&:hover": { + backgroundColor: background.fill, + }, + }, + }, + }, MuiPaper: { styleOverrides: { root: { diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index c328302b3..18923613b 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -80,6 +80,16 @@ const lightTheme = createTheme({ disableRipple: true, }, }, + MuiIconButton: { + styleOverrides: { + root: { + padding: 4, + "&:hover": { + backgroundColor: background.fill, + }, + }, + }, + }, MuiPaper: { styleOverrides: { root: { From e402e3511913a2bd12588b9c5afd6feea4e284c8 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Thu, 29 Aug 2024 21:02:15 -0400 Subject: [PATCH 063/101] Removed old theme file --- Client/src/Pages/Monitors/Home/index.jsx | 6 +- Client/src/Utils/Theme.js | 251 ----------------------- 2 files changed, 4 insertions(+), 253 deletions(-) delete mode 100644 Client/src/Utils/Theme.js diff --git a/Client/src/Pages/Monitors/Home/index.jsx b/Client/src/Pages/Monitors/Home/index.jsx index 295ded93e..e17b56e37 100644 --- a/Client/src/Pages/Monitors/Home/index.jsx +++ b/Client/src/Pages/Monitors/Home/index.jsx @@ -132,7 +132,8 @@ const Monitors = ({ isAdmin }) => { { - Current monitors + Actively monitoring Date: Fri, 30 Aug 2024 12:19:24 -0400 Subject: [PATCH 064/101] Moved toast notif to top right and some other small fixes --- Client/src/Components/Inputs/Field/index.jsx | 4 ++++ Client/src/Pages/Auth/index.css | 1 - Client/src/Pages/Monitors/Configure/skeleton.jsx | 8 ++++---- Client/src/Utils/Theme/darkTheme.js | 11 ++++++----- Client/src/Utils/Theme/lightTheme.js | 1 - Client/src/Utils/toastUtils.jsx | 2 +- Client/src/index.css | 5 +++++ 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Client/src/Components/Inputs/Field/index.jsx b/Client/src/Components/Inputs/Field/index.jsx index 293cbcdd3..62c50eeff 100644 --- a/Client/src/Components/Inputs/Field/index.jsx +++ b/Client/src/Components/Inputs/Field/index.jsx @@ -120,6 +120,10 @@ const Field = forwardRef( inputProps={{ sx: { color: theme.palette.text.secondary, + "&:-webkit-autofill": { + WebkitBoxShadow: `0 0 0 100px ${theme.palette.background.fill} inset`, + WebkitTextFillColor: theme.palette.text.secondary, + }, }, }} sx={ diff --git a/Client/src/Pages/Auth/index.css b/Client/src/Pages/Auth/index.css index 58987366d..33280e8f4 100644 --- a/Client/src/Pages/Auth/index.css +++ b/Client/src/Pages/Auth/index.css @@ -8,7 +8,6 @@ } .auth button:not(.MuiIconButton-root), .auth p, -.auth .field input, .auth span { font-size: var(--env-var-font-size-medium-plus); } diff --git a/Client/src/Pages/Monitors/Configure/skeleton.jsx b/Client/src/Pages/Monitors/Configure/skeleton.jsx index e8ac0d55d..08eb071cf 100644 --- a/Client/src/Pages/Monitors/Configure/skeleton.jsx +++ b/Client/src/Pages/Monitors/Configure/skeleton.jsx @@ -12,8 +12,8 @@ const SkeletonLayout = () => { return ( <> - - + + { variant="rounded" width="50%" height={24} - sx={{ mb: theme.gap.small }} + sx={{ mb: theme.spacing(4) }} /> { const toastConfig = { - position: "bottom-right", + position: "top-right", autoClose: 3000, hideProgressBar: true, closeButton: false, diff --git a/Client/src/index.css b/Client/src/index.css index a61074d19..105776bd8 100644 --- a/Client/src/index.css +++ b/Client/src/index.css @@ -67,6 +67,8 @@ body { } .Toastify__toast-body .alert { min-width: 150px; + padding: 5px 10px; + align-items: center; } .Toastify [class^="Toastify__toast"] { padding: 0; @@ -76,6 +78,9 @@ body { min-height: 0; border-radius: 4px; } +.Toastify [class*="Toastify__toast-theme"] { + background-color: transparent; +} .MuiTouchRipple-root { display: none; From 22770cc343d67599ed11d37c4e9ac0b3aa4c458b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 30 Aug 2024 09:41:27 -0700 Subject: [PATCH 065/101] Add db method for deleting checks by team --- Server/db/mongo/modules/checkModule.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Server/db/mongo/modules/checkModule.js b/Server/db/mongo/modules/checkModule.js index 56a40d2ad..89d0e707f 100644 --- a/Server/db/mongo/modules/checkModule.js +++ b/Server/db/mongo/modules/checkModule.js @@ -170,7 +170,7 @@ const getTeamChecks = async (req) => { }; /** - * Delete all checks for a user + * Delete all checks for a monitor * @async * @param {string} monitorId * @returns {number} @@ -185,10 +185,33 @@ const deleteChecks = async (monitorId) => { throw error; } }; + +/** + * Delete all checks for a team + * @async + * @param {string} monitorId + * @returns {number} + * @throws {Error} + */ + +const deleteChecksByTeam = async (teamId) => { + try { + const teamMonitors = await Monitor.find({ teamId: teamId }); + teamMonitors.forEach(async (monitor) => { + await Check.deleteMany({ monitorId: monitor._id }); + }); + + return true; + } catch (error) { + throw error; + } +}; + module.exports = { createCheck, getChecksCount, getChecks, getTeamChecks, deleteChecks, + deleteChecksByTeam, }; From fd3985190b3b483c5e074f295db24f1259d27c81 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 30 Aug 2024 09:41:42 -0700 Subject: [PATCH 066/101] Add controller method and validation for deleting check by team --- Server/controllers/checkController.js | 19 +++++++++++++++++++ Server/validation/joi.js | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index f553dabcb..3e3a0203c 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -6,6 +6,7 @@ const { getTeamChecksParamValidation, getTeamChecksQueryValidation, deleteChecksParamValidation, + deleteChecksByTeamParamValidation, } = require("../validation/joi"); const { successMessages } = require("../utils/messages"); const SERVICE_NAME = "check"; @@ -112,9 +113,27 @@ const deleteChecks = async (req, res, next) => { } }; +const deleteChecksByTeam = async (req, res, next) => { + try { + const res = await deleteChecksByTeamParamValidation.validateAsync( + req.params + ); + return res.status(200).json({ + success: true, + msg: successMessages.CHECK_DELETE, + data: { deletedCount: res }, + }); + } catch (error) { + error.service = SERVICE_NAME; + error.method = "deleteChecksByTeam"; + error.status = 422; + } +}; + module.exports = { createCheck, getChecks, getTeamChecks, deleteChecks, + deleteChecksByTeam, }; diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 2a7ff173d..9a2dba06c 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -292,6 +292,10 @@ const deleteChecksParamValidation = joi.object({ monitorId: joi.string().required(), }); +const deleteChecksByTeamParamValidation = joi.object({ + teamId: joi.string().required(), +}); + //**************************************** // PageSpeedCheckValidation //**************************************** @@ -372,6 +376,7 @@ module.exports = { getTeamChecksParamValidation, getTeamChecksQueryValidation, deleteChecksParamValidation, + deleteChecksByTeamParamValidation, deleteUserParamValidation, getPageSpeedCheckParamValidation, createPageSpeedCheckParamValidation, From 6708027d66d56c6e64e5551bd39dbc9f1f09075f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 30 Aug 2024 09:43:16 -0700 Subject: [PATCH 067/101] Add route --- Server/routes/checkRoute.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index 562b91263..e5c3b9d63 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -1,6 +1,7 @@ const router = require("express").Router(); const checkController = require("../controllers/checkController"); const { verifyOwnership } = require("../middleware/verifyOwnership"); +const { isAllowed } = require("../middleware/isAllowed"); const Monitor = require("../models/Monitor"); router.post( @@ -19,4 +20,10 @@ router.delete( checkController.deleteChecks ); +router.delete( + "/team/:teamId", + isAllowed(["admin", "superadmin"]), + checkController.deleteChecks +); + module.exports = router; From 13039ed2ff17ebdc17b2e430acab79b4f6c930e4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 30 Aug 2024 09:47:11 -0700 Subject: [PATCH 068/101] Add thunk and network methods --- .../UptimeMonitors/uptimeMonitorsSlice.js | 38 +++++++++++++++++++ Client/src/Utils/NetworkService.js | 19 ++++++++++ 2 files changed, 57 insertions(+) diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 79af537e0..61da63ba0 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -149,6 +149,26 @@ export const pauseUptimeMonitor = createAsyncThunk( } ); +export const deleteMonitorChecksByTeamId = createAsyncThunk( + "monitors/deleteChecksByTeamId", + async (data, thunkApi) => { + try { + const { authToken, teamId } = data; + const res = await networkService.deleteChecksByTeamId(authToken, teamId); + return res.data; + } catch (error) { + if (error.response && error.response.data) { + return thunkApi.rejectWithValue(error.response.data); + } + const payload = { + status: false, + msg: error.message ? error.message : "Unknown error", + }; + return thunkApi.rejectWithValue(payload); + } + } +); + const uptimeMonitorsSlice = createSlice({ name: "uptimeMonitors", initialState, @@ -256,6 +276,24 @@ const uptimeMonitorsSlice = createSlice({ : "Failed to delete uptime monitor"; }) // ***************************************************** + // Delete Monitor checks by Team ID + // ***************************************************** + .addCase(deleteMonitorChecksByTeamId.pending, (state) => { + state.isLoading = true; + }) + .addCase(deleteMonitorChecksByTeamId.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }) + .addCase(deleteMonitorChecksByTeamId.rejected, (state, action) => { + state.isLoading = false; + state.success = false; + state.msg = action.payload + ? action.payload.msg + : "Failed to delete monitor checks"; + }) + // ***************************************************** // Pause Monitor // ***************************************************** .addCase(pauseUptimeMonitor.pending, (state) => { diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 74bf8460b..31a23b5b1 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -184,6 +184,25 @@ class NetworkService { }, }); } + + /** + * ************************************ + * Deletes all checks for all monitor by teamID + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} monitorId - The ID of the monitor to be deleted. + * @returns {Promise} The response from the axios DELETE request. + */ + async deleteChecksByTeamId(authToken, teamId) { + return this.axiosInstance.delete(`/checks/team/${teamId}`, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); + } /** * ************************************ * Pauses a single monitor by its ID From d56ee2abb7105a178733fd6a1c77d19e0968517f Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Fri, 30 Aug 2024 12:53:23 -0400 Subject: [PATCH 069/101] Added darkmode warning palette --- Client/src/Components/BasicTable/index.jsx | 37 ++----------------- Client/src/Components/Sidebar/index.jsx | 21 +++++++++-- .../src/Pages/Monitors/Home/actionsMenu.jsx | 13 +------ Client/src/Utils/Theme/darkTheme.js | 15 ++++---- 4 files changed, 32 insertions(+), 54 deletions(-) diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index e2de29ae1..aed322beb 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -200,31 +200,12 @@ const BasicTable = ({ data, paginated, reversed, table }) => { return ( <> - +
- + {data.cols.map((col) => ( - - {col.name} - + {col.name} ))} @@ -242,17 +223,7 @@ const BasicTable = ({ data, paginated, reversed, table }) => { onClick={row.handleClick ? row.handleClick : null} > {row.data.map((cell) => { - return ( - - {cell.data} - - ); + return {cell.data}; })} ); diff --git a/Client/src/Components/Sidebar/index.jsx b/Client/src/Components/Sidebar/index.jsx index 2988efb54..722d48431 100644 --- a/Client/src/Components/Sidebar/index.jsx +++ b/Client/src/Components/Sidebar/index.jsx @@ -598,8 +598,9 @@ function Sidebar() { MenuListProps={{ sx: { p: 2, + "& li": { m: 0 }, "& li:has(.MuiBox-root):hover": { - backgroundColor: theme.palette.background.main, + backgroundColor: "transparent", }, }, }} @@ -620,8 +621,22 @@ function Sidebar() { )} {collapsed && } - dispatch(setMode("light"))}>Light - dispatch(setMode("dark"))}>Dark + { + dispatch(setMode("light")); + closePopup(); + }} + > + Light + + { + dispatch(setMode("dark")); + closePopup(); + }} + > + Dark + { slotProps={{ paper: { sx: { - "& ul": { - p: theme.spacing(2.5), - minWidth: "100px", - }, - "& li": { - color: theme.palette.text.secondary, - fontSize: 13, - px: theme.spacing(4), - py: theme.spacing(2.5), - borderRadius: theme.shape.borderRadius, - }, + "& ul": { p: theme.spacing(2.5) }, + "& li": { m: 0 }, "& li:last-of-type": { color: theme.palette.error.text, }, diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index c2e137004..0a945e6a8 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -38,22 +38,22 @@ const darkTheme = createTheme({ success: { text: "#079455", main: "#45bb7a", - light: "#93d5aa", + light: "#1e1e1e", bg: "#27272a", }, error: { text: "#f04438", main: "#d32f2f", - light: "#f04438", + light: "#1e1e1e", bg: "#27272a", border: "#f04438", }, warning: { - text: "#DC6803", - main: "#e88c30", - light: "#fffcf5", - bg: "#ffecbc", - border: "#fec84b", + text: "#e88c30", + main: "#FF9F00", + light: "#27272a", + bg: "#1E1E1E", + border: "#e88c30", }, unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, divider: border.light, @@ -102,6 +102,7 @@ const darkTheme = createTheme({ borderRadius: 4, boxShadow: shadow, backgroundColor: background.main, + backgroundImage: "none", }, }, }, From eedf2879ee52796aa4510cc40a8448d1769a60a4 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 30 Aug 2024 10:04:47 -0700 Subject: [PATCH 070/101] finish implementation --- Client/src/Pages/Settings/index.jsx | 29 ++++++++++++++++++++++++-- Server/controllers/checkController.js | 29 ++++++++++++++++---------- Server/db/mongo/MongoDB.js | 2 ++ Server/db/mongo/modules/checkModule.js | 4 ++-- Server/routes/checkRoute.js | 2 +- Server/validation/joi.js | 4 ++-- 6 files changed, 52 insertions(+), 18 deletions(-) diff --git a/Client/src/Pages/Settings/index.jsx b/Client/src/Pages/Settings/index.jsx index d908e33c1..06bc00e1e 100644 --- a/Client/src/Pages/Settings/index.jsx +++ b/Client/src/Pages/Settings/index.jsx @@ -1,14 +1,37 @@ import { useTheme } from "@emotion/react"; import { Box, Stack, styled, Typography } from "@mui/material"; import Button from "../../Components/Button"; +import ButtonSpinner from "../../Components/ButtonSpinner"; import Field from "../../Components/Inputs/Field"; import Link from "../../Components/Link"; import Select from "../../Components/Inputs/Select"; import { logger } from "../../Utils/Logger"; import "./index.css"; - +import { useDispatch, useSelector } from "react-redux"; +import { createToast } from "../../Utils/toastUtils"; +import { deleteMonitorChecksByTeamId } from "../../Features/UptimeMonitors/uptimeMonitorsSlice"; const Settings = () => { const theme = useTheme(); + const { user, authToken } = useSelector((state) => state.auth); + const { isLoading } = useSelector((state) => state.uptimeMonitors); + + const dispatch = useDispatch(); + const handleClearStats = async () => { + try { + const action = await dispatch( + deleteMonitorChecksByTeamId({ teamId: user.teamId, authToken }) + ); + + if (deleteMonitorChecksByTeamId.fulfilled.match(action)) { + createToast({ body: "Stats cleared successfully" }); + } else { + createToast({ body: "Failed to clear stats" }); + } + } catch (error) { + logger.error(error); + createToast({ body: "Failed to clear stats" }); + } + }; const ConfigBox = styled("div")({ display: "flex", @@ -100,9 +123,11 @@ const Settings = () => { /> Clear all stats. This is irreversible. - )} diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index 76dd80a3a..e61526b29 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -14,6 +14,7 @@ const background = { accent: "#18181a", }; const border = { light: "#27272a", dark: "#2c2c2c" }; +const common = { main: "#1570ef", dark: "#0e4ea7", contrastText: "#FFFFFF" }; const fontFamilyDefault = '"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif'; @@ -24,7 +25,7 @@ const darkTheme = createTheme({ typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, palette: { mode: "dark", - common: { main: "#1570ef" }, + common: common, text: text, background: background, border: border, @@ -46,6 +47,7 @@ const darkTheme = createTheme({ main: "#d32f2f", light: "#1e1e1e", bg: "#27272a", + dark: "#932020", border: "#f04438", }, warning: { @@ -77,10 +79,25 @@ const darkTheme = createTheme({ }, spacing: 2, components: { - MuiButtonBase: { + MuiButton: { defaultProps: { disableRipple: true, }, + styleOverrides: { + root: { + variants: [], + fontWeight: 400, + borderRadius: 4, + boxShadow: "none", + textTransform: "none", + "&:focus": { + outline: "none", + }, + "&:hover": { + boxShadow: "none", + }, + }, + }, }, MuiIconButton: { styleOverrides: { diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index 4b2742e87..17d52f3cd 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -13,6 +13,7 @@ const background = { accent: "#f9fafb", }; const border = { light: "#eaecf0", dark: "#d0d5dd" }; +const common = { main: "#1570ef", dark: "#0e4ea7", contrastText: "#FFFFFF" }; const fontFamilyDefault = '"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif'; @@ -22,16 +23,16 @@ const shadow = const lightTheme = createTheme({ typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, palette: { - common: { main: "#1570ef" }, + common: common, text: text, background: background, border: border, info: { - text: "#475467", - main: "#475467", - bg: "#ffffff", - light: "#ffffff", - border: "#D0D5DD", + text: text.primary, + main: text.primary, + bg: background.main, + light: background.main, + border: border.dark, }, success: { text: "#079455", @@ -75,10 +76,25 @@ const lightTheme = createTheme({ }, spacing: 2, components: { - MuiButtonBase: { + MuiButton: { defaultProps: { disableRipple: true, }, + styleOverrides: { + root: { + variants: [], + fontWeight: 400, + borderRadius: 4, + boxShadow: "none", + textTransform: "none", + "&:focus": { + outline: "none", + }, + "&:hover": { + boxShadow: "none", + }, + }, + }, }, MuiIconButton: { styleOverrides: { From ac483786148ad856972fca8b92436d91f8163b50 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 31 Aug 2024 01:33:33 -0400 Subject: [PATCH 084/101] Refactored theme common color props and fixed button background delay on theme change --- .../Charts/MonitorDetailsAreaChart/index.jsx | 2 +- Client/src/Components/Inputs/Image/index.jsx | 6 +++--- Client/src/Components/Link/index.jsx | 4 ++-- Client/src/Components/Sidebar/index.jsx | 2 +- .../Components/TabPanels/Account/ProfilePanel.jsx | 2 +- Client/src/Pages/Auth/CheckEmail.jsx | 6 +++--- Client/src/Pages/Auth/ForgotPassword.jsx | 4 ++-- Client/src/Pages/Auth/Login.jsx | 8 ++++---- Client/src/Pages/Auth/NewPasswordConfirmed.jsx | 4 ++-- Client/src/Pages/Auth/Register/Register.jsx | 4 ++-- Client/src/Pages/Auth/SetNewPassword.jsx | 4 ++-- .../Maintenance/CreateMaintenanceWindow/index.jsx | 2 +- Client/src/Pages/Monitors/Details/index.jsx | 2 +- Client/src/Pages/Monitors/Home/index.jsx | 2 +- Client/src/Pages/PageSpeed/Details/index.jsx | 6 +++--- Client/src/Pages/PageSpeed/index.jsx | 2 +- Client/src/Utils/Theme/darkTheme.js | 14 +++++++++----- Client/src/Utils/Theme/lightTheme.js | 14 +++++++++----- 18 files changed, 48 insertions(+), 40 deletions(-) diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx index 3e69c0d60..4e5d1d7b0 100644 --- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx +++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx @@ -22,7 +22,7 @@ const CustomToolTip = ({ active, payload, label }) => { > diff --git a/Client/src/Components/Inputs/Image/index.jsx b/Client/src/Components/Inputs/Image/index.jsx index f7bdc9cf0..cdc7d8c7f 100644 --- a/Client/src/Components/Inputs/Image/index.jsx +++ b/Client/src/Components/Inputs/Image/index.jsx @@ -38,12 +38,12 @@ const ImageField = ({ id, src, loading, onChange }) => { border: "dashed", borderRadius: theme.shape.borderRadius, borderColor: isDragging - ? theme.palette.common.main + ? theme.palette.primary.main : theme.palette.border.light, borderWidth: "2px", transition: "0.2s", "&:hover": { - borderColor: theme.palette.common.main, + borderColor: theme.palette.primary.main, backgroundColor: "hsl(215, 87%, 51%, 0.05)", }, }} @@ -96,7 +96,7 @@ const ImageField = ({ id, src, loading, onChange }) => { Click to upload diff --git a/Client/src/Components/Link/index.jsx b/Client/src/Components/Link/index.jsx index 025bd0c25..5a055e28e 100644 --- a/Client/src/Components/Link/index.jsx +++ b/Client/src/Components/Link/index.jsx @@ -28,11 +28,11 @@ const Link = ({ level, label, url }) => { sx: { textDecoration: "underline", textDecorationStyle: "dashed", - textDecorationColor: theme.palette.common.main, + textDecorationColor: theme.palette.primary.main, textUnderlineOffset: "1px", ":hover": { color: theme.palette.text.tertiary, - textDecorationColor: theme.palette.common.main, + textDecorationColor: theme.palette.primary.main, backgroundColor: theme.palette.background.fill, }, }, diff --git a/Client/src/Components/Sidebar/index.jsx b/Client/src/Components/Sidebar/index.jsx index 722d48431..c372f8c66 100644 --- a/Client/src/Components/Sidebar/index.jsx +++ b/Client/src/Components/Sidebar/index.jsx @@ -154,7 +154,7 @@ function Sidebar() { color="white" sx={{ position: "relative", - backgroundColor: theme.palette.common.main, + backgroundColor: theme.palette.primary.main, borderRadius: theme.shape.borderRadius, userSelect: "none", }} diff --git a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx index 732919085..67c48d034 100644 --- a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx +++ b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx @@ -302,7 +302,7 @@ const ProfilePanel = () => { label="Update" onClick={openPictureModal} sx={{ - color: theme.palette.common.main, + color: theme.palette.primary.main, }} /> diff --git a/Client/src/Pages/Auth/CheckEmail.jsx b/Client/src/Pages/Auth/CheckEmail.jsx index 120923bb2..0936a1b2f 100644 --- a/Client/src/Pages/Auth/CheckEmail.jsx +++ b/Client/src/Pages/Auth/CheckEmail.jsx @@ -90,7 +90,7 @@ const CheckEmail = () => { overflow="hidden" sx={{ "& h1": { - color: theme.palette.common.main, + color: theme.palette.primary.main, fontWeight: 600, fontSize: 26, }, @@ -164,7 +164,7 @@ const CheckEmail = () => { component="span" onClick={resendToken} sx={{ - color: theme.palette.common.main, + color: theme.palette.primary.main, userSelect: "none", pointerEvents: disabled ? "none" : "auto", cursor: disabled ? "default" : "pointer", @@ -181,7 +181,7 @@ const CheckEmail = () => { diff --git a/Client/src/Pages/Auth/ForgotPassword.jsx b/Client/src/Pages/Auth/ForgotPassword.jsx index f174b2322..89b8095b9 100644 --- a/Client/src/Pages/Auth/ForgotPassword.jsx +++ b/Client/src/Pages/Auth/ForgotPassword.jsx @@ -92,7 +92,7 @@ const ForgotPassword = () => { overflow="hidden" sx={{ "& h1": { - color: theme.palette.common.main, + color: theme.palette.primary.main, fontWeight: 600, fontSize: 24, }, @@ -185,7 +185,7 @@ const ForgotPassword = () => { Go back to — { Forgot password? { overflow="hidden" sx={{ "& h1": { - color: theme.palette.common.main, + color: theme.palette.primary.main, fontWeight: 600, fontSize: 30, }, @@ -491,7 +491,7 @@ const Login = () => { { navigate("/register"); diff --git a/Client/src/Pages/Auth/NewPasswordConfirmed.jsx b/Client/src/Pages/Auth/NewPasswordConfirmed.jsx index 89e8fd110..2d07de23e 100644 --- a/Client/src/Pages/Auth/NewPasswordConfirmed.jsx +++ b/Client/src/Pages/Auth/NewPasswordConfirmed.jsx @@ -27,7 +27,7 @@ const NewPasswordConfirmed = () => { overflow="hidden" sx={{ "& h1": { - color: theme.palette.common.main, + color: theme.palette.primary.main, fontWeight: 600, fontSize: 22, }, @@ -99,7 +99,7 @@ const NewPasswordConfirmed = () => { Go back to — { overflow="hidden" sx={{ "& h1": { - color: theme.palette.common.main, + color: theme.palette.primary.main, fontWeight: 600, fontSize: 30, }, @@ -731,7 +731,7 @@ const Register = ({ isSuperAdmin }) => { onClick={() => { navigate("/login"); }} - sx={{ userSelect: "none", color: theme.palette.common.main }} + sx={{ userSelect: "none", color: theme.palette.primary.main }} > Log In diff --git a/Client/src/Pages/Auth/SetNewPassword.jsx b/Client/src/Pages/Auth/SetNewPassword.jsx index ca54e6fc8..9345df0fb 100644 --- a/Client/src/Pages/Auth/SetNewPassword.jsx +++ b/Client/src/Pages/Auth/SetNewPassword.jsx @@ -109,7 +109,7 @@ const SetNewPassword = () => { overflow="hidden" sx={{ "& h1": { - color: theme.palette.common.main, + color: theme.palette.primary.main, fontWeight: 600, fontSize: 24, }, @@ -280,7 +280,7 @@ const SetNewPassword = () => { Go back to — navigate("/login")} sx={{ userSelect: "none" }} diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index 0c6a16d5e..c4b142e2a 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -215,7 +215,7 @@ const CreateNewMaintenanceWindow = () => { sx={{ width: "fit-content", fontSize: "var(--env-var-font-size-small)", - borderBottom: `1px dashed ${theme.palette.common.main}`, + borderBottom: `1px dashed ${theme.palette.primary.main}`, paddingBottom: "4px", }} > diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 1506cd86f..02fb769bf 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -37,7 +37,7 @@ const StatBox = ({ title, value }) => { mb={theme.spacing(2)} fontSize={14} fontWeight={500} - color={theme.palette.common.main} + color={theme.palette.primary.main} sx={{ "& span": { color: theme.palette.text.accent, diff --git a/Client/src/Pages/Monitors/Home/index.jsx b/Client/src/Pages/Monitors/Home/index.jsx index cb2cee505..318a9da20 100644 --- a/Client/src/Pages/Monitors/Home/index.jsx +++ b/Client/src/Pages/Monitors/Home/index.jsx @@ -77,7 +77,7 @@ const Monitors = ({ isAdmin }) => { {monitorState.monitors?.length !== 0 && ( { mt={theme.spacing(8)} justifyContent="flex-end" > - { justifyContent="flex-end" > + diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.jsx b/Client/src/Pages/Monitors/CreateMonitor/index.jsx index bc0f55ed3..5147236e2 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/Monitors/CreateMonitor/index.jsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Box, ButtonGroup, Stack, Typography } from "@mui/material"; +import { Box, Button, ButtonGroup, Stack, Typography } from "@mui/material"; import { useSelector, useDispatch } from "react-redux"; import { monitorValidation } from "../../../Validation/validation"; import { createUptimeMonitor } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; @@ -9,7 +9,6 @@ import { createToast } from "../../../Utils/toastUtils"; import { logger } from "../../../Utils/Logger"; import { ConfigBox } from "../styled"; import Radio from "../../../Components/Inputs/Radio"; -import Button from "../../../Components/Button"; import Field from "../../../Components/Inputs/Field"; import Select from "../../../Components/Inputs/Select"; import Checkbox from "../../../Components/Inputs/Checkbox"; @@ -232,29 +231,19 @@ const CreateMonitor = () => { {monitor.type === "http" ? ( ) : ( "" @@ -354,12 +343,13 @@ const CreateMonitor = () => { diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 02fb769bf..616f18657 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -1,6 +1,13 @@ import PropTypes from "prop-types"; import { useEffect, useState, useCallback } from "react"; -import { Box, Skeleton, Stack, Typography, useTheme } from "@mui/material"; +import { + Box, + Button, + Skeleton, + Stack, + Typography, + useTheme, +} from "@mui/material"; import { useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; import { networkService } from "../../../main"; @@ -11,7 +18,6 @@ import { } from "../../../Utils/timeUtils"; import MonitorDetailsAreaChart from "../../../Components/Charts/MonitorDetailsAreaChart"; import ButtonGroup from "@mui/material/ButtonGroup"; -import Button from "../../../Components/Button"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; import PaginationTable from "./PaginationTable"; import Breadcrumbs from "../../../Components/Breadcrumbs"; @@ -237,28 +243,23 @@ const DetailsPage = ({ isAdmin }) => { {isAdmin && ( )} { > Response Times - + { > diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index 05c5942d9..61d37fcab 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -25,12 +25,13 @@ const darkTheme = createTheme({ palette: { mode: "dark", primary: { main: "#1570ef" }, + secondary: { main: "#2e2e2e" }, text: text, background: background, border: border, info: { text: text.primary, - main: text.primary, + main: text.secondary, bg: background.main, light: background.main, border: border.light, @@ -65,9 +66,6 @@ const darkTheme = createTheme({ grid: "#454546", }, // TO BE REMOVED // - secondary: { - main: "#e6e6e6", - }, tertiary: { main: "#e6e6e6", }, @@ -80,8 +78,26 @@ const darkTheme = createTheme({ disableRipple: true, }, styleOverrides: { - root: { - variants: [], + root: ({ theme }) => ({ + variants: [ + { + props: (props) => props.variant === "group", + style: { + color: theme.palette.secondary.contrastText, + backgroundColor: theme.palette.background.main, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + }, + }, + { + props: (props) => + props.variant === "group" && props.filled === "true", + style: { + backgroundColor: theme.palette.secondary.main, + }, + }, + ], fontWeight: 400, borderRadius: 4, boxShadow: "none", @@ -92,7 +108,7 @@ const darkTheme = createTheme({ "&:hover": { boxShadow: "none", }, - }, + }), }, }, MuiIconButton: { diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index 1610ec322..92481a4df 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -23,12 +23,13 @@ const lightTheme = createTheme({ typography: { fontFamily: fontFamilyDefault, fontSize: 13 }, palette: { primary: { main: "#1570EF" }, + secondary: { main: "#F4F4F4", dark: "#e3e3e3", contrastText: "#475467" }, text: text, background: background, border: border, info: { text: text.primary, - main: text.primary, + main: text.secondary, bg: background.main, light: background.main, border: border.dark, @@ -62,9 +63,6 @@ const lightTheme = createTheme({ grid: "#a2a3a3", }, // TO BE REMOVED // - secondary: { - main: "#475467", - }, tertiary: { main: "#475467", }, @@ -77,8 +75,26 @@ const lightTheme = createTheme({ disableRipple: true, }, styleOverrides: { - root: { - variants: [], + root: ({ theme }) => ({ + variants: [ + { + props: (props) => props.variant === "group", + style: { + color: theme.palette.secondary.contrastText, + backgroundColor: theme.palette.background.main, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + }, + }, + { + props: (props) => + props.variant === "group" && props.filled === "true", + style: { + backgroundColor: theme.palette.secondary.main, + }, + }, + ], fontWeight: 400, borderRadius: 4, boxShadow: "none", @@ -89,7 +105,7 @@ const lightTheme = createTheme({ "&:hover": { boxShadow: "none", }, - }, + }), }, }, MuiIconButton: { From cca02d30b962e04d929e9fae274d8db2831ecfa5 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 31 Aug 2024 17:37:55 -0400 Subject: [PATCH 086/101] Refactored buttons --- Client/src/Components/Alert/index.jsx | 18 ++-- Client/src/Components/BasicTable/index.jsx | 43 ++++------ Client/src/Components/Fallback/index.jsx | 11 +-- .../TabPanels/Account/ProfilePanel.jsx | 70 +++++++-------- Client/src/Pages/Auth/CheckEmail.jsx | 13 +-- Client/src/Pages/Auth/Login.jsx | 75 +++++++++------- .../src/Pages/Auth/NewPasswordConfirmed.jsx | 11 +-- Client/src/Pages/Auth/Register/Register.jsx | 86 +++++++++++-------- Client/src/Pages/Incidents/index.jsx | 57 +++++------- Client/src/Pages/Integrations/index.jsx | 11 +-- .../CreateMaintenanceWindow/index.jsx | 39 ++++----- .../src/Pages/Monitors/Home/actionsMenu.jsx | 18 ++-- Client/src/Pages/Monitors/Home/fallback.jsx | 11 +-- Client/src/Pages/NotFound/index.jsx | 11 +-- .../src/Pages/PageSpeed/Configure/index.jsx | 53 +++++++----- .../Pages/PageSpeed/CreatePageSpeed/index.css | 1 + .../Pages/PageSpeed/CreatePageSpeed/index.jsx | 11 +-- Client/src/Pages/PageSpeed/Details/index.jsx | 29 +++---- Client/src/Pages/Settings/index.jsx | 11 +-- Client/src/Utils/Theme/lightTheme.js | 2 +- 20 files changed, 292 insertions(+), 289 deletions(-) diff --git a/Client/src/Components/Alert/index.jsx b/Client/src/Components/Alert/index.jsx index cd9dcc18e..eb5fbd13b 100644 --- a/Client/src/Components/Alert/index.jsx +++ b/Client/src/Components/Alert/index.jsx @@ -1,12 +1,11 @@ import PropTypes from "prop-types"; import { useTheme } from "@emotion/react"; -import { Box, IconButton, Stack, Typography } from "@mui/material"; +import { Box, Button, IconButton, Stack, Typography } from "@mui/material"; import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import ErrorOutlineOutlinedIcon from "@mui/icons-material/ErrorOutlineOutlined"; import WarningAmberOutlinedIcon from "@mui/icons-material/WarningAmberOutlined"; import CloseIcon from "@mui/icons-material/Close"; import "./index.css"; -import Button from "../Button"; /** * Icons mapping for different alert variants. @@ -65,8 +64,8 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => { )} {hasIcon && isToast && ( + > + Dismiss + )} {isToast && ( diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index aed322beb..33073d838 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -13,6 +13,7 @@ import { Box, Typography, Stack, + Button, } from "@mui/material"; import { useDispatch, useSelector } from "react-redux"; import { setRowsPerPage } from "../../Features/UI/uiSlice"; @@ -21,7 +22,6 @@ import RightArrowDouble from "../../assets/icons/right-arrow-double.svg?react"; import LeftArrow from "../../assets/icons/left-arrow.svg?react"; import RightArrow from "../../assets/icons/right-arrow.svg?react"; import SelectorVertical from "../../assets/icons/selector-vertical.svg?react"; -import Button from "../Button"; import "./index.css"; /** * Component for pagination actions (first, previous, next, last). @@ -54,37 +54,37 @@ const TablePaginationActions = (props) => { return ( ); }; @@ -293,19 +293,10 @@ const BasicTable = ({ data, paginated, reversed, table }) => { sx={{ mt: theme.spacing(6), color: theme.palette.text.secondary, - "& button.MuiButtonBase-root, & .MuiSelect-select": { - border: 1, - borderColor: theme.palette.border.light, - borderRadius: theme.shape.borderRadius, - }, "& svg path": { stroke: theme.palette.text.tertiary, strokeWidth: 1.3, }, - "& button:not(.Mui-disabled):hover": { - backgroundColor: theme.palette.background.fill, - borderColor: theme.palette.background.fill, - }, }} /> diff --git a/Client/src/Components/Fallback/index.jsx b/Client/src/Components/Fallback/index.jsx index 26d818bdf..8d6b21f73 100644 --- a/Client/src/Components/Fallback/index.jsx +++ b/Client/src/Components/Fallback/index.jsx @@ -1,10 +1,9 @@ import PropTypes from "prop-types"; import { useTheme } from "@emotion/react"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import Skeleton from "../../assets/Images/create-placeholder.svg?react"; import SkeletonDark from "../../assets/Images/create-placeholder-dark.svg?react"; import Background from "../../assets/Images/background-grid.svg?react"; -import Button from "../Button"; import Check from "../Check/Check"; import { useNavigate } from "react-router-dom"; import { useSelector } from "react-redux"; @@ -66,11 +65,13 @@ const Fallback = ({ title, checks, link = "/", isAdmin }) => { {/* TODO - display a different fallback if user is not an admin*/} {isAdmin && ( )} ); diff --git a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx index 67c48d034..1611db818 100644 --- a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx +++ b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx @@ -1,9 +1,8 @@ import { useTheme } from "@emotion/react"; import { useRef, useState } from "react"; import TabPanel from "@mui/lab/TabPanel"; -import { Box, Divider, Modal, Stack, Typography } from "@mui/material"; +import { Box, Button, Divider, Modal, Stack, Typography } from "@mui/material"; import ButtonSpinner from "../../ButtonSpinner"; -import Button from "../../Button"; import Avatar from "../../Avatar"; import Field from "../../Inputs/Field"; import ImageField from "../../Inputs/Image"; @@ -292,19 +291,12 @@ const ProfilePanel = () => { } sx={{ mr: "8px" }} /> - + { borderColor: theme.palette.border.light, }} /> - - + + Delete account Note that deleting your account will remove all data from our @@ -353,12 +340,13 @@ const ProfilePanel = () => { + {/* TODO - Update ModalPopup Component with @mui for reusability */} { mt={theme.spacing(5)} justifyContent="flex-end" > - { justifyContent="flex-end" > + diff --git a/Client/src/Pages/Auth/CheckEmail.jsx b/Client/src/Pages/Auth/CheckEmail.jsx index 0936a1b2f..88bc1983c 100644 --- a/Client/src/Pages/Auth/CheckEmail.jsx +++ b/Client/src/Pages/Auth/CheckEmail.jsx @@ -1,11 +1,10 @@ -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import { useEffect, useState } from "react"; import { useTheme } from "@emotion/react"; import { useDispatch } from "react-redux"; import { useNavigate } from "react-router"; import { createToast } from "../../Utils/toastUtils"; import { forgotPassword } from "../../Features/Auth/authSlice"; -import Button from "../../Components/Button"; import background from "../../assets/Images/background_pattern_decorative.png"; import EmailIcon from "../../assets/icons/email.svg?react"; import Logo from "../../assets/icons/bwu-icon.svg?react"; @@ -92,7 +91,7 @@ const CheckEmail = () => { "& h1": { color: theme.palette.primary.main, fontWeight: 600, - fontSize: 26, + fontSize: 22, }, "& p": { fontSize: 14, @@ -150,14 +149,16 @@ const CheckEmail = () => { Didn't receive the email?{" "} { @@ -151,27 +155,29 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => { @@ -219,6 +225,7 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { <> @@ -243,29 +250,39 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { - + { diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 8de08e2d3..e454b355f 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -2,7 +2,7 @@ import PropTypes from "prop-types"; import { useState, useEffect, useRef } from "react"; import { useNavigate } from "react-router-dom"; import { useTheme } from "@emotion/react"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import { useDispatch } from "react-redux"; import { credentials } from "../../../Validation/validation"; import { createToast } from "../../../Utils/toastUtils"; @@ -13,11 +13,9 @@ 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 Check from "../../../Components/Check/Check"; -import Button from "../../../Components/Button"; import Field from "../../../Components/Inputs/Field"; import { networkService } from "../../../main"; import "../index.css"; -import { logger } from "../../../Utils/Logger"; /** * Displays the initial landing page. @@ -46,17 +44,22 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => { @@ -180,26 +183,29 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => { @@ -270,26 +276,29 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { @@ -443,26 +452,29 @@ const StepThree = ({ form, errors, onSubmit, onChange, onBack }) => { diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 75e8fb174..5d756298e 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -1,7 +1,12 @@ import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; -import { ButtonGroup, Stack, Skeleton, Typography } from "@mui/material"; -import Button from "../../Components/Button"; +import { + ButtonGroup, + Stack, + Skeleton, + Typography, + Button, +} from "@mui/material"; import { networkService } from "../../main"; import { useTheme } from "@emotion/react"; import Select from "../../Components/Inputs/Select"; @@ -78,11 +83,7 @@ const Incidents = () => { }; return ( - + {loading ? ( ) : ( @@ -114,38 +115,26 @@ const Incidents = () => { }} > { ); diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index c4b142e2a..43102ac21 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -1,7 +1,6 @@ -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import "./index.css"; import { useState } from "react"; -import Button from "../../../Components/Button"; import Back from "../../../assets/icons/left-arrow-long.svg?react"; import Select from "../../../Components/Inputs/Select"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; @@ -230,18 +229,17 @@ const CreateNewMaintenanceWindow = () => {
{ +
diff --git a/Client/src/Pages/Monitors/Home/actionsMenu.jsx b/Client/src/Pages/Monitors/Home/actionsMenu.jsx index 272aeb6fd..7d342f5d7 100644 --- a/Client/src/Pages/Monitors/Home/actionsMenu.jsx +++ b/Client/src/Pages/Monitors/Home/actionsMenu.jsx @@ -4,6 +4,7 @@ import { useTheme } from "@emotion/react"; import { useNavigate } from "react-router-dom"; import { createToast } from "../../../Utils/toastUtils"; import { + Button, IconButton, Menu, MenuItem, @@ -16,7 +17,6 @@ import { getUptimeMonitorsByTeamId, } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; import Settings from "../../../assets/icons/settings-bold.svg?react"; -import Button from "../../../Components/Button"; import PropTypes from "prop-types"; const ActionsMenu = ({ monitor, isAdmin }) => { @@ -189,21 +189,25 @@ const ActionsMenu = ({ monitor, isAdmin }) => { justifyContent="flex-end" > diff --git a/Client/src/Pages/Monitors/Home/fallback.jsx b/Client/src/Pages/Monitors/Home/fallback.jsx index c5d41ee48..f9a444e7c 100644 --- a/Client/src/Pages/Monitors/Home/fallback.jsx +++ b/Client/src/Pages/Monitors/Home/fallback.jsx @@ -1,6 +1,5 @@ -import { Stack, Typography } from "@mui/material"; +import { Button, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; -import Button from "../../../Components/Button"; import { useNavigate } from "react-router-dom"; import PropTypes from "prop-types"; @@ -25,13 +24,15 @@ const Fallback = ({ isAdmin }) => {
{isAdmin && ( )} ); diff --git a/Client/src/Pages/NotFound/index.jsx b/Client/src/Pages/NotFound/index.jsx index 17949ce4f..7d7adf149 100644 --- a/Client/src/Pages/NotFound/index.jsx +++ b/Client/src/Pages/NotFound/index.jsx @@ -1,8 +1,7 @@ -import Button from "../../Components/Button"; import React from "react"; import PropTypes from "prop-types"; import NotFoundSvg from "../../../src/assets/Images/sushi_404.svg"; -import { Stack, Typography } from "@mui/material"; +import { Button, Stack, Typography } from "@mui/material"; import { useNavigate } from "react-router"; import { useTheme } from "@emotion/react"; @@ -48,11 +47,13 @@ const NotFound = ({ title = DefaultValue.title, desc = DefaultValue.desc }) => {
{desc} ); diff --git a/Client/src/Pages/PageSpeed/Configure/index.jsx b/Client/src/Pages/PageSpeed/Configure/index.jsx index 756e52d2b..92dd5bb36 100644 --- a/Client/src/Pages/PageSpeed/Configure/index.jsx +++ b/Client/src/Pages/PageSpeed/Configure/index.jsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import { useTheme } from "@emotion/react"; -import { Box, Modal, Skeleton, Stack, Typography } from "@mui/material"; +import { Box, Button, Modal, Skeleton, Stack, Typography } from "@mui/material"; import { useDispatch, useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router"; import { @@ -11,7 +11,6 @@ import { import { monitorValidation } from "../../../Validation/validation"; import { createToast } from "../../../Utils/toastUtils"; import { logger } from "../../../Utils/Logger"; -import Button from "../../../Components/Button"; import Field from "../../../Components/Inputs/Field"; import Select from "../../../Components/Inputs/Select"; import Checkbox from "../../../Components/Inputs/Checkbox"; @@ -197,29 +196,33 @@ const PageSpeedConfigure = () => { { @@ -376,11 +381,15 @@ const PageSpeedConfigure = () => { justifyContent="flex-end" > + diff --git a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css index 4ac8d4a10..4b46fd3f0 100644 --- a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css +++ b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css @@ -22,6 +22,7 @@ .create-page-speed .section-disabled { opacity: 0.4; padding: 10px; + margin-right: -5px; border-radius: 8px; user-select: none; pointer-events: none; diff --git a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx index 342eefc71..00c02a362 100644 --- a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx +++ b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx @@ -1,11 +1,10 @@ -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import { useState } from "react"; import { useTheme } from "@emotion/react"; import { useDispatch, useSelector } from "react-redux"; import { useNavigate } from "react-router"; import Field from "../../../Components/Inputs/Field"; import Select from "../../../Components/Inputs/Select"; -import Button from "../../../Components/Button"; import Checkbox from "../../../Components/Inputs/Checkbox"; import { monitorValidation } from "../../../Validation/validation"; import { createToast } from "../../../Utils/toastUtils"; @@ -229,11 +228,13 @@ const CreatePageSpeed = () => { diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index f63af43db..29c0b72e0 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -1,5 +1,5 @@ import PropTypes from "prop-types"; -import { Box, Skeleton, Stack, Typography } from "@mui/material"; +import { Box, Button, Skeleton, Stack, Typography } from "@mui/material"; import { PieChart } from "@mui/x-charts/PieChart"; import { useDrawingArea } from "@mui/x-charts"; import { useEffect, useState } from "react"; @@ -12,7 +12,6 @@ import { } from "../../../Utils/timeUtils"; import { logger } from "../../../Utils/Logger"; import { networkService } from "../../../main"; -import Button from "../../../Components/Button"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; import LastCheckedIcon from "../../../assets/icons/calendar-check.svg?react"; import ClockIcon from "../../../assets/icons/maintenance.svg?react"; @@ -398,28 +397,24 @@ const PageSpeedDetails = () => {
{ diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index 92481a4df..49f864e53 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -29,7 +29,7 @@ const lightTheme = createTheme({ border: border, info: { text: text.primary, - main: text.secondary, + main: text.tertiary, bg: background.main, light: background.main, border: border.dark, From 9fc2d5c33abf9bc438a257324a5218c7b5cc2aac Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 31 Aug 2024 17:39:37 -0400 Subject: [PATCH 087/101] Removed button component --- Client/src/Components/Button/index.css | 33 --------- Client/src/Components/Button/index.jsx | 97 -------------------------- 2 files changed, 130 deletions(-) delete mode 100644 Client/src/Components/Button/index.css delete mode 100644 Client/src/Components/Button/index.jsx diff --git a/Client/src/Components/Button/index.css b/Client/src/Components/Button/index.css deleted file mode 100644 index 63791d46b..000000000 --- a/Client/src/Components/Button/index.css +++ /dev/null @@ -1,33 +0,0 @@ -.MuiButtonBase-root.button-rotate90 svg { - transition: transform 500ms ease; -} -.MuiButtonBase-root.button-rotate90:hover svg { - transform: rotate(90deg); - transform-origin: center; -} - -.MuiButtonBase-root.button-rotate180 svg { - transition: transform 700ms ease; -} -.MuiButtonBase-root.button-rotate180:hover svg { - transform: rotate(180deg); - transform-origin: center; -} - -.MuiButtonBase-root.button-slideLeft { - padding-left: 45px; -} -.MuiButtonBase-root.button-slideLeft svg { - position: absolute; - left: 15px; - transition: left 250ms cubic-bezier(0.65, 0, 0.076, 1); -} -.MuiButtonBase-root.button-slideLeft:hover svg { - left: 11px; -} - -.MuiButtonBase-root.button-slideLeft:hover, -.MuiButtonBase-root.button-rotate180:hover, -.MuiButtonBase-root.button-rotate90:hover { - background-color: rgba(71, 84, 103, 0.08); -} diff --git a/Client/src/Components/Button/index.jsx b/Client/src/Components/Button/index.jsx deleted file mode 100644 index 12de33be2..000000000 --- a/Client/src/Components/Button/index.jsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Button as MuiButton } from "@mui/material"; -import PropTypes from "prop-types"; -import "./index.css"; - -const levelConfig = { - primary: { - variant: "contained", - color: "primary", - }, - secondary: { - variant: "outlined", - color: "secondary", - }, - tertiary: { - variant: "text", - color: "tertiary", - }, - error: { - variant: "contained", - color: "error", - }, - imagePrimary: { - color: "primary", - variant: "text", - }, - imageSecondary: { - color: "secondary", - variant: "text", - }, - imageTertiary: { - color: "tertiary", - variant: "text", - }, -}; - -/** - * @component - * @param {Object} props - * @param {'primary' | 'secondary' | 'tertiary' | 'error' | 'imagePrimary' | 'imageSecondary' | 'imageTertiary'} props.level - The level of the button - * @param {string} props.type - The type of the button - * @param {string} props.label - The label of the button - * @param {React.ReactNode} props.img - Image for button - * @param {boolean} [props.disabled] - Whether the button is disabled - * @param {function} props.onClick - Function to run when the button is clicked - * @param {Object} props.sx - Styles for the button - * @returns {JSX.Element} - * @example - * // Render an error button - * - + loading={isLoading} + > + Delete account + diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 97235049e..8c4630b19 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -11,7 +11,6 @@ import { TextField, Typography, } from "@mui/material"; -import ButtonSpinner from "../../ButtonSpinner"; import { useEffect, useState } from "react"; import EditSvg from "../../../assets/icons/edit.svg?react"; import Field from "../../Inputs/Field"; @@ -22,6 +21,7 @@ import { useSelector } from "react-redux"; import BasicTable from "../../BasicTable"; import Remove from "../../../assets/icons/trash-bin.svg?react"; import Select from "../../Inputs/Select"; +import LoadingButton from "@mui/lab/LoadingButton"; /** * TeamPanel component manages the organization and team members, @@ -392,13 +392,15 @@ const TeamPanel = () => { - + > + Send invite + diff --git a/Client/src/Pages/Auth/ForgotPassword.jsx b/Client/src/Pages/Auth/ForgotPassword.jsx index 89b8095b9..338da645c 100644 --- a/Client/src/Pages/Auth/ForgotPassword.jsx +++ b/Client/src/Pages/Auth/ForgotPassword.jsx @@ -7,10 +7,10 @@ import { useEffect, useState } from "react"; import { credentials } from "../../Validation/validation"; import { useNavigate } from "react-router-dom"; import Field from "../../Components/Inputs/Field"; -import ButtonSpinner from "../../Components/ButtonSpinner"; import Logo from "../../assets/icons/bwu-icon.svg?react"; import Key from "../../assets/icons/key.svg?react"; import background from "../../assets/Images/background_pattern_decorative.png"; +import LoadingButton from "@mui/lab/LoadingButton"; import "./index.css"; const ForgotPassword = () => { @@ -166,18 +166,19 @@ const ForgotPassword = () => { onChange={handleChange} error={errors.email} /> - + > + Send instructions + diff --git a/Client/src/Pages/Auth/SetNewPassword.jsx b/Client/src/Pages/Auth/SetNewPassword.jsx index 9345df0fb..a01e9bd51 100644 --- a/Client/src/Pages/Auth/SetNewPassword.jsx +++ b/Client/src/Pages/Auth/SetNewPassword.jsx @@ -8,11 +8,11 @@ import { useState } from "react"; import { credentials } from "../../Validation/validation"; import { useNavigate } from "react-router-dom"; import Check from "../../Components/Check/Check"; -import ButtonSpinner from "../../Components/ButtonSpinner"; import Field from "../../Components/Inputs/Field"; import LockIcon from "../../assets/icons/lock-button-icon.svg?react"; import background from "../../assets/Images/background_pattern_decorative.png"; import Logo from "../../assets/icons/bwu-icon.svg?react"; +import LoadingButton from "@mui/lab/LoadingButton"; import "./index.css"; const SetNewPassword = () => { @@ -266,14 +266,16 @@ const SetNewPassword = () => { /> - + > + Reset password + diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx index 380f97b9e..38c0635f2 100644 --- a/Client/src/Pages/Monitors/Configure/index.jsx +++ b/Client/src/Pages/Monitors/Configure/index.jsx @@ -16,13 +16,15 @@ import { } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice"; import Field from "../../../Components/Inputs/Field"; import PauseCircleOutlineIcon from "@mui/icons-material/PauseCircleOutline"; +import PlayCircleOutlineRoundedIcon from "@mui/icons-material/PlayCircleOutlineRounded"; import Select from "../../../Components/Inputs/Select"; import Checkbox from "../../../Components/Inputs/Checkbox"; import Breadcrumbs from "../../../Components/Breadcrumbs"; import PulseDot from "../../../Components/Animated/PulseDot"; -import "./index.css"; import SkeletonLayout from "./skeleton"; -import ButtonSpinner from "../../../Components/ButtonSpinner"; +import LoadingButton from "@mui/lab/LoadingButton"; +import "./index.css"; + /** * Parses a URL string and returns a URL object. * @@ -247,27 +249,40 @@ const Configure = () => { ml: "auto", }} > - } + - + {monitor?.isActive ? ( + <> + + Pause + + ) : ( + <> + + Resume + + )} + + @@ -374,13 +389,15 @@ const Configure = () => { - + > + Save + @@ -439,9 +456,14 @@ const Configure = () => { > Cancel - + diff --git a/Client/src/Pages/Settings/index.jsx b/Client/src/Pages/Settings/index.jsx index 688c6d92f..fc615d848 100644 --- a/Client/src/Pages/Settings/index.jsx +++ b/Client/src/Pages/Settings/index.jsx @@ -1,6 +1,5 @@ import { useTheme } from "@emotion/react"; import { Box, Button, Stack, styled, Typography } from "@mui/material"; -import ButtonSpinner from "../../Components/ButtonSpinner"; import Field from "../../Components/Inputs/Field"; import Link from "../../Components/Link"; import Select from "../../Components/Inputs/Select"; @@ -10,6 +9,7 @@ import { useDispatch, useSelector } from "react-redux"; import { createToast } from "../../Utils/toastUtils"; import { deleteMonitorChecksByTeamId } from "../../Features/UptimeMonitors/uptimeMonitorsSlice"; import PropTypes from "prop-types"; +import LoadingButton from "@mui/lab/LoadingButton"; const Settings = ({ isAdmin }) => { const theme = useTheme(); const { user, authToken } = useSelector((state) => state.auth); @@ -124,13 +124,15 @@ const Settings = ({ isAdmin }) => { /> Clear all stats. This is irreversible. - + > + Clear all stats + From d2da8e7dff527d758057c31f01a9a00350d36ce5 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 31 Aug 2024 18:11:23 -0400 Subject: [PATCH 089/101] Removed button spinner component --- Client/src/Components/ButtonSpinner/index.jsx | 105 ------------------ 1 file changed, 105 deletions(-) delete mode 100644 Client/src/Components/ButtonSpinner/index.jsx diff --git a/Client/src/Components/ButtonSpinner/index.jsx b/Client/src/Components/ButtonSpinner/index.jsx deleted file mode 100644 index 8c6d1deb8..000000000 --- a/Client/src/Components/ButtonSpinner/index.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import LoadingButton from "@mui/lab/LoadingButton"; -import PropTypes from "prop-types"; - -const levelConfig = { - primary: { - variant: "contained", - color: "primary", - }, - secondary: { - variant: "outlined", - color: "secondary", - }, - tertiary: { - variant: "text", - color: "tertiary", - }, - error: { - variant: "contained", - color: "error", - }, -}; - -/** - * @component - * @param {Object} props - * @param {'primary' | 'secondary' | 'tertiary' | 'error'} props.level - The style level of the button. - * @param {string} props.label - The label text displayed on the button. - * @param {React.ReactNode} [props.img] - Icon or image element to display within the button. - * @param {boolean} [props.disabled=false] - Determines if the button is disabled. - * @param {string} [props.loadingText] - Text displayed when the button is in a loading state. - * @param {'start' | 'end'} [props.position] - Specifies where the icon or loading loadingText should be positioned relative to the label. - * @param {function} props.onClick - Callback function invoked when the button is clicked. - * @param {boolean} props.isLoading - Indicates if the button is in a loading state. - * @param {Object} [props.sx] - Additional styles to apply to the button. - * @returns {JSX.Element} - * @example - * // Render a primary button with an icon at the end - * } - * position="end" - * onClick={handleSaveClick} - * isLoading={loading} - * /> - */ - -const ButtonSpinner = ({ - level, - label, - disabled, - loadingText, - position, - img, - onClick, - isLoading, - sx, -}) => { - const { variant, color } = levelConfig[level]; - //if both a loadingPosition and loadingIndicator are provided, the spinner overlaps with the text and it breaks - if (position && loadingText) loadingText = null; - return ( - - {label} - - ); -}; - -ButtonSpinner.propTypes = { - level: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - loadingText: PropTypes.string, - position: PropTypes.oneOf(["start", "end"]), - img: PropTypes.node, - onClick: PropTypes.func.isRequired, - isLoading: PropTypes.bool.isRequired, - sx: PropTypes.object, - disabled: PropTypes.bool, -}; - -export default ButtonSpinner; From 8b9641aee8d11c0dbb232d556f2a9480dff259a1 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 31 Aug 2024 18:13:03 -0400 Subject: [PATCH 090/101] Removed redundant color vars --- Client/src/Utils/Theme/darkTheme.js | 5 ----- Client/src/Utils/Theme/lightTheme.js | 5 ----- 2 files changed, 10 deletions(-) diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index 61d37fcab..15df7c1b8 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -65,11 +65,6 @@ const darkTheme = createTheme({ fill: "#18181a", grid: "#454546", }, - // TO BE REMOVED // - tertiary: { - main: "#e6e6e6", - }, - // ----------------- // }, spacing: 2, components: { diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index 49f864e53..bb83d09b2 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -62,11 +62,6 @@ const lightTheme = createTheme({ fill: "#e3e3e3", grid: "#a2a3a3", }, - // TO BE REMOVED // - tertiary: { - main: "#475467", - }, - // ----------------- // }, spacing: 2, components: { From 8ac53a9e1689759db0fb7b232eb892ecc1dab274 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 31 Aug 2024 16:48:02 -0700 Subject: [PATCH 091/101] Add safety check for monitor --- Server/db/mongo/modules/monitorModule.js | 3 ++ Server/index.js | 6 +-- Server/service/networkService.js | 62 +++++++++++++----------- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index eebb8f496..79e8917ea 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -280,6 +280,9 @@ const getMonitorStatsById = async (req) => { const getMonitorById = async (monitorId) => { try { const monitor = await Monitor.findById(monitorId); + if (monitor === null || monitor === undefined) { + throw new Error(errorMessages.DB_FIND_MONTIOR_BY_ID(monitorId)); + } // Get notifications const notifications = await Notification.find({ monitorId: monitorId, diff --git a/Server/index.js b/Server/index.js index 846b11e3d..47b7cfd90 100644 --- a/Server/index.js +++ b/Server/index.js @@ -140,9 +140,9 @@ const startApp = async () => { } process.exit(0); }; - process.on("SIGUSR2", cleanup); - process.on("SIGINT", cleanup); - process.on("SIGTERM", cleanup); + // process.on("SIGUSR2", cleanup); + // process.on("SIGINT", cleanup); + // process.on("SIGTERM", cleanup); }; startApp().catch((error) => { diff --git a/Server/service/networkService.js b/Server/service/networkService.js index 4f76194ac..f5c333a60 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -16,37 +16,45 @@ class NetworkService { } async handleNotification(job, isAlive) { - const { _id } = job.data; - const monitor = await this.db.getMonitorById(_id); - if (monitor === null || monitor === undefined) { - logger.error(`Null Monitor: ${_id}`, { + try { + const { _id } = job.data; + const monitor = await this.db.getMonitorById(_id); + if (monitor === null || monitor === undefined) { + logger.error(`Null Monitor: ${_id}`, { + method: "handleNotification", + service: this.SERVICE_NAME, + jobId: job.id, + }); + return; + } + + // If monitor status changes, update monitor status and send notification + if (monitor.status !== isAlive) { + monitor.status = !monitor.status; + await monitor.save(); + + let template = + isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate"; + let status = isAlive === true ? "up" : "down"; + + const notifications = await this.db.getNotificationsByMonitorId(_id); + for (const notification of notifications) { + if (notification.type === "email") { + await this.emailService.buildAndSendEmail( + template, + { monitorName: monitor.name, monitorUrl: monitor.url }, + notification.address, + `Monitor ${monitor.name} is ${status}` + ); + } + } + } + } catch (error) { + logger.error(error.message, { method: "handleNotification", service: this.SERVICE_NAME, jobId: job.id, }); - return; - } - - // If monitor status changes, update monitor status and send notification - if (monitor.status !== isAlive) { - monitor.status = !monitor.status; - await monitor.save(); - - let template = - isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate"; - let status = isAlive === true ? "up" : "down"; - - const notifications = await this.db.getNotificationsByMonitorId(_id); - for (const notification of notifications) { - if (notification.type === "email") { - await this.emailService.buildAndSendEmail( - template, - { monitorName: monitor.name, monitorUrl: monitor.url }, - notification.address, - `Monitor ${monitor.name} is ${status}` - ); - } - } } } From cbd5a2ab86424fd00c4aef71359d55fe90604e1d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 31 Aug 2024 16:51:11 -0700 Subject: [PATCH 092/101] uncommented out cleanup code' --- Server/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Server/index.js b/Server/index.js index 47b7cfd90..846b11e3d 100644 --- a/Server/index.js +++ b/Server/index.js @@ -140,9 +140,9 @@ const startApp = async () => { } process.exit(0); }; - // process.on("SIGUSR2", cleanup); - // process.on("SIGINT", cleanup); - // process.on("SIGTERM", cleanup); + process.on("SIGUSR2", cleanup); + process.on("SIGINT", cleanup); + process.on("SIGTERM", cleanup); }; startApp().catch((error) => { From cf49201be1df38da159ed527bc89feec621555b7 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Sat, 31 Aug 2024 20:00:29 -0400 Subject: [PATCH 093/101] Add correct variant prop --- Client/src/Pages/Monitors/Home/fallback.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Monitors/Home/fallback.jsx b/Client/src/Pages/Monitors/Home/fallback.jsx index f9a444e7c..270f23f29 100644 --- a/Client/src/Pages/Monitors/Home/fallback.jsx +++ b/Client/src/Pages/Monitors/Home/fallback.jsx @@ -24,7 +24,7 @@ const Fallback = ({ isAdmin }) => {
{isAdmin && (