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,
- },
- },
-}));