mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-21 00:59:44 -06:00
Merge branch 'develop' into feat/search-infra-moniters
This commit is contained in:
@@ -10,6 +10,7 @@ import { logger } from "./Utils/Logger"; // Import the logger
|
||||
import { networkService } from "./main";
|
||||
import { Routes } from "./Routes";
|
||||
import WalletProvider from "./Components/WalletProvider";
|
||||
import AppLayout from "./Components/Layouts/AppLayout";
|
||||
|
||||
function App() {
|
||||
const mode = useSelector((state) => state.ui.mode);
|
||||
@@ -27,17 +28,10 @@ function App() {
|
||||
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
|
||||
<WalletProvider>
|
||||
<CssBaseline />
|
||||
<GlobalStyles
|
||||
styles={({ palette }) => {
|
||||
return {
|
||||
body: {
|
||||
backgroundImage: `radial-gradient(circle, ${palette.gradient.color1}, ${palette.gradient.color2}, ${palette.gradient.color3}, ${palette.gradient.color4}, ${palette.gradient.color5})`,
|
||||
color: palette.primary.contrastText,
|
||||
},
|
||||
};
|
||||
}}
|
||||
/>
|
||||
<Routes />
|
||||
|
||||
<AppLayout>
|
||||
<Routes />
|
||||
</AppLayout>
|
||||
<ToastContainer />
|
||||
</WalletProvider>
|
||||
</ThemeProvider>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
// Components
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import Settings from "../../assets/icons/settings-bold.svg?react";
|
||||
import Dialog from "../../Components/Dialog";
|
||||
|
||||
// Utils
|
||||
import { useState } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createToast } from "../../Utils/toastUtils";
|
||||
import { logger } from "../../Utils/Logger";
|
||||
import { IconButton, Menu, MenuItem } from "@mui/material";
|
||||
import {
|
||||
deleteUptimeMonitor,
|
||||
pauseUptimeMonitor,
|
||||
} from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import Settings from "../../assets/icons/settings-bold.svg?react";
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
import Dialog from "../../Components/Dialog";
|
||||
import { usePauseMonitor, useDeleteMonitor } from "../../Hooks/monitorHooks";
|
||||
|
||||
const ActionsMenu = ({
|
||||
monitor,
|
||||
@@ -23,38 +24,27 @@ const ActionsMenu = ({
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const [actions, setActions] = useState({});
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const theme = useTheme();
|
||||
const { isLoading } = useSelector((state) => state.uptimeMonitors);
|
||||
const [pauseMonitor, isPausing, error] = usePauseMonitor();
|
||||
const [deleteMonitor, isDeleting] = useDeleteMonitor();
|
||||
|
||||
const handleRemove = async (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let monitor = { _id: actions.id };
|
||||
const action = await dispatch(deleteUptimeMonitor({ monitor }));
|
||||
if (action.meta.requestStatus === "fulfilled") {
|
||||
setIsOpen(false); // close modal
|
||||
updateRowCallback();
|
||||
createToast({ body: "Monitor deleted successfully." });
|
||||
} else {
|
||||
createToast({ body: "Failed to delete monitor." });
|
||||
}
|
||||
await deleteMonitor({ monitor });
|
||||
updateRowCallback();
|
||||
};
|
||||
|
||||
const handlePause = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const action = await dispatch(pauseUptimeMonitor({ monitorId: monitor._id }));
|
||||
if (pauseUptimeMonitor.fulfilled.match(action)) {
|
||||
const state = action?.payload?.data.isActive === false ? "resumed" : "paused";
|
||||
createToast({ body: `Monitor ${state} successfully.` });
|
||||
pauseCallback();
|
||||
} else {
|
||||
throw new Error(action?.error?.message ?? "Failed to pause monitor.");
|
||||
}
|
||||
await pauseMonitor({ monitorId: monitor._id });
|
||||
pauseCallback();
|
||||
} catch (error) {
|
||||
logger.error("Error pausing monitor:", monitor._id, error);
|
||||
createToast({ body: "Failed to pause monitor." });
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -210,7 +200,7 @@ const ActionsMenu = ({
|
||||
e.stopPropagation();
|
||||
handleRemove(e);
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
isLoading={isDeleting}
|
||||
modelTitle="modal-delete-monitor"
|
||||
modelDescription="delete-monitor-confirmation"
|
||||
/>
|
||||
|
||||
@@ -57,7 +57,7 @@ Dialog.propTypes = {
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
confirmationButtonLabel: PropTypes.string.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
isLoading: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Dialog;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useSelector } from "react-redux";
|
||||
import Alert from "../Alert";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import "./index.css";
|
||||
import { useFetchSettings } from "../../Hooks/useFetchSettings";
|
||||
import { useFetchSettings } from "../../Hooks/settingsHooks";
|
||||
import { useState } from "react";
|
||||
/**
|
||||
* Fallback component to display a fallback UI with a title, a list of checks, and a navigation button.
|
||||
|
||||
@@ -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"]),
|
||||
|
||||
@@ -102,27 +102,7 @@ const Search = ({
|
||||
...(endAdornment && { endAdornment: endAdornment }),
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
"& fieldset": {
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
"& .MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus)) fieldset":
|
||||
{
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
paddingY: 0,
|
||||
},
|
||||
"& .MuiAutocomplete-tag": {
|
||||
// CAIO_REVIEW
|
||||
color: theme.palette.primary.contrastText,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"& .MuiChip-deleteIcon": {
|
||||
color: theme.palette.primary.contrastText, // CAIO_REVIEW
|
||||
},
|
||||
}}
|
||||
sx={{}}
|
||||
/>
|
||||
{error && (
|
||||
<Typography
|
||||
|
||||
30
client/src/Components/Layouts/AppLayout/index.jsx
Normal file
30
client/src/Components/Layouts/AppLayout/index.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import BackgroundSVG from "../../../assets/Images/background.svg";
|
||||
|
||||
const AppLayout = ({ children }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: "100vh",
|
||||
backgroundColor: theme.palette.primaryBackground.main,
|
||||
backgroundImage: `url("${BackgroundSVG}")`,
|
||||
backgroundSize: "100% 100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
color: theme.palette.primary.contrastText,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
AppLayout.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default AppLayout;
|
||||
@@ -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"}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 />;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { clearAuthState } from "../../Features/Auth/authSlice";
|
||||
import { toggleSidebar } from "../../Features/UI/uiSlice";
|
||||
import { clearUptimeMonitorState } from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
|
||||
const getMenu = (t) => [
|
||||
{ name: t("menu.uptime"), path: "uptime", icon: <Monitors /> },
|
||||
@@ -197,7 +196,6 @@ function Sidebar() {
|
||||
const logout = async () => {
|
||||
// Clear auth state
|
||||
dispatch(clearAuthState());
|
||||
dispatch(clearUptimeMonitorState());
|
||||
navigate("/login");
|
||||
};
|
||||
|
||||
@@ -231,7 +229,6 @@ function Sidebar() {
|
||||
borderRight: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: 0,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
"& :is(p, span, .MuiListSubheader-root)": {
|
||||
/*
|
||||
Text color for unselected menu items and menu headings
|
||||
|
||||
@@ -33,7 +33,6 @@ const StarPrompt = ({ repoUrl = "https://github.com/bluewave-labs/checkmate" })
|
||||
borderBottom: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
borderRadius: 0,
|
||||
gap: theme.spacing(1.5),
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
|
||||
@@ -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
|
||||
@@ -136,8 +136,8 @@ const StatBox = ({
|
||||
};
|
||||
|
||||
StatBox.propTypes = {
|
||||
heading: PropTypes.string.isRequired,
|
||||
subHeading: PropTypes.node.isRequired,
|
||||
heading: PropTypes.string,
|
||||
subHeading: PropTypes.node,
|
||||
gradient: PropTypes.bool,
|
||||
status: PropTypes.string,
|
||||
sx: PropTypes.object,
|
||||
|
||||
@@ -8,7 +8,6 @@ import ImageUpload from "../../Inputs/ImageUpload";
|
||||
import { newOrChangedCredentials } from "../../../Validation/validation";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { clearAuthState, deleteUser, update } from "../../../Features/Auth/authSlice";
|
||||
import { clearUptimeMonitorState } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import { createToast } from "../../../Utils/toastUtils";
|
||||
import { logger } from "../../../Utils/Logger";
|
||||
import { GenericDialog } from "../../Dialog/genericDialog";
|
||||
@@ -162,7 +161,6 @@ const ProfilePanel = () => {
|
||||
const action = await dispatch(deleteUser());
|
||||
if (action.payload.success) {
|
||||
dispatch(clearAuthState());
|
||||
dispatch(clearUptimeMonitorState());
|
||||
} else {
|
||||
if (action.payload) {
|
||||
// dispatch errors
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||
import { networkService } from "../../main";
|
||||
const initialState = {
|
||||
isLoading: false,
|
||||
monitorsSummary: [],
|
||||
success: null,
|
||||
msg: null,
|
||||
};
|
||||
|
||||
export const createInfrastructureMonitor = createAsyncThunk(
|
||||
"infrastructureMonitors/createMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const res = await networkService.createMonitor({ monitor: monitor });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const checkInfrastructureEndpointResolution = createAsyncThunk(
|
||||
"infrastructureMonitors/CheckEndpoint",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorURL } = data;
|
||||
const res = await networkService.checkEndpointResolution({
|
||||
monitorURL: monitorURL,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const getInfrastructureMonitorById = createAsyncThunk(
|
||||
"infrastructureMonitors/getMonitorById",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorId } = data;
|
||||
const res = await networkService.getMonitorById({ monitorId: monitorId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const getInfrastructureMonitorsByTeamId = createAsyncThunk(
|
||||
"infrastructureMonitors/getMonitorsByTeamId",
|
||||
async (_, thunkApi) => {
|
||||
const user = thunkApi.getState().auth.user;
|
||||
try {
|
||||
const res = await networkService.getMonitorsAndSummaryByTeamId({
|
||||
teamId: user.teamId,
|
||||
types: ["hardware"],
|
||||
limit: 1,
|
||||
rowsPerPage: 0,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const updateInfrastructureMonitor = createAsyncThunk(
|
||||
"infrastructureMonitors/updateMonitor",
|
||||
async ({ monitorId, monitor }, thunkApi) => {
|
||||
try {
|
||||
const updatedFields = {
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
interval: monitor.interval,
|
||||
notifications: monitor.notifications,
|
||||
thresholds: monitor.thresholds,
|
||||
secret: monitor.secret,
|
||||
};
|
||||
const res = await networkService.updateMonitor({
|
||||
monitorId,
|
||||
monitor,
|
||||
updatedFields,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteInfrastructureMonitor = createAsyncThunk(
|
||||
"infrastructureMonitors/deleteMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const res = await networkService.deleteMonitorById({ monitorId: monitor._id });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const pauseInfrastructureMonitor = createAsyncThunk(
|
||||
"infrastructureMonitors/pauseMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorId } = data;
|
||||
const res = await networkService.pauseMonitorById({ monitorId: monitorId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteInfrastructureMonitorChecksByTeamId = createAsyncThunk(
|
||||
"infrastructureMonitors/deleteChecksByTeamId",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { teamId } = data;
|
||||
const res = await networkService.deleteChecksByTeamId({ teamId: teamId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteAllInfrastructureMonitors = createAsyncThunk(
|
||||
"infrastructureMonitors/deleteAllMonitors",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const res = await networkService.deleteAllMonitors();
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const infrastructureMonitorsSlice = createSlice({
|
||||
name: "infrastructureMonitors",
|
||||
initialState,
|
||||
reducers: {
|
||||
clearInfrastructureMonitorState: (state) => {
|
||||
state.isLoading = false;
|
||||
state.monitorsSummary = [];
|
||||
state.success = null;
|
||||
state.msg = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
// *****************************************************
|
||||
// Monitors by teamId
|
||||
// *****************************************************
|
||||
|
||||
.addCase(getInfrastructureMonitorsByTeamId.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(getInfrastructureMonitorsByTeamId.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.msg;
|
||||
state.monitorsSummary = action.payload.data;
|
||||
})
|
||||
.addCase(getInfrastructureMonitorsByTeamId.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Getting infrastructure monitors failed";
|
||||
})
|
||||
|
||||
// *****************************************************
|
||||
// Create Monitor
|
||||
// *****************************************************
|
||||
.addCase(createInfrastructureMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(createInfrastructureMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(createInfrastructureMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to create infrastructure monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Resolve Endpoint
|
||||
// *****************************************************
|
||||
.addCase(checkInfrastructureEndpointResolution.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(checkInfrastructureEndpointResolution.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(checkInfrastructureEndpointResolution.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to check endpoint resolution";
|
||||
})
|
||||
// *****************************************************
|
||||
// Get Monitor By Id
|
||||
// *****************************************************
|
||||
.addCase(getInfrastructureMonitorById.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(getInfrastructureMonitorById.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(getInfrastructureMonitorById.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to get infrastructure monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// update Monitor
|
||||
// *****************************************************
|
||||
.addCase(updateInfrastructureMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(updateInfrastructureMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(updateInfrastructureMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to update infrastructure monitor";
|
||||
})
|
||||
|
||||
// *****************************************************
|
||||
// Delete Monitor
|
||||
// *****************************************************
|
||||
.addCase(deleteInfrastructureMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deleteInfrastructureMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deleteInfrastructureMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to delete infrastructure monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Delete Monitor checks by Team ID
|
||||
// *****************************************************
|
||||
.addCase(deleteInfrastructureMonitorChecksByTeamId.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deleteInfrastructureMonitorChecksByTeamId.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deleteInfrastructureMonitorChecksByTeamId.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to delete monitor checks";
|
||||
})
|
||||
// *****************************************************
|
||||
// Pause Monitor
|
||||
// *****************************************************
|
||||
.addCase(pauseInfrastructureMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(pauseInfrastructureMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(pauseInfrastructureMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to pause infrastructure monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Delete all Monitors
|
||||
// *****************************************************
|
||||
.addCase(deleteAllInfrastructureMonitors.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deleteAllInfrastructureMonitors.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deleteAllInfrastructureMonitors.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload ? action.payload.msg : "Failed to delete all monitors";
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { setInfrastructureMonitors, clearInfrastructureMonitorState } =
|
||||
infrastructureMonitorsSlice.actions;
|
||||
|
||||
export default infrastructureMonitorsSlice.reducer;
|
||||
@@ -1,309 +0,0 @@
|
||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||
import { networkService } from "../../main";
|
||||
const initialState = {
|
||||
isLoading: false,
|
||||
monitorsSummary: [],
|
||||
success: null,
|
||||
msg: null,
|
||||
};
|
||||
|
||||
export const createPageSpeed = createAsyncThunk(
|
||||
"pageSpeedMonitors/createPageSpeed",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const res = await networkService.createMonitor({ monitor: monitor });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const checkEndpointResolution = createAsyncThunk(
|
||||
"monitors/checkEndpoint",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorURL } = data;
|
||||
const res = await networkService.checkEndpointResolution({
|
||||
monitorURL: monitorURL,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const getPagespeedMonitorById = createAsyncThunk(
|
||||
"monitors/getMonitorById",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorId } = data;
|
||||
const res = await networkService.getMonitorById({ monitorId: monitorId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const getPageSpeedByTeamId = createAsyncThunk(
|
||||
"pageSpeedMonitors/getPageSpeedByTeamId",
|
||||
async (_, thunkApi) => {
|
||||
const user = thunkApi.getState().auth.user;
|
||||
try {
|
||||
const res = await networkService.getMonitorsAndSummaryByTeamId({
|
||||
teamId: user.teamId,
|
||||
types: ["pagespeed"],
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const updatePageSpeed = createAsyncThunk(
|
||||
"pageSpeedMonitors/updatePageSpeed",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const updatedFields = {
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
interval: monitor.interval,
|
||||
notifications: monitor.notifications,
|
||||
};
|
||||
const res = await networkService.updateMonitor({
|
||||
monitorId: monitor._id,
|
||||
updatedFields: updatedFields,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deletePageSpeed = createAsyncThunk(
|
||||
"pageSpeedMonitors/deletePageSpeed",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const res = await networkService.deleteMonitorById({ monitorId: monitor._id });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
export const pausePageSpeed = createAsyncThunk(
|
||||
"pageSpeedMonitors/pausePageSpeed",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorId } = data;
|
||||
const res = await networkService.pauseMonitorById({ monitorId: monitorId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const pageSpeedMonitorSlice = createSlice({
|
||||
name: "pageSpeedMonitor",
|
||||
initialState,
|
||||
reducers: {
|
||||
clearMonitorState: (state) => {
|
||||
state.isLoading = false;
|
||||
state.monitorsSummary = [];
|
||||
state.success = null;
|
||||
state.msg = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
// *****************************************************
|
||||
// Monitors by teamId
|
||||
// *****************************************************
|
||||
|
||||
.addCase(getPageSpeedByTeamId.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(getPageSpeedByTeamId.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.msg;
|
||||
state.monitorsSummary = action.payload.data;
|
||||
})
|
||||
.addCase(getPageSpeedByTeamId.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Getting page speed monitors failed";
|
||||
})
|
||||
|
||||
// *****************************************************
|
||||
.addCase(getPagespeedMonitorById.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(getPagespeedMonitorById.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(getPagespeedMonitorById.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to get pagespeed monitor";
|
||||
})
|
||||
|
||||
// *****************************************************
|
||||
// Create Monitor
|
||||
// *****************************************************
|
||||
.addCase(createPageSpeed.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(createPageSpeed.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(createPageSpeed.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to create page speed monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Resolve Endpoint
|
||||
// *****************************************************
|
||||
.addCase(checkEndpointResolution.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(checkEndpointResolution.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(checkEndpointResolution.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to check endpoint resolution";
|
||||
})
|
||||
// *****************************************************
|
||||
// Update Monitor
|
||||
// *****************************************************
|
||||
.addCase(updatePageSpeed.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(updatePageSpeed.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(updatePageSpeed.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to update page speed monitor";
|
||||
})
|
||||
|
||||
// *****************************************************
|
||||
// Delete Monitor
|
||||
// *****************************************************
|
||||
.addCase(deletePageSpeed.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deletePageSpeed.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deletePageSpeed.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to delete page speed monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Pause Monitor
|
||||
// *****************************************************
|
||||
.addCase(pausePageSpeed.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(pausePageSpeed.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(pausePageSpeed.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to pause page speed monitor";
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { setMonitors, clearMonitorState } = pageSpeedMonitorSlice.actions;
|
||||
|
||||
export default pageSpeedMonitorSlice.reducer;
|
||||
@@ -1,100 +0,0 @@
|
||||
import { networkService } from "../../main";
|
||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
const initialState = {
|
||||
isLoading: false,
|
||||
apiBaseUrl: "",
|
||||
logLevel: "debug",
|
||||
pagespeedApiKey: "",
|
||||
};
|
||||
|
||||
export const getAppSettings = createAsyncThunk(
|
||||
"settings/getSettings",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const res = await networkService.getAppSettings();
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const updateAppSettings = createAsyncThunk(
|
||||
"settings/updateSettings",
|
||||
async ({ settings }, thunkApi) => {
|
||||
try {
|
||||
const parsedSettings = {
|
||||
language: settings.language,
|
||||
pagespeedApiKey: settings.pagespeedApiKey,
|
||||
};
|
||||
const res = await networkService.updateAppSettings({ settings: parsedSettings });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleGetSettingsFulfilled = (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
state.apiBaseUrl = action.payload.data.apiBaseUrl;
|
||||
state.logLevel = action.payload.data.logLevel;
|
||||
state.language = action.payload.data.language;
|
||||
state.pagespeedApiKey = action.payload.data.pagespeedApiKey;
|
||||
};
|
||||
const handleGetSettingsRejected = (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload ? action.payload.msg : "Failed to get settings.";
|
||||
};
|
||||
const handleUpdateSettingsFulfilled = (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
state.apiBaseUrl = action.payload.data.apiBaseUrl;
|
||||
state.logLevel = action.payload.data.logLevel;
|
||||
};
|
||||
const handleUpdateSettingsRejected = (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload ? action.payload.msg : "Failed to update settings.";
|
||||
};
|
||||
|
||||
const settingsSlice = createSlice({
|
||||
name: "settings",
|
||||
initialState,
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(getAppSettings.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(getAppSettings.fulfilled, handleGetSettingsFulfilled)
|
||||
.addCase(getAppSettings.rejected, handleGetSettingsRejected);
|
||||
|
||||
builder
|
||||
.addCase(updateAppSettings.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(updateAppSettings.fulfilled, handleUpdateSettingsFulfilled)
|
||||
.addCase(updateAppSettings.rejected, handleUpdateSettingsRejected);
|
||||
},
|
||||
});
|
||||
|
||||
export default settingsSlice.reducer;
|
||||
@@ -1,380 +0,0 @@
|
||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||
import { networkService } from "../../main";
|
||||
const initialState = {
|
||||
isLoading: false,
|
||||
monitorsSummary: [],
|
||||
success: null,
|
||||
msg: null,
|
||||
};
|
||||
|
||||
export const createUptimeMonitor = createAsyncThunk(
|
||||
"monitors/createMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const res = await networkService.createMonitor({ monitor: monitor });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const checkEndpointResolution = createAsyncThunk(
|
||||
"monitors/checkEndpoint",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorURL } = data;
|
||||
const res = await networkService.checkEndpointResolution({
|
||||
monitorURL: monitorURL,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const getUptimeMonitorById = createAsyncThunk(
|
||||
"monitors/getMonitorById",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorId } = data;
|
||||
const res = await networkService.getMonitorById({ monitorId: monitorId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const updateUptimeMonitor = createAsyncThunk(
|
||||
"monitors/updateMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
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 }),
|
||||
};
|
||||
const res = await networkService.updateMonitor({
|
||||
monitorId: monitor._id,
|
||||
updatedFields,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteUptimeMonitor = createAsyncThunk(
|
||||
"monitors/deleteMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitor } = data;
|
||||
const res = await networkService.deleteMonitorById({ monitorId: monitor._id });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const pauseUptimeMonitor = createAsyncThunk(
|
||||
"monitors/pauseMonitor",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { monitorId } = data;
|
||||
const res = await networkService.pauseMonitorById({ monitorId: monitorId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteMonitorChecksByTeamId = createAsyncThunk(
|
||||
"monitors/deleteChecksByTeamId",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const { teamId } = data;
|
||||
const res = await networkService.deleteChecksByTeamId({ teamId: teamId });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
export const addDemoMonitors = createAsyncThunk(
|
||||
"monitors/addDemoMonitors",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const res = await networkService.addDemoMonitors();
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteAllMonitors = createAsyncThunk(
|
||||
"monitors/deleteAllMonitors",
|
||||
async (data, thunkApi) => {
|
||||
try {
|
||||
const res = await networkService.deleteAllMonitors();
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) {
|
||||
return thunkApi.rejectWithValue(error.response.data);
|
||||
}
|
||||
const payload = {
|
||||
status: false,
|
||||
msg: error.message ? error.message : "Unknown error",
|
||||
};
|
||||
return thunkApi.rejectWithValue(payload);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const uptimeMonitorsSlice = createSlice({
|
||||
name: "uptimeMonitors",
|
||||
initialState,
|
||||
reducers: {
|
||||
clearUptimeMonitorState: (state) => {
|
||||
state.isLoading = false;
|
||||
state.monitorsSummary = [];
|
||||
state.success = null;
|
||||
state.msg = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
// *****************************************************
|
||||
// Create Monitor
|
||||
// *****************************************************
|
||||
.addCase(createUptimeMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(createUptimeMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(createUptimeMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to create uptime monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Resolve Endpoint
|
||||
// *****************************************************
|
||||
.addCase(checkEndpointResolution.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(checkEndpointResolution.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(checkEndpointResolution.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to check endpoint resolution";
|
||||
})
|
||||
// *****************************************************
|
||||
// Get Monitor By Id
|
||||
// *****************************************************
|
||||
.addCase(getUptimeMonitorById.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(getUptimeMonitorById.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(getUptimeMonitorById.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload ? action.payload.msg : "Failed to get uptime monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// update Monitor
|
||||
// *****************************************************
|
||||
.addCase(updateUptimeMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(updateUptimeMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(updateUptimeMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to update uptime monitor";
|
||||
})
|
||||
|
||||
// *****************************************************
|
||||
// Delete Monitor
|
||||
// *****************************************************
|
||||
.addCase(deleteUptimeMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deleteUptimeMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deleteUptimeMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to delete uptime monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Delete Monitor checks by Team ID
|
||||
// *****************************************************
|
||||
.addCase(deleteMonitorChecksByTeamId.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deleteMonitorChecksByTeamId.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deleteMonitorChecksByTeamId.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to delete monitor checks";
|
||||
})
|
||||
// *****************************************************
|
||||
// Pause Monitor
|
||||
// *****************************************************
|
||||
.addCase(pauseUptimeMonitor.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(pauseUptimeMonitor.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(pauseUptimeMonitor.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to pause uptime monitor";
|
||||
})
|
||||
// *****************************************************
|
||||
// Add Demo Monitors
|
||||
// *****************************************************
|
||||
.addCase(addDemoMonitors.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(addDemoMonitors.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(addDemoMonitors.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload
|
||||
? action.payload.msg
|
||||
: "Failed to add demo uptime monitors";
|
||||
})
|
||||
// *****************************************************
|
||||
// Delete all Monitors
|
||||
// *****************************************************
|
||||
.addCase(deleteAllMonitors.pending, (state) => {
|
||||
state.isLoading = true;
|
||||
})
|
||||
.addCase(deleteAllMonitors.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
state.msg = action.payload.msg;
|
||||
})
|
||||
.addCase(deleteAllMonitors.rejected, (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = false;
|
||||
state.msg = action.payload ? action.payload.msg : "Failed to delete all monitors";
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { setUptimeMonitors, clearUptimeMonitorState } = uptimeMonitorsSlice.actions;
|
||||
|
||||
export default uptimeMonitorsSlice.reducer;
|
||||
85
client/src/Hooks/checkHooks.js
Normal file
85
client/src/Hooks/checkHooks.js
Normal 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 };
|
||||
471
client/src/Hooks/monitorHooks.js
Normal file
471
client/src/Hooks/monitorHooks.js
Normal file
@@ -0,0 +1,471 @@
|
||||
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";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const useFetchMonitorsWithSummary = ({ 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({
|
||||
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();
|
||||
}, [types, monitorUpdateTrigger]);
|
||||
return [monitors, monitorsSummary, isLoading, networkError];
|
||||
};
|
||||
|
||||
const useFetchMonitorsWithChecks = ({
|
||||
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({
|
||||
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,
|
||||
theme,
|
||||
types,
|
||||
monitorUpdateTrigger,
|
||||
]);
|
||||
return [monitors, count, isLoading, networkError];
|
||||
};
|
||||
|
||||
const useFetchMonitorsByTeamId = ({
|
||||
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({
|
||||
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();
|
||||
}, [
|
||||
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];
|
||||
};
|
||||
|
||||
const useAddDemoMonitors = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const addDemoMonitors = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await networkService.addDemoMonitors();
|
||||
createToast({ body: t("settingsDemoMonitorsAdded") });
|
||||
} catch (error) {
|
||||
createToast({ body: t("settingsFailedToAddDemoMonitors") });
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
return [addDemoMonitors, isLoading];
|
||||
};
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
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]; // [success, data, error]
|
||||
} catch (err) {
|
||||
const errorMessage = err?.response?.data?.msg || err.message;
|
||||
return [false, null, errorMessage];
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return [createBulkMonitors, isLoading];
|
||||
};
|
||||
|
||||
export {
|
||||
useFetchMonitorsWithSummary,
|
||||
useFetchMonitorsWithChecks,
|
||||
useFetchMonitorsByTeamId,
|
||||
useFetchStatsByMonitorId,
|
||||
useFetchMonitorById,
|
||||
useFetchUptimeMonitorById,
|
||||
useFetchHardwareMonitorById,
|
||||
useCreateMonitor,
|
||||
useDeleteMonitor,
|
||||
useUpdateMonitor,
|
||||
usePauseMonitor,
|
||||
useAddDemoMonitors,
|
||||
useDeleteAllMonitors,
|
||||
useDeleteMonitorStats,
|
||||
useCreateBulkMonitors,
|
||||
};
|
||||
@@ -33,12 +33,13 @@ const useSaveSettings = () => {
|
||||
const saveSettings = async (settings) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await networkService.updateAppSettings({ settings });
|
||||
const settingsResponse = await networkService.updateAppSettings({ settings });
|
||||
if (settings.checkTTL) {
|
||||
await networkService.updateChecksTTL({
|
||||
ttl: settings.checkTTL,
|
||||
});
|
||||
}
|
||||
console.log({ settingsResponse });
|
||||
createToast({ body: t("settingsSuccessSaved") });
|
||||
} catch (error) {
|
||||
createToast({ body: t("settingsFailedToSave") });
|
||||
@@ -1,27 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { networkService } from "../main";
|
||||
|
||||
export const useBulkMonitors = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const createBulkMonitors = async (file, user) => {
|
||||
setIsLoading(true);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("csvFile", file);
|
||||
formData.append("userId", user._id);
|
||||
formData.append("teamId", user.teamId);
|
||||
|
||||
try {
|
||||
const response = await networkService.createBulkMonitors(formData);
|
||||
return [true, response.data, null]; // [success, data, error]
|
||||
} catch (err) {
|
||||
const errorMessage = err?.response?.data?.msg || err.message;
|
||||
return [false, null, errorMessage];
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return [createBulkMonitors, isLoading];
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { networkService } from "../main";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const UseDeleteMonitorStats = () => {
|
||||
const { t } = useTranslation();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const deleteMonitorStats = async ({ teamId }) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const res = await networkService.deleteChecksByTeamId({ teamId });
|
||||
createToast({ body: t("settingsStatsCleared") });
|
||||
} catch (error) {
|
||||
createToast({ body: t("settingsFailedToClearStats") });
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return [deleteMonitorStats, isLoading];
|
||||
};
|
||||
|
||||
export { UseDeleteMonitorStats };
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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 };
|
||||
@@ -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;
|
||||
@@ -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 };
|
||||
@@ -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 };
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useState, useEffect, useCallback } from "react";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
import { networkService } from "../main";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { NOTIFICATION_TYPES } from "../Pages/Notifications/utils";
|
||||
|
||||
@@ -37,15 +36,12 @@ const useGetNotificationsByTeamId = (updateTrigger) => {
|
||||
const [notifications, setNotifications] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getNotifications = useCallback(async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await networkService.getNotificationsByTeamId({
|
||||
teamId: user.teamId,
|
||||
});
|
||||
const response = await networkService.getNotificationsByTeamId();
|
||||
setNotifications(response?.data?.data ?? []);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
@@ -55,7 +51,7 @@ const useGetNotificationsByTeamId = (updateTrigger) => {
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [user.teamId]);
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => {
|
||||
getNotifications();
|
||||
|
||||
@@ -5,7 +5,7 @@ import Button from "@mui/material/Button";
|
||||
import TextInput from "../../../Components/Inputs/TextInput";
|
||||
import { PasswordEndAdornment } from "../../../Components/Inputs/TextInput/Adornments";
|
||||
import { loginCredentials } from "../../../Validation/validation";
|
||||
import TextLink from "../components/TextLink";
|
||||
import TextLink from "../../../Components/TextLink";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
// Utils
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useTheme } from "@emotion/react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { clearAuthState } from "../../Features/Auth/authSlice";
|
||||
import { clearUptimeMonitorState } from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import Background from "../../assets/Images/background-grid.svg?react";
|
||||
import ConfirmIcon from "../../assets/icons/check-outlined.svg?react";
|
||||
import Logo from "../../assets/icons/checkmate-icon.svg?react";
|
||||
@@ -19,7 +18,6 @@ const NewPasswordConfirmed = () => {
|
||||
|
||||
const handleNavigate = () => {
|
||||
dispatch(clearAuthState());
|
||||
dispatch(clearUptimeMonitorState());
|
||||
navigate("/login");
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -26,17 +26,25 @@ const IncidentTable = ({
|
||||
const uiTimezone = useSelector((state) => state.ui.timezone);
|
||||
|
||||
//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 +58,16 @@ const IncidentTable = ({
|
||||
setRowsPerPage(event.target.value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedMonitor === "0") {
|
||||
setTeamId("placeholder"); // TODO this isn't needed any longer, fix hook
|
||||
setMonitorId(undefined);
|
||||
} else {
|
||||
setMonitorId(selectedMonitor);
|
||||
setTeamId(undefined);
|
||||
}
|
||||
}, [selectedMonitor]);
|
||||
|
||||
const headers = [
|
||||
{
|
||||
id: "monitorName",
|
||||
|
||||
@@ -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;
|
||||
@@ -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 };
|
||||
@@ -1,22 +1,20 @@
|
||||
// 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 { useSelector } from "react-redux";
|
||||
import OptionsHeader from "./Components/OptionsHeader";
|
||||
import { useState } from "react";
|
||||
import IncidentTable from "./Components/IncidentTable";
|
||||
import GenericFallback from "../../Components/GenericFallback";
|
||||
import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks";
|
||||
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);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const BREADCRUMBS = [
|
||||
@@ -27,12 +25,23 @@ 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] = useFetchMonitorsByTeamId({});
|
||||
|
||||
const { monitors, isLoading, networkError } = useMonitorsFetch({
|
||||
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 (
|
||||
@@ -47,7 +56,7 @@ const Incidents = () => {
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<OptionsHeader
|
||||
shouldRender={!isLoading}
|
||||
monitors={monitors}
|
||||
monitors={monitorLookup}
|
||||
selectedMonitor={selectedMonitor}
|
||||
setSelectedMonitor={setSelectedMonitor}
|
||||
filter={filter}
|
||||
@@ -57,7 +66,7 @@ const Incidents = () => {
|
||||
/>
|
||||
<IncidentTable
|
||||
shouldRender={!isLoading}
|
||||
monitors={monitors}
|
||||
monitors={monitorLookup ? monitorLookup : {}}
|
||||
selectedMonitor={selectedMonitor}
|
||||
filter={filter}
|
||||
dateRange={dateRange}
|
||||
|
||||
@@ -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,29 +183,18 @@ const CreateInfrastructureMonitor = () => {
|
||||
};
|
||||
|
||||
form = {
|
||||
...(isCreate ? {} : { _id: monitorId }),
|
||||
...rest,
|
||||
description: form.name,
|
||||
teamId: user.teamId,
|
||||
userId: user._id,
|
||||
type: "hardware",
|
||||
notifications: infrastructureMonitor.notifications,
|
||||
thresholds,
|
||||
};
|
||||
|
||||
// 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 +433,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="accent"
|
||||
loading={monitorState?.isLoading}
|
||||
loading={isLoading || isUpdating || isCreating || notificationsAreLoading}
|
||||
>
|
||||
{t(isCreate ? "infrastructureCreateMonitor" : "infrastructureEditMonitor")}
|
||||
</Button>
|
||||
|
||||
@@ -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 ?? {};
|
||||
|
||||
@@ -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 };
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -12,7 +12,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";
|
||||
@@ -27,7 +27,7 @@ const MonitorsTable = ({
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { determineState } = useUtils();
|
||||
const { determineState } = useMonitorUtils();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Handlers
|
||||
@@ -94,6 +94,7 @@ const MonitorsTable = ({
|
||||
monitor={row}
|
||||
isAdmin={isAdmin}
|
||||
updateCallback={handleActionMenuDelete}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -151,7 +152,7 @@ const MonitorsTable = ({
|
||||
};
|
||||
|
||||
MonitorsTable.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
monitors: PropTypes.array,
|
||||
isAdmin: PropTypes.bool,
|
||||
handleActionMenuDelete: PropTypes.func,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* TODO I basically copied and pasted this component from the actionsMenu. Check how we can make it reusable */
|
||||
|
||||
import { useRef, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createToast } from "../../../../../Utils/toastUtils";
|
||||
@@ -30,7 +29,6 @@ const InfrastructureMenu = ({ monitor, isAdmin, updateCallback }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
const theme = useTheme();
|
||||
const { isLoading } = useSelector((state) => state.uptimeMonitors);
|
||||
|
||||
const openMenu = (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -117,7 +115,6 @@ const InfrastructureMenu = ({ monitor, isAdmin, updateCallback }) => {
|
||||
onCancel={cancelRemove}
|
||||
confirmationButtonLabel="Delete"
|
||||
onConfirm={handleRemove}
|
||||
isLoading={isLoading}
|
||||
modelTitle="modal-delete-monitor"
|
||||
modelDescription="delete-monitor-confirmation"
|
||||
/>
|
||||
|
||||
@@ -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 };
|
||||
@@ -11,15 +11,18 @@ import Filter from "./Components/Filters";
|
||||
import SearchComponent from "../../Uptime/Monitors/Components/SearchComponent";
|
||||
// Utils
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useMonitorFetch } from "./Hooks/useMonitorFetch";
|
||||
import { useState } from "react";
|
||||
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
|
||||
|
||||
// Local state
|
||||
const [page, setPage] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(5);
|
||||
const [updateTrigger, setUpdateTrigger] = useState(false);
|
||||
@@ -53,7 +56,9 @@ const InfrastructureMonitors = () => {
|
||||
|
||||
const field = toFilterStatus !== undefined ? "status" : undefined;
|
||||
|
||||
const { monitors, summary, isLoading, networkError } = useMonitorFetch({
|
||||
const [monitors, summary, isLoading, networkError] = useFetchMonitorsByTeamId({
|
||||
limit: 1,
|
||||
types: TYPES,
|
||||
page,
|
||||
field: field,
|
||||
filter: toFilterStatus ?? search,
|
||||
@@ -119,7 +124,7 @@ const InfrastructureMonitors = () => {
|
||||
</Stack>
|
||||
|
||||
<MonitorsTable
|
||||
shouldRender={!isLoading}
|
||||
isLoading={isLoading}
|
||||
monitors={monitors}
|
||||
isAdmin={isAdmin}
|
||||
handleActionMenuDelete={handleActionMenuDelete}
|
||||
|
||||
@@ -135,7 +135,6 @@ const CreateMaintenance = () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await networkService.getMonitorsByTeamId({
|
||||
teamId: user.teamId,
|
||||
limit: null,
|
||||
types: ["http", "ping", "pagespeed", "port"],
|
||||
});
|
||||
|
||||
@@ -48,8 +48,6 @@ const CreateNotifications = () => {
|
||||
|
||||
// local state
|
||||
const [notification, setNotification] = useState({
|
||||
userId: user._id,
|
||||
teamId: user.teamId,
|
||||
notificationName: "",
|
||||
address: "",
|
||||
type: NOTIFICATION_TYPES[0]._id,
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
useDeleteNotification,
|
||||
} from "../../Hooks/useNotifications";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
const Notifications = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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,33 +83,13 @@ 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,
|
||||
teamId: user.teamId,
|
||||
userId: user._id,
|
||||
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 +300,7 @@ const CreatePageSpeed = () => {
|
||||
variant="contained"
|
||||
color="accent"
|
||||
disabled={!Object.values(errors).every((value) => value === undefined)}
|
||||
loading={isLoading}
|
||||
loading={isCreating}
|
||||
>
|
||||
{t("createMonitor")}
|
||||
</Button>
|
||||
|
||||
@@ -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 };
|
||||
@@ -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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
@@ -5,26 +5,29 @@ 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();
|
||||
const isAdmin = useIsAdmin();
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
const { pagespeedApiKey } = useSelector((state) => state.settings);
|
||||
|
||||
const { isLoading, monitors, summary, networkError } = useMonitorsFetch({
|
||||
teamId: user.teamId,
|
||||
const [monitors, monitorsSummary, isLoading, networkError] = useFetchMonitorsByTeamId({
|
||||
limit: 10,
|
||||
types: TYPES,
|
||||
page: null,
|
||||
rowsPerPage: null,
|
||||
filter: null,
|
||||
field: null,
|
||||
order: null,
|
||||
});
|
||||
|
||||
if (networkError === true) {
|
||||
@@ -53,7 +56,7 @@ const PageSpeed = () => {
|
||||
]}
|
||||
link="/pagespeed/create"
|
||||
isAdmin={isAdmin}
|
||||
showPageSpeedWarning={isAdmin && !pagespeedApiKey}
|
||||
// showPageSpeedWarning={isAdmin && !pagespeedApiKey}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -68,7 +71,7 @@ const PageSpeed = () => {
|
||||
/>
|
||||
<MonitorCountHeader
|
||||
shouldRender={!isLoading}
|
||||
monitorCount={summary?.totalMonitors}
|
||||
monitorCount={monitorsSummary?.totalMonitors}
|
||||
sx={{ mb: theme.spacing(8) }}
|
||||
/>
|
||||
<MonitorGrid
|
||||
|
||||
@@ -11,22 +11,20 @@ import SettingsEmail from "./SettingsEmail";
|
||||
import Button from "@mui/material/Button";
|
||||
// Utils
|
||||
import { settingsValidation } from "../../Validation/validation";
|
||||
import { createToast } from "../../Utils/toastUtils";
|
||||
import { useState } from "react";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { setTimezone, setMode, setLanguage, setShowURL } from "../../Features/UI/uiSlice";
|
||||
import SettingsStats from "./SettingsStats";
|
||||
import {
|
||||
deleteMonitorChecksByTeamId,
|
||||
addDemoMonitors,
|
||||
deleteAllMonitors,
|
||||
} from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import { useFetchSettings, useSaveSettings } from "../../Hooks/useFetchSettings";
|
||||
import { UseDeleteMonitorStats } from "../../Hooks/useDeleteMonitorStats";
|
||||
import { useIsAdmin } from "../../Hooks/useIsAdmin";
|
||||
|
||||
import { useFetchSettings, useSaveSettings } from "../../Hooks/settingsHooks";
|
||||
import { useIsAdmin } from "../../Hooks/useIsAdmin";
|
||||
import {
|
||||
useAddDemoMonitors,
|
||||
useDeleteAllMonitors,
|
||||
useDeleteMonitorStats,
|
||||
} from "../../Hooks/monitorHooks";
|
||||
// Constants
|
||||
const BREADCRUMBS = [{ name: `Settings`, path: "/settings" }];
|
||||
|
||||
@@ -43,15 +41,17 @@ const Settings = () => {
|
||||
const [isSettingsLoading, settingsError] = useFetchSettings({
|
||||
setSettingsData,
|
||||
});
|
||||
const [addDemoMonitors, isAddingDemoMonitors] = useAddDemoMonitors();
|
||||
|
||||
const [isSaving, saveError, saveSettings] = useSaveSettings();
|
||||
const [deleteMonitorStats, isDeletingMonitorStats] = UseDeleteMonitorStats();
|
||||
const [deleteAllMonitors, isDeletingMonitors] = useDeleteAllMonitors();
|
||||
const [deleteMonitorStats, isDeletingMonitorStats] = useDeleteMonitorStats();
|
||||
|
||||
// Setup
|
||||
const isAdmin = useIsAdmin();
|
||||
const theme = useTheme();
|
||||
const HEADING_SX = { mt: theme.spacing(2), mb: theme.spacing(2) };
|
||||
const { t, i18n } = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Handlers
|
||||
@@ -96,35 +96,17 @@ const Settings = () => {
|
||||
}
|
||||
|
||||
if (name === "deleteStats") {
|
||||
await deleteMonitorStats({ teamId: user.teamId });
|
||||
await deleteMonitorStats();
|
||||
return;
|
||||
}
|
||||
|
||||
if (name === "demo") {
|
||||
try {
|
||||
const action = await dispatch(addDemoMonitors());
|
||||
if (addDemoMonitors.fulfilled.match(action)) {
|
||||
createToast({ body: t("settingsDemoMonitorsAdded") });
|
||||
} else {
|
||||
createToast({ body: t("settingsFailedToAddDemoMonitors") });
|
||||
}
|
||||
} catch (error) {
|
||||
createToast({ body: t("settingsFailedToAddDemoMonitors") });
|
||||
}
|
||||
await addDemoMonitors();
|
||||
return;
|
||||
}
|
||||
|
||||
if (name === "deleteMonitors") {
|
||||
try {
|
||||
const action = await dispatch(deleteAllMonitors());
|
||||
if (deleteAllMonitors.fulfilled.match(action)) {
|
||||
createToast({ body: t("settingsMonitorsDeleted") });
|
||||
} else {
|
||||
createToast({ body: t("settingsFailedToDeleteMonitors") });
|
||||
}
|
||||
} catch (error) {
|
||||
createToast({ body: t("settingsFailedToDeleteMonitors") });
|
||||
}
|
||||
await deleteAllMonitors();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -185,7 +167,9 @@ const Settings = () => {
|
||||
isAdmin={isAdmin}
|
||||
HEADER_SX={HEADING_SX}
|
||||
handleChange={handleChange}
|
||||
isLoading={isSettingsLoading || isSaving || isDeletingMonitorStats}
|
||||
isLoading={
|
||||
isSettingsLoading || isSaving || isDeletingMonitorStats || isAddingDemoMonitors
|
||||
}
|
||||
/>
|
||||
<SettingsEmail
|
||||
isAdmin={isAdmin}
|
||||
@@ -219,7 +203,9 @@ const Settings = () => {
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
loading={isSaving || isDeletingMonitorStats || isSettingsLoading}
|
||||
loading={
|
||||
isSaving || isDeletingMonitorStats || isSettingsLoading || isDeletingMonitors
|
||||
}
|
||||
disabled={Object.keys(errors).length > 0}
|
||||
variant="contained"
|
||||
color="accent"
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { useState } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
|
||||
const useCreateStatusPage = (isCreate, url) => {
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
const createStatusPage = async ({ form }) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await networkService.createStatusPage({ user, form, isCreate, url });
|
||||
await networkService.createStatusPage({ form, isCreate, url });
|
||||
return true;
|
||||
} catch (error) {
|
||||
setNetworkError(true);
|
||||
|
||||
@@ -13,7 +13,6 @@ const useMonitorsFetch = () => {
|
||||
const fetchMonitors = async () => {
|
||||
try {
|
||||
const response = await networkService.getMonitorsByTeamId({
|
||||
teamId: user.teamId,
|
||||
limit: null, // donot return any checks for the monitors
|
||||
types: ["http", "ping", "port"], // status page is available for uptime, ping, and port monitors
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import StatusBar from "./Components/StatusBar";
|
||||
import MonitorsList from "./Components/MonitorsList";
|
||||
import Dialog from "../../../Components/Dialog";
|
||||
import Breadcrumbs from "../../../Components/Breadcrumbs/index.jsx";
|
||||
import TextLink from "../../../Components/TextLink";
|
||||
|
||||
// Utils
|
||||
import { useStatusPageFetch } from "./Hooks/useStatusPageFetch";
|
||||
@@ -30,6 +31,7 @@ const PublicStatus = () => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const isAdmin = useIsAdmin();
|
||||
|
||||
const [statusPage, monitors, isLoading, networkError, fetchStatusPage] =
|
||||
useStatusPageFetch(false, url);
|
||||
@@ -60,6 +62,26 @@ const PublicStatus = () => {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
|
||||
if (monitors.length === 0) {
|
||||
return (
|
||||
<GenericFallback>
|
||||
<Typography
|
||||
variant="h1"
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
{"Theres nothing here yet"}
|
||||
</Typography>
|
||||
{isAdmin && (
|
||||
<TextLink
|
||||
linkText={"Add a monitor to get started"}
|
||||
href={`/status/uptime/configure/${url}`}
|
||||
/>
|
||||
)}
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
|
||||
// Error fetching data
|
||||
if (networkError === true) {
|
||||
return (
|
||||
|
||||
@@ -13,9 +13,7 @@ const useStatusPagesFetch = () => {
|
||||
useEffect(() => {
|
||||
const fetchStatusPages = async () => {
|
||||
try {
|
||||
const res = await networkService.getStatusPagesByTeamId({
|
||||
teamId: user.teamId,
|
||||
});
|
||||
const res = await networkService.getStatusPagesByTeamId();
|
||||
setStatusPages(res?.data?.data);
|
||||
} catch (error) {
|
||||
setNetworkError(true);
|
||||
|
||||
@@ -12,7 +12,7 @@ import UploadFile from "./Upload";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useNavigate } from "react-router";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { useBulkMonitors } from "../../../Hooks/useBulkMonitors";
|
||||
import { useCreateBulkMonitors } from "../../../Hooks/monitorHooks";
|
||||
|
||||
const BulkImport = () => {
|
||||
const theme = useTheme();
|
||||
@@ -26,7 +26,7 @@ const BulkImport = () => {
|
||||
{ name: t("bulkImport.title"), path: `/uptime/bulk-import` },
|
||||
];
|
||||
|
||||
const [createBulkMonitors, hookLoading] = useBulkMonitors();
|
||||
const [createBulkMonitors, hookLoading] = useCreateBulkMonitors();
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!selectedFile) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,35 +1,30 @@
|
||||
// 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";
|
||||
import Checkbox from "../../../Components/Inputs/Checkbox";
|
||||
|
||||
// Utils
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useState } from "react";
|
||||
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({});
|
||||
const [https, setHttps] = useState(true);
|
||||
@@ -39,6 +34,8 @@ const CreateMonitor = () => {
|
||||
name: "",
|
||||
type: "http",
|
||||
matchMethod: "equal",
|
||||
expectedValue: "",
|
||||
jsonPath: "",
|
||||
notifications: [],
|
||||
interval: 1,
|
||||
ignoreTlsErrors: false,
|
||||
@@ -47,8 +44,8 @@ const CreateMonitor = () => {
|
||||
// Setup
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [notifications, notificationsAreLoading, error] = useGetNotificationsByTeamId();
|
||||
const [createMonitor, isCreating] = useCreateMonitor();
|
||||
|
||||
const MS_PER_MINUTE = 60000;
|
||||
const SELECT_VALUES = [
|
||||
@@ -142,18 +139,10 @@ const CreateMonitor = () => {
|
||||
form = {
|
||||
...form,
|
||||
description: monitor.name || monitor.url,
|
||||
teamId: user.teamId,
|
||||
userId: user._id,
|
||||
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) => {
|
||||
@@ -162,6 +151,12 @@ const CreateMonitor = () => {
|
||||
if (name === "ignoreTlsErrors") {
|
||||
newValue = checked;
|
||||
}
|
||||
|
||||
if (name === "useAdvancedMatching") {
|
||||
setUseAdvancedMatching(checked);
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedMonitor = {
|
||||
...monitor,
|
||||
[name]: newValue,
|
||||
@@ -399,7 +394,13 @@ const CreateMonitor = () => {
|
||||
onChange={onChange}
|
||||
items={SELECT_VALUES}
|
||||
/>
|
||||
{monitor.type === "http" && (
|
||||
<Checkbox
|
||||
name="useAdvancedMatching"
|
||||
label={t("advancedMatching")}
|
||||
isChecked={useAdvancedMatching}
|
||||
onChange={onChange}
|
||||
/>
|
||||
{monitor.type === "http" && useAdvancedMatching && (
|
||||
<>
|
||||
<Select
|
||||
name="matchMethod"
|
||||
@@ -472,7 +473,7 @@ const CreateMonitor = () => {
|
||||
variant="contained"
|
||||
color="accent"
|
||||
disabled={!Object.values(errors).every((value) => value === undefined)}
|
||||
loading={isLoading}
|
||||
loading={isCreating}
|
||||
>
|
||||
{t("createMonitor")}
|
||||
</Button>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -61,7 +64,6 @@ CreateMonitorButton.propTypes = {
|
||||
|
||||
const UptimeMonitors = () => {
|
||||
// Redux state
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
const rowsPerPage = useSelector((state) => state.ui.monitors.rowsPerPage);
|
||||
|
||||
// Local state
|
||||
@@ -78,7 +80,6 @@ const UptimeMonitors = () => {
|
||||
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
const isAdmin = useIsAdmin();
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
@@ -104,11 +105,8 @@ const UptimeMonitors = () => {
|
||||
setMonitorUpdateTrigger((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const teamId = user.teamId;
|
||||
|
||||
const [monitors, monitorsSummary, monitorsWithSummaryIsLoading, networkError] =
|
||||
useFetchMonitorsWithSummary({
|
||||
teamId,
|
||||
types: TYPES,
|
||||
monitorUpdateTrigger,
|
||||
});
|
||||
@@ -138,7 +136,6 @@ const UptimeMonitors = () => {
|
||||
monitorsWithChecksIsLoading,
|
||||
monitorsWithChecksNetworkError,
|
||||
] = useFetchMonitorsWithChecks({
|
||||
teamId,
|
||||
types: effectiveTypes,
|
||||
limit: 25,
|
||||
page: page,
|
||||
|
||||
@@ -6,8 +6,7 @@ class Logger {
|
||||
constructor() {
|
||||
let logLevel = LOG_LEVEL;
|
||||
this.unsubscribe = store.subscribe(() => {
|
||||
const state = store.getState();
|
||||
logLevel = state.settings.logLevel || "debug";
|
||||
logLevel = "debug";
|
||||
this.updateLogLevel(logLevel);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import i18next from "i18next";
|
||||
const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL;
|
||||
const FALLBACK_BASE_URL = "http://localhost:5000/api/v1";
|
||||
import { clearAuthState } from "../Features/Auth/authSlice";
|
||||
import { clearUptimeMonitorState } from "../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
class NetworkService {
|
||||
constructor(store, dispatch, navigate) {
|
||||
this.store = store;
|
||||
@@ -56,7 +55,6 @@ class NetworkService {
|
||||
|
||||
if (error.response && error.response.status === 401) {
|
||||
dispatch(clearAuthState());
|
||||
dispatch(clearUptimeMonitorState());
|
||||
navigate("/login");
|
||||
} else if (error.request && !error.response) {
|
||||
return Promise.reject(error);
|
||||
@@ -137,36 +135,6 @@ class NetworkService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* ************************************
|
||||
* Gets monitors and summary of stats by TeamID
|
||||
* ************************************
|
||||
*
|
||||
* @async
|
||||
* @param {Object} config - The configuration object.
|
||||
* @param {string} config.teamId - Team ID
|
||||
* @param {Array<string>} config.types - Array of monitor types
|
||||
* @returns {Promise<AxiosResponse>} The response from the axios POST request.
|
||||
*/
|
||||
async getMonitorsSummaryByTeamId(config) {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (config.types) {
|
||||
config.types.forEach((type) => {
|
||||
params.append("type", type);
|
||||
});
|
||||
}
|
||||
return this.axiosInstance.get(
|
||||
`/monitors/team/summary/${config.teamId}?${params.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
* Get all uptime monitors for a Team
|
||||
@@ -186,7 +154,7 @@ class NetworkService {
|
||||
*/
|
||||
|
||||
async getMonitorsByTeamId(config) {
|
||||
const { teamId, limit, types, page, rowsPerPage, filter, field, order } = config;
|
||||
const { limit, types, page, rowsPerPage, filter, field, order } = config;
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (limit) params.append("limit", limit);
|
||||
@@ -201,7 +169,7 @@ class NetworkService {
|
||||
if (field) params.append("field", field);
|
||||
if (order) params.append("order", order);
|
||||
|
||||
return this.axiosInstance.get(`/monitors/team/${teamId}?${params.toString()}`, {
|
||||
return this.axiosInstance.get(`/monitors/team?${params.toString()}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
@@ -304,7 +272,7 @@ class NetworkService {
|
||||
* @returns {Promise<AxiosResponse>} The response from the axios DELETE request.
|
||||
*/
|
||||
async deleteChecksByTeamId(config) {
|
||||
return this.axiosInstance.delete(`/checks/team/${config.teamId}`, {
|
||||
return this.axiosInstance.delete(`/checks/team`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
@@ -587,7 +555,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 +567,7 @@ class NetworkService {
|
||||
if (config.status !== undefined) params.append("status", config.status);
|
||||
|
||||
return this.axiosInstance.get(`/checks/${config.monitorId}?${params.toString()}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@@ -618,7 +586,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);
|
||||
@@ -627,8 +595,8 @@ class NetworkService {
|
||||
if (config.page) params.append("page", config.page);
|
||||
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()}`);
|
||||
}
|
||||
return this.axiosInstance.get(`/checks/team?${params.toString()}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* ************************************
|
||||
@@ -870,8 +838,7 @@ class NetworkService {
|
||||
}
|
||||
|
||||
async getStatusPagesByTeamId(config) {
|
||||
const { teamId } = config;
|
||||
return this.axiosInstance.get(`/status-page/team/${teamId}`, {
|
||||
return this.axiosInstance.get(`/status-page/team`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
@@ -879,11 +846,9 @@ class NetworkService {
|
||||
}
|
||||
|
||||
async createStatusPage(config) {
|
||||
const { user, form, isCreate } = config;
|
||||
const { form, isCreate } = config;
|
||||
|
||||
const fd = new FormData();
|
||||
fd.append("teamId", user.teamId);
|
||||
fd.append("userId", user._id);
|
||||
fd.append("type", form.type);
|
||||
form.isPublished !== undefined && fd.append("isPublished", form.isPublished);
|
||||
form.companyName && fd.append("companyName", form.companyName);
|
||||
@@ -951,7 +916,7 @@ class NetworkService {
|
||||
// Fetch monitors with summary by TeamID
|
||||
// ************************************
|
||||
async getMonitorsWithSummaryByTeamId(config) {
|
||||
const { teamId, types } = config;
|
||||
const { types } = config;
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (types) {
|
||||
@@ -960,21 +925,18 @@ class NetworkService {
|
||||
});
|
||||
}
|
||||
|
||||
return this.axiosInstance.get(
|
||||
`/monitors/summary/team/${teamId}?${params.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
return this.axiosInstance.get(`/monitors/summary/team?${params.toString()}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ************************************
|
||||
// Fetch monitors with checks by TeamID
|
||||
// ************************************
|
||||
async getMonitorsWithChecksByTeamId(config) {
|
||||
const { teamId, limit, types, page, rowsPerPage, filter, field, order } = config;
|
||||
const { limit, types, page, rowsPerPage, filter, field, order } = config;
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (limit) params.append("limit", limit);
|
||||
@@ -989,14 +951,11 @@ class NetworkService {
|
||||
if (field) params.append("field", field);
|
||||
if (order) params.append("order", order);
|
||||
|
||||
return this.axiosInstance.get(
|
||||
`/monitors/team/${teamId}/with-checks?${params.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
return this.axiosInstance.get(`/monitors/team/with-checks?${params.toString()}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ************************************
|
||||
@@ -1034,8 +993,7 @@ class NetworkService {
|
||||
}
|
||||
|
||||
async getNotificationsByTeamId(config) {
|
||||
const { teamId } = config;
|
||||
return this.axiosInstance.get(`/notifications/team/${teamId}`);
|
||||
return this.axiosInstance.get(`/notifications/team`);
|
||||
}
|
||||
|
||||
async deleteNotificationById(config) {
|
||||
|
||||
@@ -85,6 +85,7 @@ const semanticColors = {
|
||||
const newColors = {
|
||||
offWhite: "#FEFEFE",
|
||||
offBlack: "#131315",
|
||||
gray10: "#F4F4FF",
|
||||
gray100: "#F3F3F3",
|
||||
gray200: "#EFEFEF",
|
||||
gray500: "#A2A3A3",
|
||||
@@ -175,6 +176,12 @@ const newSemanticColors = {
|
||||
dark: newColors.blueGray600,
|
||||
},
|
||||
},
|
||||
primaryBackground: {
|
||||
main: {
|
||||
light: newColors.gray10,
|
||||
dark: "#000000",
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
main: {
|
||||
light: newColors.gray200,
|
||||
|
||||
@@ -380,6 +380,33 @@ const baseTheme = (palette) => ({
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
MuiAutocomplete: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
"& .MuiOutlinedInput-root": {
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
"& fieldset": {
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
"& .MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus)) fieldset":
|
||||
{
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
|
||||
"& .MuiAutocomplete-tag": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
"& .MuiChip-deleteIcon": {
|
||||
color: theme.palette.primary.contrastText, // CAIO_REVIEW
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
|
||||
49
client/src/assets/Images/background.svg
Normal file
49
client/src/assets/Images/background.svg
Normal file
@@ -0,0 +1,49 @@
|
||||
<svg width="1440" height="1025" viewBox="0 0 1440 1025" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_f_563_20635)">
|
||||
<ellipse cx="971.521" cy="1024.07" rx="278.644" ry="273.684" fill="#7054FF" fill-opacity="0.2" />
|
||||
</g>
|
||||
<g filter="url(#filter1_f_563_20635)">
|
||||
<ellipse cx="44.3184" cy="1161.28" rx="513.227" ry="529.699" fill="#7282FF" fill-opacity="0.12" />
|
||||
</g>
|
||||
<g filter="url(#filter2_f_563_20635)">
|
||||
<ellipse cx="1484.89" cy="1016.24" rx="376.575" ry="404.555" fill="#4C7FFF" fill-opacity="0.2" />
|
||||
</g>
|
||||
<g filter="url(#filter3_f_563_20635)">
|
||||
<ellipse cx="505.276" cy="-87.3996" rx="339.168" ry="238.417" fill="#7054FF" fill-opacity="0.2" />
|
||||
</g>
|
||||
<g filter="url(#filter4_f_563_20635)">
|
||||
<ellipse cx="915.714" cy="-111.32" rx="358.17" ry="325.578" fill="#4C7FFF" fill-opacity="0.16" />
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_f_563_20635" x="212.877" y="270.389" width="1517.29" height="1507.37"
|
||||
filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="240" result="effect1_foregroundBlur_563_20635" />
|
||||
</filter>
|
||||
<filter id="filter1_f_563_20635" x="-948.908" y="151.583" width="1986.45" height="2019.4"
|
||||
filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="240" result="effect1_foregroundBlur_563_20635" />
|
||||
</filter>
|
||||
<filter id="filter2_f_563_20635" x="628.316" y="131.683" width="1713.15" height="1769.11"
|
||||
filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="240" result="effect1_foregroundBlur_563_20635" />
|
||||
</filter>
|
||||
<filter id="filter3_f_563_20635" x="-313.893" y="-805.816" width="1638.34" height="1436.83"
|
||||
filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="240" result="effect1_foregroundBlur_563_20635" />
|
||||
</filter>
|
||||
<filter id="filter4_f_563_20635" x="77.5449" y="-916.898" width="1676.34" height="1611.16"
|
||||
filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
|
||||
<feGaussianBlur stdDeviation="240" result="effect1_foregroundBlur_563_20635" />
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -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?",
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { configureStore, combineReducers } from "@reduxjs/toolkit";
|
||||
|
||||
import uptimeMonitorsReducer from "./Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import infrastructureMonitorsReducer from "./Features/InfrastructureMonitors/infrastructureMonitorsSlice";
|
||||
import pageSpeedMonitorReducer from "./Features/PageSpeedMonitor/pageSpeedMonitorSlice";
|
||||
import authReducer from "./Features/Auth/authSlice";
|
||||
import uiReducer from "./Features/UI/uiSlice";
|
||||
import settingsReducer from "./Features/Settings/settingsSlice";
|
||||
import storage from "redux-persist/lib/storage";
|
||||
import { persistReducer, persistStore, createTransform } from "redux-persist";
|
||||
|
||||
@@ -23,17 +19,13 @@ const authTransform = createTransform(
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage,
|
||||
whitelist: ["auth", "monitors", "pageSpeed", "ui", "settings"],
|
||||
whitelist: ["auth", "ui"],
|
||||
transforms: [authTransform],
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
uptimeMonitors: uptimeMonitorsReducer,
|
||||
infrastructureMonitors: infrastructureMonitorsReducer,
|
||||
auth: authReducer,
|
||||
pageSpeedMonitors: pageSpeedMonitorReducer,
|
||||
ui: uiReducer,
|
||||
settings: settingsReducer,
|
||||
});
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
@@ -54,7 +54,18 @@ class CheckController {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.db.getChecksByMonitor(req);
|
||||
const { monitorId } = req.params;
|
||||
let { type, sortOrder, dateRange, filter, page, rowsPerPage, status } = req.query;
|
||||
const result = await this.db.getChecksByMonitor({
|
||||
monitorId,
|
||||
type,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
filter,
|
||||
page,
|
||||
rowsPerPage,
|
||||
status,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkGet,
|
||||
@@ -74,8 +85,17 @@ class CheckController {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const checkData = await this.db.getChecksByTeam(req);
|
||||
let { sortOrder, dateRange, filter, page, rowsPerPage } = req.query;
|
||||
const { teamId } = req.user;
|
||||
|
||||
const checkData = await this.db.getChecksByTeam({
|
||||
sortOrder,
|
||||
dateRange,
|
||||
filter,
|
||||
page,
|
||||
rowsPerPage,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.checkGet,
|
||||
data: checkData,
|
||||
@@ -114,7 +134,8 @@ class CheckController {
|
||||
}
|
||||
|
||||
try {
|
||||
const deletedCount = await this.db.deleteChecksByTeamId(req.params.teamId);
|
||||
const { teamId } = req.user;
|
||||
const deletedCount = await this.db.deleteChecksByTeamId(teamId);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.checkDelete,
|
||||
@@ -137,9 +158,7 @@ class CheckController {
|
||||
|
||||
try {
|
||||
// Get user's teamId
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = this.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const { teamId } = req.user;
|
||||
const ttl = parseInt(req.body.ttl, 10) * SECONDS_PER_DAY;
|
||||
await this.db.updateChecksTTL(teamId, ttl);
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ import {
|
||||
getMaintenanceWindowsByTeamIdQueryValidation,
|
||||
deleteMaintenanceWindowByIdParamValidation,
|
||||
} from "../validation/joi.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { getTokenFromHeaders } from "../utils/utils.js";
|
||||
import { handleValidationError, handleError } from "./controllerUtils.js";
|
||||
|
||||
const SERVICE_NAME = "maintenanceWindowController";
|
||||
@@ -28,9 +26,7 @@ class MaintenanceWindowController {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = this.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const { teamId } = req.user;
|
||||
const monitorIds = req.body.monitors;
|
||||
const dbTransactions = monitorIds.map((monitorId) => {
|
||||
return this.db.createMaintenanceWindow({
|
||||
@@ -81,9 +77,7 @@ class MaintenanceWindowController {
|
||||
}
|
||||
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = this.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const { teamId } = req.user;
|
||||
const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(
|
||||
teamId,
|
||||
req.query
|
||||
|
||||
@@ -78,7 +78,14 @@ class MonitorController {
|
||||
|
||||
getUptimeDetailsById = async (req, res, next) => {
|
||||
try {
|
||||
const data = await this.db.getUptimeDetailsById(req);
|
||||
const { monitorId } = req.params;
|
||||
const { dateRange, normalize } = req.query;
|
||||
|
||||
const data = await this.db.getUptimeDetailsById({
|
||||
monitorId,
|
||||
dateRange,
|
||||
normalize,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data,
|
||||
@@ -107,7 +114,17 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const monitorStats = await this.db.getMonitorStatsById(req);
|
||||
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
|
||||
const { monitorId } = req.params;
|
||||
|
||||
const monitorStats = await this.db.getMonitorStatsById({
|
||||
monitorId,
|
||||
limit,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
numToDisplay,
|
||||
normalize,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.monitorStatsById,
|
||||
data: monitorStats,
|
||||
@@ -135,7 +152,9 @@ class MonitorController {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const monitor = await this.db.getHardwareDetailsById(req);
|
||||
const { monitorId } = req.params;
|
||||
const { dateRange } = req.query;
|
||||
const monitor = await this.db.getHardwareDetailsById({ monitorId, dateRange });
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data: monitor,
|
||||
@@ -219,7 +238,12 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const monitor = await this.db.createMonitor(req, res);
|
||||
const { _id, teamId } = req.user;
|
||||
const monitor = await this.db.createMonitor({
|
||||
body: req.body,
|
||||
teamId,
|
||||
userId: _id,
|
||||
});
|
||||
|
||||
// Add monitor to job queue
|
||||
this.jobQueue.addJob(monitor._id, monitor);
|
||||
@@ -261,10 +285,10 @@ class MonitorController {
|
||||
throw new Error("File is empty");
|
||||
}
|
||||
|
||||
const { userId, teamId } = req.body;
|
||||
const { _id, teamId } = req.user;
|
||||
|
||||
if (!userId || !teamId) {
|
||||
throw new Error("Missing userId or teamId in form data");
|
||||
if (!_id || !teamId) {
|
||||
throw new Error("Missing userId or teamId");
|
||||
}
|
||||
|
||||
// Get file buffer from memory and convert to string
|
||||
@@ -299,7 +323,7 @@ class MonitorController {
|
||||
}
|
||||
|
||||
const enrichedData = data.map((monitor) => ({
|
||||
userId,
|
||||
userId: _id,
|
||||
teamId,
|
||||
...monitor,
|
||||
description: monitor.description || monitor.name || monitor.url,
|
||||
@@ -388,7 +412,8 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const monitor = await this.db.deleteMonitor(req, res, next);
|
||||
const monitorId = req.params.monitorId;
|
||||
const monitor = await this.db.deleteMonitor({ monitorId });
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.deleteStatusPagesByMonitorId(monitor._id);
|
||||
return res.success({ msg: this.stringService.monitorDelete });
|
||||
@@ -410,9 +435,7 @@ class MonitorController {
|
||||
*/
|
||||
deleteAllMonitors = async (req, res, next) => {
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = this.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const { teamId } = req.user;
|
||||
const { monitors, deletedCount } = await this.db.deleteAllMonitors(teamId);
|
||||
await Promise.all(
|
||||
monitors.map(async (monitor) => {
|
||||
@@ -494,18 +517,8 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const monitor = await Monitor.findOneAndUpdate(
|
||||
{ _id: req.params.monitorId },
|
||||
[
|
||||
{
|
||||
$set: {
|
||||
isActive: { $not: "$isActive" },
|
||||
status: "$$REMOVE",
|
||||
},
|
||||
},
|
||||
],
|
||||
{ new: true }
|
||||
);
|
||||
const monitorId = req.params.monitorId;
|
||||
const monitor = await this.db.pauseMonitor({ monitorId });
|
||||
monitor.isActive === true
|
||||
? await this.jobQueue.resumeJob(monitor._id, monitor)
|
||||
: await this.jobQueue.pauseJob(monitor);
|
||||
@@ -534,9 +547,7 @@ class MonitorController {
|
||||
*/
|
||||
addDemoMonitors = async (req, res, next) => {
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = this.settingsService.getSettings();
|
||||
const { _id, teamId } = jwt.verify(token, jwtSecret);
|
||||
const { _id, teamId } = req.user;
|
||||
const demoMonitors = await this.db.addDemoMonitors(_id, teamId);
|
||||
await Promise.all(
|
||||
demoMonitors.map((monitor) => this.jobQueue.addJob(monitor._id, monitor))
|
||||
@@ -603,7 +614,19 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const monitors = await this.db.getMonitorsByTeamId(req);
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const teamId = req.user.teamId;
|
||||
|
||||
const monitors = await this.db.getMonitorsByTeamId({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByTeamId,
|
||||
data: monitors,
|
||||
@@ -622,7 +645,15 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.db.getMonitorsAndSummaryByTeamId(req);
|
||||
const { explain } = req;
|
||||
const { type } = req.query;
|
||||
const { teamId } = req.user;
|
||||
|
||||
const result = await this.db.getMonitorsAndSummaryByTeamId({
|
||||
type,
|
||||
explain,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: "OK", // TODO
|
||||
data: result,
|
||||
@@ -641,7 +672,21 @@ class MonitorController {
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.db.getMonitorsWithChecksByTeamId(req);
|
||||
const { explain } = req;
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const { teamId } = req.user;
|
||||
|
||||
const result = await this.db.getMonitorsWithChecksByTeamId({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
explain,
|
||||
});
|
||||
return res.success({
|
||||
msg: "OK", // TODO
|
||||
data: result,
|
||||
@@ -653,11 +698,7 @@ class MonitorController {
|
||||
|
||||
seedDb = async (req, res, next) => {
|
||||
try {
|
||||
const { type } = req.body;
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = this.settingsService.getSettings();
|
||||
const { _id, teamId } = jwt.verify(token, jwtSecret);
|
||||
|
||||
const { _id, teamId } = req.user;
|
||||
await seedDb(_id, teamId);
|
||||
res.success({ msg: "Database seeded" });
|
||||
} catch (error) {
|
||||
|
||||
@@ -140,7 +140,7 @@ class NotificationController {
|
||||
|
||||
getNotificationsByTeamId = async (req, res, next) => {
|
||||
try {
|
||||
const notifications = await this.db.getNotificationsByTeamId(req.params.teamId);
|
||||
const notifications = await this.db.getNotificationsByTeamId(req.user.teamId);
|
||||
return res.success({
|
||||
msg: "Notifications fetched successfully",
|
||||
data: notifications,
|
||||
|
||||
@@ -24,7 +24,13 @@ class StatusPageController {
|
||||
}
|
||||
|
||||
try {
|
||||
const statusPage = await this.db.createStatusPage(req.body, req.file);
|
||||
const { _id, teamId } = req.user;
|
||||
const statusPage = await this.db.createStatusPage({
|
||||
statusPageData: req.body,
|
||||
image: req.file,
|
||||
userId: _id,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.statusPageCreate,
|
||||
data: statusPage,
|
||||
@@ -93,7 +99,7 @@ class StatusPageController {
|
||||
|
||||
getStatusPagesByTeamId = async (req, res, next) => {
|
||||
try {
|
||||
const teamId = req.params.teamId;
|
||||
const teamId = req.user.teamId;
|
||||
const statusPages = await this.db.getStatusPagesByTeamId(teamId);
|
||||
|
||||
return res.success({
|
||||
|
||||
@@ -3,6 +3,7 @@ import HardwareCheck from "./HardwareCheck.js";
|
||||
import PageSpeedCheck from "./PageSpeedCheck.js";
|
||||
import Check from "./Check.js";
|
||||
import MonitorStats from "./MonitorStats.js";
|
||||
import StatusPage from "./StatusPage.js";
|
||||
|
||||
const MonitorSchema = mongoose.Schema(
|
||||
{
|
||||
@@ -105,6 +106,9 @@ MonitorSchema.pre("findOneAndDelete", async function (next) {
|
||||
await Check.deleteMany({ monitorId: doc._id });
|
||||
}
|
||||
|
||||
// Deal with status pages
|
||||
await StatusPage.updateMany({ monitors: doc._id }, { $pull: { monitors: doc._id } });
|
||||
|
||||
await MonitorStats.deleteMany({ monitorId: doc._id.toString() });
|
||||
next();
|
||||
} catch (error) {
|
||||
|
||||
@@ -57,10 +57,17 @@ const createChecks = async (checks) => {
|
||||
* @returns {Promise<Array<Check>>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getChecksByMonitor = async (req) => {
|
||||
const getChecksByMonitor = async ({
|
||||
monitorId,
|
||||
type,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
filter,
|
||||
page,
|
||||
rowsPerPage,
|
||||
status,
|
||||
}) => {
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
let { type, sortOrder, dateRange, filter, page, rowsPerPage, status } = req.query;
|
||||
status = typeof status !== "undefined" ? false : undefined;
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
@@ -142,12 +149,17 @@ const getChecksByMonitor = async (req) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getChecksByTeam = async (req) => {
|
||||
const getChecksByTeam = async ({
|
||||
sortOrder,
|
||||
dateRange,
|
||||
filter,
|
||||
page,
|
||||
rowsPerPage,
|
||||
teamId,
|
||||
}) => {
|
||||
try {
|
||||
let { sortOrder, dateRange, filter, page, rowsPerPage } = req.query;
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
const { teamId } = req.params;
|
||||
const matchStage = {
|
||||
teamId: ObjectId.createFromHexString(teamId),
|
||||
status: false,
|
||||
|
||||
@@ -6,10 +6,7 @@ import {
|
||||
buildMonitorSummaryByTeamIdPipeline,
|
||||
buildMonitorsByTeamIdPipeline,
|
||||
buildFilteredMonitorsByTeamIdPipeline,
|
||||
buildDePINDetailsByDateRange,
|
||||
buildDePINLatestChecks,
|
||||
} from "./monitorModuleQueries.js";
|
||||
import { getDateRange } from "./monitorModule.js";
|
||||
|
||||
const getMonitorsByTeamIdExecutionStats = async (req) => {
|
||||
try {
|
||||
|
||||
@@ -3,7 +3,6 @@ import MonitorStats from "../../models/MonitorStats.js";
|
||||
import Check from "../../models/Check.js";
|
||||
import PageSpeedCheck from "../../models/PageSpeedCheck.js";
|
||||
import HardwareCheck from "../../models/HardwareCheck.js";
|
||||
import Notification from "../../models/Notification.js";
|
||||
import { NormalizeData, NormalizeDataUptimeDetails } from "../../../utils/dataUtils.js";
|
||||
import ServiceRegistry from "../../../service/serviceRegistry.js";
|
||||
import StringService from "../../../service/stringService.js";
|
||||
@@ -15,14 +14,11 @@ import { ObjectId } from "mongodb";
|
||||
import {
|
||||
buildUptimeDetailsPipeline,
|
||||
buildHardwareDetailsPipeline,
|
||||
buildMonitorStatsPipeline,
|
||||
buildMonitorSummaryByTeamIdPipeline,
|
||||
buildMonitorsByTeamIdPipeline,
|
||||
buildMonitorsAndSummaryByTeamIdPipeline,
|
||||
buildMonitorsWithChecksByTeamIdPipeline,
|
||||
buildFilteredMonitorsByTeamIdPipeline,
|
||||
buildDePINDetailsByDateRange,
|
||||
buildDePINLatestChecks,
|
||||
} from "./monitorModuleQueries.js";
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -335,11 +331,9 @@ const calculateGroupStats = (group) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getUptimeDetailsById = async (req) => {
|
||||
const getUptimeDetailsById = async ({ monitorId, dateRange, normalize }) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
const { dateRange, normalize } = req.query;
|
||||
const dates = getDateRange(dateRange);
|
||||
const formatLookup = {
|
||||
recent: "%Y-%m-%dT%H:%M:00Z",
|
||||
@@ -392,11 +386,16 @@ const getUptimeDetailsById = async (req) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getMonitorStatsById = async (req) => {
|
||||
const getMonitorStatsById = async ({
|
||||
monitorId,
|
||||
limit,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
numToDisplay,
|
||||
normalize,
|
||||
}) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
|
||||
// Get monitor, if we can't find it, abort with error
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
if (monitor === null || monitor === undefined) {
|
||||
@@ -404,7 +403,6 @@ const getMonitorStatsById = async (req) => {
|
||||
}
|
||||
|
||||
// Get query params
|
||||
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
|
||||
const sort = sortOrder === "asc" ? 1 : -1;
|
||||
|
||||
// Get Checks for monitor in date range requested
|
||||
@@ -454,10 +452,8 @@ const getMonitorStatsById = async (req) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getHardwareDetailsById = async (req) => {
|
||||
const getHardwareDetailsById = async ({ monitorId, dateRange }) => {
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
const { dateRange } = req.query;
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
const dates = getDateRange(dateRange);
|
||||
const formatLookup = {
|
||||
@@ -509,8 +505,16 @@ const getMonitorById = async (monitorId) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getMonitorsByTeamId = async (req) => {
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const getMonitorsByTeamId = async ({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
}) => {
|
||||
limit = parseInt(limit);
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
@@ -519,7 +523,7 @@ const getMonitorsByTeamId = async (req) => {
|
||||
order = "asc";
|
||||
}
|
||||
// Build match stage
|
||||
const matchStage = { teamId: ObjectId.createFromHexString(req.params.teamId) };
|
||||
const matchStage = { teamId: ObjectId.createFromHexString(teamId) };
|
||||
if (type !== undefined) {
|
||||
matchStage.type = Array.isArray(type) ? { $in: type } : type;
|
||||
}
|
||||
@@ -557,16 +561,15 @@ const getMonitorsByTeamId = async (req) => {
|
||||
return { summary, monitors, filteredMonitors: normalizedFilteredMonitors };
|
||||
};
|
||||
|
||||
const getMonitorsAndSummaryByTeamId = async (req) => {
|
||||
const getMonitorsAndSummaryByTeamId = async ({ type, explain, teamId }) => {
|
||||
try {
|
||||
const { type } = req.query;
|
||||
const teamId = ObjectId.createFromHexString(req.params.teamId);
|
||||
const matchStage = { teamId };
|
||||
const parsedTeamId = ObjectId.createFromHexString(teamId);
|
||||
const matchStage = { teamId: parsedTeamId };
|
||||
if (type !== undefined) {
|
||||
matchStage.type = Array.isArray(type) ? { $in: type } : type;
|
||||
}
|
||||
|
||||
if (req.explain === true) {
|
||||
if (explain === true) {
|
||||
return Monitor.aggregate(
|
||||
buildMonitorsAndSummaryByTeamIdPipeline({ matchStage })
|
||||
).explain("executionStats");
|
||||
@@ -584,9 +587,18 @@ const getMonitorsAndSummaryByTeamId = async (req) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getMonitorsWithChecksByTeamId = async (req) => {
|
||||
const getMonitorsWithChecksByTeamId = async ({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
explain,
|
||||
}) => {
|
||||
try {
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
limit = parseInt(limit);
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
@@ -594,14 +606,14 @@ const getMonitorsWithChecksByTeamId = async (req) => {
|
||||
field = "name";
|
||||
order = "asc";
|
||||
}
|
||||
const teamId = ObjectId.createFromHexString(req.params.teamId);
|
||||
const parsedTeamId = ObjectId.createFromHexString(teamId);
|
||||
// Build match stage
|
||||
const matchStage = { teamId };
|
||||
const matchStage = { teamId: parsedTeamId };
|
||||
if (type !== undefined) {
|
||||
matchStage.type = Array.isArray(type) ? { $in: type } : type;
|
||||
}
|
||||
|
||||
if (req.explain === true) {
|
||||
if (explain === true) {
|
||||
return Monitor.aggregate(
|
||||
buildMonitorsWithChecksByTeamIdPipeline({
|
||||
matchStage,
|
||||
@@ -653,9 +665,9 @@ const getMonitorsWithChecksByTeamId = async (req) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const createMonitor = async (req, res) => {
|
||||
const createMonitor = async ({ body, teamId, userId }) => {
|
||||
try {
|
||||
const monitor = new Monitor({ ...req.body });
|
||||
const monitor = new Monitor({ ...body, teamId, userId });
|
||||
const saved = await monitor.save();
|
||||
return saved;
|
||||
} catch (error) {
|
||||
@@ -694,15 +706,15 @@ const createBulkMonitors = async (req) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const deleteMonitor = async (req, res) => {
|
||||
const deleteMonitor = async ({ monitorId }) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
|
||||
const monitorId = req.params.monitorId;
|
||||
try {
|
||||
const monitor = await Monitor.findByIdAndDelete(monitorId);
|
||||
|
||||
if (!monitor) {
|
||||
throw new Error(stringService.getDbFindMonitorById(monitorId));
|
||||
}
|
||||
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
@@ -788,6 +800,29 @@ const addDemoMonitors = async (userId, teamId) => {
|
||||
}
|
||||
};
|
||||
|
||||
const pauseMonitor = async ({ monitorId }) => {
|
||||
try {
|
||||
const monitor = await Monitor.findOneAndUpdate(
|
||||
{ _id: monitorId },
|
||||
[
|
||||
{
|
||||
$set: {
|
||||
isActive: { $not: "$isActive" },
|
||||
status: "$$REMOVE",
|
||||
},
|
||||
},
|
||||
],
|
||||
{ new: true }
|
||||
);
|
||||
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "pauseMonitor";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
getAllMonitors,
|
||||
getAllMonitorsWithUptimeStats,
|
||||
@@ -805,6 +840,7 @@ export {
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
getHardwareDetailsById,
|
||||
pauseMonitor,
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
@@ -902,102 +902,6 @@ const buildGetMonitorsByTeamIdPipeline = (req) => {
|
||||
];
|
||||
};
|
||||
|
||||
const buildDePINDetailsByDateRange = (monitor, dates, dateString) => {
|
||||
return [
|
||||
{
|
||||
$match: {
|
||||
monitorId: monitor._id,
|
||||
updatedAt: { $gte: dates.start, $lte: dates.end },
|
||||
},
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
city: 1,
|
||||
updatedAt: 1,
|
||||
"location.lat": 1,
|
||||
"location.lng": 1,
|
||||
responseTime: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
$facet: {
|
||||
groupedMapChecks: [
|
||||
{
|
||||
$group: {
|
||||
_id: {
|
||||
city: "$city",
|
||||
lat: "$location.lat",
|
||||
lng: "$location.lng",
|
||||
},
|
||||
|
||||
avgResponseTime: {
|
||||
$avg: "$responseTime",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
groupedChecks: [
|
||||
{
|
||||
$group: {
|
||||
_id: {
|
||||
date: {
|
||||
$dateToString: {
|
||||
format: dateString,
|
||||
date: "$updatedAt",
|
||||
},
|
||||
},
|
||||
},
|
||||
avgResponseTime: {
|
||||
$avg: "$responseTime",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$sort: {
|
||||
"_id.date": 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
groupedMapChecks: "$groupedMapChecks",
|
||||
groupedChecks: "$groupedChecks",
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const buildDePINLatestChecks = (monitor) => {
|
||||
return [
|
||||
{
|
||||
$match: {
|
||||
monitorId: monitor._id,
|
||||
},
|
||||
},
|
||||
{
|
||||
$sort: { updatedAt: -1 },
|
||||
},
|
||||
{
|
||||
$limit: 5,
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
responseTime: 1,
|
||||
city: 1,
|
||||
countryCode: 1,
|
||||
uptBurnt: {
|
||||
$toString: {
|
||||
$ifNull: ["$uptBurnt", 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export {
|
||||
buildUptimeDetailsPipeline,
|
||||
buildHardwareDetailsPipeline,
|
||||
@@ -1008,6 +912,4 @@ export {
|
||||
buildMonitorsAndSummaryByTeamIdPipeline,
|
||||
buildMonitorsWithChecksByTeamIdPipeline,
|
||||
buildFilteredMonitorsByTeamIdPipeline,
|
||||
buildDePINDetailsByDateRange,
|
||||
buildDePINLatestChecks,
|
||||
};
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import StatusPage from "../../models/StatusPage.js";
|
||||
import Monitor from "../../models/Monitor.js";
|
||||
import { NormalizeData } from "../../../utils/dataUtils.js";
|
||||
import ServiceRegistry from "../../../service/serviceRegistry.js";
|
||||
import StringService from "../../../service/stringService.js";
|
||||
|
||||
const SERVICE_NAME = "statusPageModule";
|
||||
|
||||
const createStatusPage = async (statusPageData, image) => {
|
||||
const createStatusPage = async ({ statusPageData, image, userId, teamId }) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
|
||||
try {
|
||||
const statusPage = new StatusPage({ ...statusPageData });
|
||||
const statusPage = new StatusPage({
|
||||
...statusPageData,
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
if (image) {
|
||||
statusPage.logo = {
|
||||
data: image.buffer,
|
||||
@@ -103,7 +106,10 @@ const getStatusPage = async (url) => {
|
||||
},
|
||||
},
|
||||
{
|
||||
$unwind: "$monitors",
|
||||
$unwind: {
|
||||
path: "$monitors",
|
||||
preserveNullAndEmptyArrays: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
@@ -150,9 +156,17 @@ const getStatusPage = async (url) => {
|
||||
url: 1,
|
||||
},
|
||||
monitors: {
|
||||
$sortArray: {
|
||||
input: "$monitors",
|
||||
sortBy: { orderIndex: 1 },
|
||||
$filter: {
|
||||
input: {
|
||||
$sortArray: {
|
||||
input: "$monitors",
|
||||
sortBy: { orderIndex: 1 },
|
||||
},
|
||||
},
|
||||
as: "monitor",
|
||||
cond: {
|
||||
$ne: ["$$monitor.orderIndex", -1],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -11,7 +11,15 @@ class CheckRoutes {
|
||||
}
|
||||
|
||||
initRoutes() {
|
||||
this.router.get("/team", this.checkController.getChecksByTeam);
|
||||
this.router.delete(
|
||||
"/team",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.checkController.deleteChecksByTeamId
|
||||
);
|
||||
|
||||
this.router.get("/:monitorId", this.checkController.getChecksByMonitor);
|
||||
|
||||
this.router.post(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
@@ -23,14 +31,6 @@ class CheckRoutes {
|
||||
this.checkController.deleteChecks
|
||||
);
|
||||
|
||||
this.router.get("/team/:teamId", this.checkController.getChecksByTeam);
|
||||
|
||||
this.router.delete(
|
||||
"/team/:teamId",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.checkController.deleteChecksByTeamId
|
||||
);
|
||||
|
||||
this.router.put(
|
||||
"/team/ttl",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
|
||||
@@ -35,17 +35,17 @@ class MonitorRoutes {
|
||||
fetchMonitorCertificate
|
||||
);
|
||||
});
|
||||
this.router.get("/team", this.monitorController.getMonitorsByTeamId);
|
||||
|
||||
this.router.get("/:monitorId", this.monitorController.getMonitorById);
|
||||
|
||||
this.router.get("/team/:teamId", this.monitorController.getMonitorsByTeamId);
|
||||
|
||||
this.router.get(
|
||||
"/summary/team/:teamId",
|
||||
"/summary/team",
|
||||
this.monitorController.getMonitorsAndSummaryByTeamId
|
||||
);
|
||||
|
||||
this.router.get(
|
||||
"/team/:teamId/with-checks",
|
||||
"/team/with-checks",
|
||||
this.monitorController.getMonitorsWithChecksByTeamId
|
||||
);
|
||||
|
||||
|
||||
@@ -17,10 +17,7 @@ class NotificationRoutes {
|
||||
|
||||
this.router.post("/", this.notificationController.createNotification);
|
||||
|
||||
this.router.get(
|
||||
"/team/:teamId",
|
||||
this.notificationController.getNotificationsByTeamId
|
||||
);
|
||||
this.router.get("/team", this.notificationController.getNotificationsByTeamId);
|
||||
|
||||
this.router.delete("/:id", this.notificationController.deleteNotification);
|
||||
|
||||
|
||||
@@ -12,11 +12,7 @@ class StatusPageRoutes {
|
||||
|
||||
initRoutes() {
|
||||
this.router.get("/", this.statusPageController.getStatusPage);
|
||||
this.router.get(
|
||||
"/team/:teamId",
|
||||
verifyJWT,
|
||||
this.statusPageController.getStatusPagesByTeamId
|
||||
);
|
||||
this.router.get("/team", verifyJWT, this.statusPageController.getStatusPagesByTeamId);
|
||||
this.router.get("/:url", this.statusPageController.getStatusPageByUrl);
|
||||
|
||||
this.router.post(
|
||||
|
||||
@@ -126,9 +126,7 @@ const getMonitorByIdQueryValidation = joi.object({
|
||||
normalize: joi.boolean(),
|
||||
});
|
||||
|
||||
const getMonitorsByTeamIdParamValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
const getMonitorsByTeamIdParamValidation = joi.object({});
|
||||
|
||||
const getMonitorsByTeamIdQueryValidation = joi.object({
|
||||
limit: joi.number(),
|
||||
@@ -167,8 +165,6 @@ const getCertificateParamValidation = joi.object({
|
||||
|
||||
const createMonitorBodyValidation = joi.object({
|
||||
_id: joi.string(),
|
||||
userId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
name: joi.string().required(),
|
||||
description: joi.string().required(),
|
||||
type: joi.string().required(),
|
||||
@@ -190,7 +186,12 @@ const createMonitorBodyValidation = joi.object({
|
||||
matchMethod: joi.string(),
|
||||
});
|
||||
|
||||
const createMonitorsBodyValidation = joi.array().items(createMonitorBodyValidation);
|
||||
const createMonitorsBodyValidation = joi.array().items(
|
||||
createMonitorBodyValidation.keys({
|
||||
userId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
})
|
||||
);
|
||||
|
||||
const editMonitorBodyValidation = joi.object({
|
||||
name: joi.string(),
|
||||
@@ -303,9 +304,7 @@ const getChecksQueryValidation = joi.object({
|
||||
status: joi.boolean(),
|
||||
});
|
||||
|
||||
const getTeamChecksParamValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
const getTeamChecksParamValidation = joi.object({});
|
||||
|
||||
const getTeamChecksQueryValidation = joi.object({
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
@@ -321,9 +320,7 @@ const deleteChecksParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const deleteChecksByTeamIdParamValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
const deleteChecksByTeamIdParamValidation = joi.object({});
|
||||
|
||||
const updateChecksTTLBodyValidation = joi.object({
|
||||
ttl: joi.number().required(),
|
||||
@@ -430,8 +427,6 @@ const getStatusPageQueryValidation = joi.object({
|
||||
});
|
||||
|
||||
const createStatusPageBodyValidation = joi.object({
|
||||
userId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
type: joi.string().valid("uptime").required(),
|
||||
companyName: joi.string().required(),
|
||||
url: joi
|
||||
|
||||
Reference in New Issue
Block a user