From e10bf5608166d6d2430ebb24b73c38d9a6095556 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 20 Feb 2025 16:23:22 -0800 Subject: [PATCH 1/6] allow attaching standard monitors to depin status page --- .../DistributedUptimeStatus/Create/index.jsx | 50 ++++++++++++++++++- src/Utils/NetworkService.js | 4 ++ src/Validation/validation.js | 1 + 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/Pages/DistributedUptimeStatus/Create/index.jsx b/src/Pages/DistributedUptimeStatus/Create/index.jsx index 3aa16a074..0dc6aeb93 100644 --- a/src/Pages/DistributedUptimeStatus/Create/index.jsx +++ b/src/Pages/DistributedUptimeStatus/Create/index.jsx @@ -7,6 +7,8 @@ import VisuallyHiddenInput from "./Components/VisuallyHiddenInput"; import Image from "../../../Components/Image"; import LogoPlaceholder from "../../../assets/Images/logo_placeholder.svg"; import Breadcrumbs from "../../../Components/Breadcrumbs"; +import Search from "../../../Components/Inputs/Search"; +import MonitorList from "../../StatusPage/Create/Components/MonitorList"; // Utils import { useTheme } from "@emotion/react"; import { useState, useEffect } from "react"; @@ -17,6 +19,7 @@ import { statusPageValidation } from "../../../Validation/validation"; import { buildErrors } from "../../../Validation/error"; import { createToast } from "../../../Utils/toastUtils"; import { useNavigate } from "react-router-dom"; +import { useMonitorsFetch } from "../../StatusPage/Create/Hooks/useMonitorsFetch"; const CreateStatus = () => { const theme = useTheme(); @@ -28,6 +31,8 @@ const CreateStatus = () => { const [statusPage, statusPageMonitors, statusPageIsLoading, statusPageNetworkError] = useStatusPageFetch(isCreate, url); + const [monitors, monitorsIsLoading, monitorsNetworkError] = useMonitorsFetch(); + const BREADCRUMBS = [ { name: "distributed uptime", path: "/distributed-uptime" }, { name: "details", path: `/distributed-uptime/${monitorId}` }, @@ -43,6 +48,8 @@ const CreateStatus = () => { monitors: [monitorId], }); const [errors, setErrors] = useState({}); + const [search, setSearch] = useState(""); + const [selectedMonitors, setSelectedMonitors] = useState([]); const handleFormChange = (e) => { const { name, value, checked, type } = e.target; @@ -62,6 +69,16 @@ const CreateStatus = () => { setForm({ ...form, [name]: value }); }; + const handleMonitorsChange = (selectedMonitors) => { + handleFormChange({ + target: { + name: "subMonitors", + value: selectedMonitors.map((monitor) => monitor._id), + }, + }); + setSelectedMonitors(selectedMonitors); + }; + const handleImageUpload = (e) => { const img = e.target?.files?.[0]; setForm((prev) => ({ @@ -85,7 +102,6 @@ const CreateStatus = () => { if (typeof logoToSubmit !== "undefined") { formToSubmit.logo = logoToSubmit; } - // Validate const { error } = statusPageValidation.validate(formToSubmit, { abortEarly: false }); if (typeof error === "undefined") { @@ -134,6 +150,12 @@ const CreateStatus = () => { }); }, [isCreate, statusPage, statusPageMonitors]); + const imgSrc = form?.logo?.src + ? form.logo.src + : form.logo + ? URL.createObjectURL(form.logo) + : undefined; + return ( @@ -212,7 +234,7 @@ const CreateStatus = () => { alignItems="center" > Logo { + + + Standard Monitors + + Attach standard monitors to your status page. + + + + + + + { fd.append("monitors[]", monitorId); }); + form.subMonitors && + form.subMonitors.forEach((monitorId) => { + fd.append("subMonitors[]", monitorId); + }); if (form?.logo?.src && form?.logo?.src !== "") { const imageResult = await axios.get(form.logo.src, { responseType: "blob", diff --git a/src/Validation/validation.js b/src/Validation/validation.js index 04088e44c..68c0b5f12 100644 --- a/src/Validation/validation.js +++ b/src/Validation/validation.js @@ -226,6 +226,7 @@ const statusPageValidation = joi.object({ "array.empty": "At least one monitor is required", "any.required": "At least one monitor is required", }), + subMonitors: joi.array().optional(), logo: logoImageValidation, showUptimePercentage: joi.boolean(), showCharts: joi.boolean(), From f98b07dba37661300a55b88773a47fcae86f325c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 21 Feb 2025 11:21:56 -0800 Subject: [PATCH 2/6] add DU specific hook --- .../Create/Hooks/useDUStatusPageFetch.jsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/Pages/DistributedUptimeStatus/Create/Hooks/useDUStatusPageFetch.jsx diff --git a/src/Pages/DistributedUptimeStatus/Create/Hooks/useDUStatusPageFetch.jsx b/src/Pages/DistributedUptimeStatus/Create/Hooks/useDUStatusPageFetch.jsx new file mode 100644 index 000000000..eecb161a3 --- /dev/null +++ b/src/Pages/DistributedUptimeStatus/Create/Hooks/useDUStatusPageFetch.jsx @@ -0,0 +1,46 @@ +import { useEffect, useState, useCallback } from "react"; +import { networkService } from "../../../../main"; +import { useSelector } from "react-redux"; +import { createToast } from "../../../../Utils/toastUtils"; + +const useDUStatusPageFetch = (isCreate = false, url) => { + const [isLoading, setIsLoading] = useState(true); + const [networkError, setNetworkError] = useState(false); + const [statusPage, setStatusPage] = useState(undefined); + const { authToken } = useSelector((state) => state.auth); + const fetchStatusPage = useCallback(async () => { + try { + const response = await networkService.getStatusPageByUrl({ + authToken, + url, + type: "distributed", + }); + + if (!response?.data?.data) return; + + const statusPage = response.data.data; + setStatusPage(statusPage); + } catch (error) { + // If there is a 404, status page is not found + if (error?.response?.status === 404) { + setStatusPage(undefined); + return; + } + createToast({ body: error.message }); + setNetworkError(true); + } finally { + setIsLoading(false); + } + }, [authToken, url]); + + useEffect(() => { + if (isCreate === true) { + return; + } + fetchStatusPage(); + }, [isCreate, fetchStatusPage]); + + return [statusPage, isLoading, networkError, fetchStatusPage]; +}; + +export { useDUStatusPageFetch }; From 09a066426a5dbf2f5dcdb860d17612f82851d6d2 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 21 Feb 2025 11:22:20 -0800 Subject: [PATCH 3/6] handle deleting submonitors --- src/Utils/NetworkService.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Utils/NetworkService.js b/src/Utils/NetworkService.js index 365d9ad85..6fb376035 100644 --- a/src/Utils/NetworkService.js +++ b/src/Utils/NetworkService.js @@ -1041,10 +1041,15 @@ class NetworkService { form.monitors.forEach((monitorId) => { fd.append("monitors[]", monitorId); }); - form.subMonitors && + // Handle subMonitors, even if it's an empty array + if (form.subMonitors && form.subMonitors.length > 0) { form.subMonitors.forEach((monitorId) => { fd.append("subMonitors[]", monitorId); }); + } else { + fd.append("deleteSubmonitors", true); + } + if (form?.logo?.src && form?.logo?.src !== "") { const imageResult = await axios.get(form.logo.src, { responseType: "blob", @@ -1055,6 +1060,7 @@ class NetworkService { URL.revokeObjectURL(form.logo.src); } } + if (isCreate) { return this.axiosInstance.post(`/status-page`, fd, { headers: { From c467933021a31533360c0e016f7cbb0805144022 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 21 Feb 2025 11:22:49 -0800 Subject: [PATCH 4/6] remove console log --- src/Pages/Settings/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Pages/Settings/index.jsx b/src/Pages/Settings/index.jsx index f06be40e3..e34dfa06a 100644 --- a/src/Pages/Settings/index.jsx +++ b/src/Pages/Settings/index.jsx @@ -139,7 +139,6 @@ const Settings = () => { } } } catch (error) { - console.log(error); createToast({ body: "Failed to save settings" }); } finally { setChecksIsLoading(false); @@ -368,7 +367,8 @@ const Settings = () => { Wallet - Connect your wallet here. This is required for the Distributed Uptime monitor to connect to multiple nodes globally. + Connect your wallet here. This is required for the Distributed Uptime + monitor to connect to multiple nodes globally. From b9a89469c6b821e222c4216cb340b14409194b7b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 21 Feb 2025 11:23:38 -0800 Subject: [PATCH 5/6] add monitors list --- src/Pages/DistributedUptimeStatus/Status/index.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Pages/DistributedUptimeStatus/Status/index.jsx b/src/Pages/DistributedUptimeStatus/Status/index.jsx index a1c6b473f..dce15ca5c 100644 --- a/src/Pages/DistributedUptimeStatus/Status/index.jsx +++ b/src/Pages/DistributedUptimeStatus/Status/index.jsx @@ -16,6 +16,7 @@ import UptLogo from "../../../assets/icons/upt_logo.png"; import PeopleAltOutlinedIcon from "@mui/icons-material/PeopleAltOutlined"; import InfoBox from "../../../Components/InfoBox"; import StatusHeader from "../../DistributedUptime/Details/Components/StatusHeader"; +import MonitorsList from "../../StatusPage/Status/Components/MonitorsList"; //Utils import { useTheme } from "@mui/material/styles"; @@ -26,6 +27,7 @@ import { useStatusPageFetchByUrl } from "./Hooks/useStatusPageFetchByUrl"; import { useStatusPageDelete } from "../../StatusPage/Status/Hooks/useStatusPageDelete"; import { useNavigate } from "react-router-dom"; import { useLocation } from "react-router-dom"; + const DistributedUptimeStatus = () => { const { url } = useParams(); const location = useLocation(); @@ -38,6 +40,7 @@ const DistributedUptimeStatus = () => { // Utils const theme = useTheme(); const navigate = useNavigate(); + const [ statusPageIsLoading, statusPageNetworkError, @@ -54,6 +57,7 @@ const DistributedUptimeStatus = () => { const [deleteStatusPage, isDeleting] = useStatusPageDelete(() => { navigate("/distributed-uptime"); }, url); + // Constants const BREADCRUMBS = [ { name: "Distributed Uptime", path: "/distributed-uptime" }, @@ -213,6 +217,7 @@ const DistributedUptimeStatus = () => { monitor={monitor} lastUpdateTrigger={lastUpdateTrigger} /> +