Feat: Hooks for Summary

This commit is contained in:
Br0wnHammer committed 2025-07-01 18:10:35 +05:30
1 parent 5428999d46
commit 644de5f34a
8 files changed
+91 -38

No files matched your search

+27 -1
View File
@@ -122,4 +122,30 @@ const useFetchChecksByMonitor = ({
return [checks, checksCount, isLoading, networkError];
};
export { useFetchChecksByMonitor, useFetchChecksTeam };
const useFetchChecksSummaryByTeamId = () => {
const [summary, setSummary] = useState(undefined);
const [isLoading, setIsLoading] = useState(false);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchSummary = async () => {
try {
setIsLoading(true);
const res = await networkService.getChecksAndSummaryByTeamId();
setSummary(res.data.data);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchSummary();
}, []);
return [summary, isLoading, networkError];
};
export { useFetchChecksByMonitor, useFetchChecksTeam, useFetchChecksSummaryByTeamId };
@@ -22,31 +22,31 @@ const StatusBox = ({ title, value, status }) => {
color = theme.palette.success.lowContrast;
icon = (
<Box sx={{ ...sharedStyles, top: 8 }}>
<TaskAltOutlinedIcon fontSize="small"/>
<TaskAltOutlinedIcon fontSize="small" />
</Box>
);
} else if (status === "down") {
color = theme.palette.error.lowContrast;
icon = (
<Box sx={{ ...sharedStyles, transform: "rotate(180deg)", top: 5 }}>
<CancelOutlinedIcon fontSize="small"/>
<CancelOutlinedIcon fontSize="small" />
</Box>
);
} else if (status === "paused") {
color = theme.palette.warning.lowContrast;
icon = (
<Box sx={{ ...sharedStyles, top: 12, right: 12 }}>
<WarningAmberRoundedIcon fontSize="small"/>
<WarningAmberRoundedIcon fontSize="small" />
</Box>
);
} else {
color = theme.palette.accent.main;
icon = (
<Box sx={{ ...sharedStyles, top: 12, right: 12 }}>
<MonitorHeartOutlinedIcon fontSize="small"/>
</Box>
);
}
color = theme.palette.accent.main;
icon = (
<Box sx={{ ...sharedStyles, top: 12, right: 12 }}>
<MonitorHeartOutlinedIcon fontSize="small" />
</Box>
);
}
return (
<Box
@@ -113,4 +113,4 @@ StatusBox.propTypes = {
status: PropTypes.string,
};
export default StatusBox;
export default StatusBox;
@@ -4,7 +4,7 @@ import StatusBox from "./StatusBox";
import { useTheme } from "@emotion/react";
import SkeletonLayout from "./skeleton";
const StatusBoxes = ({ isLoading, statusCounts }) => {
const StatusBoxes = ({ isLoading, summary }) => {
const theme = useTheme();
if (isLoading) return <SkeletonLayout shouldRender={isLoading} />;
return (
@@ -15,35 +15,30 @@ const StatusBoxes = ({ isLoading, statusCounts }) => {
>
<StatusBox
title={"Total Incidents"}
value={statusCounts?.total || 0}
value={summary?.totalChecks || 0}
/>
<StatusBox
title={"Resolved"}
status="up"
value={statusCounts?.resolved || 0}
value={summary?.resolvedChecks || 0}
/>
<StatusBox
title={"Cannot Resolve"}
status="paused"
value={summary?.cannotResolveChecks || 0}
/>
<StatusBox
title={"Down"}
status="down"
value={summary?.downChecks || 0}
/>
<StatusBox
title={"Cannot Resolve"}
status="paused"
value={statusCounts?.cannotResolve || 0}
/>
<StatusBox
title={"Down"}
status="down"
value={statusCounts?.down || 0}
/>
</Stack>
);
};
StatusBoxes.propTypes = {
isLoading: PropTypes.bool,
statusCounts: PropTypes.shape({
total: PropTypes.number,
resolved: PropTypes.number,
cannotResolve: PropTypes.number,
down: PropTypes.number,
}),
summary: PropTypes.object,
};
export default StatusBoxes;
export default StatusBoxes;
+6 -2
View File
@@ -9,6 +9,7 @@ import StatusBoxes from "./Components/StatusBoxes";
//Utils
import { useTheme } from "@emotion/react";
import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks";
import { useFetchChecksSummaryByTeamId } from "../../Hooks/checkHooks";
import { useState, useEffect } from "react";
import NetworkError from "../../Components/GenericFallback/NetworkError";
import { useTranslation } from "react-i18next";
@@ -32,6 +33,8 @@ const Incidents = () => {
//Utils
const theme = useTheme();
const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({});
const [summary, isLoadingSummary, networkErrorSummary] =
useFetchChecksSummaryByTeamId();
const { monitorId } = useParams();
useEffect(() => {
@@ -52,7 +55,7 @@ const Incidents = () => {
setMonitorLookup(monitorLookup);
}, [monitors]);
if (networkError) {
if (networkError || networkErrorSummary) {
return (
<GenericFallback>
<NetworkError />
@@ -64,7 +67,8 @@ const Incidents = () => {
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<StatusBoxes
isLoading={isLoading}
isLoading={isLoadingSummary}
summary={summary}
/>
<OptionsHeader
shouldRender={!isLoading}
+12
View File
@@ -601,6 +601,18 @@ class NetworkService {
return this.axiosInstance.get(`/checks/team?${params.toString()}`);
};
/**
* ************************************
* Get summary of checks by team ID
* ************************************
*
* @async
* @returns {Promise<AxiosResponse>} The response from the axios GET request.
*/
getChecksAndSummaryByTeamId = async () => {
return this.axiosInstance.get(`/checks/team/summary`);
};
/**
* ************************************
* Update the status of a check
+13
View File
@@ -111,6 +111,19 @@ class CheckController {
}
};
getChecksSummaryByTeamId = async (req, res, next) => {
try {
const { teamId } = req.user;
const summary = await this.db.getChecksSummaryByTeamId({ teamId });
return res.success({
msg: this.stringService.checkGetSummary,
data: summary,
});
} catch (error) {
next(handleError(error, SERVICE_NAME, "getChecksSummaryByTeamId"));
}
};
ackCheck = async (req, res, next) => {
try {
await ackCheckBodyValidation.validateAsync(req.body);
+6 -4
View File
@@ -312,12 +312,14 @@ const ackAllChecks = async (monitorId, teamId, ack, path) => {
* @returns {Promise<Object>}
* @throws {Error}
*/
const getChecksAndSummaryByTeamId = async ({ teamId }) => {
const getChecksSummaryByTeamId = async ({ teamId }) => {
try {
const matchStage = {
teamId: new ObjectId(teamId),
}
const checks = await Check.aggregate(buildChecksAndSummaryByTeamIdPipeline({ matchStage }));
};
const checks = await Check.aggregate(
buildChecksAndSummaryByTeamIdPipeline({ matchStage })
);
return checks[0].summary;
} catch (error) {
error.service = SERVICE_NAME;
@@ -409,7 +411,7 @@ export {
getChecksByTeam,
ackCheck,
ackAllChecks,
getChecksAndSummaryByTeamId,
getChecksSummaryByTeamId,
deleteChecks,
deleteChecksByTeamId,
updateChecksTTL,
+1
View File
@@ -14,6 +14,7 @@ class CheckRoutes {
initRoutes() {
this.router.get("/team", this.checkController.getChecksByTeam);
this.router.get("/team/summary", this.checkController.getChecksSummaryByTeamId);
this.router.delete(
"/team",
isAllowed(["admin", "superadmin"]),