mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-05 07:59:30 -05:00
fix: update diagnostic page design to match infrastructure page
- Remove 'System diagnostics' title and divider line - Add infrastructure-style status boxes with dynamic status - Update gauge components to use BaseContainer styling - Match infrastructure page layout and spacing Resolves #2725
This commit is contained in:
@@ -1,34 +1,83 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Gauge from "../../../../../Components/Charts/CustomGauge";
|
||||
import CustomGauge from "../../../../../Components/Charts/CustomGauge";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
// Utils
|
||||
import { useTheme } from "@emotion/react";
|
||||
import PropTypes from "prop-types";
|
||||
import { getPercentage } from "../../utils/utils";
|
||||
import { getPercentage, formatBytes } from "../../utils/utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
const GaugeBox = ({ title, subtitle, children }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack
|
||||
alignItems="center"
|
||||
p={theme.spacing(2)}
|
||||
maxWidth={150}
|
||||
width={150}
|
||||
>
|
||||
{children}
|
||||
|
||||
<Typography variant="h2">{title}</Typography>
|
||||
<Typography variant="body2">{subtitle}</Typography>
|
||||
</Stack>
|
||||
const BaseContainer = ({children}) => {
|
||||
const theme = useTheme()
|
||||
return(
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
padding: theme.spacing(3),
|
||||
borderRadius: theme.spacing(2),
|
||||
border: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
minWidth: 250,
|
||||
width: "fit-content",
|
||||
}}>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
GaugeBox.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
subtitle: PropTypes.string.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
const InfrastructureStyleGauge = ({ value, heading, metricOne, valueOne, metricTwo, valueTwo }) => {
|
||||
const theme = useTheme();
|
||||
const valueStyle = {
|
||||
borderRadius: theme.spacing(2),
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
width: "40%",
|
||||
mb: theme.spacing(2),
|
||||
mt: theme.spacing(2),
|
||||
pr: theme.spacing(2),
|
||||
textAlign: "right",
|
||||
};
|
||||
|
||||
return(
|
||||
<BaseContainer>
|
||||
<Stack direction="column" gap={theme.spacing(2)} alignItems="center">
|
||||
<Box
|
||||
sx = {{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
backgroundColor: theme.palette.gradient?.color1 || "transparent"
|
||||
}}
|
||||
>
|
||||
<CustomGauge progress={value} radius={100}/>
|
||||
<Typography component="h2" sx={{fontWeight: 600}}>
|
||||
{heading}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ width:"100%", borderTop:`1px solid ${theme.palette.primary.lowContrast}`}}>
|
||||
<Stack
|
||||
justifyContent={"space-between"}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<Typography>{metricOne}</Typography>
|
||||
<Typography sx={valueStyle}>{valueOne}</Typography>
|
||||
</Stack>
|
||||
<Stack
|
||||
justifyContent={"space-between"}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<Typography>{metricTwo}</Typography>
|
||||
<Typography sx={valueStyle}>{valueTwo}</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
</BaseContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const Gauges = ({ diagnostics, isLoading }) => {
|
||||
@@ -53,50 +102,41 @@ const Gauges = ({ diagnostics, isLoading }) => {
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={theme.spacing(4)}
|
||||
spacing={theme.spacing(8)}
|
||||
flexWrap="wrap"
|
||||
>
|
||||
<GaugeBox
|
||||
title={t("diagnosticsPage.gauges.heapAllocationTitle")}
|
||||
subtitle={t("diagnosticsPage.gauges.heapAllocationSubtitle")}
|
||||
>
|
||||
<Gauge
|
||||
isLoading={isLoading}
|
||||
radius={100}
|
||||
progress={heapTotalSize}
|
||||
/>
|
||||
</GaugeBox>
|
||||
<GaugeBox
|
||||
title={t("diagnosticsPage.gauges.heapUsageTitle")}
|
||||
subtitle={t("diagnosticsPage.gauges.heapUsageSubtitle")}
|
||||
>
|
||||
<Gauge
|
||||
isLoading={isLoading}
|
||||
radius={100}
|
||||
progress={heapUsedSize}
|
||||
/>
|
||||
</GaugeBox>
|
||||
<GaugeBox
|
||||
title={t("diagnosticsPage.gauges.heapUtilizationTitle")}
|
||||
subtitle={t("diagnosticsPage.gauges.heapUtilizationSubtitle")}
|
||||
>
|
||||
<Gauge
|
||||
isLoading={isLoading}
|
||||
radius={100}
|
||||
progress={actualHeapUsed}
|
||||
/>
|
||||
</GaugeBox>
|
||||
<GaugeBox
|
||||
title={t("diagnosticsPage.gauges.instantCpuUsageTitle")}
|
||||
subtitle={t("diagnosticsPage.gauges.instantCpuUsageSubtitle")}
|
||||
>
|
||||
<Gauge
|
||||
isLoading={isLoading}
|
||||
radius={100}
|
||||
progress={diagnostics?.cpuUsage?.usagePercentage}
|
||||
precision={2}
|
||||
/>
|
||||
</GaugeBox>
|
||||
<InfrastructureStyleGauge
|
||||
value={heapTotalSize}
|
||||
heading={t("diagnosticsPage.gauges.heapAllocationTitle")}
|
||||
metricOne="% of available memory"
|
||||
valueOne={`${heapTotalSize?.toFixed(1)}%`}
|
||||
metricTwo="Total Heap Limit"
|
||||
valueTwo={formatBytes(diagnostics?.v8HeapStats?.heapSizeLimitBytes)}
|
||||
/>
|
||||
<InfrastructureStyleGauge
|
||||
value={heapUsedSize}
|
||||
heading={t("diagnosticsPage.gauges.heapUsageTitle")}
|
||||
metricOne="% of available memory"
|
||||
valueOne={`${heapTotalSize?.toFixed(1)}%`}
|
||||
metricTwo="Used Heap Size"
|
||||
valueTwo={formatBytes(diagnostics?.v8HeapStats?.usedHeapSizeBytes)}
|
||||
/>
|
||||
<InfrastructureStyleGauge
|
||||
value={actualHeapUsed}
|
||||
heading={t("diagnosticsPage.gauges.heapUtilizationTitle")}
|
||||
metricOne="% of available memory"
|
||||
valueOne={`${heapTotalSize?.toFixed(1)}%`}
|
||||
metricTwo="Total Heap Limit"
|
||||
valueTwo={formatBytes(diagnostics?.v8HeapStats?.totalHeapSizeBytes)}
|
||||
/>
|
||||
<InfrastructureStyleGauge
|
||||
value={diagnostics?.cpuUsage?.usagePercentage}
|
||||
heading={t("diagnosticsPage.gauges.instantCpuUsageTitle")}
|
||||
metricOne="% of CPU used"
|
||||
valueOne={`${diagnostics?.cpuUsage?.usagePercentage?.toFixed(2)}%`}
|
||||
metricTwo="Usage level"
|
||||
valueTwo={diagnostics?.cpuUsage?.usagePercentage > 80 ? "High" : diagnostics?.cpuUsage?.usagePercentage > 50 ? "Medium" : "Low"}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Gauges from "./components/gauges";
|
||||
import Stats from "./components/stats";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
import StatBox from "../../../Components/StatBox";
|
||||
import StatusBoxes from "../../../Components/StatusBoxes";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useFetchDiagnostics } from "../../../Hooks/logHooks";
|
||||
import { getHumanReadableDuration } from "../../../Utils/timeUtils";
|
||||
import { formatBytes, getPercentage } from "./utils/utils";
|
||||
|
||||
const Diagnostics = () => {
|
||||
// Local state
|
||||
@@ -19,34 +19,57 @@ const Diagnostics = () => {
|
||||
const [diagnostics, fetchDiagnostics, isLoading, error] = useFetchDiagnostics();
|
||||
// Setup
|
||||
return (
|
||||
<Stack gap={theme.spacing(4)}>
|
||||
<Stack gap={theme.spacing(10)}>
|
||||
<StatusBoxes shouldRender={!isLoading} flexWrap="wrap">
|
||||
<StatBox
|
||||
gradient={true}
|
||||
status="up"
|
||||
heading={t("status")}
|
||||
subHeading={
|
||||
error
|
||||
? "Error"
|
||||
: isLoading
|
||||
? "Loading..."
|
||||
: diagnostics
|
||||
? "Diagnostics Available"
|
||||
: "No Data"
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Event loop delay"
|
||||
subHeading={getHumanReadableDuration(diagnostics?.eventLoopDelayMs)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Uptime"
|
||||
subHeading={getHumanReadableDuration(diagnostics?.uptimeMs)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Used Heap Size"
|
||||
subHeading={formatBytes(diagnostics?.v8HeapStats?.usedHeapSizeBytes)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Total Heap Size"
|
||||
subHeading={formatBytes(diagnostics?.v8HeapStats?.totalHeapSizeBytes)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="OS Memory Limit"
|
||||
subHeading={formatBytes(diagnostics?.osStats?.totalMemoryBytes)}
|
||||
/>
|
||||
</StatusBoxes>
|
||||
<Gauges
|
||||
diagnostics={diagnostics}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<Box>
|
||||
<Typography variant="h2">{t("diagnosticsPage.diagnosticDescription")}</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={fetchDiagnostics}
|
||||
loading={isLoading}
|
||||
>
|
||||
Fetch Diagnostics
|
||||
</Button>
|
||||
</Box>
|
||||
<Divider color={theme.palette.accent.main} />
|
||||
<Stack
|
||||
gap={theme.spacing(20)}
|
||||
mt={theme.spacing(10)}
|
||||
>
|
||||
<Gauges
|
||||
diagnostics={diagnostics}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<Stats
|
||||
diagnostics={diagnostics}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={fetchDiagnostics}
|
||||
loading={isLoading}
|
||||
>
|
||||
Fetch Diagnostics
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user