diff --git a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js
index 6cd91ac28..b2da2cbe6 100644
--- a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js
+++ b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js
@@ -40,7 +40,7 @@ export const checkEndpointResolution = createAsyncThunk(
const res = await networkService.checkEndpointResolution({
authToken: authToken,
monitorURL: monitorURL,
- })
+ });
return res.data;
} catch (error) {
if (error.response && error.response.data) {
@@ -53,7 +53,7 @@ export const checkEndpointResolution = createAsyncThunk(
return thunkApi.rejectWithValue(payload);
}
}
-)
+);
export const getPagespeedMonitorById = createAsyncThunk(
"monitors/getMonitorById",
@@ -88,7 +88,6 @@ export const getPageSpeedByTeamId = createAsyncThunk(
teamId: user.teamId,
types: ["pagespeed"],
});
-
return res.data;
} catch (error) {
if (error.response && error.response.data) {
diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js
index 8782948ae..7ea34b9ea 100644
--- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js
+++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js
@@ -78,62 +78,6 @@ export const getUptimeMonitorById = createAsyncThunk(
}
);
-export const getUptimeSummaryByTeamId = createAsyncThunk(
- "monitors/getSummaryByTeamId",
- async (token, thunkApi) => {
- const user = jwtDecode(token);
- try {
- const res = await networkService.getMonitorsSummaryByTeamId({
- authToken: token,
- teamId: user.teamId,
- types: ["http", "ping", "docker", "port"],
- });
- return res.data;
- } catch (error) {
- if (error.response && error.response.data) {
- return thunkApi.rejectWithValue(error.response.data);
- }
- const payload = {
- status: false,
- msg: error.message ? error.message : "Unknown error",
- };
- return thunkApi.rejectWithValue(payload);
- }
- }
-);
-
-export const getUptimeMonitorsByTeamId = createAsyncThunk(
- "monitors/getMonitorsByTeamId",
- async (config, thunkApi) => {
- try {
- const res = await networkService.getMonitorsByTeamId({
- authToken: config.authToken,
- teamId: config.teamId,
- limit: 25,
- types: ["http", "ping", "docker", "port"],
- status: null,
- checkOrder: "desc",
- normalize: true,
- page: config.page,
- rowsPerPage: config.rowsPerPage,
- filter: config.filter,
- field: config.sort.field,
- order: config.sort.order,
- });
- return res.data;
- } catch (error) {
- if (error.response && error.response.data) {
- return thunkApi.rejectWithValue(error.response.data);
- }
- const payload = {
- status: false,
- msg: error.message ? error.message : "Unknown error",
- };
- return thunkApi.rejectWithValue(payload);
- }
- }
-);
-
export const updateUptimeMonitor = createAsyncThunk(
"monitors/updateMonitor",
async (data, thunkApi) => {
@@ -289,42 +233,6 @@ const uptimeMonitorsSlice = createSlice({
},
extraReducers: (builder) => {
builder
- // *****************************************************
- // Summary by teamId
- // *****************************************************
-
- .addCase(getUptimeSummaryByTeamId.pending, (state) => {
- state.isLoading = true;
- })
- .addCase(getUptimeSummaryByTeamId.fulfilled, (state, action) => {
- state.isLoading = false;
- state.success = action.payload.msg;
- state.monitorsSummary = action.payload.data;
- })
- .addCase(getUptimeSummaryByTeamId.rejected, (state, action) => {
- state.isLoading = false;
- state.success = false;
- state.msg = action.payload ? action.payload.msg : "Getting uptime summary failed";
- })
-
- // *****************************************************
- // Monitors by teamId
- // *****************************************************
- .addCase(getUptimeMonitorsByTeamId.pending, (state) => {
- state.isLoading = true;
- })
- .addCase(getUptimeMonitorsByTeamId.fulfilled, (state, action) => {
- state.isLoading = false;
- state.success = action.payload.success;
- state.msg = action.payload.msg;
- })
- .addCase(getUptimeMonitorsByTeamId.rejected, (state, action) => {
- state.isLoading = false;
- state.success = false;
- state.msg = action.payload
- ? action.payload.msg
- : "Getting uptime monitors failed";
- })
// *****************************************************
// Create Monitor
// *****************************************************
diff --git a/Client/src/Pages/Infrastructure/index.jsx b/Client/src/Pages/Infrastructure/index.jsx
index be7d7e9ed..d9ef7528e 100644
--- a/Client/src/Pages/Infrastructure/index.jsx
+++ b/Client/src/Pages/Infrastructure/index.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from "react";
+import { useEffect, useState, useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { /* useDispatch, */ useSelector } from "react-redux";
import { useTheme } from "@emotion/react";
@@ -50,12 +50,13 @@ function Infrastructure() {
setRowsPerPage(parseInt(event.target.value));
setPage(0);
};
- const [monitorState, setMonitorState] = useState({ monitors: [], total: 0 });
+ const [monitors, setMonitors] = useState([]);
+ const [summary, setSummary] = useState({});
const { authToken } = useSelector((state) => state.auth);
const user = jwtDecode(authToken);
- const fetchMonitors = async () => {
+ const fetchMonitors = useCallback(async () => {
try {
setIsLoading(true);
const response = await networkService.getMonitorsByTeamId({
@@ -63,29 +64,23 @@ function Infrastructure() {
teamId: user.teamId,
limit: 1,
types: ["hardware"],
- status: null,
- checkOrder: "desc",
- normalize: true,
page: page,
rowsPerPage: rowsPerPage,
});
- setMonitorState({
- monitors: response?.data?.data?.monitors ?? [],
- total: response?.data?.data?.monitorCount ?? 0,
- });
+ setMonitors(response?.data?.data?.monitors ?? []);
+ setSummary(response?.data?.data?.summary ?? {});
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
- };
+ }, [page, rowsPerPage, authToken, user.teamId]);
useEffect(() => {
fetchMonitors();
- }, [page, rowsPerPage]);
+ }, [fetchMonitors]);
const { determineState } = useUtils();
- const { monitors, total: totalMonitors } = monitorState;
// do it here
function openDetails(id) {
navigate(`/infrastructure/${id}`);
@@ -191,7 +186,7 @@ function Infrastructure() {
};
});
- let isActuallyLoading = isLoading && monitorState.monitors?.length === 0;
+ let isActuallyLoading = isLoading && monitors?.length === 0;
return (
{isActuallyLoading ? (
- ) : monitorState.monitors?.length !== 0 ? (
+ ) : monitors?.length !== 0 ? (
@@ -254,7 +249,7 @@ function Infrastructure() {
borderColor={theme.palette.border.light}
backgroundColor={theme.palette.background.accent}
>
- {totalMonitors}
+ {summary?.totalMonitors ?? 0}
@@ -272,7 +267,7 @@ function Infrastructure() {
data={monitorsAsRows}
/>
{
sx={{ gridColumnStart: 1, gridColumnEnd: 4 }}
>
diff --git a/Client/src/Pages/PageSpeed/index.jsx b/Client/src/Pages/PageSpeed/index.jsx
index b18148aa8..98761be6f 100644
--- a/Client/src/Pages/PageSpeed/index.jsx
+++ b/Client/src/Pages/PageSpeed/index.jsx
@@ -1,8 +1,7 @@
import { Box, Button, Grid, Stack } from "@mui/material";
import { useEffect, useState } from "react";
import { useTheme } from "@emotion/react";
-import { useDispatch, useSelector } from "react-redux";
-import { getPageSpeedByTeamId } from "../../Features/PageSpeedMonitor/pageSpeedMonitorSlice";
+import { useSelector } from "react-redux";
import Fallback from "../../Components/Fallback";
import "./index.css";
import { useNavigate } from "react-router";
@@ -15,16 +14,12 @@ import { Heading } from "../../Components/Heading";
import { useIsAdmin } from "../../Hooks/useIsAdmin";
const PageSpeed = () => {
const theme = useTheme();
- const dispatch = useDispatch();
const navigate = useNavigate();
const isAdmin = useIsAdmin();
const { user, authToken } = useSelector((state) => state.auth);
const [isLoading, setIsLoading] = useState(true);
const [monitors, setMonitors] = useState([]);
- const [monitorCount, setMonitorCount] = useState(0);
- useEffect(() => {
- dispatch(getPageSpeedByTeamId(authToken));
- }, [authToken, dispatch]);
+ const [summary, setSummary] = useState({});
useEffect(() => {
const fetchMonitors = async () => {
@@ -35,9 +30,6 @@ const PageSpeed = () => {
teamId: user.teamId,
limit: 10,
types: ["pagespeed"],
- status: null,
- checkOrder: "desc",
- normalize: true,
page: null,
rowsPerPage: null,
filter: null,
@@ -46,7 +38,7 @@ const PageSpeed = () => {
});
if (res?.data?.data?.monitors) {
setMonitors(res.data.data.monitors);
- setMonitorCount(res.data.data.monitorCount);
+ setSummary(res.data.data.summary);
}
} catch (error) {
console.log(error);
@@ -118,7 +110,7 @@ const PageSpeed = () => {
borderColor={theme.palette.border.light}
backgroundColor={theme.palette.background.accent}
>
- {monitorCount}
+ {summary?.totalMonitors ?? 0}
} props.monitors - Array of monitor objects to display
+ * @param {number} props.monitorCount - Total count of monitors
+ * @param {Object} props.sort - Current sort configuration
+ * @param {string} props.sort.field - Field to sort by
+ * @param {'asc'|'desc'} props.sort.order - Sort direction
+ * @param {Function} props.setSort - Callback to update sort configuration
+ * @param {string} props.search - Current search query
+ * @param {Function} props.setSearch - Callback to update search query
+ * @param {boolean} props.isSearching - Whether a search is in progress
+ * @param {Function} props.setIsSearching - Callback to update search state
+ * @param {Function} props.setIsLoading - Callback to update loading state
+ * @param {Function} props.triggerUpdate - Callback to trigger a data refresh
+ * @returns {JSX.Element} Rendered component
+ */
const UptimeDataTable = ({
isAdmin,
isLoading,
@@ -30,6 +59,7 @@ const UptimeDataTable = ({
setSearch,
isSearching,
setIsSearching,
+ setIsLoading,
triggerUpdate,
}) => {
const { determineState } = useUtils();
@@ -37,8 +67,6 @@ const UptimeDataTable = ({
const theme = useTheme();
const navigate = useNavigate();
- //Utils
- const debouncedFilter = useDebounce(search, 500);
const handleSearch = (value) => {
setIsSearching(true);
setSearch(value);
@@ -146,6 +174,7 @@ const UptimeDataTable = ({
monitor={row.monitor}
isAdmin={isAdmin}
updateRowCallback={triggerUpdate}
+ setIsLoading={setIsLoading}
pauseCallback={triggerUpdate}
/>
),
@@ -187,7 +216,7 @@ const UptimeDataTable = ({
- {isSearching && (
+ {(isSearching || isLoading) && (
<>
{
+const ActionsMenu = ({
+ monitor,
+ isAdmin,
+ updateRowCallback,
+ pauseCallback,
+ setIsLoading,
+}) => {
const [anchorEl, setAnchorEl] = useState(null);
const [actions, setActions] = useState({});
const [isOpen, setIsOpen] = useState(false);
@@ -33,7 +38,6 @@ const ActionsMenu = ({ monitor, isAdmin, updateRowCallback, pauseCallback }) =>
);
if (action.meta.requestStatus === "fulfilled") {
setIsOpen(false); // close modal
- dispatch(getUptimeMonitorsByTeamId(authState.authToken));
updateRowCallback();
createToast({ body: "Monitor deleted successfully." });
} else {
@@ -43,6 +47,7 @@ const ActionsMenu = ({ monitor, isAdmin, updateRowCallback, pauseCallback }) =>
const handlePause = async () => {
try {
+ setIsLoading(true);
const action = await dispatch(
pauseUptimeMonitor({ authToken, monitorId: monitor._id })
);
@@ -223,6 +228,7 @@ ActionsMenu.propTypes = {
isAdmin: PropTypes.bool,
updateRowCallback: PropTypes.func,
pauseCallback: PropTypes.func,
+ setIsLoading: PropTypes.func,
};
export default ActionsMenu;
diff --git a/Client/src/Pages/Uptime/Home/index.jsx b/Client/src/Pages/Uptime/Home/index.jsx
index 3dffb3ac9..391be0aed 100644
--- a/Client/src/Pages/Uptime/Home/index.jsx
+++ b/Client/src/Pages/Uptime/Home/index.jsx
@@ -9,11 +9,7 @@ import { Pagination } from "../../../Components/Table/TablePagination";
// Utils
import { useTheme } from "@emotion/react";
-import { useEffect, useState, useCallback, useMemo, useRef } from "react";
-import {
- getUptimeSummaryByTeamId,
- getUptimeMonitorsByTeamId,
-} from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
+import { useEffect, useState, useCallback, useMemo } from "react";
import { setRowsPerPage } from "../../../Features/UI/uiSlice";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import { useSelector, useDispatch } from "react-redux";
@@ -21,6 +17,7 @@ import { useNavigate } from "react-router-dom";
import { createToast } from "../../../Utils/toastUtils";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import useDebounce from "../../../Utils/debounce";
+import { networkService } from "../../../main";
const BREADCRUMBS = [{ name: `Uptime`, path: "/uptime" }];
@@ -33,7 +30,9 @@ const UptimeMonitors = () => {
const [search, setSearch] = useState("");
const [page, setPage] = useState(0);
const [isSearching, setIsSearching] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
const [monitorUpdateTrigger, setMonitorUpdateTrigger] = useState(false);
+ const [monitorsSummary, setMonitorsSummary] = useState({});
// Utils
const debouncedFilter = useDebounce(search, 500);
@@ -41,7 +40,6 @@ const UptimeMonitors = () => {
const theme = useTheme();
const navigate = useNavigate();
const isAdmin = useIsAdmin();
- const { isLoading, monitorsSummary } = useSelector((state) => state.uptimeMonitors);
const authState = useSelector((state) => state.auth);
const fetchParams = useMemo(
@@ -89,30 +87,38 @@ const UptimeMonitors = () => {
const fetchMonitors = useCallback(async () => {
try {
- const action = await dispatch(getUptimeMonitorsByTeamId(fetchParams));
- if (action.payload.success) {
- const { monitors } = action.payload.data;
- const mappedMonitors = monitors.map((monitor) =>
- getMonitorWithPercentage(monitor, theme)
- );
- setMonitors(mappedMonitors);
- } else {
- // TODO: Check for other errors?
- throw new Error("Error fetching monitors");
- }
+ setIsLoading(true);
+ const config = fetchParams;
+ const res = await networkService.getMonitorsByTeamId({
+ authToken: config.authToken,
+ teamId: config.teamId,
+ limit: 25,
+ types: ["http", "ping", "docker", "port"],
+ page: config.page,
+ rowsPerPage: config.rowsPerPage,
+ filter: config.filter,
+ field: config.sort.field,
+ order: config.sort.order,
+ });
+ const { monitors, summary } = res.data.data;
+ const mappedMonitors = monitors.map((monitor) =>
+ getMonitorWithPercentage(monitor, theme)
+ );
+ setMonitors(mappedMonitors);
+ setMonitorsSummary(summary);
} catch (error) {
createToast({
body: "Error fetching monitors",
});
} finally {
+ setIsLoading(false);
setIsSearching(false);
}
- }, [fetchParams, dispatch, getMonitorWithPercentage, theme]);
+ }, [fetchParams, getMonitorWithPercentage, theme]);
useEffect(() => {
- dispatch(getUptimeSummaryByTeamId(authState.authToken));
fetchMonitors();
- }, [fetchMonitors, monitorUpdateTrigger, authState.authToken, dispatch]);
+ }, [fetchMonitors, monitorUpdateTrigger]);
const handleChangePage = (event, newPage) => {
setPage(newPage);
@@ -131,7 +137,7 @@ const UptimeMonitors = () => {
const triggerUpdate = () => {
setMonitorUpdateTrigger((prev) => !prev);
};
- const totalMonitors = monitorsSummary?.monitorCounts?.total;
+ const totalMonitors = monitorsSummary.totalMonitors;
const hasMonitors = totalMonitors > 0;
const canAddMonitor = isAdmin && hasMonitors;
@@ -176,19 +182,20 @@ const UptimeMonitors = () => {
>
{
setSearch={setSearch}
isSearching={isSearching}
setIsSearching={setIsSearching}
+ setIsLoading={setIsLoading}
triggerUpdate={triggerUpdate}
/>
} [config.types] - The types of monitors to retrieve.
- * @param {string} [config.status] - The status of the monitors to retrieve.
- * @param {string} [config.checkOrder] - The order in which to sort the retrieved monitors.
- * @param {boolean} [config.normalize] - Whether to normalize the retrieved monitors.
* @param {number} [config.page] - The page number for pagination.
* @param {number} [config.rowsPerPage] - The number of rows per page for pagination.
* @param {string} [config.filter] - The filter to apply to the monitors.
@@ -167,21 +164,10 @@ class NetworkService {
* @param {string} [config.order] - The order in which to sort the field.
* @returns {Promise} The response from the axios GET request.
*/
+
async getMonitorsByTeamId(config) {
- const {
- authToken,
- teamId,
- limit,
- types,
- status,
- checkOrder,
- normalize,
- page,
- rowsPerPage,
- filter,
- field,
- order,
- } = config;
+ const { authToken, teamId, limit, types, page, rowsPerPage, filter, field, order } =
+ config;
const params = new URLSearchParams();
@@ -191,9 +177,6 @@ class NetworkService {
params.append("type", type);
});
}
- if (status) params.append("status", status);
- if (checkOrder) params.append("checkOrder", checkOrder);
- if (normalize) params.append("normalize", normalize);
if (page) params.append("page", page);
if (rowsPerPage) params.append("rowsPerPage", rowsPerPage);
if (filter) params.append("filter", filter);
diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js
index f5e7994b2..686661a00 100644
--- a/Server/controllers/monitorController.js
+++ b/Server/controllers/monitorController.js
@@ -1,13 +1,11 @@
import {
getMonitorByIdParamValidation,
getMonitorByIdQueryValidation,
- getMonitorsByTeamIdValidation,
+ getMonitorsByTeamIdParamValidation,
+ getMonitorsByTeamIdQueryValidation,
createMonitorBodyValidation,
getMonitorURLByQueryValidation,
editMonitorBodyValidation,
- getMonitorsSummaryByTeamIdParamValidation,
- getMonitorsSummaryByTeamIdQueryValidation,
- getMonitorsByTeamIdQueryValidation,
pauseMonitorParamValidation,
getMonitorStatsByIdParamValidation,
getMonitorStatsByIdQueryValidation,
@@ -204,77 +202,6 @@ class MonitorController {
}
};
- /**
- * Retrieves all monitors and a summary for a team based on the team ID.
- * @async
- * @param {Object} req - The Express request object.
- * @property {Object} req.params - The parameters of the request.
- * @property {string} req.params.teamId - The ID of the team.
- * @property {Object} req.query - The query parameters of the request.
- * @property {string} req.query.type - The type of the request.
- * @param {Object} res - The Express response object.
- * @param {function} next - The next middleware function.
- * @returns {Object} The response object with a success status, a message, and the data containing the monitors and summary for the team.
- * @throws {Error} If there is an error during the process, especially if there is a validation error (422).
- */
- getMonitorsSummaryByTeamId = async (req, res, next) => {
- try {
- await getMonitorsSummaryByTeamIdParamValidation.validateAsync(req.params);
- await getMonitorsSummaryByTeamIdQueryValidation.validateAsync(req.query);
- } catch (error) {
- next(handleValidationError(error, SERVICE_NAME));
- return;
- }
-
- try {
- const { teamId } = req.params;
- const { type } = req.query;
- const monitorsSummary = await this.db.getMonitorsSummaryByTeamId(teamId, type);
- return res.status(200).json({
- success: true,
- msg: successMessages.MONITOR_GET_BY_USER_ID(teamId),
- data: monitorsSummary,
- });
- } catch (error) {
- next(handleError(error, SERVICE_NAME, "getMonitorsAndSummaryByTeamId"));
- }
- };
-
- /**
- * Retrieves all monitors associated with a team by the team's ID.
- * @async
- * @param {Object} req - The Express request object.
- * @property {Object} req.params - The parameters of the request.
- * @property {string} req.params.teamId - The ID of the team.
- * @property {Object} req.query - The query parameters of the request.
- * @param {Object} res - The Express response object.
- * @param {function} next - The next middleware function.
- * @returns {Object} The response object with a success status, a message, and the data containing the monitors for the team.
- * @throws {Error} If there is an error during the process, especially if there is a validation error (422).
- */
- getMonitorsByTeamId = async (req, res, next) => {
- try {
- await getMonitorsByTeamIdValidation.validateAsync(req.params);
- await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
- } catch (error) {
- next(handleValidationError(error, SERVICE_NAME));
- return;
- }
-
- try {
- const teamId = req.params.teamId;
- const monitors = await this.db.getMonitorsByTeamId(req, res);
- return res.status(200).json({
- success: true,
- msg: successMessages.MONITOR_GET_BY_USER_ID(teamId),
- data: monitors,
- });
- } catch (error) {
- next(handleError(error, SERVICE_NAME, "getMonitorsByTeamId"));
- next(error);
- }
- };
-
/**
* Creates a new monitor and adds it to the job queue.
* @async
@@ -564,6 +491,26 @@ class MonitorController {
next(handleError(error, SERVICE_NAME, "addDemoMonitors"));
}
};
+
+ getMonitorsByTeamId = async (req, res, next) => {
+ try {
+ await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
+ await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
+ } catch (error) {
+ next(handleValidationError(error, SERVICE_NAME));
+ }
+
+ try {
+ const monitors = await this.db.getMonitorsByTeamId(req);
+ return res.status(200).json({
+ success: true,
+ msg: "good",
+ data: monitors,
+ });
+ } catch (error) {
+ next(handleError(error, SERVICE_NAME, "getMonitorsForDisplay"));
+ }
+ };
}
export default MonitorController;
diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js
index aa4cafbb7..77c290c52 100644
--- a/Server/db/mongo/modules/monitorModule.js
+++ b/Server/db/mongo/modules/monitorModule.js
@@ -505,202 +505,162 @@ const getMonitorById = async (monitorId) => {
}
};
-/**
- * Get monitors and Summary by TeamID
- * @async
- * @param {Express.Request} req
- * @param {Express.Response} res
- * @returns {Promise>}
- * @throws {Error}
- */
+const getMonitorsByTeamId = async (req) => {
+ let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
-const getMonitorsSummaryByTeamId = async (teamId, type) => {
- try {
- const monitorCounts = await Monitor.aggregate([
- {
- $match: {
- type: { $in: type },
- },
- },
- {
- $facet: {
- total: [{ $count: "count" }],
- up: [{ $match: { status: true } }, { $count: "count" }],
- down: [{ $match: { status: false } }, { $count: "count" }],
- paused: [{ $match: { isActive: false } }, { $count: "count" }],
- },
- },
- {
- $project: {
- total: { $arrayElemAt: ["$total.count", 0] },
- up: { $arrayElemAt: ["$up.count", 0] },
- down: { $arrayElemAt: ["$down.count", 0] },
- paused: { $arrayElemAt: ["$paused.count", 0] },
- },
- },
- ]);
- return { monitorCounts: monitorCounts[0] };
- } catch (error) {
- error.service = SERVICE_NAME;
- error.method = "getMonitorsAndSummaryByTeamId";
- throw error;
+ // Parse ints
+ limit = parseInt(limit);
+ page = parseInt(page);
+ rowsPerPage = parseInt(rowsPerPage);
+
+ // Build the match stage
+ const matchStage = { teamId: ObjectId.createFromHexString(req.params.teamId) };
+ if (type !== undefined) {
+ matchStage.type = Array.isArray(type) ? { $in: type } : type;
}
-};
-/**
- * Get monitors by TeamID
- * @async
- * @param {Express.Request} req
- * @param {Express.Response} res
- * @returns {Promise>}
- * @throws {Error}
- */
-const getMonitorsByTeamId = async (req, res) => {
- try {
- let {
- limit,
- type,
- status,
- checkOrder,
- normalize,
- page,
- rowsPerPage,
- filter,
- field,
- order,
- } = req.query;
+ const skip = page && rowsPerPage ? page * rowsPerPage : 0;
- const monitorQuery = { teamId: req.params.teamId };
- const monitorCount = await Monitor.countDocuments(monitorQuery);
+ const sort = { [field]: order === "asc" ? 1 : -1 };
- if (type !== undefined) {
- monitorQuery.type = Array.isArray(type) ? { $in: type } : type;
- }
- // Add filter if provided
- // $options: "i" makes the search case-insensitive
- if (filter !== undefined) {
- monitorQuery.$or = [
- { name: { $regex: filter, $options: "i" } },
- { url: { $regex: filter, $options: "i" } },
- ];
- }
+ if (filter !== undefined) {
+ matchStage.$or = [
+ { name: { $regex: filter, $options: "i" } },
+ { url: { $regex: filter, $options: "i" } },
+ ];
+ }
- // Pagination
- const skip = page && rowsPerPage ? page * rowsPerPage : 0;
-
- // Build Sort option
- const sort = { [field]: order === "asc" ? 1 : -1 };
-
- const matchStage = { teamId: new ObjectId(req.params.teamId) };
- if (type !== undefined) {
- matchStage.type = Array.isArray(type) ? { $in: type } : type;
- }
- if (filter !== undefined) {
- matchStage.$or = [
- { name: { $regex: filter, $options: "i" } },
- { url: { $regex: filter, $options: "i" } },
- ];
- }
-
- let result = await Monitor.aggregate([
- { $match: matchStage },
- { $skip: parseInt(skip) },
- ...(rowsPerPage ? [{ $limit: parseInt(rowsPerPage) }] : []),
- { $sort: sort },
- {
- $lookup: {
- from: "checks",
- let: { monitorId: "$_id" },
- pipeline: [
- {
- $match: {
- $expr: { $eq: ["$monitorId", "$$monitorId"] },
- ...(status && { status }),
- },
- },
- { $sort: { createdAt: checkOrder === "asc" ? 1 : -1 } },
- { $limit: parseInt(limit) || 0 },
- ],
- as: "standardchecks",
- },
- },
- {
- $lookup: {
- from: "pagespeedchecks",
- let: { monitorId: "$_id" },
- pipeline: [
- {
- $match: {
- $expr: { $eq: ["$monitorId", "$$monitorId"] },
- ...(status && { status }),
- },
- },
- { $sort: { createdAt: checkOrder === "asc" ? 1 : -1 } },
- { $limit: parseInt(limit) || 0 },
- ],
- as: "pagespeedchecks",
- },
- },
- {
- $lookup: {
- from: "hardwarechecks",
- let: { monitorId: "$_id" },
- pipeline: [
- {
- $match: {
- $expr: { $eq: ["$monitorId", "$$monitorId"] },
- ...(status && { status }),
- },
- },
- { $sort: { createdAt: checkOrder === "asc" ? 1 : -1 } },
- { $limit: parseInt(limit) || 0 },
- ],
- as: "hardwarechecks",
- },
- },
- {
- $addFields: {
- checks: {
- $switch: {
- branches: [
- {
- case: { $in: ["$type", ["http", "ping", "docker", "port"]] },
- then: "$standardchecks",
+ const results = await Monitor.aggregate([
+ { $match: matchStage },
+ {
+ $facet: {
+ summary: [
+ {
+ $group: {
+ _id: null,
+ totalMonitors: { $sum: 1 },
+ upMonitors: {
+ $sum: {
+ $cond: [{ $eq: ["$status", true] }, 1, 0],
},
- {
- case: { $eq: ["$type", "pagespeed"] },
- then: "$pagespeedchecks",
+ },
+ downMonitors: {
+ $sum: {
+ $cond: [{ $eq: ["$status", false] }, 1, 0],
},
- {
- case: { $eq: ["$type", "hardware"] },
- then: "$hardwarechecks",
+ },
+ pausedMonitors: {
+ $sum: {
+ $cond: [{ $eq: ["$isActive", false] }, 1, 0],
},
- ],
- default: [],
+ },
},
},
- },
+ {
+ $project: {
+ _id: 0,
+ },
+ },
+ ],
+ monitors: [
+ { $sort: sort },
+ { $skip: skip },
+ ...(rowsPerPage ? [{ $limit: rowsPerPage }] : []),
+ {
+ $lookup: {
+ from: "checks",
+ let: { monitorId: "$_id" },
+ pipeline: [
+ {
+ $match: {
+ $expr: { $eq: ["$monitorId", "$$monitorId"] },
+ },
+ },
+ { $sort: { createdAt: -1 } },
+ ...(limit ? [{ $limit: limit }] : []),
+ ],
+ as: "standardchecks",
+ },
+ },
+ {
+ $lookup: {
+ from: "pagespeedchecks",
+ let: { monitorId: "$_id" },
+ pipeline: [
+ {
+ $match: {
+ $expr: { $eq: ["$monitorId", "$$monitorId"] },
+ },
+ },
+ { $sort: { createdAt: -1 } },
+ ...(limit ? [{ $limit: limit }] : []),
+ ],
+ as: "pagespeedchecks",
+ },
+ },
+ {
+ $lookup: {
+ from: "hardwarechecks",
+ let: { monitorId: "$_id" },
+ pipeline: [
+ {
+ $match: {
+ $expr: { $eq: ["$monitorId", "$$monitorId"] },
+ },
+ },
+ { $sort: { createdAt: -1 } },
+ ...(limit ? [{ $limit: limit }] : []),
+ ],
+ as: "hardwarechecks",
+ },
+ },
+ {
+ $addFields: {
+ checks: {
+ $switch: {
+ branches: [
+ {
+ case: { $in: ["$type", ["http", "ping", "docker", "port"]] },
+ then: "$standardchecks",
+ },
+ {
+ case: { $eq: ["$type", "pagespeed"] },
+ then: "$pagespeedchecks",
+ },
+ {
+ case: { $eq: ["$type", "hardware"] },
+ then: "$hardwarechecks",
+ },
+ ],
+ default: [],
+ },
+ },
+ },
+ },
+ {
+ $project: {
+ standardchecks: 0,
+ pagespeedchecks: 0,
+ hardwarechecks: 0,
+ },
+ },
+ ],
},
- {
- $project: {
- standardchecks: 0,
- pagespeedchecks: 0,
- hardwarechecks: 0,
- },
+ },
+ {
+ $project: {
+ summary: { $arrayElemAt: ["$summary", 0] },
+ monitors: 1,
},
- ]);
- if (normalize) {
- result = result.map((monitor) => {
- monitor.checks = NormalizeData(monitor.checks, 10, 100);
- return monitor;
- });
- }
- return { monitors: result, monitorCount };
- } catch (error) {
- error.service = SERVICE_NAME;
- error.method = "getMonitorsByTeamId";
- throw error;
- }
+ },
+ ]);
+
+ let { monitors, summary } = results[0];
+ monitors = monitors.map((monitor) => {
+ monitor.checks = NormalizeData(monitor.checks, 10, 100);
+ return monitor;
+ });
+ return { monitors, summary };
};
/**
@@ -832,9 +792,8 @@ export {
getAllMonitorsWithUptimeStats,
getMonitorStatsById,
getMonitorById,
- getUptimeDetailsById,
- getMonitorsSummaryByTeamId,
getMonitorsByTeamId,
+ getUptimeDetailsById,
createMonitor,
deleteMonitor,
deleteAllMonitors,
diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js
index f3af8e806..92b529417 100644
--- a/Server/routes/monitorRoute.js
+++ b/Server/routes/monitorRoute.js
@@ -17,6 +17,7 @@ class MonitorRoutes {
"/hardware/details/:monitorId",
this.monitorController.getHardwareDetailsById
);
+
this.router.get(
"/uptime/details/:monitorId",
this.monitorController.getUptimeDetailsById
@@ -30,10 +31,7 @@ class MonitorRoutes {
);
});
this.router.get("/:monitorId", this.monitorController.getMonitorById);
- this.router.get(
- "/team/summary/:teamId",
- this.monitorController.getMonitorsSummaryByTeamId
- );
+
this.router.get("/team/:teamId", this.monitorController.getMonitorsByTeamId);
this.router.get(
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index 825c90cdb..d30235048 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -136,32 +136,12 @@ const getMonitorByIdQueryValidation = joi.object({
normalize: joi.boolean(),
});
-const getMonitorsSummaryByTeamIdParamValidation = joi.object({
- teamId: joi.string().required(),
-});
-
-const getMonitorsSummaryByTeamIdQueryValidation = joi.object({
- type: joi
- .alternatives()
- .try(
- joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port"),
- joi
- .array()
- .items(
- joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port")
- )
- ),
-});
-
-const getMonitorsByTeamIdValidation = joi.object({
+const getMonitorsByTeamIdParamValidation = joi.object({
teamId: joi.string().required(),
});
const getMonitorsByTeamIdQueryValidation = joi.object({
- status: joi.boolean(),
- checkOrder: joi.string().valid("asc", "desc"),
limit: joi.number(),
- normalize: joi.boolean(),
type: joi
.alternatives()
.try(
@@ -467,9 +447,7 @@ export {
createMonitorBodyValidation,
getMonitorByIdParamValidation,
getMonitorByIdQueryValidation,
- getMonitorsSummaryByTeamIdParamValidation,
- getMonitorsSummaryByTeamIdQueryValidation,
- getMonitorsByTeamIdValidation,
+ getMonitorsByTeamIdParamValidation,
getMonitorsByTeamIdQueryValidation,
getMonitorStatsByIdParamValidation,
getMonitorStatsByIdQueryValidation,