From 6dde4646d8206eb612932b9e6337409c5be58ede Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 2 Aug 2024 10:53:24 -0700 Subject: [PATCH 1/9] Add prevent default to action toggle --- Client/src/Components/BasicTable/index.jsx | 4 +++- Client/src/Pages/Monitors/index.jsx | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index 2a580d512..3f89de700 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -135,7 +135,9 @@ const BasicTable = ({ data, paginated, reversed, rowsPerPage = 5 }) => { {displayData.map((row) => { return ( diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index 9c9f99d15..d7e3d542d 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -60,6 +60,7 @@ const Monitors = () => { const [anchorEl, setAnchorEl] = useState(null); const [actions, setActions] = useState({}); const openMenu = (event, id, url) => { + event.preventDefault(); setAnchorEl(event.currentTarget); setActions({ id: id, url: url }); }; @@ -137,7 +138,7 @@ const Monitors = () => { return { id: monitor._id, // disabled for now - // handleClick: () => navigate(`/monitors/${monitor._id}`), + handleClick: () => navigate(`/monitors/${monitor._id}`), data: [ { id: idx, data: }, { @@ -163,7 +164,10 @@ const Monitors = () => { <> openMenu(event, monitor._id, monitor.url)} + onClick={(event) => { + event.stopPropagation(); + openMenu(event, monitor._id, monitor.url); + }} sx={{ "&:focus": { outline: "none", @@ -227,7 +231,10 @@ const Monitors = () => { onClose={closeMenu} > window.open(actions.url, "_blank", "noreferrer")} + onClick={(event) => { + event.stopPropagation(); + window.open(actions.url, "_blank", "noreferrer"); + }} > Open site From 004e43092b5de425e5fa38859d7e65bb2986bb0b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 2 Aug 2024 10:57:12 -0700 Subject: [PATCH 2/9] Stop event bubbling on link to monitor site --- Client/src/Pages/Monitors/index.jsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx index d7e3d542d..451c76f30 100644 --- a/Client/src/Pages/Monitors/index.jsx +++ b/Client/src/Pages/Monitors/index.jsx @@ -41,7 +41,14 @@ import { const Host = ({ params }) => { return ( - + { + event.stopPropagation(); + }} + > {params.title} @@ -231,8 +238,7 @@ const Monitors = () => { onClose={closeMenu} > { - event.stopPropagation(); + onClick={() => { window.open(actions.url, "_blank", "noreferrer"); }} > From 8d5850607071f9718a8099f0526f1e48360514cd Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 2 Aug 2024 11:16:02 -0700 Subject: [PATCH 3/9] Add inline style to ResponseTime chart --- Client/src/Components/Charts/ResponseTimeChart/index.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Client/src/Components/Charts/ResponseTimeChart/index.jsx b/Client/src/Components/Charts/ResponseTimeChart/index.jsx index d76abc196..063ce3b16 100644 --- a/Client/src/Components/Charts/ResponseTimeChart/index.jsx +++ b/Client/src/Components/Charts/ResponseTimeChart/index.jsx @@ -8,7 +8,12 @@ const ResponseTimeChart = ({ checks = [] }) => { return (
- + {normalizedChecks.map((check, index) => ( Date: Fri, 2 Aug 2024 11:24:15 -0700 Subject: [PATCH 4/9] Added empty query to request object --- Server/controllers/authController.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 6f34f71ce..ffb38559e 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -440,6 +440,7 @@ const deleteUserController = async (req, res, next) => { const { _id, email } = decodedToken; const decodedTokenCastedAsRequest = { + query: {}, params: { userId: _id, }, From a04ecad11f91c73d15a21260cc8dd2fd0338226f Mon Sep 17 00:00:00 2001 From: Alexander Holliday Date: Fri, 2 Aug 2024 11:25:35 -0700 Subject: [PATCH 5/9] Update authController.js --- Server/controllers/authController.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index ffb38559e..296b3fd63 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -439,6 +439,7 @@ const deleteUserController = async (req, res, next) => { const decodedToken = jwt.decode(token); const { _id, email } = decodedToken; + // TODO fix this hack const decodedTokenCastedAsRequest = { query: {}, params: { From 6c92dbe3581f0c35ef9a926365681cd98c06572a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 2 Aug 2024 11:38:38 -0700 Subject: [PATCH 6/9] Delete pagespeed checks when user deleted --- Server/controllers/authController.js | 1 + Server/controllers/monitorController.js | 1 + Server/db/mongo/MongoDB.js | 4 ++-- Server/db/mongo/modules/pageSpeedCheckModule.js | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index ffb38559e..041395161 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -481,6 +481,7 @@ const deleteUserController = async (req, res, next) => { await req.jobQueue.deleteJob(monitor); await req.db.deleteChecks(monitor._id); await req.db.deleteAlertByMonitorId(monitor._id); + await req.db.deletePageSpeedChecksByMonitorId(monitor._id); await req.db.deleteNotificationsByMonitorId(monitor._id); }) ); diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index e05ed0389..d45b300f8 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -182,6 +182,7 @@ const deleteMonitor = async (req, res, next) => { await req.jobQueue.deleteJob(monitor); await req.db.deleteChecks(monitor._id); await req.db.deleteAlertByMonitorId(monitor._id); + await req.db.deletePageSpeedChecksByMonitorId(monitor._id); await req.db.deleteNotificationsByMonitorId(monitor._id); /** diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 2813a3c00..68597a794 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -79,7 +79,7 @@ const { const { createPageSpeedCheck, getPageSpeedChecks, - deletePageSpeedChecks, + deletePageSpeedChecksByMonitorId, } = require("./modules/pageSpeedCheckModule"); //**************************************** @@ -157,7 +157,7 @@ module.exports = { deleteMonitorsByUserId, createPageSpeedCheck, getPageSpeedChecks, - deletePageSpeedChecks, + deletePageSpeedChecksByMonitorId, createMaintenanceWindow, getMaintenanceWindowsByUserId, getMaintenanceWindowsByMonitorId, diff --git a/Server/db/mongo/modules/pageSpeedCheckModule.js b/Server/db/mongo/modules/pageSpeedCheckModule.js index 65376a324..92f87d060 100644 --- a/Server/db/mongo/modules/pageSpeedCheckModule.js +++ b/Server/db/mongo/modules/pageSpeedCheckModule.js @@ -48,7 +48,7 @@ const getPageSpeedChecks = async (monitorId) => { * @throws {Error} */ -const deletePageSpeedChecks = async (monitorId) => { +const deletePageSpeedChecksByMonitorId = async (monitorId) => { try { const result = await PageSpeedCheck.deleteMany({ monitorId }); return result.deletedCount; @@ -60,5 +60,5 @@ const deletePageSpeedChecks = async (monitorId) => { module.exports = { createPageSpeedCheck, getPageSpeedChecks, - deletePageSpeedChecks, + deletePageSpeedChecksByMonitorId, }; From aed4881eac1068b13c43a1085c4303d2e1d72e7b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 2 Aug 2024 11:54:46 -0700 Subject: [PATCH 7/9] Fix rest verbs --- Client/src/Features/Auth/authSlice.js | 6 ++---- .../UptimeMonitors/uptimeMonitorsSlice.js | 20 ++++++++----------- Server/routes/authRoute.js | 2 +- Server/routes/monitorRoute.js | 6 +++--- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index 2b75c8d33..a30c295d9 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -61,7 +61,7 @@ export const update = createAsyncThunk( form.deleteProfileImage && fd.append("deleteProfileImage", form.deleteProfileImage); - const res = await axiosInstance.post(`/auth/user/${user._id}`, fd, { + const res = await axiosInstance.put(`/auth/user/${user._id}`, fd, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "multipart/form-data", @@ -185,9 +185,7 @@ const handleForgotRejected = (state, action) => { const handleNewPasswordRejected = (state, action) => { state.isLoading = false; state.success = false; - state.msg = action.payload - ? action.payload.msg - : "Failed to reset password."; + state.msg = action.payload ? action.payload.msg : "Failed to reset password."; }; const authSlice = createSlice({ diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 05c182f5f..52a02cd55 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -77,9 +77,9 @@ export const updateUptimeMonitor = createAsyncThunk( name: monitor.name, description: monitor.description, interval: monitor.interval, - notifications: monitor.notifications + notifications: monitor.notifications, }; - const res = await axiosInstance.post( + const res = await axiosInstance.put( `/monitors/edit/${monitor._id}`, updatedFields, { @@ -104,16 +104,12 @@ export const deleteUptimeMonitor = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.post( - `/monitors/delete/${monitor._id}`, - {}, - { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - } - ); + const res = await axiosInstance.delete(`/monitors/${monitor._id}`, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); return res.data; } catch (error) { if (error.response && error.response.data) { diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 137434b7a..b01e90294 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -23,7 +23,7 @@ const { //Auth routes router.post("/register", upload.single("profileImage"), registerController); router.post("/login", loginController); -router.post( +router.put( "/user/:userId", upload.single("profileImage"), verifyJWT, diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index ae7a5852e..1f50c9e70 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -8,12 +8,12 @@ router.get("/:monitorId", monitorController.getMonitorById); router.get("/user/:userId", monitorController.getMonitorsByUserId); router.post("/", monitorController.createMonitor); -router.post( - "/delete/:monitorId", +router.delete( + "/:monitorId", verifyOwnership(Monitor, "monitorId"), monitorController.deleteMonitor ); -router.post( +router.put( "/edit/:monitorId", verifyOwnership(Monitor, "monitorId"), monitorController.editMonitor From 907dcf4072a8725148f148ba02516ecea991261d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 2 Aug 2024 12:32:08 -0700 Subject: [PATCH 8/9] Add required stats to PagespeedCheck model --- Server/models/PageSpeedCheck.js | 38 ++++++++++++++++++++++++++++++++ Server/service/networkService.js | 24 ++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/Server/models/PageSpeedCheck.js b/Server/models/PageSpeedCheck.js index 8ff630197..3ae0bada9 100644 --- a/Server/models/PageSpeedCheck.js +++ b/Server/models/PageSpeedCheck.js @@ -1,5 +1,39 @@ const mongoose = require("mongoose"); +const AuditSchema = mongoose.Schema({ + id: { type: String, required: true }, + title: { type: String, required: true }, + description: { type: String, required: true }, + score: { type: Number, required: true }, + scoreDisplayMode: { type: String, required: true }, + displayValue: { type: String, required: true }, + numericValue: { type: Number, required: true }, + numericUnit: { type: String, required: true }, +}); + +const AuditsSchema = mongoose.Schema({ + cls: { + type: AuditSchema, + required: true, + }, + si: { + type: AuditSchema, + required: true, + }, + fcp: { + type: AuditSchema, + required: true, + }, + lcp: { + type: AuditSchema, + required: true, + }, + tbt: { + type: AuditSchema, + required: true, + }, +}); + /** * Mongoose schema for storing metrics from Google Lighthouse. * @typedef {Object} PageSpeedCheck @@ -37,6 +71,10 @@ const PageSpeedCheck = mongoose.Schema( type: Number, required: true, }, + audits: { + type: AuditsSchema, + required: true, + }, }, { timestamps: true, diff --git a/Server/service/networkService.js b/Server/service/networkService.js index 0ee65c424..dc8994945 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -129,6 +129,22 @@ class NetworkService { ); const pageSpeedResults = response.data; const categories = pageSpeedResults.lighthouseResult?.categories; + const audits = pageSpeedResults.lighthouseResult?.audits; + const { + "cumulative-layout-shift": cls, + "speed-index": si, + "first-contentful-paint": fcp, + "largest-contentful-paint": lcp, + "total-blocking-time": tbt, + } = audits; + + // Weights + // First Contentful Paint 10% + // Speed Index 10% + // Largest Contentful Paint 25% + // Total Blocking Time 30% + // Cumulative Layout Shift 25% + const checkData = { monitorId: job.data._id, status: true, @@ -136,7 +152,15 @@ class NetworkService { bestPractices: (categories["best-practices"]?.score || 0) * 100, seo: (categories.seo?.score || 0) * 100, performance: (categories.performance?.score || 0) * 100, + audits: { + cls, + si, + fcp, + lcp, + tbt, + }, }; + this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck); } catch (error) { const checkData = { From 420b65209ed3aa0fd934d112fc9f7fc9613b43c1 Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Sat, 3 Aug 2024 09:40:08 +0330 Subject: [PATCH 9/9] fixes --- Client/src/App.jsx | 5 + .../CreateMaintenanceWindow/index.css | 21 +++ .../CreateMaintenanceWindow/index.jsx | 151 ++++++++++++++++++ Client/src/Pages/Maintenance/index.jsx | 1 + Client/src/assets/icons/left-arrow.svg | 3 + Client/src/index.css | 2 + 6 files changed, 183 insertions(+) create mode 100644 Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css create mode 100644 Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx create mode 100644 Client/src/assets/icons/left-arrow.svg diff --git a/Client/src/App.jsx b/Client/src/App.jsx index a5b649e8b..69edf9a6d 100644 --- a/Client/src/App.jsx +++ b/Client/src/App.jsx @@ -24,6 +24,7 @@ import withAdminCheck from "./HOC/withAdminCheck"; import Configure from "./Pages/Monitors/Configure"; import PageSpeed from "./Pages/PageSpeed"; import CreatePageSpeed from "./Pages/PageSpeed/CreatePageSpeed"; +import CreateNewMaintenanceWindow from "./Pages/Maintenance/CreateMaintenanceWindow"; function App() { const AdminCheckedRegister = withAdminCheck(Register); @@ -69,6 +70,10 @@ function App() { path="maintenance" element={} /> + } + /> } diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css new file mode 100644 index 000000000..a799bf0af --- /dev/null +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css @@ -0,0 +1,21 @@ +.maintenance-options > .MuiStack-root > .MuiStack-root.select-wrapper { + width: 380px; +} + +.date-picker .MuiOutlinedInput-root, +.time-picker .MuiOutlinedInput-root { + height: 34px; + font-size: var(--env-var-font-size-medium); +} + +.date-picker .MuiOutlinedInput-root { + width: 140px; +} + +.time-picker .MuiOutlinedInput-root { + width: 90px; +} + +.MuiInputAdornment-outlined .MuiIconButton-root svg { + width: 20px; +} diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx new file mode 100644 index 000000000..aea012e2c --- /dev/null +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -0,0 +1,151 @@ +import { Box, Stack, Typography } from "@mui/material"; +import "./index.css"; +import React, { useState } from "react"; +import Button from "../../../Components/Button"; +import Back from "../../../assets/icons/left-arrow.svg?react"; +import Select from "../../../Components/Inputs/Select"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; +import dayjs from "dayjs"; +import { DatePicker } from "@mui/x-date-pickers/DatePicker"; +import { MobileTimePicker } from "@mui/x-date-pickers/MobileTimePicker"; + +const directory = { + title: "Create a maintenance window", + description: "Your pings won’t be sent in this time frame.", +}; + +const repeatOptions = [ + { _id: 1, name: "Don't repeat" }, + { _id: 2, name: "Repeat daily" }, + { _id: 3, name: "Repeat weekly" }, +]; + +const configOptionTitle = (title, description) => { + return ( + + + {title} + + {description && ( + + {description} + + )} + + ); +}; + +const CreateNewMaintenanceWindow = () => { + const [values, setValues] = useState({ + repeat: 1, + }); + + const handleChange = (event, name) => { + const { value } = event.target; + setValues((prev) => ({ + ...prev, + [name]: value, + })); + }; + + const configOptions = [ + { + title: "Repeat", + component: ( +