From b28e4df546207d18dd6e208a849cd180994ea115 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 8 Aug 2024 14:27:01 -0700 Subject: [PATCH 1/9] Add endpoints and route for all user checks --- Server/controllers/checkController.js | 15 ++++++++++ Server/db/mongo/MongoDB.js | 2 ++ Server/db/mongo/modules/checkModule.js | 39 +++++++++++++++++++++++++- Server/routes/checkRoute.js | 4 ++- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js index 20c2e0b8c..2b4a08b3d 100644 --- a/Server/controllers/checkController.js +++ b/Server/controllers/checkController.js @@ -60,6 +60,20 @@ const getChecks = async (req, res, next) => { } }; +const getUserChecks = async (req, res, next) => { + try { + const checks = req.db.getUserChecks(req); + return res.status(200).json({ + success: true, + msg: successMessages.CHECK_GET, + data: { checksCount, checks }, + }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } +}; + const deleteChecks = async (req, res, next) => { try { await deleteChecksParamValidation.validateAsync(req.params); @@ -88,5 +102,6 @@ const deleteChecks = async (req, res, next) => { module.exports = { createCheck, getChecks, + getUserChecks, deleteChecks, }; diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 1dbc4e3b8..ed1b9e4b1 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -90,6 +90,7 @@ const { createCheck, getChecksCount, getChecks, + getUserChecks, deleteChecks, } = require("./modules/checkModule"); @@ -148,6 +149,7 @@ module.exports = { createCheck, getChecksCount, getChecks, + getUserChecks, deleteChecks, createAlert, getAlertsByUserId, diff --git a/Server/db/mongo/modules/checkModule.js b/Server/db/mongo/modules/checkModule.js index 4d315dc9a..f2322150a 100644 --- a/Server/db/mongo/modules/checkModule.js +++ b/Server/db/mongo/modules/checkModule.js @@ -1,4 +1,6 @@ const Check = require("../../../models/Check"); +const Monitor = require("../../../models/Monitor"); +const mongoose = require("mongoose"); const filterLookup = { day: new Date(new Date().setDate(new Date().getDate() - 1)), week: new Date(new Date().setDate(new Date().getDate() - 7)), @@ -92,6 +94,35 @@ const getChecks = async (req) => { * @throws {Error} */ +const getUserChecks = async (req) => { + const { userId } = req.params; + try { + const objectId = mongoose.Types.ObjectId.createFromHexString(userId); + + const checks = await Check.aggregate([ + { + $lookup: { + from: "monitors", // The name of the Monitor collection + localField: "monitorId", + foreignField: "_id", + as: "monitorDetails", + }, + }, + { + $unwind: "$monitorDetails", + }, + { + $match: { + "monitorDetails.userId": objectId, + }, + }, + ]); + return checks; + } catch (error) { + throw error; + } +}; + const deleteChecks = async (monitorId) => { try { const result = await Check.deleteMany({ monitorId }); @@ -100,4 +131,10 @@ const deleteChecks = async (monitorId) => { throw error; } }; -module.exports = { createCheck, getChecksCount, getChecks, deleteChecks }; +module.exports = { + createCheck, + getChecksCount, + getChecks, + getUserChecks, + deleteChecks, +}; diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index 0216343c8..bb06594ac 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -21,4 +21,6 @@ router.post( checkController.deleteChecks ); -module.exports = router; \ No newline at end of file +router.get("/user/:userId", checkController.getUserChecks); + +module.exports = router; From 60996da4013b706d0cec7c0ee50cf3f6c3dd7b1d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 8 Aug 2024 14:56:26 -0700 Subject: [PATCH 2/9] iniital refactor --- Client/src/Pages/Incidents/index.jsx | 60 +++------------------------- 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 4c328a364..d150b11ad 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -42,6 +42,7 @@ const Incidents = () => { const theme = useTheme(); const navigate = useNavigate(); const authState = useSelector((state) => state.auth); + const [monitors, setMonitors] = useState({}); const [selectedMonitor, setSelectedMonitor] = useState("0"); const [loading, setLoading] = useState(false); @@ -49,21 +50,11 @@ const Incidents = () => { // TODO do something with these filters const [filter, setFilter] = useState("all"); - let data = { - cols: [ - { id: 1, name: "Status" }, - { id: 2, name: "Timestamp" }, - { id: 3, name: "Monitor" }, - { id: 4, name: "Message" }, - ], - rows: [], - }; - useEffect(() => { - const fetchIncidents = async () => { + const fetchMonitors = async () => { setLoading(true); const res = await axiosInstance.get( - `/monitors/user/${authState.user._id}?status=false`, + `/monitors/user/${authState.user._id}?status=false&limit=1`, { headers: { Authorization: `Bearer ${authState.authToken}`, @@ -82,58 +73,19 @@ const Incidents = () => { setLoading(false); }; - fetchIncidents(); + fetchMonitors(); }, [authState]); const handleSelect = (event) => { setSelectedMonitor(event.target.value); }; - let incidents = []; - let hasAnyIncidents = false; - let hasSpecificIncidents = false; - if (selectedMonitor === "0") { - Object.values(monitors).forEach((monitor) => { - incidents = incidents.concat(monitor.checks); - }); - if (incidents.length !== 0) hasAnyIncidents = true; - hasSpecificIncidents = hasAnyIncidents; - } else { - const monitor = monitors[selectedMonitor]; - incidents = monitor.checks; - if (incidents.length !== 0) hasSpecificIncidents = true; - hasAnyIncidents = true; - } - incidents = incidents - .sort((a, b) => { - return new Date(b.createdAt) - new Date(a.createdAt); - }) - .filter((incident) => { - if (filter === "all") return true; - else if (filter === "resolve") return incident.statusCode === 5000; - else if (filter === "down") return incident.status === false; - }) - .map((incident, idx) => { - return { - id: idx, - data: [ - { - id: idx + 0, - data: , - }, - { id: idx + 1, data: new Date(incident.createdAt).toLocaleString() }, - { id: idx + 2, data: monitors[incident.monitorId].name }, - { id: idx + 3, data: incident.statusCode }, - ], - }; - }); - data.rows = incidents; return ( <> {loading ? ( - ) : hasAnyIncidents ? ( + ) : false ? ( <> Incident history for: @@ -178,7 +130,7 @@ const Incidents = () => { )} {hasAnyIncidents && hasSpecificIncidents ? ( - +
thing
) : ( The monitor you have selected, has no recorded incidents yet. From d95fcb119dd6e016a99449c7463846df1ac943a3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 8 Aug 2024 16:13:08 -0700 Subject: [PATCH 3/9] Renamed filter to dateRange, add incidents table --- .../Charts/MonitorDetailsAreaChart/index.jsx | 1 - .../Pages/Incidents/IncidentTable/index.jsx | 125 ++++++++++ Client/src/Pages/Incidents/index.jsx | 219 +++++++++++------- .../Details/PaginationTable/index.jsx | 8 +- Client/src/Pages/Monitors/Details/index.jsx | 27 ++- Server/db/mongo/modules/checkModule.js | 15 +- Server/validation/joi.js | 3 +- 7 files changed, 285 insertions(+), 113 deletions(-) create mode 100644 Client/src/Pages/Incidents/IncidentTable/index.jsx diff --git a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx index 567de0b68..91657f542 100644 --- a/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx +++ b/Client/src/Components/Charts/MonitorDetailsAreaChart/index.jsx @@ -79,7 +79,6 @@ const MonitorDetailsAreaChart = ({ checks }) => { MonitorDetailsAreaChart.propTypes = { checks: PropTypes.array, - filter: PropTypes.string, }; CustomToolTip.propTypes = { diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx new file mode 100644 index 000000000..bfcaed1e6 --- /dev/null +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -0,0 +1,125 @@ +import PropTypes from "prop-types"; +import { + TableContainer, + Table, + TableHead, + TableRow, + TableCell, + TableBody, + TableFooter, + TablePagination, +} from "@mui/material"; + +import { useState, useEffect } from "react"; +import { useSelector } from "react-redux"; +import axiosInstance from "../../../Utils/axiosConfig"; +import { StatusLabel } from "../../../Components/Label"; + +const IncidentTable = ({ monitorId, filter }) => { + const { authToken } = useSelector((state) => state.auth); + const [checks, setChecks] = useState([]); + const [checksCount, setChecksCount] = useState(0); + const [paginationController, setPaginationController] = useState({ + page: 0, + rowsPerPage: 5, + }); + + useEffect(() => { + const fetchPage = async () => { + try { + if (monitorId === "0") { + return; + } + const res = await axiosInstance.get( + `/checks/${monitorId}?sortOrder=desc&filter=${filter}&page=${paginationController.page}&rowsPerPage=${paginationController.rowsPerPage}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); + setChecks(res.data.data.checks); + setChecksCount(res.data.data.checksCount); + } catch (error) { + console.log(error); + } + }; + fetchPage(); + }, [ + authToken, + monitorId, + filter, + paginationController.page, + paginationController.rowsPerPage, + ]); + + const handlePageChange = (_, newPage) => { + setPaginationController({ + ...paginationController, + page: newPage, + }); + }; + + const handleChangeRowsPerPage = (event) => { + setPaginationController({ + ...paginationController, + rowsPerPage: parseInt(event.target.value, 10), + page: 0, + }); + }; + + return ( + + + + + Monitor Name + Status + Date & Time + Message + + + + {checks.map((check) => { + const status = check.status === true ? "up" : "down"; + + return ( + + + + + + {new Date(check.createdAt).toLocaleString()} + + {check.statusCode} + + ); + })} + + + + + + +
+
+ ); +}; + +IncidentTable.propTypes = { + monitorId: PropTypes.string.isRequired, + filter: PropTypes.string.isRequired, +}; + +export default IncidentTable; diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index d150b11ad..45237a0d1 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -9,7 +9,7 @@ import { StatusLabel } from "../../Components/Label"; import { useTheme } from "@emotion/react"; import { useNavigate } from "react-router"; import Select from "../../Components/Inputs/Select"; - +import IncidentTable from "./IncidentTable"; import "./index.css"; /** @@ -76,99 +76,142 @@ const Incidents = () => { fetchMonitors(); }, [authState]); + useEffect(() => {}, []); + const handleSelect = (event) => { setSelectedMonitor(event.target.value); }; return ( - <> - - {loading ? ( - - ) : false ? ( - <> - - Incident history for: - + +