diff --git a/Client/src/Pages/Monitors/Home/index.jsx b/Client/src/Pages/Monitors/Home/index.jsx
index 31f4800a7..b66076387 100644
--- a/Client/src/Pages/Monitors/Home/index.jsx
+++ b/Client/src/Pages/Monitors/Home/index.jsx
@@ -96,7 +96,12 @@ const Monitors = ({ isAdmin }) => {
alignItems="center"
mb={theme.spacing(8)}
>
-
+
Actively monitoring
{
"& h2": { color: theme.palette.warning.main },
},
};
+ const pagespeedStyles = {
+ up: {
+ bg: theme.palette.success.bg,
+ light: theme.palette.success.light,
+ stroke: theme.palette.success.main,
+ },
+ down: {
+ bg: theme.palette.error.bg,
+ light: theme.palette.error.light,
+ stroke: theme.palette.error.main,
+ },
+ paused: {
+ bg: theme.palette.warning.bg,
+ light: theme.palette.warning.light,
+ stroke: theme.palette.warning.main,
+ },
+ pending: {
+ bg: theme.palette.warning.bg,
+ light: theme.palette.warning.light,
+ stroke: theme.palette.warning.main,
+ },
+ };
return {
determineState,
statusColor,
statusMsg,
pagespeedStatusMsg,
+ pagespeedStyles,
statusStyles,
};
};
diff --git a/Client/src/Pages/PageSpeed/Configure/index.css b/Client/src/Pages/PageSpeed/Configure/index.css
index 14c2df3de..ee04d7ab2 100644
--- a/Client/src/Pages/PageSpeed/Configure/index.css
+++ b/Client/src/Pages/PageSpeed/Configure/index.css
@@ -1,37 +1,7 @@
-.configure-pagespeed span.MuiTypography-root {
- font-size: var(--env-var-font-size-small-plus);
-}
-.configure-pagespeed h3.MuiTypography-root {
- font-weight: 500;
-}
-.configure-pagespeed .MuiBox-root > .field + p.MuiTypography-root {
- font-size: var(--env-var-font-size-small-plus);
-}
-.configure-pagespeed .MuiBox-root > .field + p.MuiTypography-root,
-.configure-pagespeed h3.MuiTypography-root > span.MuiTypography-root {
- opacity: 0.6;
-}
-.configure-pagespeed .checkbox-wrapper {
- margin-bottom: 1px;
-}
-
-/* to be removed */
-.configure-pagespeed .section-disabled {
- opacity: 0.4;
- padding: 10px;
- border-radius: 8px;
- user-select: none;
- pointer-events: none;
-}
-
.configure-pagespeed button {
height: var(--env-var-height-2);
}
-.configure-pagespeed h3.MuiTypography-root {
- flex: 0.7;
-}
-
.configure-pagespeed .field,
.configure-pagespeed .section-disabled,
.configure-pagespeed .select-wrapper {
diff --git a/Client/src/Pages/PageSpeed/Configure/index.jsx b/Client/src/Pages/PageSpeed/Configure/index.jsx
index 80786bc89..297940cd3 100644
--- a/Client/src/Pages/PageSpeed/Configure/index.jsx
+++ b/Client/src/Pages/PageSpeed/Configure/index.jsx
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import { useTheme } from "@emotion/react";
-import { Box, Button, Modal, Stack, Typography } from "@mui/material";
+import { Box, Button, Modal, Stack, Tooltip, Typography } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router";
import {
@@ -13,6 +13,7 @@ import {
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import { logger } from "../../../Utils/Logger";
+import { ConfigBox } from "../../Monitors/styled";
import Field from "../../../Components/Inputs/Field";
import Select from "../../../Components/Inputs/Select";
import Checkbox from "../../../Components/Inputs/Checkbox";
@@ -22,20 +23,27 @@ import PulseDot from "../../../Components/Animated/PulseDot";
import LoadingButton from "@mui/lab/LoadingButton";
import PlayCircleOutlineRoundedIcon from "@mui/icons-material/PlayCircleOutlineRounded";
import SkeletonLayout from "./skeleton";
-import "./index.css";
import useUtils from "../../Monitors/utils";
+import "./index.css";
const PageSpeedConfigure = () => {
const theme = useTheme();
const navigate = useNavigate();
const dispatch = useDispatch();
const MS_PER_MINUTE = 60000;
- const { authToken } = useSelector((state) => state.auth);
+ const { user, authToken } = useSelector((state) => state.auth);
const { isLoading } = useSelector((state) => state.pageSpeedMonitors);
const { monitorId } = useParams();
const [monitor, setMonitor] = useState({});
const [errors, setErrors] = useState({});
- const { determineState, statusColor } = useUtils();
+ const { statusColor, pagespeedStatusMsg, determineState } = useUtils();
+ const idMap = {
+ "monitor-url": "url",
+ "monitor-name": "name",
+ "monitor-checks-http": "type",
+ "monitor-checks-ping": "type",
+ "notify-email-default": "notification-email",
+ };
const frequencies = [
{ _id: 3, name: "3 minutes" },
@@ -68,24 +76,58 @@ const PageSpeedConfigure = () => {
fetchMonitor();
}, [dispatch, authToken, monitorId, navigate]);
- const handleChange = (event, id) => {
- let { value } = event.target;
- if (id === "interval") {
- value = value * MS_PER_MINUTE;
+ const handleChange = (event, name) => {
+ let { value, id } = event.target;
+ if (!name) name = idMap[id];
+
+ if (name.includes("notification-")) {
+ name = name.replace("notification-", "");
+ let hasNotif = monitor.notifications.some(
+ (notification) => notification.type === name
+ );
+ setMonitor((prev) => {
+ const notifs = [...prev.notifications];
+ if (hasNotif) {
+ return {
+ ...prev,
+ notifications: notifs.filter((notif) => notif.type !== name),
+ };
+ } else {
+ return {
+ ...prev,
+ notifications: [
+ ...notifs,
+ name === "email"
+ ? { type: name, address: value }
+ : // TODO - phone number
+ { type: name, phone: value },
+ ],
+ };
+ }
+ });
+ } else {
+ if (name === "interval") {
+ value = value * MS_PER_MINUTE;
+ }
+ setMonitor((prev) => ({
+ ...prev,
+ [name]: value,
+ }));
+
+ const validation = monitorValidation.validate(
+ { [name]: value },
+ { abortEarly: false }
+ );
+
+ setErrors((prev) => {
+ const updatedErrors = { ...prev };
+
+ if (validation.error)
+ updatedErrors[name] = validation.error.details[0].message;
+ else delete updatedErrors[name];
+ return updatedErrors;
+ });
}
- setMonitor((prev) => ({ ...prev, [id]: value }));
-
- const { error } = monitorValidation.validate(
- { [id]: value },
- { abortEarly: false }
- );
-
- setErrors((prev) => {
- const newErrors = { ...prev };
- if (error) newErrors[id] = error.details[0].message;
- else delete newErrors[id];
- return newErrors;
- });
};
const handlePause = async () => {
@@ -128,7 +170,7 @@ const PageSpeedConfigure = () => {
};
return (
-
+
{Object.keys(monitor).length === 0 ? (
) : (
@@ -146,22 +188,65 @@ const PageSpeedConfigure = () => {
spellCheck="false"
onSubmit={handleSave}
flex={1}
- gap={theme.spacing(12)}
+ gap={theme.spacing(10)}
>
-
-
- {monitor?.url}
+
+ {monitor.name}
-
- Your pagespeed monitor is {determineState(monitor)}.
-
+
+
+
+
+
+
+ {monitor.url?.replace(/^https?:\/\//, "") || "..."}
+
+
+ Editting...
+
+
{
-
-
- Monitor display name
- handleChange(event, "name")}
- error={errors.name}
- />
-
+
+
+ General settings
+
+ Here you can select the URL of the host, together with the
+ type of monitor.
+
+
.Mui-disabled)": {
backgroundColor: theme.palette.background.accent,
},
}}
>
- URL
handleChange(event, "url")}
+ onChange={handleChange}
error={errors.url}
disabled={true}
/>
-
-
- Check frequency
-
-
-
- Incidents notifications{" "}
- (coming soon)
+
+
+
+ Incident notifications
+
+ When there is an incident, notify users.
-
-
- When there is a new incident,
-
-
-
-
+
+
+
+ When there is a new incident,
+
+ logger.warn("disabled")}
+ isDisabled={true}
+ />
+ notification.type === "email"
+ ) || false
+ }
+ value={user?.email}
+ onChange={(event) => handleChange(event)}
+ />
+ logger.warn("disabled")}
+ isDisabled={true}
+ />
+ {monitor?.notifications?.some(
+ (notification) => notification.type === "emails"
+ ) ? (
logger.warn("disabled")}
- error=""
/>
You can separate multiple emails with a comma
-
+ ) : (
+ ""
+ )}
-
+
+
+
+ Advanced settings
+
+
+
+
{
id="modal-delete-pagespeed-monitor"
component="h2"
variant="h2"
+ fontWeight={500}
>
Do you really want to delete this monitor?
diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx
index 9774bb97c..48d8aa86a 100644
--- a/Client/src/Pages/PageSpeed/Details/index.jsx
+++ b/Client/src/Pages/PageSpeed/Details/index.jsx
@@ -29,11 +29,13 @@ import PulseDot from "../../../Components/Animated/PulseDot";
import PagespeedDetailsAreaChart from "./Charts/AreaChart";
import Checkbox from "../../../Components/Inputs/Checkbox";
import PieChart from "./Charts/PieChart";
+import useUtils from "../../Monitors/utils";
import "./index.css";
const PageSpeedDetails = () => {
const theme = useTheme();
const navigate = useNavigate();
+ const { statusColor, pagespeedStatusMsg, determineState } = useUtils();
const [monitor, setMonitor] = useState({});
const [audits, setAudits] = useState({});
const { monitorId } = useParams();
@@ -109,11 +111,7 @@ const PageSpeedDetails = () => {
gap={theme.spacing(2)}
>
{
}}
>
-
+
diff --git a/Client/src/Pages/PageSpeed/card.jsx b/Client/src/Pages/PageSpeed/card.jsx
index 2ed4c7b91..5c688a041 100644
--- a/Client/src/Pages/PageSpeed/card.jsx
+++ b/Client/src/Pages/PageSpeed/card.jsx
@@ -1,32 +1,220 @@
+import PropTypes from "prop-types";
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 { formatDate, formatDurationRounded } from "../../Utils/timeUtils";
-import { getLastChecked } from "../../Utils/monitorUtils";
+import { IconBox } from "./Details/styled";
+import {
+ Area,
+ AreaChart,
+ CartesianGrid,
+ ResponsiveContainer,
+ Tooltip,
+} from "recharts";
+import { useSelector } from "react-redux";
+import {
+ formatDateWithTz,
+ formatDurationRounded,
+ formatDurationSplit,
+} from "../../Utils/timeUtils";
import useUtils from "../Monitors/utils";
-import PropTypes from "prop-types";
+/**
+ * CustomToolTip displays a tooltip with formatted date and score information.
+ * @param {Object} props
+ * @param {Array} props.payload - Data to display in the tooltip
+ * @returns {JSX.Element} The rendered tooltip component
+ */
+const CustomToolTip = ({ payload }) => {
+ const theme = useTheme();
+ const uiTimezone = useSelector((state) => state.ui.timezone);
+
+ return (
+
+
+ {formatDateWithTz(
+ payload[0]?.payload.createdAt,
+ "ddd, MMMM D, YYYY, h:mm A",
+ uiTimezone
+ )}
+
+
+
+
+
+ {payload[0]?.name}
+ {" "}
+ {payload[0]?.payload.score}
+
+
+ );
+};
+
+CustomToolTip.propTypes = {
+ payload: PropTypes.array,
+};
+
+/**
+ * Processes the raw data to include a score for each entry.
+ * @param {Array