From 5b395b96cd5f7001dee9d62c5a20e03471b6993f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 11 Jul 2025 11:23:50 -0700 Subject: [PATCH] implemet stats --- .../Components/Charts/CustomGauge/index.jsx | 35 ++++++- .../Diagnostics/components/gauges/index.jsx | 73 ++++++++++---- .../Diagnostics/components/gauges/utils.js | 4 - .../Diagnostics/components/stats/index.jsx | 97 +++++++++++++++++++ client/src/Pages/Logs/Diagnostics/index.jsx | 20 +++- .../src/Pages/Logs/Diagnostics/utils/utils.js | 16 +++ client/src/Pages/Logs/Logs/index.jsx | 4 + .../Logs/Queue/components/Metrics/index.jsx | 27 +++--- client/src/Pages/Logs/Queue/index.jsx | 69 +++++++------ client/src/Utils/timeUtils.js | 4 + client/src/locales/en.json | 22 ++++- 11 files changed, 294 insertions(+), 77 deletions(-) delete mode 100644 client/src/Pages/Logs/Diagnostics/components/gauges/utils.js create mode 100644 client/src/Pages/Logs/Diagnostics/components/stats/index.jsx create mode 100644 client/src/Pages/Logs/Diagnostics/utils/utils.js diff --git a/client/src/Components/Charts/CustomGauge/index.jsx b/client/src/Components/Charts/CustomGauge/index.jsx index 359b5b328..d9718d72c 100644 --- a/client/src/Components/Charts/CustomGauge/index.jsx +++ b/client/src/Components/Charts/CustomGauge/index.jsx @@ -1,8 +1,10 @@ import { useTheme } from "@emotion/react"; import { useEffect, useState, useMemo } from "react"; +import Stack from "@mui/material/Stack"; import { Box, Typography } from "@mui/material"; import PropTypes from "prop-types"; import "./index.css"; +import CircularProgress from "@mui/material/CircularProgress"; const MINIMUM_VALUE = 0; const MAXIMUM_VALUE = 100; @@ -16,6 +18,8 @@ const MAXIMUM_VALUE = 100; * @param {number} [props.radius=60] - Radius of the gauge circle * @param {number} [props.strokeWidth=15] - Width of the gauge stroke * @param {number} [props.threshold=50] - Threshold for color change + * @param {number} [props.precision=1] - Precision of the progress percentage + * @param {string} [props.unit="%"] - Unit of progress * * @example * { +const CustomGauge = ({ + isLoading = false, + progress = 0, + radius = 70, + strokeWidth = 15, + threshold = 50, + precision = 1, + unit = "%", +}) => { const theme = useTheme(); // Calculate the length of the stroke for the circle const { circumference, totalSize, strokeLength } = useMemo( @@ -57,6 +69,20 @@ const CustomGauge = ({ progress = 0, radius = 70, strokeWidth = 15, threshold = ? theme.palette.error.lowContrast : theme.palette.accent.main; + if (isLoading) { + return ( + + + + ); + } + return ( - {`${progressWithinRange.toFixed(1)}%`} + {`${progressWithinRange.toFixed(precision)}${unit}`} ); @@ -112,8 +138,11 @@ const CustomGauge = ({ progress = 0, radius = 70, strokeWidth = 15, threshold = export default CustomGauge; CustomGauge.propTypes = { + isLoading: PropTypes.bool, progress: PropTypes.number, radius: PropTypes.number, strokeWidth: PropTypes.number, threshold: PropTypes.number, + precision: PropTypes.number, + unit: PropTypes.string, }; diff --git a/client/src/Pages/Logs/Diagnostics/components/gauges/index.jsx b/client/src/Pages/Logs/Diagnostics/components/gauges/index.jsx index 21d9a35d8..e9f235112 100644 --- a/client/src/Pages/Logs/Diagnostics/components/gauges/index.jsx +++ b/client/src/Pages/Logs/Diagnostics/components/gauges/index.jsx @@ -1,12 +1,12 @@ import Stack from "@mui/material/Stack"; -import Box from "@mui/material/Box"; import Gauge 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"; +import { getPercentage } from "../../utils/utils"; +import { useTranslation } from "react-i18next"; const GaugeBox = ({ title, subtitle, children }) => { const theme = useTheme(); @@ -14,6 +14,8 @@ const GaugeBox = ({ title, subtitle, children }) => { {children} @@ -23,52 +25,85 @@ const GaugeBox = ({ title, subtitle, children }) => { ); }; -const Gauges = ({ diagnostics }) => { +GaugeBox.propTypes = { + title: PropTypes.string.isRequired, + subtitle: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, +}; + +const Gauges = ({ diagnostics, isLoading }) => { const heapTotalSize = getPercentage( - diagnostics?.v8HeapStats?.totalHeapSizeMb, - diagnostics?.v8HeapStats?.heapSizeLimitMb + diagnostics?.v8HeapStats?.totalHeapSizeBytes, + diagnostics?.v8HeapStats?.heapSizeLimitBytes ); const heapUsedSize = getPercentage( - diagnostics?.v8HeapStats?.usedHeapSizeMb, - diagnostics?.v8HeapStats?.heapSizeLimitMb + diagnostics?.v8HeapStats?.usedHeapSizeBytes, + diagnostics?.v8HeapStats?.heapSizeLimitBytes ); const actualHeapUsed = getPercentage( - diagnostics?.v8HeapStats?.usedHeapSizeMb, - diagnostics?.v8HeapStats?.totalHeapSizeMb + diagnostics?.v8HeapStats?.usedHeapSizeBytes, + diagnostics?.v8HeapStats?.totalHeapSizeBytes ); + const theme = useTheme(); + const { t } = useTranslation(); return ( - + - + - + + + + ); }; Gauges.propTypes = { - diagnostics: PropTypes.object.isRequired, + diagnostics: PropTypes.object, + isLoading: PropTypes.bool, }; export default Gauges; diff --git a/client/src/Pages/Logs/Diagnostics/components/gauges/utils.js b/client/src/Pages/Logs/Diagnostics/components/gauges/utils.js deleted file mode 100644 index bdc570a3b..000000000 --- a/client/src/Pages/Logs/Diagnostics/components/gauges/utils.js +++ /dev/null @@ -1,4 +0,0 @@ -export const getPercentage = (value, total) => { - if (!value || !total) return 0; - return (value / total) * 100; -}; diff --git a/client/src/Pages/Logs/Diagnostics/components/stats/index.jsx b/client/src/Pages/Logs/Diagnostics/components/stats/index.jsx new file mode 100644 index 000000000..103d1c698 --- /dev/null +++ b/client/src/Pages/Logs/Diagnostics/components/stats/index.jsx @@ -0,0 +1,97 @@ +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import CircularProgress from "@mui/material/CircularProgress"; + +import { useTheme } from "@emotion/react"; +import PropTypes from "prop-types"; + +import { getHumanReadableDuration } from "../../../../../Utils/timeUtils"; +import { formatBytes } from "../../utils/utils"; +import { useTranslation } from "react-i18next"; + +const StatsCard = ({ title, value, unit = "", isLoading }) => { + const theme = useTheme(); + return ( + + {isLoading ? ( + + + + ) : ( + + + {title} + + + {value} {unit} + + + )} + + ); +}; + +StatsCard.propTypes = { + title: PropTypes.string, + value: PropTypes.string, + unit: PropTypes.string, + isLoading: PropTypes.bool, +}; + +const Stats = ({ diagnostics, isLoading }) => { + const theme = useTheme(); + const { t } = useTranslation(); + return ( + + + + + + + + + + + ); +}; + +Stats.propTypes = { + diagnostics: PropTypes.object, + isLoading: PropTypes.bool, +}; + +export default Stats; diff --git a/client/src/Pages/Logs/Diagnostics/index.jsx b/client/src/Pages/Logs/Diagnostics/index.jsx index 9d7ee4639..e000c05bc 100644 --- a/client/src/Pages/Logs/Diagnostics/index.jsx +++ b/client/src/Pages/Logs/Diagnostics/index.jsx @@ -2,6 +2,8 @@ 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 { useTheme } from "@emotion/react"; import { useState } from "react"; @@ -15,14 +17,26 @@ const Diagnostics = () => { const theme = useTheme(); const { t } = useTranslation(); const [diagnostics, isLoading, error] = useFetchDiagnostics(); - console.log(diagnostics); // Setup return ( - {t("diagnosticsPage.description")} + {t("diagnosticsPage.diagnosticDescription")} - + + + + + ); }; diff --git a/client/src/Pages/Logs/Diagnostics/utils/utils.js b/client/src/Pages/Logs/Diagnostics/utils/utils.js new file mode 100644 index 000000000..a3b75631f --- /dev/null +++ b/client/src/Pages/Logs/Diagnostics/utils/utils.js @@ -0,0 +1,16 @@ +export const getPercentage = (value, total) => { + if (!value || !total) return 0; + return (value / total) * 100; +}; + +export const formatBytes = (bytes) => { + if (!bytes) return "N/A"; + + if (bytes === 0) return "0 Bytes"; + + if (bytes >= 1024 * 1024 * 1024) { + return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`; + } + + return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; +}; diff --git a/client/src/Pages/Logs/Logs/index.jsx b/client/src/Pages/Logs/Logs/index.jsx index d8bd323a3..b65f9c0fd 100644 --- a/client/src/Pages/Logs/Logs/index.jsx +++ b/client/src/Pages/Logs/Logs/index.jsx @@ -2,6 +2,7 @@ import Stack from "@mui/material/Stack"; import Box from "@mui/material/Box"; import Select from "../../../Components/Inputs/Select"; import Typography from "@mui/material/Typography"; +import Divider from "@mui/material/Divider"; import { useFetchLogs } from "../../../Hooks/logHooks"; import { useTheme } from "@emotion/react"; @@ -53,10 +54,13 @@ const Logs = () => { {t("logsPage.description")} + + {t("logsPage.logLevelSelect.title")}