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:
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,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>
|
||||
</>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 };
|
||||
@@ -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 +
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user