diff --git a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx
new file mode 100644
index 000000000..5f0f8a690
--- /dev/null
+++ b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx
@@ -0,0 +1,121 @@
+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 PaginationTable = ({ 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 {
+ 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 (
+
+
+
+
+ Status
+ Date & Time
+ Message
+
+
+
+ {checks.map((check) => {
+ const status = check.status === true ? "up" : "down";
+
+ return (
+
+
+
+
+
+ {new Date(check.createdAt).toLocaleString()}
+
+ {check.statusCode}
+
+ );
+ })}
+
+
+
+
+
+
+
+
+ );
+};
+
+PaginationTable.propTypes = {
+ monitorId: PropTypes.string.isRequired,
+ filter: PropTypes.string.isRequired,
+};
+
+export default PaginationTable;
diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx
index e097149d4..4095fdf88 100644
--- a/Client/src/Pages/Monitors/Details/index.jsx
+++ b/Client/src/Pages/Monitors/Details/index.jsx
@@ -4,7 +4,6 @@ import { Box, Skeleton, Stack, Typography, useTheme } from "@mui/material";
import { useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
import axiosInstance from "../../../Utils/axiosConfig";
-import BasicTable from "../../../Components/BasicTable";
import MonitorDetailsAreaChart from "../../../Components/Charts/MonitorDetailsAreaChart";
import { StatusLabel } from "../../../Components/Label";
import ButtonGroup from "@mui/material/ButtonGroup";
@@ -13,6 +12,7 @@ import WestRoundedIcon from "@mui/icons-material/WestRounded";
import GreenCheck from "../../../assets/icons/checkbox-green.svg?react";
import RedCheck from "../../../assets/icons/checkbox-red.svg?react";
import SettingsIcon from "../../../assets/icons/settings-bold.svg?react";
+import PaginationTable from "./PaginationTable";
import {
formatDuration,
formatDurationRounded,
@@ -111,62 +111,11 @@ const SkeletonLayout = () => {
*/
const DetailsPage = () => {
const [monitor, setMonitor] = useState({});
- const [data, setData] = useState({});
const { monitorId } = useParams();
const { authToken } = useSelector((state) => state.auth);
const [filter, setFilter] = useState("day");
const navigate = useNavigate();
- const fetchDataForTable = useCallback(async () => {
- try {
- const limit = 0;
-
- const res = await axiosInstance.get(
- `/monitors/${monitorId}?sortOrder=asc&limit=${limit}`,
- {
- headers: {
- Authorization: `Bearer ${authToken}`,
- },
- }
- );
- const data = {
- cols: [
- { id: 1, name: "Status" },
- { id: 2, name: "Date & Time" },
- { id: 3, name: "Message" },
- ],
- rows: res.data.data.checks.map((check, idx) => {
- const status = check.status === true ? "up" : "down";
-
- return {
- id: check._id,
- data: [
- {
- id: idx,
- data: (
-
- ),
- },
- {
- id: idx + 1,
- data: new Date(check.createdAt).toLocaleString(),
- },
- { id: idx + 2, data: check.statusCode },
- ],
- };
- }),
- };
-
- setData(data);
- } catch (error) {
- console.log(error);
- }
- }, [authToken, monitorId]);
-
const fetchMonitor = useCallback(async () => {
try {
const res = await axiosInstance.get(
@@ -259,9 +208,6 @@ const DetailsPage = () => {
fetchDataForTable();
}, [fetchDataForTable]);
- useEffect(() => {
- fetchDataForChart();
- }, [filter]);
const theme = useTheme();
@@ -463,7 +409,9 @@ const DetailsPage = () => {
History
-
+ {/* TODO New Table */}
+
+ {/* */}
>
diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js
index f3c85352f..20c2e0b8c 100644
--- a/Server/controllers/checkController.js
+++ b/Server/controllers/checkController.js
@@ -2,6 +2,7 @@ const {
createCheckParamValidation,
createCheckBodyValidation,
getChecksParamValidation,
+ getChecksQueryValidation,
deleteChecksParamValidation,
} = require("../validation/joi");
const { successMessages } = require("../utils/messages");
@@ -35,6 +36,7 @@ const createCheck = async (req, res, next) => {
const getChecks = async (req, res, next) => {
try {
await getChecksParamValidation.validateAsync(req.params);
+ await getChecksQueryValidation.validateAsync(req.query);
} catch (error) {
error.status = 422;
error.service = SERVICE_NAME;
@@ -45,10 +47,13 @@ const getChecks = async (req, res, next) => {
}
try {
- const checks = await req.db.getChecks(req.params.monitorId);
- return res
- .status(200)
- .json({ success: true, msg: successMessages.CHECK_GET, data: checks });
+ const checks = await req.db.getChecks(req);
+ const checksCount = await req.db.getChecksCount(req);
+ return res.status(200).json({
+ success: true,
+ msg: successMessages.CHECK_GET,
+ data: { checksCount, checks },
+ });
} catch (error) {
error.service = SERVICE_NAME;
next(error);
diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js
index 68597a794..1dbc4e3b8 100644
--- a/Server/db/mongo/MongoDB.js
+++ b/Server/db/mongo/MongoDB.js
@@ -88,6 +88,7 @@ const {
const {
createCheck,
+ getChecksCount,
getChecks,
deleteChecks,
} = require("./modules/checkModule");
@@ -145,6 +146,7 @@ module.exports = {
deleteAllMonitors,
editMonitor,
createCheck,
+ getChecksCount,
getChecks,
deleteChecks,
createAlert,
diff --git a/Server/db/mongo/modules/checkModule.js b/Server/db/mongo/modules/checkModule.js
index 35c313fd9..4d315dc9a 100644
--- a/Server/db/mongo/modules/checkModule.js
+++ b/Server/db/mongo/modules/checkModule.js
@@ -1,5 +1,9 @@
const Check = require("../../../models/Check");
-
+const filterLookup = {
+ day: new Date(new Date().setDate(new Date().getDate() - 1)),
+ week: new Date(new Date().setDate(new Date().getDate() - 7)),
+ month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
+};
/**
* Create a check for a monitor
* @async
@@ -22,6 +26,19 @@ const createCheck = async (checkData) => {
}
};
+const getChecksCount = async (req) => {
+ const monitorId = req.params.monitorId;
+ const filter = req.query.filter;
+ // Build query
+ const checksQuery = { monitorId: monitorId };
+ // Filter checks by "day", "week", or "month"
+ if (filter !== undefined) {
+ checksQuery.createdAt = { $gte: filterLookup[filter] };
+ }
+ const count = await Check.countDocuments(checksQuery);
+ return count;
+};
+
/**
* Get all checks for a monitor
* @async
@@ -30,9 +47,37 @@ const createCheck = async (checkData) => {
* @throws {Error}
*/
-const getChecks = async (monitorId) => {
+const getChecks = async (req) => {
try {
- const checks = await Check.find({ monitorId });
+ const { monitorId } = req.params;
+ let { sortOrder, limit, filter, page, rowsPerPage } = req.query;
+
+ // Default limit to 0 if not provided
+ if (limit === undefined) limit = 0;
+
+ // Default sort order is newest -> oldest
+ if (sortOrder === "asc") {
+ sortOrder = 1;
+ } else if (sortOrder === "desc") {
+ sortOrder = -1;
+ } else sortOrder = -1;
+
+ // Build query
+ const checksQuery = { monitorId: monitorId };
+ // Filter checks by "day", "week", or "month"
+ if (filter !== undefined) {
+ checksQuery.createdAt = { $gte: filterLookup[filter] };
+ }
+
+ // Need to skip and limit here
+ let skip = 0;
+ if (page && rowsPerPage) {
+ skip = page * rowsPerPage;
+ }
+ const checks = await Check.find(checksQuery)
+ .skip(skip)
+ .limit(rowsPerPage)
+ .sort({ createdAt: sortOrder });
return checks;
} catch (error) {
throw error;
@@ -55,4 +100,4 @@ const deleteChecks = async (monitorId) => {
throw error;
}
};
-module.exports = { createCheck, getChecks, deleteChecks };
+module.exports = { createCheck, getChecksCount, getChecks, deleteChecks };
diff --git a/Server/utils/dataUtils.js b/Server/utils/dataUtils.js
index 3495cc3d6..f1c4b39b2 100644
--- a/Server/utils/dataUtils.js
+++ b/Server/utils/dataUtils.js
@@ -19,7 +19,6 @@ const NormalizeData = (checks, rangeMin, rangeMax) => {
const normalizedChecks = checks.map((check) => {
const originalResponseTime = check.responseTime;
- console.log(originalResponseTime);
// Normalize the response time between 1 and 100
let normalizedResponseTime =
rangeMin +
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index 8e3dbcfec..f938fabd9 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -232,6 +232,14 @@ const getChecksParamValidation = joi.object({
monitorId: joi.string().required(),
});
+const getChecksQueryValidation = joi.object({
+ sortOrder: joi.string().valid("asc", "desc"),
+ limit: joi.number(),
+ filter: joi.string().valid("day", "week", "month"),
+ page: joi.number(),
+ rowsPerPage: joi.number(),
+});
+
const deleteChecksParamValidation = joi.object({
monitorId: joi.string().required(),
});
@@ -311,6 +319,7 @@ module.exports = {
createCheckParamValidation,
createCheckBodyValidation,
getChecksParamValidation,
+ getChecksQueryValidation,
deleteChecksParamValidation,
deleteUserParamValidation,
getPageSpeedCheckParamValidation,