Merge pull request #622 from bluewave-labs/feat/60-min-chart

implement 60 min history chart, resolves #595
This commit is contained in:
Alexander Holliday authored and GitHub committed 2024-08-14 12:56:45 -07:00
commit 9475770b8f
6 files changed
+132 -37

No files matched your search

+1 -1
View File
@@ -72,7 +72,7 @@
}
.MuiPaper-root + .MuiPagination-root {
margin-top: 35px;
margin-top: 24px;
border: solid 1px var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1-plus) var(--env-var-spacing-2);
@@ -0,0 +1,50 @@
import { BarChart, Bar, Cell, ReferenceLine, Label } from "recharts";
import PropTypes from "prop-types";
const MonitorDetails60MinChart = ({ data }) => {
const labelStyle = {
fontSize: "10px",
fill: "#475467",
};
const color = {
true: "var(--env-var-color-23)",
false: "var(--env-var-color-24)",
undefined: "var(--env-var-color-33)",
};
return (
<BarChart
width={data.length * 10 + 30}
height={35}
data={data}
margin={{ top: 14, left: 15, right: 15, bottom: 2 }}
style={{ alignSelf: "baseline" }}
>
<Bar dataKey="value" barSize={10}>
{data.map((check, index) => (
<Cell key={`cell-${index}`} fill={color[check.status]} />
))}
</Bar>
<ReferenceLine x={0} stroke="black" strokeDasharray="3 3">
<Label value="60 mins" position="top" style={labelStyle} />
</ReferenceLine>
<ReferenceLine
x={Math.floor(data.length * (2 / 3))}
stroke="black"
strokeDasharray="3 3"
>
<Label value="20 mins" position="top" style={labelStyle} />
</ReferenceLine>
<ReferenceLine x={data.length - 1} stroke="black" strokeDasharray="3 3">
<Label value="now" position="top" style={labelStyle} />
</ReferenceLine>
</BarChart>
);
};
MonitorDetails60MinChart.propTypes = {
data: PropTypes.array.isRequired,
};
export default MonitorDetails60MinChart;
+12 -8
View File
@@ -3,12 +3,10 @@
color: var(--env-var-color-1);
font-weight: 600;
}
.monitor-details h2.MuiTypography-root,
.monitor-details h6.MuiTypography-root {
.monitor-details h2.MuiTypography-root {
font-size: var(--env-var-font-size-large);
}
.monitor-details h2.MuiTypography-root,
.monitor-details h4.MuiTypography-root {
.monitor-details h2.MuiTypography-root{
font-weight: 600;
}
.monitor-details h2.MuiTypography-root,
@@ -35,15 +33,21 @@
}
.monitor-details .stat-box {
flex: 1;
flex: 1 20%;
min-width: 100px;
border: solid 1px;
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1) 18px;
padding: var(--env-var-spacing-1) 16px;
background-color: var(--env-var-color-8);
}
.monitor-details .stat-box h6.MuiTypography-root {
margin-bottom: var(--env-var-spacing-1);
.monitor-details h6.MuiTypography-root {
font-size: var(--env-var-font-size-medium-plus);
}
.monitor-details h6.MuiTypography-root span.MuiTypography-root {
font-style: italic;
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
opacity: 0.7;
}
.monitor-details button.MuiButtonBase-root,
.monitor-details .stat-box {
+52 -24
View File
@@ -17,20 +17,23 @@ import {
formatDurationRounded,
} from "../../../Utils/timeUtils";
import "./index.css";
import MonitorDetails60MinChart from "../../../Components/Charts/MonitorDetails60MinChart";
const StatBox = ({ title, value }) => {
return (
<Box className="stat-box">
<Typography variant="h6" sx={{ fontWeight: 400 }}>
<Typography variant="h6" mb={1} fontWeight={500}>
{title}
</Typography>
<Typography variant="h4">{value}</Typography>
<Typography variant="h4" fontWeight={500}>
{value}
</Typography>
</Box>
);
};
StatBox.propTypes = {
title: PropTypes.string,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
@@ -162,12 +165,12 @@ const DetailsPage = () => {
<>
<Button
level="tertiary"
label="Back to Monitors"
label="Back"
animate="slideLeft"
img={<WestRoundedIcon />}
onClick={() => navigate("/monitors")}
sx={{
backgroundColor: "#f4f4f4",
backgroundColor: theme.palette.otherColors.fillGray,
px: theme.gap.ml,
"& svg.MuiSvgIcon-root": {
mr: theme.gap.small,
@@ -176,12 +179,23 @@ const DetailsPage = () => {
}}
/>
<Stack gap={theme.gap.xl} mt={theme.gap.medium}>
<Stack direction="row" gap={theme.gap.small} mt={theme.gap.small}>
<Stack
direction="row"
gap={theme.gap.small}
mt={theme.gap.small}
alignItems="baseline"
>
{monitor?.status ? <GreenCheck /> : <RedCheck />}
<Box>
<Typography component="h1" sx={{ lineHeight: 1 }}>
{monitor.url?.replace(/^https?:\/\//, "") || "..."}
</Typography>
<Stack direction="row">
<Typography
component="h1"
sx={{ lineHeight: 1, alignSelf: "flex-end" }}
>
{monitor.url?.replace(/^https?:\/\//, "") || "..."}
</Typography>
<MonitorDetails60MinChart data={monitor.statusBar} />
</Stack>
<Typography mt={theme.gap.small}>
<Typography
component="span"
@@ -194,8 +208,6 @@ const DetailsPage = () => {
Your site is {monitor?.status ? "up" : "down"}.
</Typography>{" "}
Checking every {formatDurationRounded(monitor?.interval)}.
Last time checked{" "}
{formatDurationRounded(monitor?.lastChecked)} ago.
</Typography>
</Box>
<Button
@@ -226,41 +238,49 @@ const DetailsPage = () => {
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
flexWrap="wrap"
>
<StatBox
title="Currently up for"
value={formatDuration(monitor?.uptimeDuration)}
/>
<StatBox
title="Last checked"
value={`${formatDuration(monitor?.lastChecked)} ago`}
title="Last check"
value={`${formatDurationRounded(monitor?.lastChecked)} ago`}
/>
<StatBox title="Incidents" value={monitor?.incidents} />
<StatBox title="Certificate Expiry" value={certificateExpiry} />
</Stack>
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
>
<StatBox
title="Latest response time"
value={monitor?.latestResponseTime}
/>
<StatBox
title="Average Repsonse Time (24 hours)"
title={
<>
Avg. Response Time{" "}
<Typography component="span">(24-hr)</Typography>
</>
}
value={parseFloat(monitor?.avgResponseTime24hours)
.toFixed(2)
.replace(/\.?0+$/, "")}
/>
<StatBox
title="Uptime (24 hours)"
title={
<>
Uptime <Typography component="span">(24-hr)</Typography>
</>
}
value={`${parseFloat(monitor?.uptime24Hours)
.toFixed(2)
.replace(/\.?0+$/, "")}%`}
/>
<StatBox
title="Uptime(30 days)"
title={
<>
Uptime <Typography component="span">(30-day)</Typography>
</>
}
value={`${parseFloat(monitor?.uptime30Days)
.toFixed(2)
.replace(/\.?0+$/, "")}%`}
@@ -272,7 +292,7 @@ const DetailsPage = () => {
justifyContent="space-between"
mb={theme.gap.ml}
>
<Typography component="h2" mb={theme.gap.small}>
<Typography component="h2" alignSelf="flex-end">
Response Times
</Typography>
<ButtonGroup>
@@ -308,7 +328,15 @@ const DetailsPage = () => {
/>
</ButtonGroup>
</Stack>
<Box sx={{ height: "200px" }}>
<Box
p={theme.gap.mlplus}
pb={theme.gap.xs}
backgroundColor={theme.palette.otherColors.white}
border={1}
borderColor={theme.palette.otherColors.graishWhite}
borderRadius={`${theme.shape.borderRadius}px`}
sx={{ height: "250px" }}
>
<MonitorDetailsAreaChart
checks={[...monitor.checks].reverse()}
/>
+1
View File
@@ -58,6 +58,7 @@
--env-var-color-30: #fcfcfd;
--env-var-color-31: #1a1919;
--env-var-color-32: #f5f5f5;
--env-var-color-33: rgba(83, 83, 83, 0.1);
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
+16 -4
View File
@@ -126,10 +126,22 @@ const getIncidents = (checks) => {
* @param {Array} checks Array of check objects.
* @returns {Array<Boolean>} Array of booleans representing up/down.
*/
const getStatusBarValues = (checks) => {
return checks.map((check) => {
return check.status;
const getStatusBarValues = (monitor, checks) => {
const checksIn60Mins = Math.floor((60 * 60 * 1000) / monitor.interval);
const noBlankChecks = checksIn60Mins - checks.length;
const statusBarValues = checks.map((check) => {
return {
status: check.status,
responseTime: check.responseTime,
value: 75,
};
});
for (let i = 0; i < noBlankChecks; i++) {
statusBarValues.push({ status: undefined, responseTime: 0, value: 75 });
}
return statusBarValues.reverse();
};
/**
* Get stats by monitor ID
@@ -205,7 +217,7 @@ const getMonitorStatsById = async (req) => {
getAverageResponseTime24Hours(checks24Hours);
monitorStats.uptime24Hours = getUptimePercentage(checks24Hours);
monitorStats.uptime30Days = getUptimePercentage(checks30Days);
monitorStats.statusBar = getStatusBarValues(checks60Mins);
monitorStats.statusBar = getStatusBarValues(monitor, checks60Mins);
}
//Get checks for dateRange