Merge pull request #572 from bluewave-labs/fix/be/monitor-data-pagination

Fix/be/monitor data pagination, also resolves #567
This commit is contained in:
Alexander Holliday authored and GitHub committed 2024-08-08 14:25:14 -07:00
commit 5c91e98daf
7 files changed
+194 -65

No files matched your search

@@ -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 (
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Status</TableCell>
<TableCell>Date & Time</TableCell>
<TableCell>Message</TableCell>
</TableRow>
</TableHead>
<TableBody>
{checks.map((check) => {
const status = check.status === true ? "up" : "down";
return (
<TableRow key={check._id}>
<TableCell>
<StatusLabel
status={status}
text={status}
customStyles={{ textTransform: "capitalize" }}
/>
</TableCell>
<TableCell>
{new Date(check.createdAt).toLocaleString()}
</TableCell>
<TableCell>{check.statusCode}</TableCell>
</TableRow>
);
})}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
onPageChange={handlePageChange}
page={paginationController.page}
count={checksCount}
rowsPerPage={paginationController.rowsPerPage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
);
};
PaginationTable.propTypes = {
monitorId: PropTypes.string.isRequired,
filter: PropTypes.string.isRequired,
};
export default PaginationTable;
+4 -56
View File
@@ -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: (
<StatusLabel
status={status}
text={status}
customStyles={{ textTransform: "capitalize" }}
/>
),
},
{
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 = () => {
</Box>
<Stack gap={theme.gap.ml}>
<Typography component="h2">History</Typography>
<BasicTable data={data} paginated={true} reversed={true} />
{/* TODO New Table */}
<PaginationTable monitorId={monitorId} filter={filter} />
{/* <BasicTable data={data} paginated={true} /> */}
</Stack>
</Stack>
</>
+9 -4
View File
@@ -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);
+2
View File
@@ -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,
+49 -4
View File
@@ -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 };
-1
View File
@@ -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 +
+9
View File
@@ -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,