Feat: Hooks for Summary
This commit is contained in:
1 parent
5428999d46
commit
644de5f34a
8 files changed
+91
-38
No files matched your search
@@ -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;
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"]),
|
||||
|
||||
Reference in new issue
Block a user