Merge pull request #1712 from bluewave-labs/fix/fe/du-ui-fixes-and-refactor
fix: fe/du UI fixes and refactor
This commit is contained in:
17 files changed
+601
-574
No files matched your search
+5
-5
@@ -2,16 +2,16 @@ 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 { 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";
|
||||
} from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
|
||||
import Settings from "../../assets/icons/settings-bold.svg?react";
|
||||
import PropTypes from "prop-types";
|
||||
import Dialog from "../../../../../Components/Dialog";
|
||||
import Dialog from "../../Components/Dialog";
|
||||
|
||||
const ActionsMenu = ({
|
||||
monitor,
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import Dot from "../../../../../Components/Dot";
|
||||
import Dot from "../Dot";
|
||||
/**
|
||||
* Host component.
|
||||
* This subcomponent receives a params object and displays the host details.
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
const useMonitorUtils = () => {
|
||||
const getMonitorWithPercentage = useCallback((monitor, theme) => {
|
||||
let uptimePercentage = "";
|
||||
let percentageColor = "";
|
||||
|
||||
if (monitor.uptimePercentage !== undefined) {
|
||||
uptimePercentage =
|
||||
monitor.uptimePercentage === 0
|
||||
? "0"
|
||||
: (monitor.uptimePercentage * 100).toFixed(2);
|
||||
|
||||
percentageColor =
|
||||
monitor.uptimePercentage < 0.25
|
||||
? theme.palette.error.main
|
||||
: monitor.uptimePercentage < 0.5
|
||||
? theme.palette.warning.main
|
||||
: monitor.uptimePercentage < 0.75
|
||||
? theme.palette.success.main
|
||||
: theme.palette.success.main;
|
||||
}
|
||||
|
||||
return {
|
||||
id: monitor._id,
|
||||
name: monitor.name,
|
||||
url: monitor.url,
|
||||
title: monitor.name,
|
||||
percentage: uptimePercentage,
|
||||
percentageColor,
|
||||
monitor: monitor,
|
||||
};
|
||||
}, []);
|
||||
|
||||
const determineState = useCallback((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";
|
||||
}, []);
|
||||
|
||||
return { getMonitorWithPercentage, determineState };
|
||||
};
|
||||
|
||||
export { useMonitorUtils };
|
||||
+55
-47
@@ -8,6 +8,8 @@ import {
|
||||
ResponsiveContainer,
|
||||
Text,
|
||||
} from "recharts";
|
||||
import ChartBox from "../../../../../Components/Charts/ChartBox";
|
||||
import ResponseTimeIcon from "../../../../../assets/icons/response-time-icon.svg?react";
|
||||
import { Box, Stack, Typography } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useState } from "react";
|
||||
@@ -22,67 +24,73 @@ const CustomToolTip = ({ active, payload, label }) => {
|
||||
? payload[0]?.payload?.originalAvgResponseTime
|
||||
: (payload[0]?.payload?.avgResponseTime ?? 0);
|
||||
return (
|
||||
<Box
|
||||
className="area-tooltip"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
}}
|
||||
<ChartBox
|
||||
icon={<ResponseTimeIcon />}
|
||||
header="Response Times"
|
||||
sx={{ padding: 0 }}
|
||||
>
|
||||
<Typography
|
||||
<Box
|
||||
className="area-tooltip"
|
||||
sx={{
|
||||
color: theme.palette.text.tertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
backgroundColor: theme.palette.background.main,
|
||||
border: 1,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
py: theme.spacing(2),
|
||||
px: theme.spacing(4),
|
||||
}}
|
||||
>
|
||||
{formatDateWithTz(label, "ddd, MMMM D, YYYY, h:mm A", uiTimezone)}
|
||||
</Typography>
|
||||
<Box mt={theme.spacing(1)}>
|
||||
<Box
|
||||
display="inline-block"
|
||||
width={theme.spacing(4)}
|
||||
height={theme.spacing(4)}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
sx={{ borderRadius: "50%" }}
|
||||
/>
|
||||
<Stack
|
||||
display="inline-flex"
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
ml={theme.spacing(3)}
|
||||
<Typography
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
color: theme.palette.text.tertiary,
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{ opacity: 0.8 }}
|
||||
{formatDateWithTz(label, "ddd, MMMM D, YYYY, h:mm A", uiTimezone)}
|
||||
</Typography>
|
||||
<Box mt={theme.spacing(1)}>
|
||||
<Box
|
||||
display="inline-block"
|
||||
width={theme.spacing(4)}
|
||||
height={theme.spacing(4)}
|
||||
backgroundColor={theme.palette.primary.main}
|
||||
sx={{ borderRadius: "50%" }}
|
||||
/>
|
||||
<Stack
|
||||
display="inline-flex"
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
ml={theme.spacing(3)}
|
||||
sx={{
|
||||
"& span": {
|
||||
color: theme.palette.text.tertiary,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Response Time
|
||||
</Typography>{" "}
|
||||
<Typography component="span">
|
||||
{Math.floor(responseTime)}
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{ opacity: 0.8 }}
|
||||
>
|
||||
{" "}
|
||||
ms
|
||||
Response Time
|
||||
</Typography>{" "}
|
||||
<Typography component="span">
|
||||
{Math.floor(responseTime)}
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{ opacity: 0.8 }}
|
||||
>
|
||||
{" "}
|
||||
ms
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
{/* Display original value */}
|
||||
</Box>
|
||||
{/* Display original value */}
|
||||
</Box>
|
||||
</ChartBox>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const MonitorHeader = ({ monitor }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack direction="row">
|
||||
<Stack gap={theme.spacing(2)}>
|
||||
<Typography variant="h1">{monitor.name}</Typography>
|
||||
<Typography variant="h2">
|
||||
Distributed Uptime Monitoring powered by DePIN
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
MonitorHeader.propTypes = {
|
||||
monitor: PropTypes.object,
|
||||
};
|
||||
|
||||
export default MonitorHeader;
|
||||
@@ -0,0 +1,62 @@
|
||||
// Components
|
||||
import { Stack } from "@mui/material";
|
||||
import StatBox from "../../../../../Components/StatBox";
|
||||
import LastUpdate from "../LastUpdate";
|
||||
import UptLogo from "../../../../../assets/icons/upt_logo.png";
|
||||
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const StatBoxes = ({ monitor, lastUpdateTrigger }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<StatBox
|
||||
heading="Avg Response Time"
|
||||
subHeading={`${Math.floor(monitor?.avgResponseTime ?? 0)} ms`}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Checking every"
|
||||
subHeading={`${(monitor?.interval ?? 0) / 1000} seconds`}
|
||||
/>
|
||||
<StatBox
|
||||
heading={"Last check"}
|
||||
subHeading={
|
||||
<LastUpdate
|
||||
lastUpdateTime={monitor?.timeSinceLastCheck ?? 0}
|
||||
suffix={"seconds ago"}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Last server push"
|
||||
subHeading={
|
||||
<LastUpdate
|
||||
suffix={"seconds ago"}
|
||||
lastUpdateTime={0}
|
||||
trigger={lastUpdateTrigger}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<StatBox
|
||||
heading="UPT Burned"
|
||||
subHeading={monitor?.totalUptBurnt ?? 0}
|
||||
img={UptLogo}
|
||||
alt="Upt Logo"
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
StatBoxes.propTypes = {
|
||||
monitor: PropTypes.object,
|
||||
lastUpdateTrigger: PropTypes.number,
|
||||
};
|
||||
|
||||
export default StatBoxes;
|
||||
@@ -0,0 +1,119 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const getRandomDevice = () => {
|
||||
const manufacturers = {
|
||||
Apple: ["iPhone 15 Pro Max", "iPhone 15", "iPhone 14 Pro", "iPhone 14", "iPhone 13"],
|
||||
Samsung: [
|
||||
"Galaxy S23 Ultra",
|
||||
"Galaxy S23+",
|
||||
"Galaxy S23",
|
||||
"Galaxy Z Fold5",
|
||||
"Galaxy Z Flip5",
|
||||
],
|
||||
Google: ["Pixel 8 Pro", "Pixel 8", "Pixel 7a", "Pixel 7", "Pixel 6a"],
|
||||
OnePlus: [
|
||||
"OnePlus 11",
|
||||
"OnePlus 10T",
|
||||
"OnePlus Nord 3",
|
||||
"OnePlus 10 Pro",
|
||||
"OnePlus Nord 2T",
|
||||
],
|
||||
Xiaomi: ["13 Pro", "13", "Redmi Note 12", "POCO F5", "Redmi 12"],
|
||||
Huawei: ["P60 Pro", "Mate X3", "Nova 11", "P50 Pro", "Mate 50"],
|
||||
Sony: ["Xperia 1 V", "Xperia 5 V", "Xperia 10 V", "Xperia Pro-I", "Xperia 1 IV"],
|
||||
Motorola: ["Edge 40 Pro", "Edge 40", "G84", "G54", "Razr 40 Ultra"],
|
||||
ASUS: [
|
||||
"ROG Phone 7",
|
||||
"Zenfone 10",
|
||||
"ROG Phone 6",
|
||||
"Zenfone 9",
|
||||
"ROG Phone 7 Ultimate",
|
||||
],
|
||||
};
|
||||
|
||||
const manufacturerNames = Object.keys(manufacturers);
|
||||
const randomManufacturer =
|
||||
manufacturerNames[Math.floor(Math.random() * manufacturerNames.length)];
|
||||
|
||||
const models = manufacturers[randomManufacturer];
|
||||
const randomModel = models[Math.floor(Math.random() * models.length)];
|
||||
|
||||
return {
|
||||
manufacturer: randomManufacturer,
|
||||
model: randomModel,
|
||||
};
|
||||
};
|
||||
const useSubscribeToDetails = ({ monitorId, dateRange }) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [connectionStatus, setConnectionStatus] = useState(undefined);
|
||||
const [retryCount, setRetryCount] = useState(0);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
const [monitor, setMonitor] = useState(undefined);
|
||||
const [lastUpdateTrigger, setLastUpdateTrigger] = useState(0);
|
||||
const [devices, setDevices] = useState(Array.from({ length: 5 }, getRandomDevice));
|
||||
const authToken = useSelector((state) => state.auth.token);
|
||||
|
||||
const prevDateRangeRef = useRef(dateRange);
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const cleanup = networkService.subscribeToDistributedUptimeDetails({
|
||||
authToken,
|
||||
monitorId,
|
||||
dateRange: dateRange,
|
||||
normalize: true,
|
||||
onUpdate: (data) => {
|
||||
if (networkError === true) {
|
||||
setNetworkError(false);
|
||||
}
|
||||
setLastUpdateTrigger(Date.now());
|
||||
const latestChecksWithDevice = data?.monitor?.latestChecks.map((check, idx) => {
|
||||
check.device = devices[idx];
|
||||
return check;
|
||||
});
|
||||
const monitorWithDevice = {
|
||||
...data.monitor,
|
||||
latestChecks: latestChecksWithDevice,
|
||||
};
|
||||
setMonitor(monitorWithDevice);
|
||||
},
|
||||
onOpen: () => {
|
||||
setConnectionStatus("up");
|
||||
setRetryCount(0); // Reset retry count on successful connection
|
||||
},
|
||||
onError: () => {
|
||||
setNetworkError(true);
|
||||
setConnectionStatus("down");
|
||||
},
|
||||
});
|
||||
return cleanup;
|
||||
} catch (error) {
|
||||
setNetworkError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [
|
||||
authToken,
|
||||
dateRange,
|
||||
monitorId,
|
||||
retryCount,
|
||||
setConnectionStatus,
|
||||
networkError,
|
||||
devices,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const hasDateRangeChanged = prevDateRangeRef.current !== dateRange;
|
||||
prevDateRangeRef.current = dateRange; // Update the ref to the current dateRange
|
||||
|
||||
if (!hasDateRangeChanged) {
|
||||
setDevices(Array.from({ length: 5 }, getRandomDevice));
|
||||
}
|
||||
}, [dateRange]);
|
||||
|
||||
return [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger];
|
||||
};
|
||||
|
||||
export default useSubscribeToDetails;
|
||||
@@ -1,324 +1,102 @@
|
||||
//Components
|
||||
import DistributedUptimeMap from "./Components/DistributedUptimeMap";
|
||||
import Breadcrumbs from "../../../Components/Breadcrumbs";
|
||||
import { Stack, Typography, Box, Button, ButtonGroup } from "@mui/material";
|
||||
import ChartBox from "../../../Components/Charts/ChartBox";
|
||||
import StatBox from "../../../Components/StatBox";
|
||||
import ResponseTimeIcon from "../../../assets/icons/response-time-icon.svg?react";
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import DeviceTicker from "./Components/DeviceTicker";
|
||||
import DistributedUptimeResponseChart from "./Components/DistributedUptimeResponseChart";
|
||||
import UptLogo from "../../../assets/icons/upt_logo.png";
|
||||
import LastUpdate from "./Components/LastUpdate";
|
||||
import NextExpectedCheck from "./Components/NextExpectedCheck";
|
||||
import Footer from "./Components/Footer";
|
||||
import StatBoxes from "./Components/StatBoxes";
|
||||
import MonitorHeader from "./Components/MonitorHeader";
|
||||
import MonitorTimeFrameHeader from "../../../Components/MonitorTimeFrameHeader";
|
||||
import GenericFallback from "../../../Components/GenericFallback";
|
||||
|
||||
//Utils
|
||||
import { networkService } from "../../../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useEffect, useState, useCallback, useRef } from "react";
|
||||
import { useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
//Constants
|
||||
const BASE_BOX_PADDING_VERTICAL = 8;
|
||||
const BASE_BOX_PADDING_HORIZONTAL = 8;
|
||||
const MAX_RETRIES = 10;
|
||||
const RETRY_DELAY = 5000;
|
||||
|
||||
function getRandomDevice() {
|
||||
const manufacturers = {
|
||||
Apple: ["iPhone 15 Pro Max", "iPhone 15", "iPhone 14 Pro", "iPhone 14", "iPhone 13"],
|
||||
Samsung: [
|
||||
"Galaxy S23 Ultra",
|
||||
"Galaxy S23+",
|
||||
"Galaxy S23",
|
||||
"Galaxy Z Fold5",
|
||||
"Galaxy Z Flip5",
|
||||
],
|
||||
Google: ["Pixel 8 Pro", "Pixel 8", "Pixel 7a", "Pixel 7", "Pixel 6a"],
|
||||
OnePlus: [
|
||||
"OnePlus 11",
|
||||
"OnePlus 10T",
|
||||
"OnePlus Nord 3",
|
||||
"OnePlus 10 Pro",
|
||||
"OnePlus Nord 2T",
|
||||
],
|
||||
Xiaomi: ["13 Pro", "13", "Redmi Note 12", "POCO F5", "Redmi 12"],
|
||||
Huawei: ["P60 Pro", "Mate X3", "Nova 11", "P50 Pro", "Mate 50"],
|
||||
Sony: ["Xperia 1 V", "Xperia 5 V", "Xperia 10 V", "Xperia Pro-I", "Xperia 1 IV"],
|
||||
Motorola: ["Edge 40 Pro", "Edge 40", "G84", "G54", "Razr 40 Ultra"],
|
||||
ASUS: [
|
||||
"ROG Phone 7",
|
||||
"Zenfone 10",
|
||||
"ROG Phone 6",
|
||||
"Zenfone 9",
|
||||
"ROG Phone 7 Ultimate",
|
||||
],
|
||||
};
|
||||
|
||||
const manufacturerNames = Object.keys(manufacturers);
|
||||
const randomManufacturer =
|
||||
manufacturerNames[Math.floor(Math.random() * manufacturerNames.length)];
|
||||
|
||||
const models = manufacturers[randomManufacturer];
|
||||
const randomModel = models[Math.floor(Math.random() * models.length)];
|
||||
|
||||
return {
|
||||
manufacturer: randomManufacturer,
|
||||
model: randomModel,
|
||||
};
|
||||
}
|
||||
|
||||
// export const StatBox = ({ heading, value, img, altTxt }) => {
|
||||
// const theme = useTheme();
|
||||
// return (
|
||||
// <Stack
|
||||
// direction="row"
|
||||
// width={"25%"}
|
||||
// justifyContent="center"
|
||||
// sx={{
|
||||
// padding: `${theme.spacing(BASE_BOX_PADDING_VERTICAL)} ${theme.spacing(BASE_BOX_PADDING_HORIZONTAL)}`,
|
||||
// backgroundColor: theme.palette.background.main,
|
||||
// border: 1,
|
||||
// borderStyle: "solid",
|
||||
// borderColor: theme.palette.primary.lowContrast,
|
||||
// }}
|
||||
// >
|
||||
// {img && (
|
||||
// <img
|
||||
// style={{ marginRight: theme.spacing(8) }}
|
||||
// height={30}
|
||||
// width={30}
|
||||
// src={img}
|
||||
// alt={altTxt}
|
||||
// />
|
||||
// )}
|
||||
// <Stack direction="column">
|
||||
// <Typography variant="h2">{heading}</Typography>
|
||||
// <Typography>{value}</Typography>
|
||||
// </Stack>
|
||||
// </Stack>
|
||||
// );
|
||||
// };
|
||||
import useSubscribeToDetails from "./Hooks/useSubscribeToDetails";
|
||||
|
||||
const DistributedUptimeDetails = () => {
|
||||
// Redux State
|
||||
const { authToken } = useSelector((state) => state.auth);
|
||||
const { mode } = useSelector((state) => state.ui);
|
||||
const { monitorId } = useParams();
|
||||
|
||||
// Local State
|
||||
// const [hoveredUptimeData, setHoveredUptimeData] = useState(null);
|
||||
// const [hoveredIncidentsData, setHoveredIncidentsData] = useState(null);
|
||||
const [retryCount, setRetryCount] = useState(0);
|
||||
const [connectionStatus, setConnectionStatus] = useState("down");
|
||||
const [lastUpdateTrigger, setLastUpdateTrigger] = useState(Date.now());
|
||||
const [dateRange, setDateRange] = useState("day");
|
||||
const [monitor, setMonitor] = useState(null);
|
||||
const [devices, setDevices] = useState([]);
|
||||
|
||||
// Refs
|
||||
const prevDateRangeRef = useRef(dateRange);
|
||||
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
const { monitorId } = useParams();
|
||||
|
||||
const [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger] =
|
||||
useSubscribeToDetails({ monitorId, dateRange });
|
||||
// Constants
|
||||
const BREADCRUMBS = [
|
||||
{ name: "Distributed Uptime", path: "/distributed-uptime" },
|
||||
{ name: "Details", path: `/distributed-uptime/${monitorId}` },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
const hasDateRangeChanged = prevDateRangeRef.current !== dateRange;
|
||||
prevDateRangeRef.current = dateRange; // Update the ref to the current dateRange
|
||||
if (networkError) {
|
||||
return (
|
||||
<GenericFallback>
|
||||
<Typography
|
||||
variant="h1"
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
Network error
|
||||
</Typography>
|
||||
<Typography>Please check your connection</Typography>
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasDateRangeChanged) {
|
||||
setDevices(Array.from({ length: 5 }, getRandomDevice));
|
||||
}
|
||||
}, [dateRange]);
|
||||
|
||||
const connectToService = useCallback(() => {
|
||||
return networkService.subscribeToDistributedUptimeDetails({
|
||||
authToken,
|
||||
monitorId,
|
||||
dateRange: dateRange,
|
||||
normalize: true,
|
||||
onUpdate: (data) => {
|
||||
setLastUpdateTrigger(Date.now());
|
||||
const latestChecksWithDevice = data?.monitor?.latestChecks.map((check, idx) => {
|
||||
check.device = devices[idx];
|
||||
return check;
|
||||
});
|
||||
const monitorWithDevice = {
|
||||
...data.monitor,
|
||||
latestChecks: latestChecksWithDevice,
|
||||
};
|
||||
setMonitor(monitorWithDevice);
|
||||
},
|
||||
onOpen: () => {
|
||||
setConnectionStatus("up");
|
||||
setRetryCount(0); // Reset retry count on successful connection
|
||||
},
|
||||
onError: () => {
|
||||
setConnectionStatus("down");
|
||||
console.log("Error, attempting reconnect...");
|
||||
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
setTimeout(() => {
|
||||
setRetryCount((prev) => prev + 1);
|
||||
connectToService();
|
||||
}, RETRY_DELAY);
|
||||
} else {
|
||||
console.log("Max retries reached");
|
||||
}
|
||||
},
|
||||
});
|
||||
}, [authToken, monitorId, dateRange, retryCount, devices]);
|
||||
|
||||
useEffect(() => {
|
||||
const devices = Array.from({ length: 5 }, getRandomDevice);
|
||||
const cleanup = connectToService(devices);
|
||||
return cleanup;
|
||||
}, [connectToService]);
|
||||
if (typeof monitor === "undefined" || monitor.totalChecks === 0) {
|
||||
return (
|
||||
<Stack gap={theme.spacing(10)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<GenericFallback>
|
||||
<Typography>There is no check history for this monitor yet.</Typography>
|
||||
</GenericFallback>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
monitor && (
|
||||
<Stack
|
||||
direction="column"
|
||||
gap={theme.spacing(10)}
|
||||
>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<MonitorHeader monitor={monitor} />
|
||||
<StatBoxes
|
||||
monitor={monitor}
|
||||
lastUpdateTrigger={lastUpdateTrigger}
|
||||
/>
|
||||
<NextExpectedCheck
|
||||
lastUpdateTime={monitor?.timeSinceLastCheck ?? 0}
|
||||
interval={monitor?.interval ?? 0}
|
||||
trigger={lastUpdateTrigger}
|
||||
/>
|
||||
<MonitorTimeFrameHeader
|
||||
dateRange={dateRange}
|
||||
setDateRange={setDateRange}
|
||||
/>
|
||||
<DistributedUptimeResponseChart checks={monitor?.groupedChecks ?? []} />
|
||||
<Stack
|
||||
direction="column"
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
{monitor?.url !== "https://jup.ag/" &&
|
||||
monitor?.url !== "https://explorer.solana.com/" && (
|
||||
<Box>
|
||||
<Typography
|
||||
component="h1"
|
||||
variant="h1"
|
||||
>
|
||||
{monitor.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<Typography variant="h2">
|
||||
Distributed Uptime Monitoring powered by DePIN
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<StatBox
|
||||
heading="Avg Response Time"
|
||||
subHeading={`${Math.floor(monitor?.avgResponseTime ?? 0)} ms`}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Checking every"
|
||||
subHeading={`${(monitor?.interval ?? 0) / 1000} seconds`}
|
||||
/>
|
||||
<StatBox
|
||||
heading={"Last check"}
|
||||
subHeading={
|
||||
<LastUpdate
|
||||
lastUpdateTime={monitor?.timeSinceLastCheck ?? 0}
|
||||
suffix={"seconds ago"}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Last server push"
|
||||
subHeading={
|
||||
<LastUpdate
|
||||
suffix={"seconds ago"}
|
||||
lastUpdateTime={0}
|
||||
trigger={lastUpdateTrigger}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<StatBox
|
||||
heading="UPT Burned"
|
||||
subHeading={monitor?.totalUptBurnt ?? 0}
|
||||
img={UptLogo}
|
||||
alt="Upt Logo"
|
||||
/>
|
||||
</Stack>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<NextExpectedCheck
|
||||
lastUpdateTime={monitor?.timeSinceLastCheck ?? 0}
|
||||
interval={monitor?.interval ?? 0}
|
||||
trigger={lastUpdateTrigger}
|
||||
/>
|
||||
</Box>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="flex-end"
|
||||
gap={theme.spacing(4)}
|
||||
mb={theme.spacing(8)}
|
||||
>
|
||||
<Typography variant="body2">
|
||||
Showing statistics for past{" "}
|
||||
{dateRange === "day"
|
||||
? "24 hours"
|
||||
: dateRange === "week"
|
||||
? "7 days"
|
||||
: "30 days"}
|
||||
.
|
||||
</Typography>
|
||||
<ButtonGroup sx={{ height: 32 }}>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(dateRange === "day").toString()}
|
||||
onClick={() => setDateRange("day")}
|
||||
>
|
||||
Day
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(dateRange === "week").toString()}
|
||||
onClick={() => setDateRange("week")}
|
||||
>
|
||||
Week
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(dateRange === "month").toString()}
|
||||
onClick={() => setDateRange("month")}
|
||||
>
|
||||
Month
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
<ChartBox
|
||||
icon={<ResponseTimeIcon />}
|
||||
header="Response Times"
|
||||
sx={{ padding: 0 }}
|
||||
>
|
||||
<DistributedUptimeResponseChart checks={monitor?.groupedChecks ?? []} />
|
||||
</ChartBox>
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<DistributedUptimeMap
|
||||
checks={monitor?.groupedMapChecks ?? []}
|
||||
height={"100%"}
|
||||
width={"100%"}
|
||||
/>
|
||||
<DeviceTicker
|
||||
width={"25vw"}
|
||||
data={monitor?.latestChecks ?? []}
|
||||
connectionStatus={connectionStatus}
|
||||
/>
|
||||
</Stack>
|
||||
<Footer />
|
||||
<DistributedUptimeMap
|
||||
checks={monitor?.groupedMapChecks ?? []}
|
||||
height={"100%"}
|
||||
width={"100%"}
|
||||
/>
|
||||
<DeviceTicker
|
||||
width={"25vw"}
|
||||
data={monitor?.latestChecks ?? []}
|
||||
connectionStatus={connectionStatus}
|
||||
/>
|
||||
</Stack>
|
||||
)
|
||||
<Footer />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// Components
|
||||
import DataTable from "../../../../../Components/Table";
|
||||
import BarChart from "../../../../../Components/Charts/BarChart";
|
||||
import { Box } from "@mui/material";
|
||||
import { StatusLabel } from "../../../../../Components/Label";
|
||||
import Host from "../../../../../Components/Host";
|
||||
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useMonitorUtils } from "../../../../../Hooks/useMonitorUtils";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
// Constants
|
||||
const TYPE_MAP = {
|
||||
distributed_http: "Distributed HTTP",
|
||||
};
|
||||
|
||||
const MonitorTable = ({ isLoading, monitors }) => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
const { determineState } = useMonitorUtils();
|
||||
|
||||
const headers = [
|
||||
{
|
||||
id: "name",
|
||||
content: <Box>Host</Box>,
|
||||
render: (row) => (
|
||||
<Host
|
||||
key={row._id}
|
||||
url={row.url}
|
||||
title={row.title}
|
||||
percentageColor={row.percentageColor}
|
||||
percentage={row.percentage}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
content: <Box width="max-content"> Status</Box>,
|
||||
render: (row) => {
|
||||
const status = determineState(row?.monitor);
|
||||
return (
|
||||
<StatusLabel
|
||||
status={status}
|
||||
text={status}
|
||||
customStyles={{ textTransform: "capitalize" }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "responseTime",
|
||||
content: "Response Time",
|
||||
render: (row) => <BarChart checks={row?.monitor?.checks.slice().reverse()} />,
|
||||
},
|
||||
{
|
||||
id: "type",
|
||||
content: "Type",
|
||||
render: (row) => <span>{TYPE_MAP[row.monitor.type]}</span>,
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
content: "Actions",
|
||||
render: (row) => <span>{"TODO"}</span>,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
shouldRender={!isLoading}
|
||||
headers={headers}
|
||||
data={monitors}
|
||||
config={{
|
||||
rowSX: {
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
},
|
||||
},
|
||||
onRowClick: (row) => {
|
||||
navigate(`/distributed-uptime/${row.id}`);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
MonitorTable.propTypes = {
|
||||
isLoading: PropTypes.bool,
|
||||
monitors: PropTypes.array,
|
||||
};
|
||||
|
||||
export default MonitorTable;
|
||||
@@ -0,0 +1,58 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
|
||||
const useSubscribeToMonitors = () => {
|
||||
// Redux
|
||||
const { authToken, user } = useSelector((state) => state.auth);
|
||||
|
||||
// Local state
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
const [monitors, setMonitors] = useState(undefined);
|
||||
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
|
||||
const [filteredMonitors, setFilteredMonitors] = useState(undefined);
|
||||
|
||||
const theme = useTheme();
|
||||
const { getMonitorWithPercentage } = useMonitorUtils();
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const cleanup = networkService.subscribeToDistributedUptimeMonitors({
|
||||
authToken: authToken,
|
||||
teamId: user.teamId,
|
||||
limit: 25,
|
||||
types: ["distributed_http"],
|
||||
page: 0,
|
||||
rowsPerPage: 10,
|
||||
filter: null,
|
||||
field: null,
|
||||
order: null,
|
||||
onUpdate: (data) => {
|
||||
const res = data.monitors;
|
||||
const { monitors, filteredMonitors, summary } = res;
|
||||
const mappedMonitors = filteredMonitors.map((monitor) =>
|
||||
getMonitorWithPercentage(monitor, theme)
|
||||
);
|
||||
setMonitors(monitors);
|
||||
setMonitorsSummary(summary);
|
||||
setFilteredMonitors(mappedMonitors);
|
||||
},
|
||||
});
|
||||
|
||||
return cleanup;
|
||||
} catch (error) {
|
||||
createToast({
|
||||
body: error.message,
|
||||
});
|
||||
setNetworkError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [authToken, user, getMonitorWithPercentage, theme]);
|
||||
return [isLoading, networkError, monitors, monitorsSummary, filteredMonitors];
|
||||
};
|
||||
export { useSubscribeToMonitors };
|
||||
@@ -1,185 +1,69 @@
|
||||
// Components
|
||||
import { Stack, Box, Button } from "@mui/material";
|
||||
import DataTable from "../../../Components/Table";
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import Breadcrumbs from "../../../Components/Breadcrumbs";
|
||||
import Host from "../../Uptime/Monitors/Components/Host";
|
||||
import BarChart from "../../../Components/Charts/BarChart";
|
||||
import ActionsMenu from "../../Uptime/Monitors/Components/ActionsMenu";
|
||||
import { StatusLabel } from "../../../Components/Label";
|
||||
// Utils
|
||||
import { networkService } from "../../../main";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useUtils from "../../Uptime/Monitors/Hooks/useUtils";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import CreateMonitorHeader from "../../../Components/MonitorCreateHeader";
|
||||
import MonitorTable from "./Components/MonitorTable";
|
||||
import Fallback from "../../../Components/Fallback";
|
||||
import GenericFallback from "../../../Components/GenericFallback";
|
||||
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
|
||||
import { useSubscribeToMonitors } from "./Hooks/useSubscribeToMonitors";
|
||||
// Constants
|
||||
const BREADCRUMBS = [{ name: `Distributed Uptime`, path: "/distributed-uptime" }];
|
||||
const TYPE_MAP = {
|
||||
distributed_http: "Distributed HTTP",
|
||||
};
|
||||
|
||||
const DistributedUptimeMonitors = () => {
|
||||
// Redux state
|
||||
const { authToken, user } = useSelector((state) => state.auth);
|
||||
// Local state
|
||||
const [monitors, setMonitors] = useState([]);
|
||||
const [filteredMonitors, setFilteredMonitors] = useState([]);
|
||||
const [monitorsSummary, setMonitorsSummary] = useState({});
|
||||
// Utils
|
||||
|
||||
const { determineState } = useUtils();
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
const headers = [
|
||||
{
|
||||
id: "name",
|
||||
content: <Box>Host</Box>,
|
||||
render: (row) => (
|
||||
<Host
|
||||
key={row._id}
|
||||
url={row.url}
|
||||
title={row.title}
|
||||
percentageColor={row.percentageColor}
|
||||
percentage={row.percentage}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
content: <Box width="max-content"> Status</Box>,
|
||||
render: (row) => {
|
||||
const status = determineState(row?.monitor);
|
||||
return (
|
||||
<StatusLabel
|
||||
status={status}
|
||||
text={status}
|
||||
customStyles={{ textTransform: "capitalize" }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "responseTime",
|
||||
content: "Response Time",
|
||||
render: (row) => <BarChart checks={row?.monitor?.checks.slice().reverse()} />,
|
||||
},
|
||||
{
|
||||
id: "type",
|
||||
content: "Type",
|
||||
render: (row) => <span>{TYPE_MAP[row.monitor.type]}</span>,
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
content: "Actions",
|
||||
render: (row) => (
|
||||
<ActionsMenu
|
||||
monitor={row.monitor}
|
||||
isAdmin={true}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
const isAdmin = useIsAdmin();
|
||||
const [isLoading, networkError, monitors, monitorsSummary, filteredMonitors] =
|
||||
useSubscribeToMonitors();
|
||||
|
||||
const getMonitorWithPercentage = (monitor, theme) => {
|
||||
let uptimePercentage = "";
|
||||
let percentageColor = "";
|
||||
|
||||
if (monitor.uptimePercentage !== undefined) {
|
||||
uptimePercentage =
|
||||
monitor.uptimePercentage === 0
|
||||
? "0"
|
||||
: (monitor.uptimePercentage * 100).toFixed(2);
|
||||
|
||||
percentageColor =
|
||||
monitor.uptimePercentage < 0.25
|
||||
? theme.palette.error.main
|
||||
: monitor.uptimePercentage < 0.5
|
||||
? theme.palette.warning.main
|
||||
: monitor.uptimePercentage < 0.75
|
||||
? theme.palette.success.main
|
||||
: theme.palette.success.main;
|
||||
}
|
||||
|
||||
return {
|
||||
id: monitor._id,
|
||||
name: monitor.name,
|
||||
url: monitor.url,
|
||||
title: monitor.name,
|
||||
percentage: uptimePercentage,
|
||||
percentageColor,
|
||||
monitor: monitor,
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const cleanup = networkService.subscribeToDistributedUptimeMonitors({
|
||||
authToken: authToken,
|
||||
teamId: user.teamId,
|
||||
limit: 25,
|
||||
types: ["distributed_http"],
|
||||
page: 0,
|
||||
rowsPerPage: 10,
|
||||
filter: null,
|
||||
field: null,
|
||||
order: null,
|
||||
onUpdate: (data) => {
|
||||
const res = data.monitors;
|
||||
const { monitors, filteredMonitors, summary } = res;
|
||||
const mappedMonitors = filteredMonitors.map((monitor) =>
|
||||
getMonitorWithPercentage(monitor, theme)
|
||||
);
|
||||
setMonitors(monitors);
|
||||
setFilteredMonitors(mappedMonitors);
|
||||
setMonitorsSummary(summary);
|
||||
},
|
||||
});
|
||||
|
||||
return cleanup;
|
||||
}, [user.teamId, authToken, theme]);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="column"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="end"
|
||||
alignItems="center"
|
||||
mt={theme.spacing(5)}
|
||||
gap={theme.spacing(6)}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
navigate("/distributed-uptime/create");
|
||||
}}
|
||||
sx={{ fontWeight: 500, whiteSpace: "nowrap" }}
|
||||
if (networkError) {
|
||||
return (
|
||||
<GenericFallback>
|
||||
<Typography
|
||||
variant="h1"
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
Create new
|
||||
</Button>
|
||||
</Stack>
|
||||
{monitors.length > 0 && (
|
||||
<DataTable
|
||||
headers={headers}
|
||||
data={filteredMonitors}
|
||||
config={{
|
||||
rowSX: {
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
},
|
||||
},
|
||||
onRowClick: (row) => {
|
||||
navigate(`/distributed-uptime/${row.id}`);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
Network error
|
||||
</Typography>
|
||||
<Typography>Please check your connection</Typography>
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof monitorsSummary !== "undefined" && monitorsSummary.totalMonitors === 0) {
|
||||
return (
|
||||
<Fallback
|
||||
vowelStart={false}
|
||||
title="distributed uptime monitor"
|
||||
checks={[
|
||||
"Check if a server is online from multiple locations",
|
||||
"Detect outages and performance issues in real time",
|
||||
"Reduce false alarms by verifying downtime from different networks",
|
||||
"Provide insights on regional availability and latency",
|
||||
]}
|
||||
link="/distributed-uptime/create"
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Stack gap={theme.spacing(10)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<CreateMonitorHeader
|
||||
isAdmin={isAdmin}
|
||||
shouldRender={!isLoading}
|
||||
path="/distributed-uptime/create"
|
||||
/>
|
||||
<MonitorTable
|
||||
isLoading={isLoading}
|
||||
monitors={filteredMonitors}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Components
|
||||
import DataTable from "../../../../../Components/Table";
|
||||
import Host from "../../../../Uptime/Monitors/Components/Host";
|
||||
import Host from "../../../../../Components/Host";
|
||||
import { StatusLabel } from "../../../../../Components/Label";
|
||||
import { Stack } from "@mui/material";
|
||||
import { InfrastructureMenu } from "../MonitorsTableMenu";
|
||||
@@ -12,6 +12,7 @@ import CustomGauge from "../../../../../Components/Charts/CustomGauge";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import useUtils from "../../../../Uptime/Monitors/Hooks/useUtils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete }) => {
|
||||
// Utils
|
||||
@@ -131,4 +132,11 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
|
||||
);
|
||||
};
|
||||
|
||||
MonitorsTable.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
monitors: PropTypes.array,
|
||||
isAdmin: PropTypes.bool,
|
||||
handleActionMenuDelete: PropTypes.func,
|
||||
};
|
||||
|
||||
export default MonitorsTable;
|
||||
@@ -1,6 +1,6 @@
|
||||
// Components
|
||||
import { Stack, Box } from "@mui/material";
|
||||
import Host from "../../../../Uptime/Monitors/Components/Host";
|
||||
import Host from "../../../../../Components/Host";
|
||||
import StatusPageBarChart from "../../../../../Components/Charts/StatusPageBarChart";
|
||||
import { StatusLabel } from "../../../../../Components/Label";
|
||||
|
||||
|
||||
@@ -3,30 +3,7 @@ import { networkService } from "../../../../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
const getMonitorWithPercentage = (monitor, theme) => {
|
||||
let uptimePercentage = "";
|
||||
let percentageColor = "";
|
||||
|
||||
if (monitor.uptimePercentage !== undefined) {
|
||||
uptimePercentage =
|
||||
monitor.uptimePercentage === 0 ? "0" : (monitor.uptimePercentage * 100).toFixed(2);
|
||||
|
||||
percentageColor =
|
||||
monitor.uptimePercentage < 0.25
|
||||
? theme.palette.error.main
|
||||
: monitor.uptimePercentage < 0.5
|
||||
? theme.palette.warning.main
|
||||
: monitor.uptimePercentage < 0.75
|
||||
? theme.palette.success.main
|
||||
: theme.palette.success.main;
|
||||
}
|
||||
|
||||
return {
|
||||
...monitor,
|
||||
percentage: uptimePercentage,
|
||||
percentageColor,
|
||||
};
|
||||
};
|
||||
import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
|
||||
|
||||
const useStatusPageFetch = (isCreate = false) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -35,7 +12,7 @@ const useStatusPageFetch = (isCreate = false) => {
|
||||
const [monitors, setMonitors] = useState(undefined);
|
||||
const { authToken } = useSelector((state) => state.auth);
|
||||
const theme = useTheme();
|
||||
|
||||
const { getMonitorWithPercentage } = useMonitorUtils();
|
||||
const fetchStatusPage = useCallback(async () => {
|
||||
try {
|
||||
const response = await networkService.getStatusPage({ authToken });
|
||||
|
||||
@@ -3,10 +3,10 @@ import { Box, Stack } from "@mui/material";
|
||||
import DataTable from "../../../../../Components/Table";
|
||||
import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded";
|
||||
import ArrowUpwardRoundedIcon from "@mui/icons-material/ArrowUpwardRounded";
|
||||
import Host from "../Host";
|
||||
import Host from "../../../../../Components/Host";
|
||||
import { StatusLabel } from "../../../../../Components/Label";
|
||||
import BarChart from "../../../../../Components/Charts/BarChart";
|
||||
import ActionsMenu from "../ActionsMenu";
|
||||
import ActionsMenu from "../../../../../Components/ActionsMenu";
|
||||
|
||||
import LoadingSpinner from "../LoadingSpinner";
|
||||
import TableSkeleton from "../../../../../Components/Table/skeleton";
|
||||
|
||||
@@ -2,34 +2,7 @@ import { useEffect, useState } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
const getMonitorWithPercentage = (monitor, theme) => {
|
||||
let uptimePercentage = "";
|
||||
let percentageColor = "";
|
||||
|
||||
if (monitor.uptimePercentage !== undefined) {
|
||||
uptimePercentage =
|
||||
monitor.uptimePercentage === 0 ? "0" : (monitor.uptimePercentage * 100).toFixed(2);
|
||||
|
||||
percentageColor =
|
||||
monitor.uptimePercentage < 0.25
|
||||
? theme.palette.error.main
|
||||
: monitor.uptimePercentage < 0.5
|
||||
? theme.palette.warning.main
|
||||
: monitor.uptimePercentage < 0.75
|
||||
? theme.palette.success.main
|
||||
: theme.palette.success.main;
|
||||
}
|
||||
|
||||
return {
|
||||
id: monitor._id,
|
||||
name: monitor.name,
|
||||
url: monitor.url,
|
||||
title: monitor.name,
|
||||
percentage: uptimePercentage,
|
||||
percentageColor,
|
||||
monitor: monitor,
|
||||
};
|
||||
};
|
||||
import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
|
||||
|
||||
export const useMonitorFetch = ({
|
||||
authToken,
|
||||
@@ -49,7 +22,7 @@ export const useMonitorFetch = ({
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const { getMonitorWithPercentage } = useMonitorUtils();
|
||||
useEffect(() => {
|
||||
const fetchMonitors = async () => {
|
||||
try {
|
||||
|
||||
@@ -905,9 +905,7 @@ class NetworkService {
|
||||
onOpen?.();
|
||||
};
|
||||
|
||||
this.eventSource.addEventListener("open", (e) => {
|
||||
console.log("getDistributedUptimeMonitors connection opened:");
|
||||
});
|
||||
this.eventSource.addEventListener("open", (e) => {});
|
||||
|
||||
this.eventSource.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
Reference in new issue
Block a user