Merge pull request #381 from bluewave-labs/feat/monitor-details-styling

Monitor details
This commit is contained in:
Alexander Holliday
2024-07-18 23:17:17 -07:00
committed by GitHub
9 changed files with 225 additions and 46 deletions

View File

@@ -124,3 +124,6 @@
.MuiPaper-root + .MuiPagination-root .MuiPaginationItem-root.Mui-selected {
background-color: var(--env-var-color-15);
}
.MuiPaper-root + .MuiPagination-root div.MuiPaginationItem-root{
user-select: none;
}

View File

@@ -0,0 +1,19 @@
.area-tooltip {
background-color: white;
border: solid 1px var(--env-var-color-4);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1) var(--env-var-spacing-2);
}
.area-tooltip p {
margin: 0;
padding: 0;
}
.area-tooltip p:first-of-type {
color: var(--env-var-color-3);
font-size: var(--env-var-font-size-medium);
}
.area-tooltip p:last-of-type {
margin-top: 5px;
color: var(--env-var-color-5);
font-size: var(--env-var-font-size-small);
}

View File

@@ -1,11 +1,12 @@
import PropTypes from "prop-types";
import { AreaChart, Area, XAxis, Tooltip, ResponsiveContainer } from "recharts";
import { NormalizeData } from "../ChartUtils";
import "./index.css";
const CustomToolTip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
return (
<div style={{ backgroundColor: "white" }}>
<div className="area-tooltip">
<p>
{new Date(label).toLocaleDateString("en-US", {
weekday: "short", // Mon
@@ -80,7 +81,7 @@ const MonitorDetailsAreaChart = ({ checks, filter }) => {
data={normalizedChecks}
margin={{
top: 10,
right: 30,
right: 0,
left: 0,
bottom: 0,
}}
@@ -89,6 +90,7 @@ const MonitorDetailsAreaChart = ({ checks, filter }) => {
dataKey="createdAt"
tickFormatter={formatDate}
tick={{ fontSize: "13px" }}
tickLine={false}
/>
<Tooltip content={<CustomToolTip />} />
<Area

View File

@@ -0,0 +1,49 @@
.monitor-details h1.MuiTypography-root {
font-size: var(--env-var-font-size-large-plus);
color: var(--env-var-color-1);
font-weight: 600;
}
.monitor-details h2.MuiTypography-root,
.monitor-details h6.MuiTypography-root {
font-size: var(--env-var-font-size-large);
}
.monitor-details h2.MuiTypography-root,
.monitor-details h4.MuiTypography-root {
font-weight: 600;
}
.monitor-details h2.MuiTypography-root,
.monitor-details h4.MuiTypography-root {
color: var(--env-var-color-5);
}
.monitor-details h6.MuiTypography-root {
color: var(--env-var-color-3);
}
.monitor-details button.MuiButtonBase-root,
.monitor-details h4.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
}
.monitor-details button.MuiButtonBase-root {
height: var(--env-var-height-2);
line-height: 1;
}
.monitor-details p.MuiTypography-root,
.monitor-details p.MuiTypography-root span.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
}
.monitor-details p.MuiTypography-root {
color: var(--env-var-color-2);
}
.monitor-details .stat-box {
flex: 1;
min-width: 100px;
border: solid 1px var(--env-var-color-4);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1-plus) var(--env-var-spacing-2);
}
.monitor-details .stat-box:not(:first-of-type) {
margin-left: var(--env-var-spacing-2);
}
.monitor-details .stat-box h6.MuiTypography-root {
margin-bottom: var(--env-var-spacing-1);
}

View File

@@ -1,14 +1,19 @@
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { Box, Typography, useTheme } from "@mui/material";
import { Box, Stack, Typography, useTheme } from "@mui/material";
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import axiosInstance from "../../../Utils/axiosConfig";
import BasicTable from "../../../Components/BasicTable";
import MonitorDetailsAreaChart from "../../../Components/Charts/MonitorDetailsAreaChart";
import { StatusLabel } from "../../../Components/Label";
import ButtonGroup from "@mui/material/ButtonGroup";
import Button from "../../../Components/Button";
import WestRoundedIcon from "@mui/icons-material/WestRounded";
import GreenCheck from "../../../assets/icons/checkbox-green.svg?react";
import RedCheck from "../../../assets/icons/checkbox-red.svg?react";
import SettingsIcon from "../../../assets/icons/settings.svg?react";
import "./index.css";
const formatDuration = (ms) => {
const seconds = Math.floor(ms / 1000);
@@ -28,9 +33,36 @@ const formatDuration = (ms) => {
return dateStr;
};
const formatDurationRounded = (ms) => {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
let time = "";
if (days > 0) {
time += `${days} day${days !== 1 ? "s" : ""}`;
return time;
}
if (hours > 0) {
time += `${hours} hour${hours !== 1 ? "s" : ""}`;
return time;
}
if (minutes > 0) {
time += `${minutes} minute${minutes !== 1 ? "s" : ""}`;
return time;
}
if (seconds > 0) {
time += `${seconds} second${seconds !== 1 ? "s" : ""}`;
return time;
}
return time;
};
const StatBox = ({ title, value }) => {
return (
<Box>
<Box className="stat-box">
<Typography variant="h6">{title}</Typography>
<Typography variant="h4">{value}</Typography>
</Box>
@@ -103,6 +135,7 @@ const DetailsPage = () => {
}, [monitorId, authToken]);
const theme = useTheme();
const navigate = useNavigate();
/**
* Function to calculate uptime duration based on the most recent check.
@@ -163,52 +196,110 @@ const DetailsPage = () => {
padding: `${theme.content.pY} ${theme.content.pX}`,
}}
>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<StatBox
title="Currently up for"
value={formatDuration(calculateUptimeDuration(monitor.checks))}
/>
<StatBox
title="Last checked"
value={`${formatDuration(getLastChecked(monitor.checks))} ago`}
/>
<StatBox title="Incidents" value={countIncidents(monitor.checks)} />
</div>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
<Button
level="tertiary"
label="Back to Monitors"
img={<WestRoundedIcon />}
onClick={() => navigate("/monitors")}
sx={{
backgroundColor: "#f4f4f4",
mb: theme.gap.medium,
px: theme.gap.ml,
"& svg.MuiSvgIcon-root": {
pr: theme.gap.small,
},
}}
>
<Typography component="h1" mb={theme.gap.small}>
Response Times
</Typography>
<ButtonGroup>
/>
<Stack gap={theme.gap.xl}>
<Stack direction="row" gap={theme.gap.small} mt={theme.gap.small}>
{monitor?.status ? <GreenCheck /> : <RedCheck />}
<Box>
<Typography component="h1" sx={{ lineHeight: 1 }}>
{monitor.url?.replace(/^https?:\/\//, "") || "..."}
</Typography>
<Typography mt={theme.gap.small}>
<Typography
component="span"
sx={{
color: monitor?.status
? "var(--env-var-color-17)"
: "var(--env-var-color-24)",
}}
>
Your site is {monitor?.status ? "up" : "down"}.
</Typography>{" "}
Checking every {formatDurationRounded(monitor?.interval)}. Last
time checked{" "}
{formatDurationRounded(getLastChecked(monitor?.checks))} ago.
</Typography>
</Box>
<Button
level="secondary"
label="Day"
onClick={() => setFilter("day")}
level="tertiary"
label="Configure"
img={<SettingsIcon />}
sx={{
ml: "auto",
alignSelf: "flex-end",
backgroundColor: "#f4f4f4",
px: theme.gap.ml,
"& svg": {
pr: theme.gap.xs,
},
}}
/>
<Button
level="secondary"
label="Week"
onClick={() => setFilter("week")}
</Stack>
<Stack direction="row" justifyContent="space-between">
<StatBox
title="Currently up for"
value={formatDuration(calculateUptimeDuration(monitor.checks))}
/>
<Button
level="secondary"
label="Month"
onClick={() => setFilter("month")}
<StatBox
title="Last checked"
value={`${formatDuration(getLastChecked(monitor.checks))} ago`}
/>
</ButtonGroup>
</div>
<div style={{ height: "33vh" }}>
<MonitorDetailsAreaChart checks={monitor.checks} filter={filter} />
</div>
<Typography component="h1" mb={theme.gap.small}>
History
</Typography>
<BasicTable data={data} paginated={true} />
<StatBox title="Incidents" value={countIncidents(monitor.checks)} />
</Stack>
<Box>
<Stack
direction="row"
justifyContent="space-between"
mb={theme.gap.ml}
>
<Typography component="h2" mb={theme.gap.small}>
Response Times
</Typography>
<ButtonGroup>
<Button
level="secondary"
label="Day"
onClick={() => setFilter("day")}
sx={{ backgroundColor: filter === "day" && "#f4f4f4" }}
/>
<Button
level="secondary"
label="Week"
onClick={() => setFilter("week")}
sx={{ backgroundColor: filter === "week" && "#f4f4f4" }}
/>
<Button
level="secondary"
label="Month"
onClick={() => setFilter("month")}
sx={{ backgroundColor: filter === "month" && "#f4f4f4" }}
/>
</ButtonGroup>
</Stack>
<Box sx={{ height: "200px" }}>
<MonitorDetailsAreaChart checks={monitor.checks} filter={filter} />
</Box>
</Box>
<Box>
<Typography component="h2" mb={theme.gap.ml}>
History
</Typography>
<BasicTable data={data} paginated={true} />
</Box>
</Stack>
</div>
);
};

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#079455"/>
<circle cx="12" cy="12" r="8" fill="#17B26A"/>
<circle cx="12" cy="12" r="3" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 243 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#D92D20"/>
<circle cx="12" cy="12" r="8" fill="#F04438"/>
<circle cx="12" cy="12" r="3" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 243 B

View File

@@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 11.4C10.3255 11.4 11.4 10.3255 11.4 9C11.4 7.67452 10.3255 6.6 9 6.6C7.67452 6.6 6.6 7.67452 6.6 9C6.6 10.3255 7.67452 11.4 9 11.4Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.3818 11.1818C14.285 11.4012 14.2561 11.6445 14.2989 11.8804C14.3417 12.1164 14.4542 12.3341 14.6218 12.5055L14.6655 12.5491C14.8007 12.6842 14.908 12.8446 14.9812 13.0212C15.0544 13.1978 15.0921 13.387 15.0921 13.5782C15.0921 13.7693 15.0544 13.9586 14.9812 14.1352C14.908 14.3118 14.8007 14.4722 14.6655 14.6073C14.5304 14.7425 14.3699 14.8498 14.1934 14.923C14.0168 14.9962 13.8275 15.0339 13.6364 15.0339C13.4452 15.0339 13.2559 14.9962 13.0794 14.923C12.9028 14.8498 12.7424 14.7425 12.6073 14.6073L12.5636 14.5636C12.3922 14.396 12.1745 14.2835 11.9386 14.2407C11.7027 14.1979 11.4594 14.2268 11.24 14.3236C11.0249 14.4158 10.8414 14.5689 10.7122 14.764C10.583 14.9591 10.5137 15.1878 10.5127 15.4218V15.5455C10.5127 15.9312 10.3595 16.3012 10.0867 16.574C9.81392 16.8468 9.44395 17 9.05818 17C8.67241 17 8.30244 16.8468 8.02966 16.574C7.75688 16.3012 7.60364 15.9312 7.60364 15.5455V15.48C7.59801 15.2393 7.52009 15.0058 7.38001 14.81C7.23993 14.6141 7.04417 14.4649 6.81818 14.3818C6.59882 14.285 6.3555 14.2561 6.11957 14.2989C5.88365 14.3417 5.66595 14.4542 5.49455 14.6218L5.45091 14.6655C5.31582 14.8007 5.1554 14.908 4.97882 14.9812C4.80224 15.0544 4.61297 15.0921 4.42182 15.0921C4.23067 15.0921 4.04139 15.0544 3.86481 14.9812C3.68824 14.908 3.52782 14.8007 3.39273 14.6655C3.25749 14.5304 3.1502 14.3699 3.077 14.1934C3.00381 14.0168 2.96613 13.8275 2.96613 13.6364C2.96613 13.4452 3.00381 13.2559 3.077 13.0794C3.1502 12.9028 3.25749 12.7424 3.39273 12.6073L3.43636 12.5636C3.60403 12.3922 3.7165 12.1745 3.75928 11.9386C3.80205 11.7027 3.77317 11.4594 3.67636 11.24C3.58417 11.0249 3.4311 10.8414 3.23597 10.7122C3.04085 10.583 2.81221 10.5137 2.57818 10.5127H2.45455C2.06878 10.5127 1.69881 10.3595 1.42603 10.0867C1.15325 9.81392 1 9.44395 1 9.05818C1 8.67241 1.15325 8.30244 1.42603 8.02966C1.69881 7.75688 2.06878 7.60364 2.45455 7.60364H2.52C2.76072 7.59801 2.99419 7.52009 3.19004 7.38001C3.38589 7.23993 3.53507 7.04417 3.61818 6.81818C3.71499 6.59882 3.74387 6.3555 3.70109 6.11957C3.65832 5.88365 3.54585 5.66595 3.37818 5.49455L3.33455 5.45091C3.19931 5.31582 3.09202 5.1554 3.01882 4.97882C2.94562 4.80224 2.90795 4.61297 2.90795 4.42182C2.90795 4.23067 2.94562 4.04139 3.01882 3.86481C3.09202 3.68824 3.19931 3.52782 3.33455 3.39273C3.46963 3.25749 3.63005 3.1502 3.80663 3.077C3.98321 3.00381 4.17249 2.96613 4.36364 2.96613C4.55479 2.96613 4.74406 3.00381 4.92064 3.077C5.09722 3.1502 5.25764 3.25749 5.39273 3.39273L5.43636 3.43636C5.60777 3.60403 5.82547 3.7165 6.06139 3.75928C6.29731 3.80205 6.54064 3.77317 6.76 3.67636H6.81818C7.03329 3.58417 7.21674 3.4311 7.34596 3.23597C7.47518 3.04085 7.54452 2.81221 7.54545 2.57818V2.45455C7.54545 2.06878 7.6987 1.69881 7.97148 1.42603C8.24426 1.15325 8.61423 1 9 1C9.38577 1 9.75574 1.15325 10.0285 1.42603C10.3013 1.69881 10.4545 2.06878 10.4545 2.45455V2.52C10.4555 2.75403 10.5248 2.98267 10.654 3.17779C10.7833 3.37291 10.9667 3.52599 11.1818 3.61818C11.4012 3.71499 11.6445 3.74387 11.8804 3.70109C12.1164 3.65832 12.3341 3.54585 12.5055 3.37818L12.5491 3.33455C12.6842 3.19931 12.8446 3.09202 13.0212 3.01882C13.1978 2.94562 13.387 2.90795 13.5782 2.90795C13.7693 2.90795 13.9586 2.94562 14.1352 3.01882C14.3118 3.09202 14.4722 3.19931 14.6073 3.33455C14.7425 3.46963 14.8498 3.63005 14.923 3.80663C14.9962 3.98321 15.0339 4.17249 15.0339 4.36364C15.0339 4.55479 14.9962 4.74406 14.923 4.92064C14.8498 5.09722 14.7425 5.25764 14.6073 5.39273L14.5636 5.43636C14.396 5.60777 14.2835 5.82547 14.2407 6.06139C14.1979 6.29731 14.2268 6.54064 14.3236 6.76V6.81818C14.4158 7.03329 14.5689 7.21674 14.764 7.34596C14.9591 7.47518 15.1878 7.54452 15.4218 7.54545H15.5455C15.9312 7.54545 16.3012 7.6987 16.574 7.97148C16.8468 8.24426 17 8.61423 17 9C17 9.38577 16.8468 9.75574 16.574 10.0285C16.3012 10.3013 15.9312 10.4545 15.5455 10.4545H15.48C15.246 10.4555 15.0173 10.5248 14.8222 10.654C14.6271 10.7833 14.474 10.9667 14.3818 11.1818Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -56,6 +56,7 @@
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-height-2: 34px;
--env-var-spacing-1: 12px;
--env-var-spacing-1-plus: 16px;