Merge pull request #2431 from bluewave-labs/fix/redux-removal-hook-cleanup

fix: redux removal hook cleanup
This commit is contained in:
Alexander Holliday
2025-06-13 09:03:25 +08:00
committed by GitHub
44 changed files with 767 additions and 1057 deletions

View File

@@ -105,7 +105,7 @@ const Checkbox = ({
};
Checkbox.propTypes = {
id: PropTypes.string.isRequired,
id: PropTypes.string,
name: PropTypes.string,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
size: PropTypes.oneOf(["small", "medium", "large"]),

View File

@@ -11,10 +11,9 @@ import EmailIcon from "@mui/icons-material/Email";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
import { useTheme } from "@mui/material/styles";
import { usePauseMonitor } from "../../Hooks/useMonitorControls";
import { usePauseMonitor } from "../../Hooks/monitorHooks";
import { useSendTestEmail } from "../../Hooks/useSendTestEmail";
import { useTranslation } from "react-i18next";
/**
* MonitorDetailsControlHeader component displays the control header for monitor details.
* It includes status display, pause/resume button, and a configure button for admins.
@@ -38,10 +37,7 @@ const MonitorDetailsControlHeader = ({
const navigate = useNavigate();
const theme = useTheme();
const { t } = useTranslation();
const [pauseMonitor, isPausing, error] = usePauseMonitor({
monitorId: monitor?._id,
triggerUpdate,
});
const [pauseMonitor, isPausing, error] = usePauseMonitor();
const [isSending, emailError, sendTestEmail] = useSendTestEmail();
@@ -88,7 +84,10 @@ const MonitorDetailsControlHeader = ({
monitor?.isActive ? <PauseOutlinedIcon /> : <PlayArrowOutlinedIcon />
}
onClick={() => {
pauseMonitor();
pauseMonitor({
monitorId: monitor?._id,
triggerUpdate,
});
}}
>
{monitor?.isActive ? "Pause" : "Resume"}

View File

@@ -7,8 +7,7 @@ import Dot from "../../Components/Dot";
import { formatDurationRounded } from "../../Utils/timeUtils";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import useUtils from "../../Pages/Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../Hooks/useMonitorUtils";
/**
* Status component displays the status information of a monitor.
* It includes the monitor's name, URL, and check interval.
@@ -23,7 +22,7 @@ import useUtils from "../../Pages/Uptime/Monitors/Hooks/useUtils";
*/
const Status = ({ monitor }) => {
const theme = useTheme();
const { statusColor, determineState } = useUtils();
const { statusColor, determineState } = useMonitorUtils();
return (
<Stack>

View File

@@ -2,7 +2,7 @@ import { Stack, Typography } from "@mui/material";
import PulseDot from "../Animated/PulseDot";
import Dot from "../Dot";
import { useTheme } from "@emotion/react";
import useUtils from "../../Pages/Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../Hooks/useMonitorUtils";
import { formatDurationRounded } from "../../Utils/timeUtils";
import ConfigButton from "./ConfigButton";
import SkeletonLayout from "./skeleton";
@@ -12,7 +12,7 @@ import { useTranslation } from "react-i18next";
const MonitorStatusHeader = ({ path, isLoading = false, isAdmin, monitor }) => {
const theme = useTheme();
const { t } = useTranslation();
const { statusColor, determineState } = useUtils();
const { statusColor, determineState } = useMonitorUtils();
if (isLoading) {
return <SkeletonLayout />;
}

View File

@@ -2,7 +2,7 @@ import { Stack, Typography } from "@mui/material";
import Image from "../Image";
import { useTheme } from "@mui/material/styles";
import PropTypes from "prop-types";
import useUtils from "../../Pages/Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../Hooks/useMonitorUtils";
/**
* StatBox Component
@@ -41,7 +41,7 @@ const StatBox = ({
sx,
}) => {
const theme = useTheme();
const { statusToTheme } = useUtils();
const { statusToTheme } = useMonitorUtils();
const themeColor = statusToTheme[status];
const statusBoxStyles = gradient

View File

@@ -0,0 +1,85 @@
import { useState, useEffect } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
const useFetchChecks = ({
teamId,
monitorId,
type,
status,
sortOrder,
limit,
dateRange,
filter,
page,
rowsPerPage,
}) => {
const [checks, setChecks] = useState(undefined);
const [checksCount, setChecksCount] = useState(undefined);
const [isLoading, setIsLoading] = useState(false);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchChecks = async () => {
if (!type && !teamId) {
return;
}
const method = monitorId
? networkService.getChecksByMonitor
: networkService.getChecksByTeam;
const config = monitorId
? {
monitorId,
type,
status,
sortOrder,
limit,
dateRange,
filter,
page,
rowsPerPage,
}
: {
status,
teamId,
sortOrder,
limit,
dateRange,
filter,
page,
rowsPerPage,
};
try {
setIsLoading(true);
const res = await method(config);
setChecks(res.data.data.checks);
setChecksCount(res.data.data.checksCount);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchChecks();
}, [
monitorId,
teamId,
type,
status,
sortOrder,
limit,
dateRange,
filter,
page,
rowsPerPage,
]);
return [checks, checksCount, isLoading, networkError];
};
export { useFetchChecks };

View File

@@ -0,0 +1,398 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
import { useTheme } from "@emotion/react";
import { useMonitorUtils } from "./useMonitorUtils";
import { useNavigate } from "react-router-dom";
const useFetchMonitorsWithSummary = ({ teamId, types, monitorUpdateTrigger }) => {
const [isLoading, setIsLoading] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsWithSummaryByTeamId({
teamId,
types,
});
const { monitors, summary } = res?.data?.data ?? {};
setMonitors(monitors);
setMonitorsSummary(summary);
} catch (error) {
console.error(error);
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [teamId, types, monitorUpdateTrigger]);
return [monitors, monitorsSummary, isLoading, networkError];
};
const useFetchMonitorsWithChecks = ({
teamId,
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
monitorUpdateTrigger,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [count, setCount] = useState(undefined);
const [monitors, setMonitors] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
const theme = useTheme();
const { getMonitorWithPercentage } = useMonitorUtils();
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsWithChecksByTeamId({
teamId,
limit,
types,
page,
rowsPerPage,
filter,
field,
order,
});
const { count, monitors } = res?.data?.data ?? {};
const mappedMonitors = monitors.map((monitor) =>
getMonitorWithPercentage(monitor, theme)
);
setMonitors(mappedMonitors);
setCount(count?.monitorsCount ?? 0);
} catch (error) {
console.error(error);
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [
field,
filter,
getMonitorWithPercentage,
limit,
order,
page,
rowsPerPage,
teamId,
theme,
types,
monitorUpdateTrigger,
]);
return [monitors, count, isLoading, networkError];
};
const useFetchMonitorsByTeamId = ({
teamId,
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
checkOrder,
normalize,
status,
updateTrigger,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [summary, setSummary] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsByTeamId({
teamId,
limit,
types,
page,
rowsPerPage,
filter,
field,
order,
checkOrder,
status,
normalize,
});
if (res?.data?.data?.filteredMonitors) {
setMonitors(res.data.data.filteredMonitors);
setSummary(res.data.data.summary);
}
} catch (error) {
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [
teamId,
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
updateTrigger,
checkOrder,
normalize,
status,
]);
return [monitors, summary, isLoading, networkError];
};
const useFetchStatsByMonitorId = ({
monitorId,
sortOrder,
limit,
dateRange,
numToDisplay,
normalize,
}) => {
const [monitor, setMonitor] = useState(undefined);
const [audits, setAudits] = useState(undefined);
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitor = async () => {
try {
setIsLoading(true);
const res = await networkService.getStatsByMonitorId({
monitorId: monitorId,
sortOrder,
limit,
dateRange,
numToDisplay,
normalize,
});
setMonitor(res?.data?.data ?? undefined);
setAudits(res?.data?.data?.checks?.[0]?.audits ?? undefined);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitor();
}, [monitorId, dateRange, numToDisplay, normalize, sortOrder, limit]);
return [monitor, audits, isLoading, networkError];
};
const useFetchMonitorById = ({ monitorId, setMonitor, updateTrigger }) => {
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchMonitor = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorById({ monitorId: monitorId });
setMonitor(res.data.data);
} catch (error) {
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitor();
}, [monitorId, setMonitor, updateTrigger]);
return [isLoading];
};
const useFetchHardwareMonitorById = ({ monitorId, dateRange }) => {
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
const [monitor, setMonitor] = useState(undefined);
useEffect(() => {
const fetchMonitor = async () => {
try {
if (!monitorId) {
return { monitor: undefined, isLoading: false, networkError: undefined };
}
const response = await networkService.getHardwareDetailsByMonitorId({
monitorId: monitorId,
dateRange: dateRange,
});
setMonitor(response.data.data);
} catch (error) {
setNetworkError(true);
} finally {
setIsLoading(false);
}
};
fetchMonitor();
}, [monitorId, dateRange]);
return [monitor, isLoading, networkError];
};
const useFetchUptimeMonitorById = ({ monitorId, dateRange, trigger }) => {
const [networkError, setNetworkError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [monitor, setMonitor] = useState(undefined);
const [monitorStats, setMonitorStats] = useState(undefined);
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getUptimeDetailsById({
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
const { monitorData, monitorStats } = res?.data?.data ?? {};
setMonitor(monitorData);
setMonitorStats(monitorStats);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [dateRange, monitorId, trigger]);
return [monitor, monitorStats, isLoading, networkError];
};
const useCreateMonitor = () => {
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const createMonitor = async ({ monitor, redirect }) => {
try {
setIsLoading(true);
await networkService.createMonitor({ monitor });
createToast({ body: "Monitor created successfully!" });
if (redirect) {
navigate(redirect);
}
} catch (error) {
createToast({ body: "Failed to create monitor." });
} finally {
setIsLoading(false);
}
};
return [createMonitor, isLoading];
};
const useDeleteMonitor = () => {
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const deleteMonitor = async ({ monitor, redirect }) => {
try {
setIsLoading(true);
await networkService.deleteMonitorById({ monitorId: monitor._id });
createToast({ body: "Monitor deleted successfully!" });
if (redirect) {
navigate(redirect);
}
} catch (error) {
createToast({ body: "Failed to delete monitor." });
} finally {
setIsLoading(false);
}
};
return [deleteMonitor, isLoading];
};
const useUpdateMonitor = () => {
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const updateMonitor = async ({ monitor, redirect }) => {
try {
setIsLoading(true);
const updatedFields = {
name: monitor.name,
description: monitor.description,
interval: monitor.interval,
notifications: monitor.notifications,
matchMethod: monitor.matchMethod,
expectedValue: monitor.expectedValue,
ignoreTlsErrors: monitor.ignoreTlsErrors,
jsonPath: monitor.jsonPath,
...(monitor.type === "port" && { port: monitor.port }),
...(monitor.type === "hardware" && {
thresholds: monitor.thresholds,
secret: monitor.secret,
}),
};
await networkService.updateMonitor({
monitorId: monitor._id,
updatedFields,
});
createToast({ body: "Monitor updated successfully!" });
if (redirect) {
navigate(redirect);
}
} catch (error) {
createToast({ body: "Failed to update monitor." });
} finally {
setIsLoading(false);
}
};
return [updateMonitor, isLoading];
};
const usePauseMonitor = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(undefined);
const pauseMonitor = async ({ monitorId, triggerUpdate }) => {
try {
setIsLoading(true);
const res = await networkService.pauseMonitorById({ monitorId });
createToast({
body: res.data.data.isActive
? "Monitor resumed successfully"
: "Monitor paused successfully",
});
triggerUpdate();
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
};
return [pauseMonitor, isLoading, error];
};
export {
useFetchMonitorsWithSummary,
useFetchMonitorsWithChecks,
useFetchMonitorsByTeamId,
useFetchStatsByMonitorId,
useFetchMonitorById,
useFetchUptimeMonitorById,
useFetchHardwareMonitorById,
useCreateMonitor,
useDeleteMonitor,
useUpdateMonitor,
usePauseMonitor,
};

View File

@@ -1,72 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
import { useTheme } from "@emotion/react";
import { useMonitorUtils } from "./useMonitorUtils";
export const useFetchMonitorsWithChecks = ({
teamId,
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
monitorUpdateTrigger,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [count, setCount] = useState(undefined);
const [monitors, setMonitors] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
const theme = useTheme();
const { getMonitorWithPercentage } = useMonitorUtils();
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsWithChecksByTeamId({
teamId,
limit,
types,
page,
rowsPerPage,
filter,
field,
order,
});
const { count, monitors } = res?.data?.data ?? {};
const mappedMonitors = monitors.map((monitor) =>
getMonitorWithPercentage(monitor, theme)
);
setMonitors(mappedMonitors);
setCount(count?.monitorsCount ?? 0);
} catch (error) {
console.error(error);
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [
field,
filter,
getMonitorWithPercentage,
limit,
order,
page,
rowsPerPage,
teamId,
theme,
types,
monitorUpdateTrigger,
]);
return [monitors, count, isLoading, networkError];
};
export default useFetchMonitorsWithChecks;

View File

@@ -1,37 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
export const useFetchMonitorsWithSummary = ({ teamId, types, monitorUpdateTrigger }) => {
const [isLoading, setIsLoading] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsWithSummaryByTeamId({
teamId,
types,
});
const { monitors, summary } = res?.data?.data ?? {};
setMonitors(monitors);
setMonitorsSummary(summary);
} catch (error) {
console.error(error);
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [teamId, types, monitorUpdateTrigger]);
return [monitors, monitorsSummary, isLoading, networkError];
};
export default useFetchMonitorsWithSummary;

View File

@@ -1,35 +0,0 @@
import { useState, useEffect } from "react";
import { useDispatch } from "react-redux";
import { getUptimeMonitorById } from "../Features/UptimeMonitors/uptimeMonitorsSlice";
import { useNavigate } from "react-router";
const useFetchUptimeMonitorById = (monitorId, updateTrigger) => {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const [monitor, setMonitor] = useState(null);
const navigate = useNavigate();
const dispatch = useDispatch();
useEffect(() => {
const fetchMonitor = async () => {
try {
setIsLoading(true);
const action = await dispatch(getUptimeMonitorById({ monitorId }));
if (getUptimeMonitorById.fulfilled.match(action)) {
const monitor = action.payload.data;
setMonitor(monitor);
} else if (getUptimeMonitorById.rejected.match(action)) {
throw new Error(action.error.message);
}
} catch (error) {
navigate("/not-found", { replace: true });
} finally {
setIsLoading(false);
}
};
fetchMonitor();
}, [monitorId, dispatch, navigate, updateTrigger]);
return [monitor, isLoading, error];
};
export { useFetchUptimeMonitorById };

View File

@@ -1,35 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { useNavigate } from "react-router-dom";
import { createToast } from "../Utils/toastUtils";
export const useFetchUptimeMonitorDetails = ({ monitorId, dateRange, trigger }) => {
const [networkError, setNetworkError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [monitor, setMonitor] = useState(undefined);
const [monitorStats, setMonitorStats] = useState(undefined);
const navigate = useNavigate();
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getUptimeDetailsById({
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
const { monitorData, monitorStats } = res?.data?.data ?? {};
setMonitor(monitorData);
setMonitorStats(monitorStats);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [dateRange, monitorId, navigate, trigger]);
return [monitor, monitorStats, isLoading, networkError];
};
export default useFetchUptimeMonitorDetails;

View File

@@ -1,28 +0,0 @@
import { useState } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
const usePauseMonitor = ({ monitorId, triggerUpdate }) => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(undefined);
const pauseMonitor = async () => {
try {
setIsLoading(true);
const res = await networkService.pauseMonitorById({ monitorId });
createToast({
body: res.data.data.isActive
? "Monitor resumed successfully"
: "Monitor paused successfully",
});
triggerUpdate();
} catch (error) {
setError(error);
} finally {
setIsLoading(false);
}
};
return [pauseMonitor, isLoading, error];
};
export { usePauseMonitor };

View File

@@ -46,7 +46,27 @@ const useMonitorUtils = () => {
pending: theme.palette.warning.lowContrast,
};
return { getMonitorWithPercentage, determineState, statusColor };
const statusToTheme = {
up: "success",
down: "error",
paused: "warning",
pending: "secondary",
"cannot resolve": "tertiary",
};
const pagespeedStatusMsg = {
up: "Live (collecting data)",
down: "Inactive",
paused: "Paused",
};
return {
getMonitorWithPercentage,
determineState,
statusColor,
statusToTheme,
pagespeedStatusMsg,
};
};
export { useMonitorUtils };

View File

@@ -10,10 +10,10 @@ import NetworkError from "../../../../Components/GenericFallback/NetworkError";
//Utils
import { formatDateWithTz } from "../../../../Utils/timeUtils";
import { useSelector } from "react-redux";
import { useState } from "react";
import useChecksFetch from "../../Hooks/useChecksFetch";
import { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { useFetchChecks } from "../../../../Hooks/checkHooks";
const IncidentTable = ({
shouldRender,
@@ -24,19 +24,28 @@ const IncidentTable = ({
}) => {
//Redux state
const uiTimezone = useSelector((state) => state.ui.timezone);
const { user } = useSelector((state) => state.auth);
//Local state
const [teamId, setTeamId] = useState(undefined);
const [monitorId, setMonitorId] = useState(undefined);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const selectedMonitorDetails = monitors?.[selectedMonitor];
const selectedMonitorType = selectedMonitorDetails?.type;
const { isLoading, networkError, checks, checksCount } = useChecksFetch({
selectedMonitor,
selectedMonitorType,
filter,
const [checks, checksCount, isLoading, networkError] = useFetchChecks({
status: false,
monitorId,
teamId,
type: selectedMonitorType,
sortOrder: "desc",
limit: null,
dateRange,
page,
rowsPerPage,
filter: filter,
page: page,
rowsPerPage: rowsPerPage,
});
const { t } = useTranslation();
@@ -50,6 +59,16 @@ const IncidentTable = ({
setRowsPerPage(event.target.value);
};
useEffect(() => {
if (selectedMonitor === "0") {
setTeamId(user.teamId);
setMonitorId(undefined);
} else {
setMonitorId(selectedMonitor);
setTeamId(undefined);
}
}, [selectedMonitor, user.teamId]);
const headers = [
{
id: "monitorName",

View File

@@ -1,66 +0,0 @@
import { useState, useEffect } from "react";
import { networkService } from "../../../main";
import { createToast } from "../../../Utils/toastUtils";
import { useSelector } from "react-redux";
const useChecksFetch = ({
selectedMonitor,
selectedMonitorType,
filter,
dateRange,
page,
rowsPerPage,
}) => {
//Redux
const { user } = useSelector((state) => state.auth);
//Local
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
const [checks, setChecks] = useState(undefined);
const [checksCount, setChecksCount] = useState(undefined);
useEffect(() => {
const fetchChecks = async () => {
try {
setIsLoading(true);
let res;
if (selectedMonitor === "0") {
res = await networkService.getChecksByTeam({
status: false,
teamId: user.teamId,
sortOrder: "desc",
limit: null,
dateRange,
filter: filter,
page: page,
rowsPerPage: rowsPerPage,
});
} else {
res = await networkService.getChecksByMonitor({
status: false,
monitorId: selectedMonitor,
type: selectedMonitorType,
sortOrder: "desc",
limit: null,
dateRange,
filter: filter,
page,
rowsPerPage,
});
}
setChecks(res.data.data.checks);
setChecksCount(res.data.data.checksCount);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchChecks();
}, [user, dateRange, page, rowsPerPage, filter, selectedMonitor, selectedMonitorType]);
return { isLoading, networkError, checks, checksCount };
};
export default useChecksFetch;

View File

@@ -1,54 +0,0 @@
import { useState, useEffect } from "react";
import { networkService } from "../../../main";
import { createToast } from "../../../Utils/toastUtils";
const useMonitorsFetch = ({ teamId }) => {
//Local state
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
const [monitors, setMonitors] = useState(undefined);
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsByTeamId({
teamId,
limit: null,
types: null,
status: null,
checkOrder: null,
normalize: null,
page: null,
rowsPerPage: null,
filter: null,
field: null,
order: null,
});
if (res?.data?.data?.filteredMonitors?.length > 0) {
const monitorLookup = res.data.data.filteredMonitors.reduce((acc, monitor) => {
acc[monitor._id] = {
_id: monitor._id,
name: monitor.name,
type: monitor.type,
};
return acc;
}, {});
setMonitors(monitorLookup);
}
} catch (error) {
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [teamId]);
return { isLoading, monitors, networkError };
};
export { useMonitorsFetch };

View File

@@ -1,19 +1,19 @@
// Components
import { Stack } from "@mui/material";
import Breadcrumbs from "../../Components/Breadcrumbs";
import GenericFallback from "../../Components/GenericFallback";
import IncidentTable from "./Components/IncidentTable";
import OptionsHeader from "./Components/OptionsHeader";
//Utils
import { useTheme } from "@emotion/react";
import { useMonitorsFetch } from "./Hooks/useMonitorsFetch";
import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks";
import { useSelector } from "react-redux";
import OptionsHeader from "./Components/OptionsHeader";
import { useState } from "react";
import IncidentTable from "./Components/IncidentTable";
import GenericFallback from "../../Components/GenericFallback";
import { useState, useEffect } from "react";
import NetworkError from "../../Components/GenericFallback/NetworkError";
import { useTranslation } from "react-i18next";
//Constants
//Constants
const Incidents = () => {
// Redux state
const { user } = useSelector((state) => state.auth);
@@ -27,13 +27,26 @@ const Incidents = () => {
const [selectedMonitor, setSelectedMonitor] = useState("0");
const [filter, setFilter] = useState(undefined);
const [dateRange, setDateRange] = useState(undefined);
const [monitorLookup, setMonitorLookup] = useState(undefined);
//Utils
const theme = useTheme();
const { monitors, isLoading, networkError } = useMonitorsFetch({
const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({
teamId: user.teamId,
});
useEffect(() => {
const monitorLookup = monitors?.reduce((acc, monitor) => {
acc[monitor._id] = {
_id: monitor._id,
name: monitor.name,
type: monitor.type,
};
return acc;
}, {});
setMonitorLookup(monitorLookup);
}, [monitors]);
if (networkError) {
return (
<GenericFallback>
@@ -47,7 +60,7 @@ const Incidents = () => {
<Breadcrumbs list={BREADCRUMBS} />
<OptionsHeader
shouldRender={!isLoading}
monitors={monitors}
monitors={monitorLookup}
selectedMonitor={selectedMonitor}
setSelectedMonitor={setSelectedMonitor}
filter={filter}
@@ -57,7 +70,7 @@ const Incidents = () => {
/>
<IncidentTable
shouldRender={!isLoading}
monitors={monitors}
monitors={monitorLookup ? monitorLookup : {}}
selectedMonitor={selectedMonitor}
filter={filter}
dateRange={dateRange}

View File

@@ -1,20 +1,17 @@
// React, Redux, Router
import { useTheme } from "@emotion/react";
import { useNavigate, useParams } from "react-router-dom";
import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useSelector } from "react-redux";
// Utility and Network
import { infrastructureMonitorValidation } from "../../../Validation/validation";
import {
createInfrastructureMonitor,
updateInfrastructureMonitor,
} from "../../../Features/InfrastructureMonitors/infrastructureMonitorsSlice";
import { useHardwareMonitorsFetch } from "../Details/Hooks/useHardwareMonitorsFetch";
import { useFetchHardwareMonitorById } from "../../../Hooks/monitorHooks";
import { capitalizeFirstLetter } from "../../../Utils/stringUtils";
import { useTranslation } from "react-i18next";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import NotificationsConfig from "../../../Components/NotificationConfig";
import { useUpdateMonitor, useCreateMonitor } from "../../../Hooks/monitorHooks";
// MUI
import { Box, Stack, Typography, Button, ButtonGroup } from "@mui/material";
@@ -55,9 +52,6 @@ const getAlertError = (errors) => {
const CreateInfrastructureMonitor = () => {
const theme = useTheme();
const { user } = useSelector((state) => state.auth);
const monitorState = useSelector((state) => state.infrastructureMonitor);
const dispatch = useDispatch();
const navigate = useNavigate();
const { monitorId } = useParams();
const { t } = useTranslation();
@@ -65,9 +59,11 @@ const CreateInfrastructureMonitor = () => {
const isCreate = typeof monitorId === "undefined";
// Fetch monitor details if editing
const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
const [monitor, isLoading, networkError] = useFetchHardwareMonitorById({ monitorId });
const [notifications, notificationsAreLoading, notificationsError] =
useGetNotificationsByTeamId();
const [updateMonitor, isUpdating] = useUpdateMonitor();
const [createMonitor, isCreating] = useCreateMonitor();
// State
const [errors, setErrors] = useState({});
@@ -187,6 +183,7 @@ const CreateInfrastructureMonitor = () => {
};
form = {
...(isCreate ? {} : { _id: monitorId }),
...rest,
description: form.name,
teamId: user.teamId,
@@ -197,19 +194,9 @@ const CreateInfrastructureMonitor = () => {
};
// Handle create or update
const action = isCreate
? await dispatch(createInfrastructureMonitor({ monitor: form }))
: await dispatch(updateInfrastructureMonitor({ monitorId, monitor: form }));
if (action.meta.requestStatus === "fulfilled") {
createToast({
body: isCreate
? t("infrastructureMonitorCreated")
: t("infrastructureMonitorUpdated"),
});
navigate("/infrastructure");
} else {
createToast({ body: "Failed to save monitor." });
}
isCreate
? await createMonitor({ monitor: form, redirect: "/infrastructure" })
: await updateMonitor({ monitor: form, redirect: "/infrastructure" });
};
const onChange = (event) => {
@@ -448,7 +435,7 @@ const CreateInfrastructureMonitor = () => {
type="submit"
variant="contained"
color="accent"
loading={monitorState?.isLoading}
loading={isLoading || isUpdating || isCreating || notificationsAreLoading}
>
{t(isCreate ? "infrastructureCreateMonitor" : "infrastructureEditMonitor")}
</Button>

View File

@@ -4,14 +4,14 @@ import StatusBoxes from "../../../../../Components/StatusBoxes";
import StatBox from "../../../../../Components/StatBox";
//Utils
import useUtils from "../../../../../Pages/Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
import { useHardwareUtils } from "../../Hooks/useHardwareUtils";
import { useTranslation } from "react-i18next";
const InfraStatBoxes = ({ shouldRender, monitor }) => {
// Utils
const { formatBytes } = useHardwareUtils();
const { determineState } = useUtils();
const { determineState } = useMonitorUtils();
const { t } = useTranslation();
const { stats } = monitor ?? {};

View File

@@ -1,38 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../../../../main";
const useHardwareMonitorsFetch = ({ monitorId, dateRange }) => {
// Abort early if creating monitor
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
const [monitor, setMonitor] = useState(undefined);
useEffect(() => {
const fetchData = async () => {
try {
if (!monitorId) {
return { monitor: undefined, isLoading: false, networkError: undefined };
}
const response = await networkService.getHardwareDetailsByMonitorId({
monitorId: monitorId,
dateRange: dateRange,
});
setMonitor(response.data.data);
} catch (error) {
setNetworkError(true);
} finally {
setIsLoading(false);
}
};
fetchData();
}, [monitorId, dateRange]);
return {
isLoading,
networkError,
monitor,
};
};
export { useHardwareMonitorsFetch };

View File

@@ -11,7 +11,7 @@ import GenericFallback from "../../../Components/GenericFallback";
// Utils
import { useTheme } from "@emotion/react";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import { useHardwareMonitorsFetch } from "./Hooks/useHardwareMonitorsFetch";
import { useFetchHardwareMonitorById } from "../../../Hooks/monitorHooks";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
@@ -33,7 +33,7 @@ const InfrastructureDetails = () => {
const { t } = useTranslation();
const isAdmin = useIsAdmin();
const { isLoading, networkError, monitor } = useHardwareMonitorsFetch({
const [monitor, isLoading, networkError] = useFetchHardwareMonitorById({
monitorId,
dateRange,
});

View File

@@ -10,7 +10,7 @@ import CustomGauge from "../../../../../Components/Charts/CustomGauge";
// Utils
import { useTheme } from "@emotion/react";
import useUtils from "../../../../Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
import { useNavigate } from "react-router-dom";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
@@ -19,7 +19,7 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
// Utils
const theme = useTheme();
const { t } = useTranslation();
const { determineState } = useUtils();
const { determineState } = useMonitorUtils();
const navigate = useNavigate();
// Handlers

View File

@@ -1,46 +0,0 @@
import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
const useMonitorFetch = ({ page, field, filter, rowsPerPage, updateTrigger }) => {
// Redux state
const { user } = useSelector((state) => state.auth);
// Local state
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [summary, setSummary] = useState(undefined);
useEffect(() => {
const fetchMonitors = async () => {
try {
const response = await networkService.getMonitorsByTeamId({
teamId: user.teamId,
limit: 1,
field: field,
filter: filter,
types: ["hardware"],
page: page,
rowsPerPage: rowsPerPage,
});
setMonitors(response?.data?.data?.filteredMonitors ?? []);
setSummary(response?.data?.data?.summary ?? {});
} catch (error) {
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [page, field, filter, rowsPerPage, user.teamId, updateTrigger]);
return { monitors, summary, isLoading, networkError };
};
export { useMonitorFetch };

View File

@@ -10,15 +10,20 @@ import Fallback from "../../../Components/Fallback";
import Filter from "./Components/Filters";
// Utils
import { useTheme } from "@emotion/react";
import { useMonitorFetch } from "./Hooks/useMonitorFetch";
import { useState } from "react";
import { useSelector } from "react-redux";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import { useTranslation } from "react-i18next";
import { useFetchMonitorsByTeamId } from "../../../Hooks/monitorHooks";
// Constants
const TYPES = ["hardware"];
const BREADCRUMBS = [{ name: `infrastructure`, path: "/infrastructure" }];
const InfrastructureMonitors = () => {
// Redux state
const { user } = useSelector((state) => state.auth);
// Local state
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [updateTrigger, setUpdateTrigger] = useState(false);
@@ -50,7 +55,10 @@ const InfrastructureMonitors = () => {
const field = toFilterStatus !== undefined ? "status" : undefined;
const { monitors, summary, isLoading, networkError } = useMonitorFetch({
const [monitors, summary, isLoading, networkError] = useFetchMonitorsByTeamId({
teamId: user.teamId,
limit: 1,
types: TYPES,
page,
field: field,
filter: toFilterStatus,

View File

@@ -12,45 +12,43 @@ import NotificationsConfig from "../../../Components/NotificationConfig";
import Dialog from "../../../Components/Dialog";
// Utils
import { useEffect, useState } from "react";
import { useState } from "react";
import { useTheme } from "@emotion/react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router";
import {
deletePageSpeed,
getPagespeedMonitorById,
getPageSpeedByTeamId,
updatePageSpeed,
pausePageSpeed,
} from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice";
import { useParams } from "react-router";
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import { useTranslation } from "react-i18next";
import useUtils from "../../Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../../Hooks/useMonitorUtils";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import {
useFetchMonitorById,
useDeleteMonitor,
useUpdateMonitor,
usePauseMonitor,
} from "../../../Hooks/monitorHooks";
const PageSpeedConfigure = () => {
// Redux state
const { isLoading } = useSelector((state) => state.pageSpeedMonitors);
// Local state
const [monitor, setMonitor] = useState({});
const [errors, setErrors] = useState({});
const [buttonLoading, setButtonLoading] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [updateTrigger, setUpdateTrigger] = useState(false);
// Utils
const theme = useTheme();
const { t } = useTranslation();
const navigate = useNavigate();
const dispatch = useDispatch();
const MS_PER_MINUTE = 60000;
const { monitorId } = useParams();
const { statusColor, pagespeedStatusMsg, determineState } = useUtils();
const { statusColor, pagespeedStatusMsg, determineState } = useMonitorUtils();
const [notifications, notificationsAreLoading, notificationsError] =
useGetNotificationsByTeamId();
const [isLoading] = useFetchMonitorById({ monitorId, setMonitor, updateTrigger });
const [deleteMonitor, isDeleting] = useDeleteMonitor();
const [updateMonitor, isUpdating] = useUpdateMonitor();
const [pauseMonitor, isPausing] = usePauseMonitor();
const frequencies = [
{ _id: 3, name: "3 minutes" },
{ _id: 5, name: "5 minutes" },
@@ -61,24 +59,10 @@ const PageSpeedConfigure = () => {
{ _id: 10080, name: "1 week" },
];
useEffect(() => {
const fetchMonitor = async () => {
try {
const action = await dispatch(getPagespeedMonitorById({ monitorId }));
if (getPagespeedMonitorById.fulfilled.match(action)) {
const monitor = action.payload.data;
setMonitor(monitor);
} else if (getPagespeedMonitorById.rejected.match(action)) {
throw new Error(action.error.message);
}
} catch (error) {
logger.error("Error fetching monitor of id: " + monitorId);
navigate("/not-found", { replace: true });
}
};
fetchMonitor();
}, [dispatch, monitorId, navigate]);
// Handlers
const triggerUpdate = () => {
setUpdateTrigger(!updateTrigger);
};
const onChange = (event) => {
let { value, name } = event.target;
@@ -106,42 +90,17 @@ const PageSpeedConfigure = () => {
};
const handlePause = async () => {
try {
const action = await dispatch(pausePageSpeed({ monitorId }));
if (pausePageSpeed.fulfilled.match(action)) {
const monitor = action.payload.data;
setMonitor(monitor);
const state = action?.payload?.data.isActive === false ? "paused" : "resumed";
createToast({ body: `Monitor ${state} successfully.` });
} else if (pausePageSpeed.rejected.match(action)) {
throw new Error(action.error.message);
}
} catch (error) {
createToast({ body: "Failed to pause monitor" });
}
await pauseMonitor({ monitorId, triggerUpdate });
};
const onSubmit = async (event) => {
event.preventDefault();
const action = await dispatch(updatePageSpeed({ monitor: monitor }));
if (action.meta.requestStatus === "fulfilled") {
createToast({ body: "Monitor updated successfully!" });
dispatch(getPageSpeedByTeamId());
} else {
createToast({ body: "Failed to update monitor." });
}
await updateMonitor({ monitor, redirect: "/pagespeed" });
};
const handleRemove = async (event) => {
event.preventDefault();
setButtonLoading(true);
const action = await dispatch(deletePageSpeed({ monitor }));
if (action.meta.requestStatus === "fulfilled") {
navigate("/pagespeed");
} else {
createToast({ body: "Failed to delete monitor." });
}
setButtonLoading(false);
await deleteMonitor({ monitor, redirect: "/pagespeed" });
};
return (
@@ -363,7 +322,7 @@ const PageSpeedConfigure = () => {
mt="auto"
>
<Button
loading={isLoading}
loading={isLoading || isDeleting || isUpdating || isPausing}
type="submit"
variant="contained"
color="accent"
@@ -383,7 +342,7 @@ const PageSpeedConfigure = () => {
onCancel={() => setIsOpen(false)}
confirmationButtonLabel={t("delete")}
onConfirm={handleRemove}
isLoading={buttonLoading}
isLoading={isLoading || isDeleting || isUpdating || isPausing}
/>
</Stack>
);

View File

@@ -1,31 +1,28 @@
// React, Redux, Router
import { useNavigate } from "react-router-dom";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
// Utility and Network
import { monitorValidation } from "../../../Validation/validation";
import {
createPageSpeed,
checkEndpointResolution,
} from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice";
import { parseDomainName } from "../../../Utils/monitorUtils";
import { useTranslation } from "react-i18next";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
// MUI
import { useTheme } from "@emotion/react";
import { Box, Stack, Typography, Button, ButtonGroup } from "@mui/material";
//Components
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import TextInput from "../../../Components/Inputs/TextInput";
import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
import ConfigBox from "../../../Components/ConfigBox";
import { createToast } from "../../../Utils/toastUtils";
import Radio from "../../../Components/Inputs/Radio";
import Select from "../../../Components/Inputs/Select";
import NotificationsConfig from "../../../Components/NotificationConfig";
// Utils
import { useState } from "react";
import { useSelector } from "react-redux";
import { monitorValidation } from "../../../Validation/validation";
import { parseDomainName } from "../../../Utils/monitorUtils";
import { useTranslation } from "react-i18next";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import { useTheme } from "@emotion/react";
import { createToast } from "../../../Utils/toastUtils";
import { useCreateMonitor } from "../../../Hooks/monitorHooks";
const MS_PER_MINUTE = 60000;
const CRUMBS = [
@@ -56,13 +53,11 @@ const CreatePageSpeed = () => {
const [https, setHttps] = useState(true);
const [errors, setErrors] = useState({});
const { user } = useSelector((state) => state.auth);
const { isLoading } = useSelector((state) => state.pageSpeedMonitors);
const [notifications, notificationsAreLoading, error] = useGetNotificationsByTeamId();
// Setup
const dispatch = useDispatch();
const navigate = useNavigate();
const theme = useTheme();
const [createMonitor, isCreating] = useCreateMonitor();
// Handlers
const onSubmit = async (event) => {
@@ -88,18 +83,6 @@ const CreatePageSpeed = () => {
return;
}
const checkEndpointAction = await dispatch(
checkEndpointResolution({ monitorURL: form.url })
);
if (checkEndpointAction.meta.requestStatus === "rejected") {
createToast({
body: "The endpoint you entered doesn't resolve. Check the URL again.",
});
setErrors({ url: "The entered URL is not reachable." });
return;
}
form = {
...form,
description: form.name,
@@ -108,13 +91,7 @@ const CreatePageSpeed = () => {
notifications: monitor.notifications,
};
const action = await dispatch(createPageSpeed({ monitor: form }));
if (action.meta.requestStatus === "fulfilled") {
createToast({ body: "Monitor created successfully!" });
navigate("/pagespeed");
} else {
createToast({ body: "Failed to create monitor." });
}
await createMonitor({ monitor: form, redirect: "/pagespeed" });
};
const handleChange = (event) => {
@@ -325,7 +302,7 @@ const CreatePageSpeed = () => {
variant="contained"
color="accent"
disabled={!Object.values(errors).every((value) => value === undefined)}
loading={isLoading}
loading={isCreating}
>
{t("createMonitor")}
</Button>

View File

@@ -1,39 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
import { useNavigate } from "react-router-dom";
const useMonitorFetch = ({ monitorId }) => {
const navigate = useNavigate();
const [monitor, setMonitor] = useState(undefined);
const [audits, setAudits] = useState(undefined);
const [isLoading, setIsLoading] = useState(true);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitor = async () => {
try {
const res = await networkService.getStatsByMonitorId({
monitorId: monitorId,
sortOrder: "desc",
limit: 50,
dateRange: "day",
numToDisplay: null,
normalize: null,
});
setMonitor(res?.data?.data ?? undefined);
setAudits(res?.data?.data?.checks?.[0]?.audits ?? undefined);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitor();
}, [monitorId, navigate]);
return { monitor, audits, isLoading };
};
export { useMonitorFetch };

View File

@@ -11,8 +11,7 @@ import GenericFallback from "../../../Components/GenericFallback";
import { useTheme } from "@emotion/react";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { useMonitorFetch } from "./Hooks/useMonitorFetch";
import { useFetchStatsByMonitorId } from "../../../Hooks/monitorHooks";
import { useState } from "react";
import { useTranslation } from "react-i18next";
// Constants
@@ -28,8 +27,13 @@ const PageSpeedDetails = () => {
const isAdmin = useIsAdmin();
const { monitorId } = useParams();
const { monitor, audits, isLoading, networkError } = useMonitorFetch({
const [monitor, audits, isLoading, networkError] = useFetchStatsByMonitorId({
monitorId,
sortOrder: "desc",
limit: 50,
dateRange: "day",
numToDisplay: null,
normalize: null,
});
const [metrics, setMetrics] = useState({

View File

@@ -8,7 +8,7 @@ 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/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import IconBox from "../../../../../Components/IconBox";
@@ -118,7 +118,7 @@ const processData = (data) => {
const PagespeedAreaChart = ({ data, status }) => {
const theme = useTheme();
const [isHovered, setIsHovered] = useState(false);
const { statusToTheme } = useUtils();
const { statusToTheme } = useMonitorUtils();
const themeColor = statusToTheme[status];
@@ -206,7 +206,7 @@ PagespeedAreaChart.propTypes = {
* @returns {JSX.Element} - The rendered card.
*/
const Card = ({ monitor }) => {
const { determineState, pagespeedStatusMsg } = useUtils();
const { determineState, pagespeedStatusMsg } = useMonitorUtils();
const theme = useTheme();
const { t } = useTranslation();
const navigate = useNavigate();
@@ -275,7 +275,7 @@ const Card = ({ monitor }) => {
sx={{ gridColumnStart: 1, gridColumnEnd: 4 }}
>
<PagespeedAreaChart
data={monitor.checks.slice().reverse()}
data={monitor?.checks?.slice().reverse()}
status={monitorState}
/>
</Box>

View File

@@ -1,44 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
const useMonitorsFetch = ({ teamId }) => {
const [isLoading, setIsLoading] = useState(true);
const [monitors, setMonitors] = useState([]);
const [summary, setSummary] = useState({});
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsByTeamId({
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) {
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [teamId]);
return { isLoading, monitors, summary, networkError };
};
export default useMonitorsFetch;

View File

@@ -5,17 +5,17 @@ import CreateMonitorHeader from "../../../Components/MonitorCreateHeader";
import MonitorCountHeader from "../../../Components/MonitorCountHeader";
import MonitorGrid from "./Components/MonitorGrid";
import Fallback from "../../../Components/Fallback";
import GenericFallback from "../../../Components/GenericFallback";
// Utils
import { useTheme } from "@emotion/react";
import { useSelector } from "react-redux";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import useMonitorsFetch from "./Hooks/useMonitorsFetch";
import GenericFallback from "../../../Components/GenericFallback";
import { useTranslation } from "react-i18next";
import { useFetchMonitorsByTeamId } from "../../../Hooks/monitorHooks";
// Constants
const BREADCRUMBS = [{ name: `pagespeed`, path: "/pagespeed" }];
const TYPES = ["pagespeed"];
const PageSpeed = () => {
const theme = useTheme();
const { t } = useTranslation();
@@ -23,8 +23,15 @@ const PageSpeed = () => {
const { user } = useSelector((state) => state.auth);
const { pagespeedApiKey } = useSelector((state) => state.settings);
const { isLoading, monitors, summary, networkError } = useMonitorsFetch({
const [monitors, monitorsSummary, isLoading, networkError] = useFetchMonitorsByTeamId({
teamId: user.teamId,
limit: 10,
types: TYPES,
page: null,
rowsPerPage: null,
filter: null,
field: null,
order: null,
});
if (networkError === true) {
@@ -68,7 +75,7 @@ const PageSpeed = () => {
/>
<MonitorCountHeader
shouldRender={!isLoading}
monitorCount={summary?.totalMonitors}
monitorCount={monitorsSummary?.totalMonitors}
sx={{ mb: theme.spacing(8) }}
/>
<MonitorGrid

View File

@@ -6,14 +6,14 @@ import { StatusLabel } from "../../../../../Components/Label";
//Utils
import { useTheme } from "@mui/material/styles";
import useUtils from "../../../../Uptime/Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
import PropTypes from "prop-types";
import { useSelector } from "react-redux";
const MonitorsList = ({ isLoading = false, shouldRender = true, monitors = [] }) => {
const theme = useTheme();
const { determineState } = useUtils();
const { determineState } = useMonitorUtils();
const { showURL } = useSelector((state) => state.ui);

View File

@@ -1,37 +1,37 @@
import { useNavigate, useParams } from "react-router";
import { useTheme } from "@emotion/react";
import { useDispatch, useSelector } from "react-redux";
import { useState, useEffect } from "react";
import {
Box,
Stack,
Tooltip,
Typography,
Button,
FormControlLabel,
Switch,
} from "@mui/material";
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import { useTranslation } from "react-i18next";
// Components
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import ConfigBox from "../../../Components/ConfigBox";
import {
updateUptimeMonitor,
deleteUptimeMonitor,
} from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import TextInput from "../../../Components/Inputs/TextInput";
import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
import Select from "../../../Components/Inputs/Select";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import PulseDot from "../../../Components/Animated/PulseDot";
import "./index.css";
import Dialog from "../../../Components/Dialog";
import { usePauseMonitor } from "../../../Hooks/useMonitorControls";
import PulseDot from "../../../Components/Animated/PulseDot";
import Checkbox from "../../../Components/Inputs/Checkbox";
// Utils
import { useParams } from "react-router";
import { useTheme } from "@emotion/react";
import { useState } from "react";
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import { useTranslation } from "react-i18next";
import PauseOutlinedIcon from "@mui/icons-material/PauseOutlined";
import PlayArrowOutlinedIcon from "@mui/icons-material/PlayArrowOutlined";
import { useMonitorUtils } from "../../../Hooks/useMonitorUtils";
import { useFetchUptimeMonitorById } from "../../../Hooks/useFetchUptimeMonitorById";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import {
useDeleteMonitor,
useUpdateMonitor,
usePauseMonitor,
useFetchMonitorById,
} from "../../../Hooks/monitorHooks";
import NotificationsConfig from "../../../Components/NotificationConfig";
/**
@@ -76,18 +76,19 @@ const Configure = () => {
};
// Network
const [monitor, isLoading, error] = useFetchUptimeMonitorById(monitorId, updateTrigger);
const [notifications, notificationsAreLoading, notificationsError] =
useGetNotificationsByTeamId();
const [pauseMonitor, isPausing, pauseError] = usePauseMonitor({
monitorId: monitor?._id,
triggerUpdate,
const [pauseMonitor, isPausing, pauseError] = usePauseMonitor({});
const [deleteMonitor, isDeleting] = useDeleteMonitor();
const [updateMonitor, isUpdating] = useUpdateMonitor();
const [isLoading] = useFetchMonitorById({
monitorId,
setMonitor: setForm,
updateTrigger,
});
const MS_PER_MINUTE = 60000;
const navigate = useNavigate();
const theme = useTheme();
const dispatch = useDispatch();
const matchMethodOptions = [
{ _id: "equal", name: "Equal" },
@@ -111,7 +112,7 @@ const Configure = () => {
// Handlers
const handlePause = async () => {
const res = await pauseMonitor();
const res = await pauseMonitor({ monitorId: form?._id, triggerUpdate });
if (typeof res !== "undefined") {
triggerUpdate();
}
@@ -119,12 +120,7 @@ const Configure = () => {
const handleRemove = async (event) => {
event.preventDefault();
const action = await dispatch(deleteUptimeMonitor({ monitor }));
if (action.meta.requestStatus === "fulfilled") {
navigate("/uptime");
} else {
createToast({ body: "Failed to delete monitor." });
}
await deleteMonitor({ monitor: form, redirect: "/uptime" });
};
const onChange = (event) => {
@@ -134,6 +130,17 @@ const Configure = () => {
value = checked;
}
if (name === "useAdvancedMatching") {
setForm((prevForm) => {
return {
...prevForm,
matchMethod: "equal",
};
});
setUseAdvancedMatching(!useAdvancedMatching);
return;
}
if (name === "interval") {
value = value * MS_PER_MINUTE;
}
@@ -146,7 +153,6 @@ const Configure = () => {
setErrors((prev) => {
const updatedErrors = { ...prev };
if (validation.error) updatedErrors[name] = validation.error.details[0].message;
else delete updatedErrors[name];
return updatedErrors;
@@ -183,7 +189,7 @@ const Configure = () => {
if (validation.error) {
const newErrors = {};
error.details.forEach((err) => {
validation.error.details.forEach((err) => {
newErrors[err.path[0]] = err.message;
});
setErrors(newErrors);
@@ -192,27 +198,12 @@ const Configure = () => {
}
toSubmit.notifications = form.notifications;
const action = await dispatch(updateUptimeMonitor({ monitor: toSubmit }));
if (action.meta.requestStatus === "fulfilled") {
createToast({ body: "Monitor updated successfully!" });
} else {
createToast({ body: "Failed to update monitor." });
}
console.log(JSON.stringify(toSubmit, null, 2));
// await updateMonitor({ monitor: toSubmit, redirect: "/uptime" });
};
// Effects
useEffect(() => {
if (monitor?.matchMethod) {
setUseAdvancedMatching(true);
}
setForm({
...monitor,
});
}, [monitor, notifications]);
// Parse the URL
const parsedUrl = parseUrl(monitor?.url);
const parsedUrl = parseUrl(form?.url);
const protocol = parsedUrl?.protocol?.replace(":", "") || "";
const { determineState, statusColor } = useMonitorUtils();
@@ -434,7 +425,13 @@ const Configure = () => {
onChange={onChange}
items={frequencies}
/>
{form.type === "http" && (
<Checkbox
name="useAdvancedMatching"
label={t("advancedMatching")}
isChecked={useAdvancedMatching}
onChange={onChange}
/>
{form.type === "http" && useAdvancedMatching && (
<>
<Select
name="matchMethod"
@@ -502,6 +499,7 @@ const Configure = () => {
mt="auto"
>
<Button
disabled={isDeleting || isUpdating}
type="submit"
variant="contained"
color="accent"

View File

@@ -1,34 +1,34 @@
// React, Redux, Router
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
// Utility and Network
import { monitorValidation } from "../../../Validation/validation";
import { createUptimeMonitor } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
// MUI
import { Box, Stack, Typography, Button, ButtonGroup } from "@mui/material";
import Switch from "@mui/material/Switch";
import FormControlLabel from "@mui/material/FormControlLabel";
//Components
import Breadcrumbs from "../../../Components/Breadcrumbs";
import TextInput from "../../../Components/Inputs/TextInput";
import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
import { createToast } from "../../../Utils/toastUtils";
import Radio from "../../../Components/Inputs/Radio";
import Select from "../../../Components/Inputs/Select";
import ConfigBox from "../../../Components/ConfigBox";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import NotificationsConfig from "../../../Components/NotificationConfig";
import Button from "@mui/material/Button";
import ButtonGroup from "@mui/material/ButtonGroup";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Switch from "@mui/material/Switch";
import FormControlLabel from "@mui/material/FormControlLabel";
// Utils
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import { useState } from "react";
import { useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
import { useCreateMonitor } from "../../../Hooks/monitorHooks";
const CreateMonitor = () => {
// Redux state
const { user } = useSelector((state) => state.auth);
const { isLoading } = useSelector((state) => state.uptimeMonitors);
const dispatch = useDispatch();
// Local state
const [errors, setErrors] = useState({});
@@ -49,6 +49,7 @@ const CreateMonitor = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const [notifications, notificationsAreLoading, error] = useGetNotificationsByTeamId();
const [createMonitor, isCreating] = useCreateMonitor();
const MS_PER_MINUTE = 60000;
const SELECT_VALUES = [
@@ -147,13 +148,7 @@ const CreateMonitor = () => {
notifications: monitor.notifications,
};
const action = await dispatch(createUptimeMonitor({ monitor: form }));
if (action.meta.requestStatus === "fulfilled") {
createToast({ body: "Monitor created successfully!" });
navigate("/uptime");
} else {
createToast({ body: "Failed to create monitor." });
}
await createMonitor({ monitor: form, redirect: "/uptime" });
};
const onChange = (event) => {
@@ -472,7 +467,7 @@ const CreateMonitor = () => {
variant="contained"
color="accent"
disabled={!Object.values(errors).every((value) => value === undefined)}
loading={isLoading}
loading={isLoading || isCreating}
>
{t("createMonitor")}
</Button>

View File

@@ -5,7 +5,7 @@ import PropTypes from "prop-types";
import { getHumanReadableDuration } from "../../../../../Utils/timeUtils";
import { useTheme } from "@mui/material/styles";
import { Typography } from "@mui/material";
import useUtils from "../../../Monitors/Hooks/useUtils";
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
const UptimeStatusBoxes = ({
isLoading = false,
@@ -14,7 +14,7 @@ const UptimeStatusBoxes = ({
certificateExpiry,
}) => {
const theme = useTheme();
const { determineState } = useUtils();
const { determineState } = useMonitorUtils();
// Determine time since last failure
const timeOfLastFailure = monitorStats?.timeOfLastFailure;

View File

@@ -1,50 +0,0 @@
import { useState } from "react";
import { useEffect } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
export const useChecksFetch = ({
monitorId,
monitorType,
dateRange,
page,
rowsPerPage,
}) => {
const [checks, setChecks] = useState(undefined);
const [checksCount, setChecksCount] = useState(undefined);
const [isLoading, setIsLoading] = useState(false);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
if (!monitorType) {
return;
}
const fetchChecks = async () => {
try {
setIsLoading(true);
const res = await networkService.getChecksByMonitor({
monitorId: monitorId,
type: monitorType,
sortOrder: "desc",
limit: null,
dateRange: dateRange,
filter: null,
page: page,
rowsPerPage: rowsPerPage,
});
setChecks(res.data.data.checks);
setChecksCount(res.data.data.checksCount);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchChecks();
}, [monitorId, monitorType, dateRange, page, rowsPerPage]);
return [checks, checksCount, isLoading, networkError];
};
export default useChecksFetch;

View File

@@ -1,33 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../../../../main";
import { useNavigate } from "react-router-dom";
import { createToast } from "../../../../Utils/toastUtils";
export const useMonitorFetch = ({ monitorId, dateRange }) => {
const [networkError, setNetworkError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [monitor, setMonitor] = useState(undefined);
const navigate = useNavigate();
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getUptimeDetailsById({
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
setMonitor(res?.data?.data ?? {});
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [dateRange, monitorId, navigate]);
return [monitor, isLoading, networkError];
};
export default useMonitorFetch;

View File

@@ -1,15 +1,14 @@
// Components
import Breadcrumbs from "../../../Components/Breadcrumbs";
import MonitorDetailsControlHeader from "../../../Components/MonitorDetailsControlHeader";
import MonitorStatusHeader from "../../../Components/MonitorStatusHeader";
import MonitorTimeFrameHeader from "../../../Components/MonitorTimeFrameHeader";
import ChartBoxes from "./Components/ChartBoxes";
import ResponseTimeChart from "./Components/Charts/ResponseTimeChart";
import ResponseTable from "./Components/ResponseTable";
import UptimeStatusBoxes from "./Components/UptimeStatusBoxes";
import GenericFallback from "../../../Components/GenericFallback";
// MUI Components
import { Stack, Typography } from "@mui/material";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
// Utils
import { useState } from "react";
@@ -17,9 +16,9 @@ import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { useTheme } from "@emotion/react";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import useFetchUptimeMonitorDetails from "../../../Hooks/useFetchUptimeMonitorDetails";
import { useFetchUptimeMonitorById } from "../../../Hooks/monitorHooks";
import useCertificateFetch from "./Hooks/useCertificateFetch";
import useChecksFetch from "./Hooks/useChecksFetch";
import { useFetchChecks } from "../../../Hooks/checkHooks";
import { useTranslation } from "react-i18next";
// Constants
@@ -50,7 +49,7 @@ const UptimeDetails = () => {
const { t } = useTranslation();
const [monitorData, monitorStats, monitorIsLoading, monitorNetworkError] =
useFetchUptimeMonitorDetails({
useFetchUptimeMonitorById({
monitorId,
dateRange,
trigger,
@@ -66,10 +65,14 @@ const UptimeDetails = () => {
});
const monitorType = monitor?.type;
const [checks, checksCount, checksAreLoading, checksNetworkError] = useChecksFetch({
const [checks, checksCount, checksAreLoading, checksNetworkError] = useFetchChecks({
monitorId,
monitorType,
type: monitorType,
sortOrder: "desc",
limit: null,
dateRange,
filter: null,
page,
rowsPerPage,
});

View File

@@ -13,7 +13,7 @@ import TableSkeleton from "../../../../../Components/Table/skeleton";
// Utils
import { useTheme } from "@emotion/react";
import useUtils from "../../Hooks/useUtils";
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
import { useNavigate } from "react-router-dom";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
@@ -58,7 +58,7 @@ const UptimeDataTable = ({
}) => {
// Utils
const navigate = useNavigate();
const { determineState } = useUtils();
const { determineState } = useMonitorUtils();
const theme = useTheme();
const { t } = useTranslation();

View File

@@ -1,77 +0,0 @@
import { useEffect, useState } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
import { useTheme } from "@emotion/react";
import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
export const useMonitorFetch = ({
teamId,
limit,
page,
rowsPerPage,
filter,
field,
order,
triggerUpdate,
}) => {
const [monitorsAreLoading, setMonitorsAreLoading] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [filteredMonitors, setFilteredMonitors] = useState(undefined);
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
const theme = useTheme();
const { getMonitorWithPercentage } = useMonitorUtils();
useEffect(() => {
const fetchMonitors = async () => {
try {
setMonitorsAreLoading(true);
const res = await networkService.getMonitorsByTeamId({
teamId,
limit,
types: ["http", "ping", "docker", "port"],
page,
rowsPerPage,
filter,
field,
order,
});
const { monitors, filteredMonitors, summary } = res.data.data;
const mappedMonitors = filteredMonitors.map((monitor) =>
getMonitorWithPercentage(monitor, theme)
);
setMonitors(monitors);
setFilteredMonitors(mappedMonitors);
setMonitorsSummary(summary);
} catch (error) {
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setMonitorsAreLoading(false);
}
};
fetchMonitors();
}, [
teamId,
limit,
field,
filter,
order,
page,
rowsPerPage,
theme,
triggerUpdate,
getMonitorWithPercentage,
]);
return {
monitors,
filteredMonitors,
monitorsSummary,
monitorsAreLoading,
networkError,
};
};
export default useMonitorFetch;

View File

@@ -1,110 +0,0 @@
import { useTheme } from "@mui/material";
const useUtils = () => {
const determineState = (monitor) => {
if (typeof monitor === "undefined") return "pending";
if (monitor.isActive === false) return "paused";
if (monitor?.status === undefined) return "pending";
return monitor?.status == true ? "up" : "down";
};
/* TODO Refactor: from here on shouldn't live in a custom hook, but on theme, or constants */
const theme = useTheme();
const statusColor = {
up: theme.palette.success.lowContrast,
down: theme.palette.error.lowContrast,
paused: theme.palette.warning.lowContrast,
pending: theme.palette.warning.lowContrast,
};
const statusMsg = {
up: "Your site is up.",
down: "Your site is down.",
paused: "Pending...",
};
const pagespeedStatusMsg = {
up: "Live (collecting data)",
down: "Inactive",
paused: "Paused",
};
/*
TODO
This is used on
1) Details > Gradient card */
/* These are rediections. We should do something that maps up to success, down to error, and get the theme by that
See Client\src\Components\Label\index.jsx
*/
const statusToTheme = {
up: "success",
down: "error",
paused: "warning",
pending: "secondary",
"cannot resolve": "tertiary",
};
const getStatusStyles = (status) => {
const themeColor = statusToTheme[status];
return {
backgroundColor: theme.palette[themeColor].lowContrast,
background: `linear-gradient(340deg, ${theme.palette[themeColor].main} -60%, ${theme.palette[themeColor].lowContrast} 35%)`,
borderColor: theme.palette[themeColor].lowContrast,
"& h2": {
color: theme.palette[themeColor].contrastText,
textTransform: "uppercase",
},
"& p": {
color: theme.palette[themeColor].contrastText,
},
};
};
const statusStyles = {
up: {
backgroundColor: theme.palette.success.lowContrast,
background: `linear-gradient(340deg, ${theme.palette.tertiary.main} -60%, ${theme.palette.success.lowContrast} 35%)`, // CAIO_REVIEW
borderColor: theme.palette.success.contrastText,
// "& h2": { color: theme.palette.success.contrastText }, // CAIO_REVIEW
},
down: {
backgroundColor: theme.palette.error.lowContrast,
background: `linear-gradient(340deg, ${theme.palette.tertiary.main} -60%, ${theme.palette.error.lowContrast} 35%)`, // CAIO_REVIEW
borderColor: theme.palette.error.contrastText,
"& h2": { color: theme.palette.error.contrastText }, // CAIO_REVIEW
"& .MuiTypography-root": { color: theme.palette.error.contrastText }, // CAIO_REVIEW
},
paused: {
backgroundColor: theme.palette.warning.lowContrast,
background: `linear-gradient(340deg, ${theme.palette.tertiary.main} -60%, ${theme.palette.warning.lowContrast} 35%)`, // CAIO_REVIEW
borderColor: theme.palette.warning.contrastText,
"& h2": { color: theme.palette.warning.contrastText }, // CAIO_REVIEW
"& .MuiTypography-root": { color: theme.palette.warning.contrastText }, // CAIO_REVIEW
},
pending: {
backgroundColor: theme.palette.warning.lowContrast,
background: `linear-gradient(340deg, ${theme.palette.tertiary.main} -60%, ${theme.palette.warning.lowContrast} 35%)`, // CAIO_REVIEW
borderColor: theme.palette.warning.contrastText,
"& h2": { color: theme.palette.warning.contrastText }, // CAIO_REVIEW
},
};
/* These are rediections. We should do something that maps up to success, down to error, and get the theme by that
*/
return {
determineState,
statusColor,
statusMsg,
pagespeedStatusMsg,
statusStyles,
statusToTheme,
getStatusStyles,
};
};
export default useUtils;

View File

@@ -28,9 +28,12 @@ import { useNavigate } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { setRowsPerPage } from "../../../Features/UI/uiSlice";
import PropTypes from "prop-types";
import useFetchMonitorsWithSummary from "../../../Hooks/useFetchMonitorsWithSummary";
import useFetchMonitorsWithChecks from "../../../Hooks/useFetchMonitorsWithChecks";
import {
useFetchMonitorsWithSummary,
useFetchMonitorsWithChecks,
} from "../../../Hooks/monitorHooks";
import { useTranslation } from "react-i18next";
const TYPES = ["http", "ping", "docker", "port"];
const CreateMonitorButton = ({ shouldRender }) => {
// Utils
@@ -78,7 +81,6 @@ const UptimeMonitors = () => {
// Utils
const theme = useTheme();
const navigate = useNavigate();
const isAdmin = useIsAdmin();
const dispatch = useDispatch();
const { t } = useTranslation();

View File

@@ -587,7 +587,7 @@ class NetworkService {
*
*/
async getChecksByMonitor(config) {
getChecksByMonitor = async (config) => {
const params = new URLSearchParams();
if (config.type) params.append("type", config.type);
if (config.sortOrder) params.append("sortOrder", config.sortOrder);
@@ -599,7 +599,7 @@ class NetworkService {
if (config.status !== undefined) params.append("status", config.status);
return this.axiosInstance.get(`/checks/${config.monitorId}?${params.toString()}`);
}
};
/**
* ************************************
@@ -618,7 +618,7 @@ class NetworkService {
* @returns {Promise<AxiosResponse>} The response from the axios GET request.
*
*/
async getChecksByTeam(config) {
getChecksByTeam = async (config) => {
const params = new URLSearchParams();
if (config.sortOrder) params.append("sortOrder", config.sortOrder);
if (config.limit) params.append("limit", config.limit);
@@ -628,7 +628,7 @@ class NetworkService {
if (config.rowsPerPage) params.append("rowsPerPage", config.rowsPerPage);
if (config.status !== undefined) params.append("status", config.status);
return this.axiosInstance.get(`/checks/team/${config.teamId}?${params.toString()}`);
}
};
/**
* ************************************

View File

@@ -525,6 +525,7 @@
"notifyEmails": "Also notify via email to multiple addresses (coming soon)",
"seperateEmails": "You can separate multiple emails with a comma",
"checkFrequency": "Check frequency",
"advancedMatching": "Advanced matching",
"matchMethod": "Match Method",
"expectedValue": "Expected value",
"deleteDialogTitle": "Do you really want to delete this monitor?",