Revamped header section
This commit is contained in:
1 parent
aa81e47fae
commit
f046f250ec
11 files changed
+205
-74
No files matched your search
@@ -3,9 +3,7 @@
|
||||
}
|
||||
|
||||
.home-layout {
|
||||
display: flex;
|
||||
position: relative;
|
||||
gap: var(--env-var-spacing-2);
|
||||
min-height: 100vh;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Sidebar from "../../Components/Sidebar";
|
||||
import { Outlet } from "react-router";
|
||||
import { Box } from "@mui/material";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
import "./index.css";
|
||||
@@ -10,10 +10,14 @@ const HomeLayout = () => {
|
||||
|
||||
return (
|
||||
<Box backgroundColor={theme.palette.background.alt}>
|
||||
<Box className="home-layout">
|
||||
<Stack
|
||||
className="home-layout"
|
||||
flexDirection="row"
|
||||
gap={theme.spacing(14)}
|
||||
>
|
||||
<Sidebar />
|
||||
<Outlet />
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -83,7 +83,7 @@ const Incidents = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack className="incidents" pt={theme.spacing(21)} gap={theme.spacing(12)}>
|
||||
<Stack className="incidents" pt={theme.spacing(20)} gap={theme.spacing(12)}>
|
||||
{loading ? (
|
||||
<SkeletonLayout />
|
||||
) : (
|
||||
|
||||
@@ -254,6 +254,7 @@ const Configure = () => {
|
||||
color="secondary"
|
||||
loading={isLoading}
|
||||
sx={{
|
||||
border: "none",
|
||||
backgroundColor: theme.palette.background.main,
|
||||
px: theme.spacing(5),
|
||||
mr: theme.spacing(6),
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
.monitor-details h1.MuiTypography-root {
|
||||
font-size: var(--env-var-font-size-large-plus);
|
||||
font-weight: 600;
|
||||
}
|
||||
.monitor-details h2.MuiTypography-root {
|
||||
font-size: var(--env-var-font-size-large);
|
||||
}
|
||||
.monitor-details h2.MuiTypography-root {
|
||||
font-weight: 600;
|
||||
}
|
||||
.monitor-details button.MuiButtonBase-root {
|
||||
height: var(--env-var-height-2);
|
||||
line-height: 1;
|
||||
|
||||
@@ -3,8 +3,10 @@ import { useEffect, useState, useCallback } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Popover,
|
||||
Skeleton,
|
||||
Stack,
|
||||
Tooltip,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
@@ -13,12 +15,14 @@ import { useNavigate, useParams } from "react-router-dom";
|
||||
import { networkService } from "../../../main";
|
||||
import { logger } from "../../../Utils/Logger";
|
||||
import {
|
||||
formatDate,
|
||||
formatDuration,
|
||||
formatDurationRounded,
|
||||
} from "../../../Utils/timeUtils";
|
||||
import MonitorDetailsAreaChart from "../../../Components/Charts/MonitorDetailsAreaChart";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
import SettingsIcon from "../../../assets/icons/settings-bold.svg?react";
|
||||
import CertificateIcon from "../../../assets/icons/certificate.svg?react";
|
||||
import PaginationTable from "./PaginationTable";
|
||||
import Breadcrumbs from "../../../Components/Breadcrumbs";
|
||||
import PulseDot from "../../../Components/Animated/PulseDot";
|
||||
@@ -154,6 +158,14 @@ const DetailsPage = ({ isAdmin }) => {
|
||||
const [certificateExpiry, setCertificateExpiry] = useState("N/A");
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const openCertificate = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const closeCertificate = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const fetchMonitor = useCallback(async () => {
|
||||
try {
|
||||
const res = await networkService.getStatsByMonitorId(
|
||||
@@ -186,7 +198,16 @@ const DetailsPage = ({ isAdmin }) => {
|
||||
authToken,
|
||||
monitorId
|
||||
);
|
||||
setCertificateExpiry(res?.data?.data?.certificateDate ?? "N/A");
|
||||
|
||||
let [month, day, year] = res?.data?.data?.certificateDate.split("/");
|
||||
const date = new Date(year, month - 1, day);
|
||||
|
||||
setCertificateExpiry(
|
||||
formatDate(date, {
|
||||
hour: undefined,
|
||||
minute: undefined,
|
||||
}) ?? "N/A"
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -207,65 +228,171 @@ const DetailsPage = ({ isAdmin }) => {
|
||||
{ name: "details", path: `/monitors/${monitorId}` },
|
||||
]}
|
||||
/>
|
||||
<Stack gap={theme.spacing(12)} mt={theme.spacing(12)}>
|
||||
<Stack gap={theme.spacing(12)} mt={theme.spacing(10)}>
|
||||
<Stack direction="row" gap={theme.spacing(2)}>
|
||||
<PulseDot
|
||||
color={
|
||||
monitor?.status
|
||||
? theme.palette.success.main
|
||||
: theme.palette.error.main
|
||||
}
|
||||
/>
|
||||
<Box>
|
||||
<Typography
|
||||
component="h1"
|
||||
fontSize={22}
|
||||
fontWeight={500}
|
||||
color={theme.palette.text.primary}
|
||||
lineHeight={1}
|
||||
>
|
||||
{monitor.url?.replace(/^https?:\/\//, "") || "..."}
|
||||
{monitor.name}
|
||||
</Typography>
|
||||
<Typography
|
||||
mt={theme.spacing(4)}
|
||||
color={theme.palette.text.tertiary}
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="flex-end"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
color: monitor?.status
|
||||
? theme.palette.success.main
|
||||
: theme.palette.success.text,
|
||||
<Tooltip
|
||||
title={`Your site is ${monitor?.status ? "up" : "down"}.`}
|
||||
disableInteractive
|
||||
slotProps={{
|
||||
popper: {
|
||||
modifiers: [
|
||||
{
|
||||
name: "offset",
|
||||
options: {
|
||||
offset: [0, -8],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}}
|
||||
>
|
||||
Your site is {monitor?.status ? "up" : "down"}.
|
||||
</Typography>{" "}
|
||||
Checking every {formatDurationRounded(monitor?.interval)}.
|
||||
</Typography>
|
||||
<Box>
|
||||
<PulseDot
|
||||
color={
|
||||
monitor?.status
|
||||
? theme.palette.success.main
|
||||
: theme.palette.error.main
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<Typography
|
||||
component="h2"
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
{monitor.url?.replace(/^https?:\/\//, "") || "..."}
|
||||
</Typography>
|
||||
<Typography
|
||||
ml={theme.spacing(6)}
|
||||
lineHeight="20px"
|
||||
position="relative"
|
||||
color={theme.palette.text.tertiary}
|
||||
sx={{
|
||||
"&:before": {
|
||||
position: "absolute",
|
||||
content: `""`,
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.text.tertiary,
|
||||
opacity: 0.8,
|
||||
left: -9,
|
||||
top: "42%",
|
||||
},
|
||||
}}
|
||||
>
|
||||
Checking every {formatDurationRounded(monitor?.interval)}.
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={() => navigate(`/monitors/configure/${monitorId}`)}
|
||||
<Stack
|
||||
direction="row"
|
||||
height={34}
|
||||
sx={{
|
||||
ml: "auto",
|
||||
alignSelf: "flex-end",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
height="100%"
|
||||
position="relative"
|
||||
minWidth={34}
|
||||
border={1}
|
||||
borderColor={theme.palette.border.dark}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
backgroundColor={theme.palette.background.accent}
|
||||
mr={theme.spacing(4)}
|
||||
onClick={openCertificate}
|
||||
sx={{
|
||||
ml: "auto",
|
||||
alignSelf: "flex-end",
|
||||
px: theme.spacing(5),
|
||||
cursor: "pointer",
|
||||
"& svg": {
|
||||
mr: theme.spacing(3),
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: 20,
|
||||
height: 20,
|
||||
"& path": {
|
||||
stroke: theme.palette.other.icon,
|
||||
stroke: theme.palette.text.tertiary,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SettingsIcon /> Configure
|
||||
</Button>
|
||||
)}
|
||||
<CertificateIcon />
|
||||
</Box>
|
||||
<Popover
|
||||
id="certificate-dropdown"
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={closeCertificate}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
}}
|
||||
slotProps={{
|
||||
paper: {
|
||||
sx: {
|
||||
py: 4,
|
||||
px: 6,
|
||||
width: 140,
|
||||
backgroundColor: theme.palette.background.accent,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography fontSize={12} color={theme.palette.text.tertiary}>
|
||||
Certificate Expiry
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
fontSize={13}
|
||||
color={theme.palette.text.primary}
|
||||
>
|
||||
{certificateExpiry}
|
||||
</Typography>
|
||||
</Popover>
|
||||
{isAdmin && (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={() => navigate(`/monitors/configure/${monitorId}`)}
|
||||
sx={{
|
||||
px: theme.spacing(5),
|
||||
"& svg": {
|
||||
mr: theme.spacing(3),
|
||||
"& path": {
|
||||
stroke: theme.palette.text.tertiary,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SettingsIcon /> Configure
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
gap={theme.spacing(12)}
|
||||
gap={theme.spacing(6)}
|
||||
flexWrap="wrap"
|
||||
>
|
||||
<StatBox
|
||||
@@ -277,7 +404,6 @@ const DetailsPage = ({ isAdmin }) => {
|
||||
value={`${formatDurationRounded(monitor?.lastChecked)} ago`}
|
||||
/>
|
||||
<StatBox title="Incidents" value={monitor?.incidents} />
|
||||
<StatBox title="Certificate Expiry" value={certificateExpiry} />
|
||||
<StatBox
|
||||
title="Latest response time"
|
||||
value={monitor?.latestResponseTime}
|
||||
@@ -360,16 +486,16 @@ const DetailsPage = ({ isAdmin }) => {
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
sx={{ height: "250px" }}
|
||||
>
|
||||
<MonitorDetailsAreaChart
|
||||
{/* <MonitorDetailsAreaChart
|
||||
checks={[...monitor.checks].reverse()}
|
||||
/>
|
||||
/> */}
|
||||
</Box>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(8)}>
|
||||
<Typography component="h2" color={theme.palette.text.secondary}>
|
||||
History
|
||||
</Typography>
|
||||
<PaginationTable monitorId={monitorId} dateRange={dateRange} />
|
||||
{/* <PaginationTable monitorId={monitorId} dateRange={dateRange} /> */}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</>
|
||||
|
||||
@@ -43,22 +43,6 @@ const Monitors = ({ isAdmin }) => {
|
||||
|
||||
let loading = monitorState.isLoading && monitorState.monitors.length === 0;
|
||||
|
||||
const now = new Date();
|
||||
const hour = now.getHours();
|
||||
|
||||
let greeting = "";
|
||||
let emoji = "";
|
||||
if (hour < 12) {
|
||||
greeting = "morning";
|
||||
emoji = "🌅";
|
||||
} else if (hour < 18) {
|
||||
greeting = "afternoon";
|
||||
emoji = "🌞";
|
||||
} else {
|
||||
greeting = "evening";
|
||||
emoji = "🌙";
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack className="monitors" gap={theme.spacing(12)}>
|
||||
{loading ? (
|
||||
|
||||
@@ -10,10 +10,10 @@ const text = {
|
||||
const background = {
|
||||
main: "#151518",
|
||||
alt: "#09090b",
|
||||
fill: "#2e2e2e",
|
||||
fill: "#2D2D33",
|
||||
accent: "#18181a",
|
||||
};
|
||||
const border = { light: "#27272a", dark: "#2c2c2c" };
|
||||
const border = { light: "#27272a", dark: "#36363e" };
|
||||
|
||||
const fontFamilyDefault =
|
||||
'"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif';
|
||||
@@ -25,7 +25,7 @@ const darkTheme = createTheme({
|
||||
palette: {
|
||||
mode: "dark",
|
||||
primary: { main: "#1570ef" },
|
||||
secondary: { main: "#2e2e2e" },
|
||||
secondary: { main: "#2D2D33" },
|
||||
text: text,
|
||||
background: background,
|
||||
border: border,
|
||||
@@ -92,6 +92,15 @@ const darkTheme = createTheme({
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) =>
|
||||
props.variant === "contained" && props.color === "secondary",
|
||||
style: {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.dark,
|
||||
},
|
||||
},
|
||||
],
|
||||
fontWeight: 400,
|
||||
borderRadius: 4,
|
||||
|
||||
@@ -89,6 +89,15 @@ const lightTheme = createTheme({
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
},
|
||||
{
|
||||
props: (props) =>
|
||||
props.variant === "contained" && props.color === "secondary",
|
||||
style: {
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.border.light,
|
||||
},
|
||||
},
|
||||
],
|
||||
fontWeight: 400,
|
||||
borderRadius: 4,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21 10H3M21 12.5V8.8C21 7.11984 21 6.27976 20.673 5.63803C20.3854 5.07354 19.9265 4.6146 19.362 4.32698C18.7202 4 17.8802 4 16.2 4H7.8C6.11984 4 5.27976 4 4.63803 4.32698C4.07354 4.6146 3.6146 5.07354 3.32698 5.63803C3 6.27976 3 7.11984 3 8.8V17.2C3 18.8802 3 19.7202 3.32698 20.362C3.6146 20.9265 4.07354 21.3854 4.63803 21.673C5.27976 22 6.11984 22 7.8 22H12M16 2V6M8 2V6M14.5 19L16.5 21L21 16.5" stroke="black" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 594 B |
@@ -4,6 +4,10 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-weight: 400;
|
||||
|
||||
Reference in new issue
Block a user