diff --git a/Client/src/Pages/Uptime/Home/UptimeDataTable/index.jsx b/Client/src/Pages/Uptime/Home/UptimeDataTable/index.jsx index d174c535f..faca0c612 100644 --- a/Client/src/Pages/Uptime/Home/UptimeDataTable/index.jsx +++ b/Client/src/Pages/Uptime/Home/UptimeDataTable/index.jsx @@ -12,13 +12,42 @@ import ActionsMenu from "../actionsMenu"; // Utils import { useTheme } from "@emotion/react"; -import useDebounce from "../../../../Utils/debounce"; -import { useState } from "react"; import useUtils from "../../utils"; import { memo } from "react"; import { useNavigate } from "react-router-dom"; import "../index.css"; +import PropTypes from "prop-types"; +/** + * UptimeDataTable displays a table of uptime monitors with sorting, searching, and action capabilities + * @param {Object} props - Component props + * @param {boolean} props.isAdmin - Whether the current user has admin privileges + * @param {boolean} props.isLoading - Loading state of the table + * @param {Array<{ + * _id: string, + * url: string, + * title: string, + * percentage: number, + * percentageColor: string, + * monitor: { + * _id: string, + * type: string, + * checks: Array + * } + * }>} 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} />