diff --git a/Client/src/Pages/Infrastructure/Details/index.jsx b/Client/src/Pages/Infrastructure/Details/index.jsx index 346fe9c5e..66cebdea7 100644 --- a/Client/src/Pages/Infrastructure/Details/index.jsx +++ b/Client/src/Pages/Infrastructure/Details/index.jsx @@ -20,6 +20,7 @@ import { TemperatureTooltip, } from "../../../Components/Charts/Utils/chartUtils"; import PropTypes from "prop-types"; +import StatBox from "../../../Components/StatBox"; const BASE_BOX_PADDING_VERTICAL = 4; const BASE_BOX_PADDING_HORIZONTAL = 8; @@ -29,18 +30,50 @@ const TYPOGRAPHY_PADDING = 8; * @param {number} bytes - Number of bytes to convert * @returns {number} Converted value in gigabytes */ -const formatBytes = (bytes) => { - if (bytes === undefined || bytes === null) return "0 GB"; - if (typeof bytes !== "number") return "0 GB"; - if (bytes === 0) return "0 GB"; +const formatBytes = (bytes, space = false) => { + if (bytes === undefined || bytes === null) + return ( + <> + {0} + {space ? " " : ""} + GB + + ); + if (typeof bytes !== "number") + return ( + <> + {0} + {space ? " " : ""} + GB + + ); + if (bytes === 0) + return ( + <> + {0} + {space ? " " : ""} + GB + + ); const GB = bytes / (1024 * 1024 * 1024); const MB = bytes / (1024 * 1024); if (GB >= 1) { - return `${Number(GB.toFixed(0))} GB`; + return ( + <> + {Number(GB.toFixed(0))} + {space ? " " : ""} + GB + + ); } else { - return `${Number(MB.toFixed(0))} MB`; + return ( + <> + {Number(MB.toFixed(0))} + MB + + ); } }; @@ -93,27 +126,6 @@ BaseBox.propTypes = { sx: PropTypes.object, }; -/** - * Renders a statistic box with a heading and subheading - * @param {Object} props - Component properties - * @param {string} props.heading - Primary heading text - * @param {string} props.subHeading - Secondary heading text - * @returns {React.ReactElement} Stat box component - */ -const StatBox = ({ heading, subHeading }) => { - return ( - - {heading} - {subHeading} - - ); -}; - -StatBox.propTypes = { - heading: PropTypes.string.isRequired, - subHeading: PropTypes.string.isRequired, -}; - /** * Renders a gauge box with usage visualization * @param {Object} props - Component properties @@ -193,7 +205,7 @@ const InfrastructureDetails = () => { const [monitor, setMonitor] = useState(null); const { authToken } = useSelector((state) => state.auth); const [dateRange, setDateRange] = useState("all"); - const { statusColor, determineState } = useUtils(); + const { statusColor, statusStyles, determineState } = useUtils(); // These calculations are needed because ResponsiveContainer // doesn't take padding of parent/siblings into account // when calculating height. @@ -205,7 +217,7 @@ const InfrastructureDetails = () => { (chartContainerHeight - totalChartContainerPadding - totalTypographyPadding) * 0.95; // end height calculations - const buildStatBoxes = (checks) => { + const buildStatBoxes = (checks, uptime) => { let latestCheck = checks[0] ?? null; if (latestCheck === null) return []; @@ -224,25 +236,51 @@ const InfrastructureDetails = () => { const platform = latestCheck?.host?.platform ?? null; const osPlatform = os === null && platform === null ? null : `${os} ${platform}`; return [ + { + id: 7, + sx: statusStyles[determineState(monitor)], + heading: "Status", + subHeading: monitor?.status === true ? "Active" : "Inactive", + }, { id: 0, heading: "CPU (Physical)", - subHeading: `${physicalCores} cores`, + subHeading: ( + <> + {physicalCores} + cores + + ), }, { id: 1, heading: "CPU (Logical)", - subHeading: `${logicalCores} cores`, + subHeading: ( + <> + {logicalCores} + cores + + ), }, { id: 2, heading: "CPU Frequency", - subHeading: `${(cpuFrequency / 1000).toFixed(2)} Ghz`, + subHeading: ( + <> + {(cpuFrequency / 1000).toFixed(2)} + Ghz + + ), }, { id: 3, heading: "Average CPU Temperature", - subHeading: `${cpuTemperature.toFixed(2)} C`, + subHeading: ( + <> + {cpuTemperature.toFixed(2)} + C + + ), }, { id: 4, @@ -254,12 +292,17 @@ const InfrastructureDetails = () => { heading: "Disk", subHeading: formatBytes(diskTotalBytes), }, - { id: 6, heading: "Uptime", subHeading: "100%" }, { - id: 7, - heading: "Status", - subHeading: monitor?.status === true ? "Active" : "Inactive", + id: 6, + heading: "Uptime", + subHeading: ( + <> + {(uptime * 100).toFixed(2)} + % + + ), }, + { id: 8, heading: "OS", @@ -285,9 +328,9 @@ const InfrastructureDetails = () => { value: decimalToPercentage(memoryUsagePercent), heading: "Memory usage", metricOne: "Used", - valueOne: formatBytes(memoryUsedBytes), + valueOne: formatBytes(memoryUsedBytes, true), metricTwo: "Total", - valueTwo: formatBytes(memoryTotalBytes), + valueTwo: formatBytes(memoryTotalBytes, true), }, { type: "cpu", @@ -304,9 +347,9 @@ const InfrastructureDetails = () => { value: decimalToPercentage(disk.usage_percent), heading: `Disk${idx} usage`, metricOne: "Used", - valueOne: formatBytes(disk.total_bytes - disk.free_bytes), + valueOne: formatBytes(disk.total_bytes - disk.free_bytes, true), metricTwo: "Total", - valueTwo: formatBytes(disk.total_bytes), + valueTwo: formatBytes(disk.total_bytes, true), })), ]; }; @@ -466,7 +509,10 @@ const InfrastructureDetails = () => { fetchData(); }, [authToken, monitorId, dateRange, navigate]); - const statBoxConfigs = buildStatBoxes(monitor?.checks ?? []); + const statBoxConfigs = buildStatBoxes( + monitor?.checks ?? [], + monitor?.uptimePercentage ?? "Unknown" + ); const gaugeBoxConfigs = buildGaugeBoxConfigs(monitor?.checks ?? []); const areaChartConfigs = buildAreaChartConfigs(monitor?.checks ?? []); diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index b0db13432..32e3b663c 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -5,7 +5,7 @@ import { useTheme } from "@emotion/react"; import { useNavigate, useParams } from "react-router-dom"; import { useSelector } from "react-redux"; import { formatDurationRounded, formatDurationSplit } from "../../../Utils/timeUtils"; -import { ChartBox, IconBox, StatBox } from "./styled"; +import { ChartBox, IconBox } from "./styled"; import { logger } from "../../../Utils/Logger"; import { networkService } from "../../../main"; import SkeletonLayout from "./skeleton"; @@ -22,6 +22,7 @@ import PieChart from "./Charts/PieChart"; import useUtils from "../../Uptime/utils"; import "./index.css"; import { useIsAdmin } from "../../../Hooks/useIsAdmin"; +import StatBox from "../../../Components/StatBox"; const PageSpeedDetails = () => { const theme = useTheme(); @@ -187,20 +188,24 @@ const PageSpeedDetails = () => { direction="row" gap={theme.spacing(8)} > - - checks since - - {splitDuration(monitor?.uptimeDuration)} - ago - - - - last check - - {splitDuration(monitor?.lastChecked)} - ago - - + + {splitDuration(monitor?.uptimeDuration)} + ago + + } + /> + + {splitDuration(monitor?.lastChecked)} + ago + + } + /> ({ }, }, })); - -export const StatBox = styled(Box)(({ theme }) => ({ - padding: `${theme.spacing(4)} ${theme.spacing(8)}`, - minWidth: 200, - width: 225, - border: 1, - borderStyle: "solid", - borderColor: theme.palette.border.light, - borderRadius: 4, - backgroundColor: theme.palette.background.main, - background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`, - "& h2": { - fontSize: 13, - fontWeight: 500, - color: theme.palette.text.secondary, - textTransform: "uppercase", - }, - "& p": { - fontSize: 18, - color: theme.palette.text.primary, - marginTop: theme.spacing(2), - "& span": { - color: theme.palette.text.tertiary, - marginLeft: theme.spacing(2), - fontSize: 15, - }, - }, -})); diff --git a/Client/src/Pages/Uptime/Details/index.jsx b/Client/src/Pages/Uptime/Details/index.jsx index 43dd86ca4..5989f643b 100644 --- a/Client/src/Pages/Uptime/Details/index.jsx +++ b/Client/src/Pages/Uptime/Details/index.jsx @@ -26,7 +26,8 @@ import HistoryIcon from "../../../assets/icons/history-icon.svg?react"; import PaginationTable from "./PaginationTable"; import Breadcrumbs from "../../../Components/Breadcrumbs"; import PulseDot from "../../../Components/Animated/PulseDot"; -import { StatBox, ChartBox, IconBox } from "./styled"; +import StatBox from "../../../Components/StatBox"; +import { ChartBox, IconBox } from "./styled"; import { DownBarChart, ResponseGaugeChart, UpBarChart } from "./Charts"; import SkeletonLayout from "./skeleton"; import "./index.css"; @@ -283,24 +284,24 @@ const DetailsPage = () => { direction="row" gap={theme.spacing(8)} > - - active for - {splitDuration(monitor?.uptimeDuration)} - - - last check - - {splitDuration(monitor?.lastChecked)} - ago - - - - last response time - - {monitor?.latestResponseTime} - ms - - + + + + {monitor?.latestResponseTime} + {"ms"} + + } + /> ({ }, }, })); - -export const StatBox = styled(Box)(({ theme }) => ({ - padding: `${theme.spacing(4)} ${theme.spacing(8)}`, - minWidth: 200, - width: 225, - border: 1, - borderStyle: "solid", - borderColor: theme.palette.border.light, - borderRadius: 4, - backgroundColor: theme.palette.background.main, - background: `linear-gradient(340deg, ${theme.palette.background.accent} 20%, ${theme.palette.background.main} 45%)`, - "& h2": { - fontSize: 13, - fontWeight: 500, - color: theme.palette.text.secondary, - textTransform: "uppercase", - }, - "& p": { - fontSize: 18, - color: theme.palette.text.primary, - marginTop: theme.spacing(2), - "& span": { - color: theme.palette.text.tertiary, - marginLeft: theme.spacing(2), - fontSize: 15, - }, - }, -}));