From 2091d8dcd78bce7ee02fb7893ff3d711f3b4b206 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 9 Feb 2026 23:16:14 +0000 Subject: [PATCH] remove monitorHooks --- .../src/Components/v1/ActionsMenu/index.jsx | 228 ------------------ client/src/Hooks/UseApi.ts | 34 +++ client/src/Hooks/monitorHooks.js | 170 ------------- client/src/Pages/Settings/index.jsx | 29 +-- client/src/Pages/Uptime/BulkImport/Upload.jsx | 73 ------ client/src/Pages/Uptime/BulkImport/index.jsx | 117 --------- client/src/Routes/index.jsx | 6 +- 7 files changed, 48 insertions(+), 609 deletions(-) delete mode 100644 client/src/Components/v1/ActionsMenu/index.jsx delete mode 100644 client/src/Hooks/monitorHooks.js delete mode 100644 client/src/Pages/Uptime/BulkImport/Upload.jsx delete mode 100644 client/src/Pages/Uptime/BulkImport/index.jsx diff --git a/client/src/Components/v1/ActionsMenu/index.jsx b/client/src/Components/v1/ActionsMenu/index.jsx deleted file mode 100644 index ea0d029b8..000000000 --- a/client/src/Components/v1/ActionsMenu/index.jsx +++ /dev/null @@ -1,228 +0,0 @@ -// Components -import IconButton from "@mui/material/IconButton"; -import Menu from "@mui/material/Menu"; -import MenuItem from "@mui/material/MenuItem"; -import Icon from "../Icon"; -import Dialog from "../Dialog/index.jsx"; - -// Utils -import { useState } from "react"; -import { useTheme } from "@emotion/react"; -import { useNavigate } from "react-router-dom"; -import { createToast } from "../../../Utils/toastUtils.jsx"; - -import PropTypes from "prop-types"; -import { usePauseMonitor, useDeleteMonitor } from "../../../Hooks/monitorHooks.js"; - -const ActionsMenu = ({ - monitor, - isAdmin, - updateRowCallback, - pauseCallback, - setIsLoading = () => {}, -}) => { - const [anchorEl, setAnchorEl] = useState(null); - const [actions, setActions] = useState({}); - const [isOpen, setIsOpen] = useState(false); - const theme = useTheme(); - const [pauseMonitor, isPausing, error] = usePauseMonitor(); - const [deleteMonitor, isDeleting] = useDeleteMonitor(); - - const handleRemove = async (event) => { - event.preventDefault(); - event.stopPropagation(); - let monitor = { id: actions.id }; - await deleteMonitor({ monitor }); - updateRowCallback(); - }; - - const handlePause = async () => { - try { - setIsLoading(true); - await pauseMonitor({ monitorId: monitor.id }); - pauseCallback(); - } catch (error) { - createToast({ body: "Failed to pause monitor." }); - } finally { - setIsLoading(false); - } - }; - - const openMenu = (event, id, url) => { - event.preventDefault(); - event.stopPropagation(); - setAnchorEl(event.currentTarget); - setActions({ id: id, url: url }); - }; - - const openRemove = (e) => { - closeMenu(e); - setIsOpen(true); - }; - - const closeMenu = (e) => { - e.stopPropagation(); - setAnchorEl(null); - }; - - const navigate = useNavigate(); - return ( - <> - { - event.stopPropagation(); - openMenu(event, monitor.id, monitor.type === "ping" ? null : monitor.url); - }} - sx={{ - "&:focus": { - outline: "none", - }, - "& svg path": { - stroke: theme.palette.primary.contrastTextTertiary, - }, - }} - > - - - - closeMenu(e)} - disableScrollLock - slotProps={{ - paper: { - sx: { - "& ul": { - p: theme.spacing(2.5), - backgroundColor: theme.palette.primary.main, - }, - "& li": { m: 0, color: theme.palette.primary.contrastTextSecondary }, - /* - This should not be set automatically on the last of type - "& li:last-of-type": { - color: theme.palette.error.main, - }, */ - }, - }, - }} - > - {actions.url !== null ? ( - { - closeMenu(e); - e.stopPropagation(); - window.open(actions.url, "_blank", "noreferrer"); - }} - > - Open site - - ) : ( - "" - )} - { - e.stopPropagation(); - navigate(`/uptime/${actions.id}`); - }} - > - Details - - {/* TODO - pass monitor id to Incidents page */} - { - e.stopPropagation(); - navigate(`/incidents/${actions.id}`); - }} - > - Incidents - - {isAdmin && ( - { - e.stopPropagation(); - - navigate(`/uptime/configure/${actions.id}`); - }} - > - Configure - - )} - {isAdmin && ( - { - e.stopPropagation(); - navigate(`/uptime/create/${actions.id}`); - }} - > - Clone - - )} - {isAdmin && ( - { - closeMenu(e); - - e.stopPropagation(); - handlePause(e); - }} - > - {monitor?.isActive === true ? "Pause" : "Resume"} - - )} - {isAdmin && ( - { - e.stopPropagation(); - openRemove(e); - }} - sx={{ "&.MuiButtonBase-root": { color: theme.palette.error.main } }} - > - Remove - - )} - - { - e.stopPropagation(); - setIsOpen(false); - }} - confirmationButtonLabel="Delete" - /* Do we need stop propagation? */ - onConfirm={(e) => { - console.log(e); - e.stopPropagation(); - handleRemove(e); - }} - isLoading={isDeleting} - modelTitle="modal-delete-monitor" - modelDescription="delete-monitor-confirmation" - /> - - ); -}; - -ActionsMenu.propTypes = { - monitor: PropTypes.shape({ - id: PropTypes.string, - url: PropTypes.string, - type: PropTypes.string, - isActive: PropTypes.bool, - }).isRequired, - isAdmin: PropTypes.bool, - updateRowCallback: PropTypes.func, - pauseCallback: PropTypes.func, - setIsLoading: PropTypes.func, -}; - -export default ActionsMenu; diff --git a/client/src/Hooks/UseApi.ts b/client/src/Hooks/UseApi.ts index dfd256bdd..e1faa2b29 100644 --- a/client/src/Hooks/UseApi.ts +++ b/client/src/Hooks/UseApi.ts @@ -179,3 +179,37 @@ export const useDelete = () => { return { deleteFn, loading, error }; }; + +export const useLazyGet = () => { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const { toastError } = useToast(); + + const getFn = async ( + endpoint: string, + config?: AxiosRequestConfig + ): Promise | null> => { + setLoading(true); + setError(null); + + try { + const res = await get>(endpoint, { + ...config, + headers: { + ...config?.headers, + }, + }); + return res.data; + } catch (err: any) { + console.error(err); + const errMsg = err?.response?.data?.msg || err.message || "An error occurred"; + toastError(errMsg); + setError(errMsg); + return null; + } finally { + setLoading(false); + } + }; + + return { get: getFn, loading, error }; +}; diff --git a/client/src/Hooks/monitorHooks.js b/client/src/Hooks/monitorHooks.js deleted file mode 100644 index 006c5b76e..000000000 --- a/client/src/Hooks/monitorHooks.js +++ /dev/null @@ -1,170 +0,0 @@ -import { useEffect, useState } from "react"; -import { networkService } from "../main.jsx"; -import { createToast } from "../Utils/toastUtils.jsx"; -import { useTranslation } from "react-i18next"; - -export const useFetchMonitorsByTeamId = ({ types, filter, updateTrigger }) => { - const [isLoading, setIsLoading] = useState(false); - const [monitors, setMonitors] = useState(undefined); - const [networkError, setNetworkError] = useState(false); - - useEffect(() => { - const fetchMonitors = async () => { - try { - setIsLoading(true); - const res = await networkService.getMonitorsByTeamId({ - types, - filter, - }); - if (res?.data?.data) { - setMonitors(res.data.data); - } - } catch (error) { - setNetworkError(true); - createToast({ - body: error.message, - }); - } finally { - setIsLoading(false); - } - }; - fetchMonitors(); - }, [types, filter, updateTrigger]); - return [monitors, isLoading, networkError]; -}; - -export const useDeleteMonitor = () => { - const [isLoading, setIsLoading] = useState(false); - const { t } = useTranslation(); - const deleteMonitor = async (monitorId, successCallback = () => {}) => { - try { - setIsLoading(true); - await networkService.deleteMonitorById({ monitorId }); - successCallback(); - createToast({ body: t("monitorDeleted") }); - } catch (error) { - createToast({ body: t("failedDeleteMonitor") }); - } finally { - setIsLoading(false); - } - }; - return [deleteMonitor, isLoading]; -}; - -export const usePauseMonitor = () => { - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const { t } = useTranslation(); - - const pauseMonitor = async (monitorId, successCallback = () => {}) => { - try { - setIsLoading(true); - const res = await networkService.pauseMonitorById({ monitorId }); - successCallback(); - if (res.data.data.isActive === false) { - createToast({ body: t("monitorPaused") }); - } else { - createToast({ body: t("monitorResumed") }); - } - } catch (error) { - setError(error.message); - createToast({ body: t("failedPauseMonitor") }); - } finally { - setIsLoading(false); - } - }; - - return [pauseMonitor, isLoading, error]; -}; - -export const useAddDemoMonitors = () => { - const [isLoading, setIsLoading] = useState(false); - const { t } = useTranslation(); - const addDemoMonitors = async () => { - try { - setIsLoading(true); - await networkService.addDemoMonitors(); - createToast({ body: t("monitorHooks.successAddDemoMonitors") }); - } catch (error) { - createToast({ body: t("monitorHooks.failureAddDemoMonitors") }); - } finally { - setIsLoading(false); - } - }; - return [addDemoMonitors, isLoading]; -}; - -export const useDeleteAllMonitors = () => { - const [isLoading, setIsLoading] = useState(false); - const { t } = useTranslation(); - const deleteAllMonitors = async () => { - try { - setIsLoading(true); - await networkService.deleteAllMonitors(); - createToast({ body: t("settingsMonitorsDeleted") }); - } catch (error) { - createToast({ body: t("settingsFailedToDeleteMonitors") }); - } finally { - setIsLoading(false); - } - }; - return [deleteAllMonitors, isLoading]; -}; - -export const useDeleteMonitorStats = () => { - const { t } = useTranslation(); - const [isLoading, setIsLoading] = useState(false); - const deleteMonitorStats = async () => { - setIsLoading(true); - try { - await networkService.deleteChecksByTeamId(); - createToast({ body: t("settingsStatsCleared") }); - } catch (error) { - createToast({ body: t("settingsFailedToClearStats") }); - } finally { - setIsLoading(false); - } - }; - - return [deleteMonitorStats, isLoading]; -}; - -export const useCreateBulkMonitors = () => { - const [isLoading, setIsLoading] = useState(false); - - const createBulkMonitors = async (file, user) => { - setIsLoading(true); - - const formData = new FormData(); - formData.append("csvFile", file); - - try { - const response = await networkService.createBulkMonitors(formData); - return [true, response.data, null]; - } catch (err) { - const errorMessage = err?.response?.data?.msg || err.message; - return [false, null, errorMessage]; - } finally { - setIsLoading(false); - } - }; - - return [createBulkMonitors, isLoading]; -}; - -export const useFetchJson = () => { - const [isLoading, setIsLoading] = useState(false); - const fetchJson = async () => { - try { - setIsLoading(true); - const res = await networkService.fetchJson(); - createToast({ body: "JSON fetched successfully" }); - return res?.data?.data ?? []; - } catch (error) { - createToast({ body: "Failed to create monitor." }); - } finally { - setIsLoading(false); - } - }; - return [fetchJson, isLoading]; -}; diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index bd3513a2c..071f414fd 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -26,14 +26,9 @@ import { } from "@/Features/UI/uiSlice.js"; import SettingsStats from "./SettingsStats.jsx"; -import { useFetchSettings, useSaveSettings } from "@/Hooks/settingsHooks.js"; +import { useFetchSettings, useSaveSettings } from "@/Hooks/settingsHooks"; import { useIsAdmin } from "@/Hooks/useIsAdmin.js"; -import { - useAddDemoMonitors, - useDeleteAllMonitors, - useDeleteMonitorStats, - useFetchJson, -} from "@/Hooks/monitorHooks.js"; +import { usePost, useDelete, useLazyGet } from "@/Hooks/UseApi"; // Constants const BREADCRUMBS = [{ name: `Settings`, path: "/settings" }]; @@ -64,8 +59,6 @@ const Settings = () => { setIsEmailPasswordSet, }); - const [addDemoMonitors, isAddingDemoMonitors] = useAddDemoMonitors(); - const [isSaving, saveError, saveSettings] = useSaveSettings({ setSettingsData, setIsApiKeySet, @@ -73,9 +66,12 @@ const Settings = () => { setIsEmailPasswordSet, setEmailPasswordHasBeenReset, }); - const [deleteAllMonitors, isDeletingMonitors] = useDeleteAllMonitors(); - const [deleteMonitorStats, isDeletingMonitorStats] = useDeleteMonitorStats(); - const [fetchJson, isFetchingJson] = useFetchJson(); + + // New API hooks to replace monitorHooks + const { post: postDemoMonitors, loading: isAddingDemoMonitors } = usePost(); + const { deleteFn: deleteAllMonitorsFn, loading: isDeletingMonitors } = useDelete(); + const { deleteFn: deleteMonitorStatsFn, loading: isDeletingMonitorStats } = useDelete(); + const { get: fetchJson, loading: isFetchingJson } = useLazyGet(); // Setup const isAdmin = useIsAdmin(); @@ -130,22 +126,23 @@ const Settings = () => { } if (name === "deleteStats") { - await deleteMonitorStats(); + await deleteMonitorStatsFn("/checks/team"); return; } if (name === "demo") { - await addDemoMonitors(); + await postDemoMonitors("/monitors/demo", {}); return; } if (name === "deleteMonitors") { - await deleteAllMonitors(); + await deleteAllMonitorsFn("/monitors/"); return; } if (name === "export") { - const json = await fetchJson(); + const res = await fetchJson("/monitors/export/json"); + const json = res?.data ?? []; if (!json || json.length === 0) { return; } diff --git a/client/src/Pages/Uptime/BulkImport/Upload.jsx b/client/src/Pages/Uptime/BulkImport/Upload.jsx deleted file mode 100644 index 24bc0ec38..000000000 --- a/client/src/Pages/Uptime/BulkImport/Upload.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useTheme } from "@emotion/react"; -import { useState, useRef } from "react"; -import { Button, Typography } from "@mui/material"; -import { useTranslation } from "react-i18next"; -import PropTypes from "prop-types"; - -const UploadFile = ({ onFileSelect }) => { - // Changed prop to onFileSelect - const theme = useTheme(); - const [file, setFile] = useState(); - const [error, setError] = useState(""); - const inputRef = useRef(); - const { t } = useTranslation(); - - const handleSelectFile = () => { - inputRef.current.click(); - }; - - const handleFileChange = (e) => { - setError(""); - const selectedFile = e.target.files[0]; - - // Basic file validation - if (!selectedFile) return; - - if (!selectedFile.name.toLowerCase().endsWith(".csv")) { - setError(t("bulkImport.invalidFileType")); - return; - } - - setFile(selectedFile); - onFileSelect(selectedFile); // Pass the file directly to parent - }; - - return ( -
- - - {file?.name || t("bulkImport.noFileSelected")} - - - {error} - - -
- ); -}; - -UploadFile.prototype = { - onFileSelect: PropTypes.func.isRequired, -}; - -export default UploadFile; diff --git a/client/src/Pages/Uptime/BulkImport/index.jsx b/client/src/Pages/Uptime/BulkImport/index.jsx deleted file mode 100644 index 6f2f7bcb5..000000000 --- a/client/src/Pages/Uptime/BulkImport/index.jsx +++ /dev/null @@ -1,117 +0,0 @@ -// React, Redux, Router -import { useTheme } from "@emotion/react"; -import { useState } from "react"; -// MUI -import { Box, Stack, Typography, Button, Link } from "@mui/material"; - -//Components -import { createToast } from "../../../Utils/toastUtils.jsx"; -import Breadcrumbs from "@/Components/v1/Breadcrumbs/index.jsx"; -import ConfigBox from "@/Components/v1/ConfigBox/index.jsx"; -import UploadFile from "./Upload.jsx"; -import { useSelector } from "react-redux"; -import { useNavigate } from "react-router-dom"; -import { Trans, useTranslation } from "react-i18next"; -import { useCreateBulkMonitors } from "../../../Hooks/monitorHooks.js"; - -const BulkImport = () => { - const theme = useTheme(); - const { user } = useSelector((state) => state.auth); - const navigate = useNavigate(); - const { t } = useTranslation(); - const [selectedFile, setSelectedFile] = useState(null); - - const crumbs = [ - { name: t("uptime"), path: "/uptime" }, - { name: t("bulkImport.title"), path: `/uptime/bulk-import` }, - ]; - - const [createBulkMonitors, hookLoading] = useCreateBulkMonitors(); - - const handleSubmit = async () => { - if (!selectedFile) { - createToast({ body: t("bulkImport.noFileSelected") }); - return; - } - - const [success, data, error] = await createBulkMonitors(selectedFile, user); - - if (success) { - // You can use `data` here if needed - createToast({ body: t("bulkImport.uploadSuccess") }); - navigate("/uptime"); - } else { - createToast({ body: error || t("bulkImport.uploadFailed") }); - } - }; - - return ( - - - - - {t("bulkImport.title")} - - - - - {t("bulkImport.selectFileTips")} - - - - ), - sample: ( - - ), - }} - /> - - - - - setSelectedFile(file)} /> - - - - - - - - - ); -}; - -export default BulkImport; diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx index 4711906c7..07dc1793c 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.jsx @@ -53,7 +53,6 @@ import CreateNewMaintenanceWindow from "@/Pages/Maintenance/create"; import ProtectedRoute from "../Components/v1/ProtectedRoute"; import RoleProtectedRoute from "../Components/v1/RoleProtectedRoute"; import withAdminCheck from "@/Components/v1/HOC/withAdminCheck"; -import BulkImport from "../Pages/Uptime/BulkImport/index.jsx"; import Logs from "../Pages/Logs"; import CreateMonitor from "@/Pages/CreateMonitor"; @@ -87,10 +86,7 @@ const Routes = () => { } /> - } - /> +