mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-18 23:48:43 -05:00
Refactor reusable components out of Uptime Details
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
// Components
|
||||
import { Stack } from "@mui/material";
|
||||
import SkeletonLayout from "./skeleton";
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import PropTypes from "prop-types";
|
||||
const StatusBoxes = ({ shouldRender, children }) => {
|
||||
const theme = useTheme();
|
||||
if (!shouldRender) {
|
||||
return <SkeletonLayout numBoxes={children?.length ?? 1} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
StatusBoxes.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default StatusBoxes;
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Stack, Skeleton } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import PropTypes from "prop-types";
|
||||
const SkeletonLayout = ({ numBoxes }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(4)}
|
||||
mt={theme.spacing(4)}
|
||||
>
|
||||
{Array.from({ length: numBoxes }).map((_, index) => {
|
||||
const width = `${100 / numBoxes}%`;
|
||||
return (
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width={width}
|
||||
height={50}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
SkeletonLayout.propTypes = {
|
||||
numBoxes: PropTypes.number,
|
||||
};
|
||||
|
||||
export default SkeletonLayout;
|
||||
@@ -1,6 +1,6 @@
|
||||
// Components
|
||||
import { Stack, Typography, Box } from "@mui/material";
|
||||
import ChartBox from "../Charts/ChartBox";
|
||||
import ChartBox from "../../../../../Components/Charts/ChartBox";
|
||||
import UptimeIcon from "../../../../../assets/icons/uptime-icon.svg?react";
|
||||
import IncidentsIcon from "../../../../../assets/icons/incidents.svg?react";
|
||||
import AverageResponseIcon from "../../../../../assets/icons/average-response-icon.svg?react";
|
||||
@@ -40,7 +40,10 @@ const ChartBoxes = ({
|
||||
icon={<UptimeIcon />}
|
||||
header="Uptime"
|
||||
>
|
||||
<Stack justifyContent="space-between">
|
||||
<Stack
|
||||
justifyContent="space-between"
|
||||
direction="row"
|
||||
>
|
||||
<Box position="relative">
|
||||
<Typography>Total Checks</Typography>
|
||||
<Typography component="span">
|
||||
@@ -129,6 +132,7 @@ const ChartBoxes = ({
|
||||
export default ChartBoxes;
|
||||
|
||||
ChartBoxes.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
monitor: PropTypes.object.isRequired,
|
||||
dateRange: PropTypes.string.isRequired,
|
||||
uiTimezone: PropTypes.string.isRequired,
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import IconBox from "../../../../../Components/IconBox";
|
||||
import PropTypes from "prop-types";
|
||||
const ChartBox = ({ children, icon, header, height = "300px" }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
flex: "1 30%",
|
||||
gap: theme.spacing(8),
|
||||
height,
|
||||
minWidth: 250,
|
||||
padding: theme.spacing(8),
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: 4,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
"& h2": {
|
||||
color: theme.palette.primary.contrastTextSecondary,
|
||||
fontSize: 15,
|
||||
fontWeight: 500,
|
||||
},
|
||||
"& .MuiBox-root:not(.area-tooltip) p": {
|
||||
color: theme.palette.primary.contrastTextTertiary,
|
||||
fontSize: 13,
|
||||
},
|
||||
"& .MuiBox-root > span": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
fontSize: 20,
|
||||
"& span": {
|
||||
opacity: 0.8,
|
||||
marginLeft: 2,
|
||||
fontSize: 15,
|
||||
},
|
||||
},
|
||||
"& .MuiStack-root": {
|
||||
flexDirection: "row",
|
||||
gap: theme.spacing(6),
|
||||
},
|
||||
"& .MuiStack-root:first-of-type": {
|
||||
alignItems: "center",
|
||||
},
|
||||
"& tspan, & text": {
|
||||
fill: theme.palette.primary.contrastTextTertiary,
|
||||
},
|
||||
"& path": {
|
||||
transition: "fill 300ms ease, stroke-width 400ms ease",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<IconBox>{icon}</IconBox>
|
||||
<Typography component="h2">{header}</Typography>
|
||||
</Stack>
|
||||
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChartBox;
|
||||
|
||||
ChartBox.propTypes = {
|
||||
children: PropTypes.node,
|
||||
icon: PropTypes.node.isRequired,
|
||||
header: PropTypes.string.isRequired,
|
||||
height: PropTypes.string,
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import ChartBox from "./ChartBox";
|
||||
import ChartBox from "../../../../../Components/Charts/ChartBox";
|
||||
import MonitorDetailsAreaChart from "../../../../../Components/Charts/MonitorDetailsAreaChart";
|
||||
import ResponseTimeIcon from "../../../../../assets/icons/response-time-icon.svg?react";
|
||||
import SkeletonLayout from "./ResponseTimeChartSkeleton";
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { Button, Box } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import SettingsIcon from "../../../../../assets/icons/settings-bold.svg?react";
|
||||
import PropTypes from "prop-types";
|
||||
const ConfigButton = ({ shouldRender, monitorId }) => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
|
||||
if (!shouldRender) return null;
|
||||
|
||||
return (
|
||||
<Box alignSelf="flex-end">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={() => navigate(`/uptime/configure/${monitorId}`)}
|
||||
sx={{
|
||||
px: theme.spacing(5),
|
||||
"& svg": {
|
||||
mr: theme.spacing(3),
|
||||
"& path": {
|
||||
/* Should always be contrastText for the button color */
|
||||
stroke: theme.palette.secondary.contrastText,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SettingsIcon /> Configure
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
ConfigButton.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
monitorId: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ConfigButton;
|
||||
@@ -1,55 +0,0 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import PulseDot from "../../../../../Components/Animated/PulseDot";
|
||||
import Dot from "../../../../../Components/Dot";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import useUtils from "../../../Monitors/Hooks/useUtils";
|
||||
import { formatDurationRounded } from "../../../../../Utils/timeUtils";
|
||||
import ConfigButton from "../ConfigButton";
|
||||
import SkeletonLayout from "./skeleton";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const MonitorHeader = ({ shouldRender = true, isAdmin, monitor }) => {
|
||||
const theme = useTheme();
|
||||
const { statusColor, statusMsg, determineState } = useUtils();
|
||||
console.log(shouldRender);
|
||||
if (!shouldRender) {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Stack>
|
||||
<Typography variant="h1">{monitor.name}</Typography>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems={"center"}
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<PulseDot color={statusColor[determineState(monitor)]} />
|
||||
<Typography variant="h2">
|
||||
{monitor?.url?.replace(/^https?:\/\//, "") || "..."}
|
||||
</Typography>
|
||||
<Dot />
|
||||
<Typography>
|
||||
Checking every {formatDurationRounded(monitor?.interval)}.
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<ConfigButton
|
||||
shouldRender={isAdmin}
|
||||
monitorId={monitor._id}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
MonitorHeader.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
isAdmin: PropTypes.bool,
|
||||
monitor: PropTypes.object,
|
||||
};
|
||||
|
||||
export default MonitorHeader;
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Stack, Skeleton } from "@mui/material";
|
||||
|
||||
const SkeletonLayout = () => {
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Skeleton
|
||||
height={40}
|
||||
variant="rounded"
|
||||
width="15%"
|
||||
/>
|
||||
<Skeleton
|
||||
height={40}
|
||||
variant="rounded"
|
||||
width="15%"
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkeletonLayout;
|
||||
@@ -1,4 +1,4 @@
|
||||
import ChartBox from "../Charts/ChartBox";
|
||||
import ChartBox from "../../../../../Components/Charts/ChartBox";
|
||||
import PropTypes from "prop-types";
|
||||
import HistoryIcon from "../../../../../assets/icons/history-icon.svg?react";
|
||||
import Table from "../../../../../Components/Table";
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Stack, Skeleton } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
const SkeletonLayout = () => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(4)}
|
||||
mt={theme.spacing(4)}
|
||||
>
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="33%"
|
||||
height={50}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="33%"
|
||||
height={50}
|
||||
/>
|
||||
<Skeleton
|
||||
variant="rounded"
|
||||
width="33%"
|
||||
height={50}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkeletonLayout;
|
||||
+9
-26
@@ -1,20 +1,13 @@
|
||||
// Components
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import StatusBoxes from "../../../../../Components/StatusBoxes";
|
||||
import StatBox from "../../../../../Components/StatBox";
|
||||
import SkeletonLayout from "./skeleton";
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import useUtils from "../../../Monitors/Hooks/useUtils";
|
||||
import { getHumanReadableDuration } from "../../../../../Utils/timeUtils";
|
||||
import PropTypes from "prop-types";
|
||||
const StatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { Typography } from "@mui/material";
|
||||
import useUtils from "../../../Monitors/Hooks/useUtils";
|
||||
|
||||
const UptimeStatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
|
||||
const theme = useTheme();
|
||||
const { determineState } = useUtils();
|
||||
|
||||
if (!shouldRender) {
|
||||
return <SkeletonLayout />;
|
||||
}
|
||||
const { time: streakTime, units: streakUnits } = getHumanReadableDuration(
|
||||
monitor?.uptimeStreak
|
||||
);
|
||||
@@ -22,12 +15,8 @@ const StatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
|
||||
const { time: lastCheckTime, units: lastCheckUnits } = getHumanReadableDuration(
|
||||
monitor?.timeSinceLastCheck
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<StatusBoxes shouldRender={shouldRender}>
|
||||
<StatBox
|
||||
gradient={true}
|
||||
status={determineState(monitor)}
|
||||
@@ -70,14 +59,8 @@ const StatusBoxes = ({ shouldRender, monitor, certificateExpiry }) => {
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
</StatusBoxes>
|
||||
);
|
||||
};
|
||||
|
||||
StatusBoxes.propTypes = {
|
||||
shouldRender: PropTypes.bool,
|
||||
monitor: PropTypes.object,
|
||||
certificateExpiry: PropTypes.string,
|
||||
};
|
||||
|
||||
export default StatusBoxes;
|
||||
export default UptimeStatusBoxes;
|
||||
@@ -1,11 +1,11 @@
|
||||
// Components
|
||||
import Breadcrumbs from "../../../Components/Breadcrumbs";
|
||||
import MonitorHeader from "./Components/MonitorHeader";
|
||||
import StatusBoxes from "./Components/StatusBoxes";
|
||||
import MonitorStatusHeader from "../../../Components/MonitorStatusHeader";
|
||||
import TimeFramePicker from "./Components/TimeFramePicker";
|
||||
import ChartBoxes from "./Components/ChartBoxes";
|
||||
import ResponseTimeChart from "./Components/Charts/ResponseTimeChart";
|
||||
import ResponseTable from "./Components/ResponseTable";
|
||||
import UptimeStatusBoxes from "./Components/UptimeStatusBoxes";
|
||||
// MUI Components
|
||||
import { Stack } from "@mui/material";
|
||||
|
||||
@@ -80,12 +80,12 @@ const UptimeDetails = () => {
|
||||
return (
|
||||
<Stack gap={theme.spacing(10)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<MonitorHeader
|
||||
<MonitorStatusHeader
|
||||
isAdmin={isAdmin}
|
||||
shouldRender={!monitorIsLoading}
|
||||
monitor={monitor}
|
||||
/>
|
||||
<StatusBoxes
|
||||
<UptimeStatusBoxes
|
||||
shouldRender={!monitorIsLoading}
|
||||
monitor={monitor}
|
||||
certificateExpiry={certificateExpiry}
|
||||
|
||||
Reference in New Issue
Block a user