Merge pull request #610 from bluewave-labs/feat/fe/monitor-details-stats

Feat/fe/monitor details stats
This commit is contained in:
Alexander Holliday
2024-08-12 19:26:31 -07:00
committed by GitHub
8 changed files with 100 additions and 8 deletions

View File

@@ -113,6 +113,7 @@ const DetailsPage = () => {
const { monitorId } = useParams();
const { authToken } = useSelector((state) => state.auth);
const [dateRange, setDateRange] = useState("day");
const [certificateExpiry, setCertificateExpiry] = useState("N/A");
const navigate = useNavigate();
const fetchMonitor = useCallback(async () => {
@@ -136,10 +137,23 @@ const DetailsPage = () => {
fetchMonitor();
}, [fetchMonitor]);
useEffect(() => {
const fetchCertificate = async () => {
const res = await axiosInstance.get(
`/monitors/certificate/${monitorId}`,
{
headers: {
Authorization: `Bearer ${authToken}`,
},
}
);
setCertificateExpiry(res.data.data.certificateDate);
};
fetchCertificate();
}, [authToken, monitorId]);
const theme = useTheme();
let loading = Object.keys(monitor).length === 0;
return (
<Box className="monitor-details">
{loading ? (
@@ -222,6 +236,35 @@ const DetailsPage = () => {
value={`${formatDuration(monitor?.lastChecked)} ago`}
/>
<StatBox title="Incidents" value={monitor?.incidents} />
<StatBox title="Certificate Expiry" value={certificateExpiry} />
</Stack>
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
>
<StatBox
title="Latest response time"
value={monitor?.latestResponseTime}
/>
<StatBox
title="Average Repsonse Time (24 hours)"
value={parseFloat(monitor?.avgResponseTime24hours)
.toFixed(2)
.replace(/\.?0+$/, "")}
/>
<StatBox
title="Uptime (24 hours)"
value={`${parseFloat(monitor?.uptime24Hours)
.toFixed(2)
.replace(/\.?0+$/, "")}%`}
/>
<StatBox
title="Uptime(30 days)"
value={`${parseFloat(monitor?.uptime30Days)
.toFixed(2)
.replace(/\.?0+$/, "")}%`}
/>
</Stack>
<Box>
<Stack
@@ -266,7 +309,9 @@ const DetailsPage = () => {
</ButtonGroup>
</Stack>
<Box sx={{ height: "200px" }}>
<MonitorDetailsAreaChart checks={monitor.checks.reverse()} />
<MonitorDetailsAreaChart
checks={[...monitor.checks].reverse()}
/>
</Box>
</Box>
<Stack gap={theme.gap.ml}>

View File

@@ -6,11 +6,9 @@ import { useTheme } from "@emotion/react";
import { useNavigate, useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import {
formatDate,
formatDuration,
formatDurationRounded,
} from "../../../Utils/timeUtils";
import { getLastChecked } from "../../../Utils/monitorUtils";
import axiosInstance from "../../../Utils/axiosConfig";
import Button from "../../../Components/Button";
import WestRoundedIcon from "@mui/icons-material/WestRounded";

View File

@@ -7,6 +7,7 @@ const {
getMonitorsByUserIdQueryValidation,
} = require("../validation/joi");
const sslChecker = require("ssl-checker");
const SERVICE_NAME = "monitorController";
const { errorMessages, successMessages } = require("../utils/messages");
const { runInNewContext } = require("vm");
@@ -65,6 +66,41 @@ const getMonitorStatsById = async (req, res, next) => {
}
};
const getMonitorCertificate = async (req, res, next) => {
try {
//validation
} catch (error) {
error.status = 422;
error.message =
error.details?.[0]?.message || error.message || "Validation Error";
next(error);
}
try {
const monitor = await req.db.getMonitorById(req, res);
const monitorUrl = new URL(monitor.url);
const certificate = await sslChecker(monitorUrl.hostname);
if (certificate && certificate.validTo) {
return res.json({
success: true,
msg: successMessages.MONITOR_CERTIFICATE,
data: {
certificateDate: new Date(certificate.validTo).toLocaleDateString(),
},
});
} else {
return res.json({
success: true,
msg: successMessages.MONITOR_CERTIFICATE,
data: { certificateDate: "N/A" },
});
}
} catch (error) {
error.service = SERVICE_NAME;
next(error);
}
};
/**
* Returns monitor with matching ID
* @async
@@ -302,6 +338,7 @@ const editMonitor = async (req, res, next) => {
module.exports = {
getAllMonitors,
getMonitorStatsById,
getMonitorCertificate,
getMonitorById,
getMonitorsByUserId,
createMonitor,

View File

@@ -57,6 +57,7 @@ const CheckSchema = mongoose.Schema(
*
* @type {Date}
*/
expiry: {
type: Date,
default: Date.now,

View File

@@ -27,6 +27,7 @@
"nodemailer": "^6.9.14",
"ping": "0.4.4",
"sharp": "0.33.4",
"ssl-checker": "2.0.10",
"winston": "^3.13.0"
},
"devDependencies": {
@@ -983,9 +984,10 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz",
"integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
@@ -5026,6 +5028,12 @@
"memory-pager": "^1.0.2"
}
},
"node_modules/ssl-checker": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/ssl-checker/-/ssl-checker-2.0.10.tgz",
"integrity": "sha512-SS6rrZocToJWHM1p6iVNb583ybB3UqT1fymCHSWuEdXDUqKA6O1D5Fb8KJVmhj3XKXE82IEWcr+idJrc4jUzFQ==",
"license": "MIT"
},
"node_modules/stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",

View File

@@ -29,6 +29,7 @@
"nodemailer": "^6.9.14",
"ping": "0.4.4",
"sharp": "0.33.4",
"ssl-checker": "2.0.10",
"winston": "^3.13.0"
},
"devDependencies": {

View File

@@ -5,6 +5,7 @@ const Monitor = require("../models/Monitor");
router.get("/", monitorController.getAllMonitors);
router.get("/stats/:monitorId", monitorController.getMonitorStatsById);
router.get("/certificate/:monitorId", monitorController.getMonitorCertificate);
router.get("/:monitorId", monitorController.getMonitorById);
router.get("/user/:userId", monitorController.getMonitorsByUserId);

View File

@@ -77,6 +77,7 @@ const successMessages = {
MONITOR_CREATE: "Monitor created successfully",
MONITOR_DELETE: "Monitor deleted successfully",
MONITOR_EDIT: "Monitor edited successfully",
MONITOR_CERTIFICATE: "Got monitor certificate successfully",
//Job Queue
JOB_QUEUE_DELETE_JOB: "Job removed successfully",