diff --git a/Client/src/Components/CreateMonitorHeader/index.jsx b/Client/src/Components/CreateMonitorHeader/index.jsx new file mode 100644 index 000000000..b8fcbc39a --- /dev/null +++ b/Client/src/Components/CreateMonitorHeader/index.jsx @@ -0,0 +1,33 @@ +import { Stack, Button } from "@mui/material"; +import { useNavigate } from "react-router-dom"; +import PropTypes from "prop-types"; +import SkeletonLayout from "./skeleton"; + +const CreateMonitorHeader = ({ isAdmin, shouldRender, path }) => { + const navigate = useNavigate(); + if (!isAdmin) return null; + if (!shouldRender) return ; + return ( + + + + ); +}; + +export default CreateMonitorHeader; + +CreateMonitorHeader.propTypes = { + isAdmin: PropTypes.bool.isRequired, + shouldRender: PropTypes.bool.isRequired, + path: PropTypes.string.isRequired, +}; diff --git a/Client/src/Components/CreateMonitorHeader/skeleton.jsx b/Client/src/Components/CreateMonitorHeader/skeleton.jsx new file mode 100644 index 000000000..7583f7849 --- /dev/null +++ b/Client/src/Components/CreateMonitorHeader/skeleton.jsx @@ -0,0 +1,19 @@ +import { Stack, Skeleton } from "@mui/material"; + +const SkeletonLayout = () => { + return ( + + + + ); +}; + +export default SkeletonLayout; diff --git a/Client/src/Components/MonitorCountHeader/index.jsx b/Client/src/Components/MonitorCountHeader/index.jsx new file mode 100644 index 000000000..f7c31a5a0 --- /dev/null +++ b/Client/src/Components/MonitorCountHeader/index.jsx @@ -0,0 +1,40 @@ +import { Stack } from "@mui/material"; +import { Heading } from "../Heading"; +import CircularCount from "../CircularCount"; +import PropTypes from "prop-types"; +import { useTheme } from "@emotion/react"; +import SkeletonLayout from "./skeleton"; + +const MonitorCountHeader = ({ + shouldRender = true, + monitorCount, + heading, + sx, + children, +}) => { + const theme = useTheme(); + if (!shouldRender) return ; + + return ( + + {heading} + + {children} + + ); +}; + +MonitorCountHeader.propTypes = { + shouldRender: PropTypes.bool, + monitorCount: PropTypes.number, + heading: PropTypes.string, + children: PropTypes.node, + sx: PropTypes.object, +}; + +export default MonitorCountHeader; diff --git a/Client/src/Components/MonitorCountHeader/skeleton.jsx b/Client/src/Components/MonitorCountHeader/skeleton.jsx new file mode 100644 index 000000000..9b4971c32 --- /dev/null +++ b/Client/src/Components/MonitorCountHeader/skeleton.jsx @@ -0,0 +1,26 @@ +import { Stack, Skeleton } from "@mui/material"; +import { useTheme } from "@emotion/react"; + +const SkeletonLayout = () => { + const theme = useTheme(); + return ( + + + + + ); +}; + +export default SkeletonLayout; diff --git a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.css b/Client/src/Pages/PageSpeed/Create/index.css similarity index 100% rename from Client/src/Pages/PageSpeed/CreatePageSpeed/index.css rename to Client/src/Pages/PageSpeed/Create/index.css diff --git a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx b/Client/src/Pages/PageSpeed/Create/index.jsx similarity index 100% rename from Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx rename to Client/src/Pages/PageSpeed/Create/index.jsx diff --git a/Client/src/Pages/PageSpeed/card.jsx b/Client/src/Pages/PageSpeed/Monitors/Components/Card/index.jsx similarity index 94% rename from Client/src/Pages/PageSpeed/card.jsx rename to Client/src/Pages/PageSpeed/Monitors/Components/Card/index.jsx index f7f6c4249..fe05da514 100644 --- a/Client/src/Pages/PageSpeed/card.jsx +++ b/Client/src/Pages/PageSpeed/Monitors/Components/Card/index.jsx @@ -1,15 +1,16 @@ import PropTypes from "prop-types"; -import PageSpeedIcon from "../../assets/icons/page-speed.svg?react"; -import { StatusLabel } from "../../Components/Label"; +// import PageSpeedIcon from "../../../../assets/icons/page-speed.svg?react"; +import PageSpeedIcon from "../../../../../assets/icons/page-speed.svg?react"; +import { StatusLabel } from "../../../../../Components/Label"; import { Box, Grid, Stack, Typography } from "@mui/material"; import { useNavigate } from "react-router"; import { useTheme } from "@emotion/react"; import { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip } from "recharts"; import { useSelector } from "react-redux"; -import { formatDateWithTz, formatDurationSplit } from "../../Utils/timeUtils"; -import useUtils from "../Uptime/Home/Hooks/useUtils"; +import { formatDateWithTz, formatDurationSplit } from "../../../../../Utils/timeUtils"; +import useUtils from "../../../../Uptime/Home/Hooks/useUtils"; import { useState } from "react"; -import IconBox from "../../Components/IconBox"; +import IconBox from "../../../../../Components/IconBox"; /** * CustomToolTip displays a tooltip with formatted date and score information. * @param {Object} props diff --git a/Client/src/Pages/PageSpeed/Monitors/Components/MonitorGrid/index.jsx b/Client/src/Pages/PageSpeed/Monitors/Components/MonitorGrid/index.jsx new file mode 100644 index 000000000..0e61c9c15 --- /dev/null +++ b/Client/src/Pages/PageSpeed/Monitors/Components/MonitorGrid/index.jsx @@ -0,0 +1,22 @@ +import { Grid, Grid2 } from "@mui/material"; +import Card from "../Card"; + +const MonitorGrid = ({ shouldRender, monitors }) => { + if (!shouldRender) return null; + + return ( + + {monitors?.map((monitor) => ( + + ))} + + ); +}; + +export default MonitorGrid; diff --git a/Client/src/Pages/PageSpeed/Monitors/Hooks/useMonitorsFetch.jsx b/Client/src/Pages/PageSpeed/Monitors/Hooks/useMonitorsFetch.jsx new file mode 100644 index 000000000..06d423acc --- /dev/null +++ b/Client/src/Pages/PageSpeed/Monitors/Hooks/useMonitorsFetch.jsx @@ -0,0 +1,43 @@ +import { useEffect, useState } from "react"; +import { networkService } from "../../../../main"; +import { createToast } from "../../../../Utils/toastUtils"; + +const useMonitorsFetch = ({ authToken, teamId }) => { + const [isLoading, setIsLoading] = useState(true); + const [monitors, setMonitors] = useState([]); + const [summary, setSummary] = useState({}); + + useEffect(() => { + const fetchMonitors = async () => { + try { + setIsLoading(true); + const res = await networkService.getMonitorsByTeamId({ + authToken: authToken, + teamId: teamId, + limit: 10, + types: ["pagespeed"], + page: null, + rowsPerPage: null, + filter: null, + field: null, + order: null, + }); + if (res?.data?.data?.filteredMonitors) { + setMonitors(res.data.data.filteredMonitors); + setSummary(res.data.data.summary); + } + } catch (error) { + createToast({ + body: error.message, + }); + } finally { + setIsLoading(false); + } + }; + + fetchMonitors(); + }, [authToken, teamId]); + return { isLoading, monitors, summary }; +}; + +export default useMonitorsFetch; diff --git a/Client/src/Pages/PageSpeed/Monitors/index.jsx b/Client/src/Pages/PageSpeed/Monitors/index.jsx new file mode 100644 index 000000000..9376d07ce --- /dev/null +++ b/Client/src/Pages/PageSpeed/Monitors/index.jsx @@ -0,0 +1,66 @@ +// Components +import Breadcrumbs from "../../../Components/Breadcrumbs"; +import { Stack, Box } from "@mui/material"; +import CreateMonitorHeader from "../../../Components/CreateMonitorHeader"; +import MonitorCountHeader from "../../../Components/MonitorCountHeader"; +import MonitorGrid from "./Components/MonitorGrid"; +import Fallback from "../../../Components/Fallback"; + +// Utils +import { useTheme } from "@emotion/react"; +import { useSelector } from "react-redux"; +import { useIsAdmin } from "../../../Hooks/useIsAdmin"; +import useMonitorsFetch from "./Hooks/useMonitorsFetch"; + +// Constants +const BREADCRUMBS = [{ name: `pagespeed`, path: "/pagespeed" }]; + +const NewPageSpeed = () => { + const theme = useTheme(); + const isAdmin = useIsAdmin(); + const { user, authToken } = useSelector((state) => state.auth); + + const { isLoading, monitors, summary } = useMonitorsFetch({ + authToken: authToken, + teamId: user.teamId, + }); + + if (!isLoading && monitors?.length === 0) { + return ( + + ); + } + + return ( + + + + + + + ); +}; + +export default NewPageSpeed; diff --git a/Client/src/Pages/PageSpeed/index.css b/Client/src/Pages/PageSpeed/index.css deleted file mode 100644 index 3741a6f0f..000000000 --- a/Client/src/Pages/PageSpeed/index.css +++ /dev/null @@ -1,8 +0,0 @@ -.page-speed .label { - padding: 7px; - height: 24px; - font-size: var(--env-var-font-size-small); -} -.page-speed:not(:has([class*="fallback__"])) button { - min-height: 34px; -} diff --git a/Client/src/Pages/PageSpeed/index.jsx b/Client/src/Pages/PageSpeed/index.jsx deleted file mode 100644 index c3d37e2c0..000000000 --- a/Client/src/Pages/PageSpeed/index.jsx +++ /dev/null @@ -1,153 +0,0 @@ -import { Box, Button, Grid, Stack } from "@mui/material"; -import { useEffect, useState } from "react"; -import { useTheme } from "@emotion/react"; -import { useSelector } from "react-redux"; -import Fallback from "../../Components/Fallback"; -import "./index.css"; -import { useNavigate } from "react-router"; -import PropTypes from "prop-types"; -import Breadcrumbs from "../../Components/Breadcrumbs"; -import SkeletonLayout from "./skeleton"; -import Card from "./card"; -import { networkService } from "../../main"; -import { Heading } from "../../Components/Heading"; -import { useIsAdmin } from "../../Hooks/useIsAdmin"; -const PageSpeed = () => { - const theme = useTheme(); - const navigate = useNavigate(); - const isAdmin = useIsAdmin(); - const { user, authToken } = useSelector((state) => state.auth); - const [isLoading, setIsLoading] = useState(true); - const [monitors, setMonitors] = useState([]); - const [summary, setSummary] = useState({}); - - useEffect(() => { - const fetchMonitors = async () => { - try { - setIsLoading(true); - const res = await networkService.getMonitorsByTeamId({ - authToken: authToken, - teamId: user.teamId, - limit: 10, - types: ["pagespeed"], - page: null, - rowsPerPage: null, - filter: null, - field: null, - order: null, - }); - if (res?.data?.data?.filteredMonitors) { - setMonitors(res.data.data.filteredMonitors); - setSummary(res.data.data.summary); - } - } catch (error) { - console.log(error); - } finally { - setIsLoading(false); - } - }; - - fetchMonitors(); - }, [authToken, user.teamId]); - - // will show skeletons only on initial load - // since monitor state is being added to redux persist, there's no reason to display skeletons on every render - let isActuallyLoading = isLoading && monitors?.length === 0; - return ( - [class*="fallback__"])': { - position: "relative", - border: 1, - borderColor: theme.palette.primary.lowContrast, - borderRadius: theme.shape.borderRadius, - borderStyle: "dashed", - backgroundColor: theme.palette.primary.main, - overflow: "hidden", - }, - }} - > - {isActuallyLoading ? ( - - ) : monitors?.length !== 0 ? ( - - - - - {isAdmin && ( - - )} - - - - PageSpeed monitors - {/* TODO Correct the class current-monitors-counter, there are some unnecessary things there */} - - {summary?.totalMonitors ?? 0} - - - - {monitors?.map((monitor) => ( - - ))} - - - ) : ( - - )} - - ); -}; -PageSpeed.propTypes = { - isAdmin: PropTypes.bool, -}; - -export default PageSpeed; diff --git a/Client/src/Pages/PageSpeed/skeleton.jsx b/Client/src/Pages/PageSpeed/skeleton.jsx deleted file mode 100644 index b6d29dc38..000000000 --- a/Client/src/Pages/PageSpeed/skeleton.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Box, Skeleton, Stack } from "@mui/material"; -import { useTheme } from "@emotion/react"; - -/** - * Renders a skeleton layout. - * - * @returns {JSX.Element} - */ -const SkeletonLayout = () => { - const theme = useTheme(); - - return ( - - - - - - - - - - - - - - - - ); -}; - -export default SkeletonLayout; diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 575c108cf..df0af2618 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -1,36 +1,49 @@ import { Navigate, Route, Routes as LibRoutes } from "react-router"; import HomeLayout from "../Components/Layouts/HomeLayout"; import { Infrastructure } from "../Pages/Infrastructure"; -import InfrastructureDetails from "../Pages/Infrastructure/Details"; import NotFound from "../Pages/NotFound"; -import Login from "../Pages/Auth/Login/Login"; -import Register from "../Pages/Auth/Register/Register"; -import Account from "../Pages/Account"; + +// Auth +import AuthLogin from "../Pages/Auth/Login/Login"; +import AuthRegister from "../Pages/Auth/Register/Register"; +import AuthForgotPassword from "../Pages/Auth/ForgotPassword"; +import AuthCheckEmail from "../Pages/Auth/CheckEmail"; +import AuthSetNewPassword from "../Pages/Auth/SetNewPassword"; +import AuthNewPasswordConfirmed from "../Pages/Auth/NewPasswordConfirmed"; + +// Uptime import Uptime from "../Pages/Uptime/Home"; import UptimeDetails from "../Pages/Uptime/Details"; +import UptimeCreate from "../Pages/Uptime/Create"; +import UptimeConfigure from "../Pages/Uptime/Configure"; + +// PageSpeed +// import PageSpeed from "../Pages/PageSpeed"; +import PageSpeed from "../Pages/PageSpeed/Monitors"; +import PageSpeedCreate from "../Pages/PageSpeed/Create"; +import PageSpeedDetails from "../Pages/PageSpeed/Details"; +import PageSpeedConfigure from "../Pages/PageSpeed/Configure"; + +// Infrastructure +import InfrastructureCreate from "../Pages/Infrastructure/Create"; +import InfrastructureDetails from "../Pages/Infrastructure/Details"; -import CreateMonitor from "../Pages/Uptime/CreateUptime"; -import CreateInfrastructureMonitor from "../Pages/Infrastructure/CreateMonitor"; import Incidents from "../Pages/Incidents"; import Status from "../Pages/Status"; import Integrations from "../Pages/Integrations"; + +// Settings +import Account from "../Pages/Account"; import Settings from "../Pages/Settings"; -import ForgotPassword from "../Pages/Auth/ForgotPassword"; -import CheckEmail from "../Pages/Auth/CheckEmail"; -import SetNewPassword from "../Pages/Auth/SetNewPassword"; -import NewPasswordConfirmed from "../Pages/Auth/NewPasswordConfirmed"; -import ProtectedRoute from "../Components/ProtectedRoute"; + import Maintenance from "../Pages/Maintenance"; -import Configure from "../Pages/Uptime/Configure"; -import PageSpeed from "../Pages/PageSpeed"; -import CreatePageSpeed from "../Pages/PageSpeed/CreatePageSpeed"; + +import ProtectedRoute from "../Components/ProtectedRoute"; import CreateNewMaintenanceWindow from "../Pages/Maintenance/CreateMaintenance"; -import PageSpeedDetails from "../Pages/PageSpeed/Details"; -import PageSpeedConfigure from "../Pages/PageSpeed/Configure"; import withAdminCheck from "../Components/HOC/withAdminCheck"; const Routes = () => { - const AdminCheckedRegister = withAdminCheck(Register); + const AdminCheckedRegister = withAdminCheck(AuthRegister); return ( { } + element={} /> { /> } + element={} /> { /> } + element={} /> { /> } + element={} /> { } + element={} /> { } + element={} /> } + element={} /> } + element={} /> } + element={} /> } + element={} />