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={}
/>