From e42b4b28081760fef67cd8638bb0e62e1c8d41ad Mon Sep 17 00:00:00 2001 From: Owaise Date: Tue, 5 Aug 2025 20:46:42 +0530 Subject: [PATCH] fixed the minor changes for FE. --- .../Components/Charts/Utils/chartUtils.jsx | 2 +- .../Components/NetworkStats/NetworkCharts.jsx | 219 ++++++++++-------- .../NetworkStats/NetworkStatBoxes.jsx | 64 ++--- .../Details/Components/NetworkStats/index.jsx | 132 +++++++---- 4 files changed, 234 insertions(+), 183 deletions(-) diff --git a/client/src/Components/Charts/Utils/chartUtils.jsx b/client/src/Components/Charts/Utils/chartUtils.jsx index bbf81ae38..af5f27c66 100644 --- a/client/src/Components/Charts/Utils/chartUtils.jsx +++ b/client/src/Components/Charts/Utils/chartUtils.jsx @@ -88,7 +88,7 @@ PercentTick.propTypes = { */ const getFormattedPercentage = (value) => { if (typeof value !== "number") return value; - return `${(value * 100).toFixed(2)}.%`; + return `${(value * 100).toFixed(2)}%`; }; /** diff --git a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkCharts.jsx b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkCharts.jsx index 9ef548b2e..343f7681b 100644 --- a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkCharts.jsx +++ b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkCharts.jsx @@ -1,111 +1,130 @@ // NetworkCharts.jsx -import { Grid, Card, CardContent, Typography } from "@mui/material"; -import { useTheme } from "@mui/material/styles"; -import AreaChart from "../../../../../Components/Charts/AreaChart"; -import { TzTick, InfrastructureTooltip } from '../../../../../Components/Charts/Utils/chartUtils'; +import PropTypes from "prop-types"; +import { Stack } from "@mui/material"; +import InfraAreaChart from "../../../../../Pages/Infrastructure/Details/Components/AreaChartBoxes/InfraAreaChart"; -const BytesTick = ({ x, y, payload }) => { - const value = payload.value; - const label = - value >= 1024 ** 3 - ? `${(value / 1024 ** 3).toFixed(2)} GB` - : value >= 1024 ** 2 - ? `${(value / 1024 ** 2).toFixed(2)} MB` - : `${(value / 1024).toFixed(2)} KB`; - - return {label}; -}; +// Utils +import { + TzTick, + InfrastructureTooltip, +} from "../../../../../Components/Charts/Utils/chartUtils"; +import { useTheme } from "@emotion/react"; const getFormattedNetworkMetric = (value) => { - if (typeof value !== "number" || isNaN(value)) return "0"; - if (value >= 1024 ** 3) return `${(value / 1024 ** 3).toFixed(1)} GB/s`; - if (value >= 1024 ** 2) return `${(value / 1024 ** 2).toFixed(1)} MB/s`; - if (value >= 1024) return `${(value / 1024).toFixed(1)} KB/s`; - return `${Math.round(value)} B/s`; + if (typeof value !== "number" || isNaN(value)) return "0"; + if (value >= 1024 ** 3) return `${(value / 1024 ** 3).toFixed(1)} GB/s`; + if (value >= 1024 ** 2) return `${(value / 1024 ** 2).toFixed(1)} MB/s`; + if (value >= 1024) return `${(value / 1024).toFixed(1)} KB/s`; + return `${Math.round(value)} B/s`; }; const NetworkCharts = ({ eth0Data, dateRange }) => { - const theme = useTheme(); - const textColor = theme.palette.primary.contrastTextTertiary; + const theme = useTheme(); - const charts = [ - { title: "Bytes per second", key: "bytesPerSec", color: theme.palette.info.main, yTick: }, - { title: "Packets per second", key: "packetsPerSec", color: theme.palette.success.main }, - { title: "Errors", key: "errors", color: theme.palette.error.main }, - { title: "Drops", key: "drops", color: theme.palette.warning.main } - ]; + const configs = [ + { + type: "network-bytes", + data: eth0Data, + dataKeys: ["bytesPerSec"], + heading: "Bytes per second", + strokeColor: theme.palette.info.main, + gradientStartColor: theme.palette.info.main, + yLabel: "Bytes per second", + xTick: , + toolTip: ( + + ), + }, + { + type: "network-packets", + data: eth0Data, + dataKeys: ["packetsPerSec"], + heading: "Packets per second", + strokeColor: theme.palette.success.main, + gradientStartColor: theme.palette.success.main, + yLabel: "Packets per second", + xTick: , + toolTip: ( + Math.round(value).toLocaleString()} + /> + ), + }, + { + type: "network-errors", + data: eth0Data, + dataKeys: ["errors"], + heading: "Errors", + strokeColor: theme.palette.error.main, + gradientStartColor: theme.palette.error.main, + yLabel: "Errors", + xTick: , + toolTip: ( + Math.round(value).toLocaleString()} + /> + ), + }, + { + type: "network-drops", + data: eth0Data, + dataKeys: ["drops"], + heading: "Drops", + strokeColor: theme.palette.warning.main, + gradientStartColor: theme.palette.warning.main, + yLabel: "Drops", + xTick: , + toolTip: ( + Math.round(value).toLocaleString()} + /> + ), + }, + ]; - const formatYAxis = (key, value) => { - if (key === "bytesPerSec") { - // Format as MB/s or GB/s if large - if (value >= 1024 ** 3) return `${(value / 1024 ** 3).toFixed(1)} GB/s`; - if (value >= 1024 ** 2) return `${(value / 1024 ** 2).toFixed(1)} MB/s`; - if (value >= 1024) return `${(value / 1024).toFixed(1)} KB/s`; - return `${Math.round(value)} B/s`; - } - return Math.round(value).toLocaleString(); - }; - - const CustomTick = ({ x, y, payload, chartKey }) => { - // Ensure value is always rounded for display - let value = payload.value; - if (typeof value === 'number') { - value = Math.round(value); - } - return ( - - {formatYAxis(chartKey, value)} - - ); - }; - - const chartConfigs = charts.map((chart) => ({ - data: eth0Data, - dataKeys: [chart.key], - heading: chart.title, - strokeColor: chart.color, - gradientStartColor: chart.color, - yTick: chart.yTick || , - xTick: , - toolTip: ( - - ), - })); - - return ( - - {chartConfigs.map((config, idx) => ( - - - - - {config.heading} - - - - - - ))} - - ); + return ( + *": { + flexBasis: `calc(50% - ${theme.spacing(8)})`, + maxWidth: `calc(50% - ${theme.spacing(8)})`, + }, + }} + > + {configs.map((config) => ( + + ))} + + ); }; -export default NetworkCharts; \ No newline at end of file +NetworkCharts.propTypes = { + eth0Data: PropTypes.array.isRequired, + dateRange: PropTypes.string.isRequired, +}; + +export default NetworkCharts; diff --git a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkStatBoxes.jsx b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkStatBoxes.jsx index 5253742a6..b2f2f7841 100644 --- a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkStatBoxes.jsx +++ b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/NetworkStatBoxes.jsx @@ -1,16 +1,9 @@ // NetworkStatBoxes.jsx -import DataUsageIcon from "@mui/icons-material/DataUsage"; -import NetworkCheckIcon from "@mui/icons-material/NetworkCheck"; -import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import PropTypes from "prop-types"; import StatusBoxes from "../../../../../Components/StatusBoxes"; import StatBox from "../../../../../Components/StatBox"; import { Typography } from "@mui/material"; -const INTERFACE_LABELS = { - en0: "Ethernet/Wi-Fi (Primary)", - wlan0: "Wi-Fi (Secondary)", -}; - function formatBytes(bytes) { if (bytes === 0 || bytes == null) return "0 B"; const k = 1024; @@ -37,48 +30,57 @@ const NetworkStatBoxes = ({ shouldRender, net }) => { shouldRender={shouldRender} flexWrap="wrap" > - {filtered.map((iface) => ( - <> + {filtered + .map((iface) => [ + />, + />, + />, + />, + />, - - ))} + />, + ]) + .flat()} ); }; +NetworkStatBoxes.propTypes = { + shouldRender: PropTypes.bool.isRequired, + net: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + bytes_sent: PropTypes.number, + bytes_recv: PropTypes.number, + packets_sent: PropTypes.number, + packets_recv: PropTypes.number, + err_in: PropTypes.number, + err_out: PropTypes.number, + }) + ), +}; + export default NetworkStatBoxes; diff --git a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx index 60825be0f..6b8ccb85a 100644 --- a/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx +++ b/client/src/Pages/Infrastructure/Details/Components/NetworkStats/index.jsx @@ -1,34 +1,10 @@ +import PropTypes from "prop-types"; import NetworkStatBoxes from "./NetworkStatBoxes"; import NetworkCharts from "./NetworkCharts"; import MonitorTimeFrameHeader from "../../../../../Components/MonitorTimeFrameHeader"; -function filterByDateRange(data, dateRange) { - if (!Array.isArray(data)) return []; - const now = Date.now(); - let cutoff; - switch (dateRange) { - case "recent": - cutoff = now - 2 * 60 * 60 * 1000; // last 2 hours - break; - case "day": - cutoff = now - 24 * 60 * 60 * 1000; // last 24 hours - break; - case "week": - cutoff = now - 7 * 24 * 60 * 60 * 1000; // last 7 days - break; - case "month": - cutoff = now - 30 * 24 * 60 * 60 * 1000; // last 30 days - break; - default: - cutoff = 0; - } - return data.filter((d) => new Date(d.time).getTime() >= cutoff); -} - const Network = ({ net, checks, isLoading, dateRange, setDateRange }) => { const eth0Data = getEth0TimeSeries(checks); - const xAxisFormatter = getXAxisFormatter(checks); - const filteredEth0Data = filterByDateRange(eth0Data, dateRange); return ( <> @@ -42,66 +18,120 @@ const Network = ({ net, checks, isLoading, dateRange, setDateRange }) => { setDateRange={setDateRange} /> ); }; +Network.propTypes = { + net: PropTypes.array, + checks: PropTypes.array, + isLoading: PropTypes.bool.isRequired, + dateRange: PropTypes.string.isRequired, + setDateRange: PropTypes.func.isRequired, +}; + export default Network; /* ---------- Helper functions ---------- */ function getEth0TimeSeries(checks) { + console.log(`[NetworkStats] Processing ${checks?.length || 0} checks`); + if (checks && checks.length > 0) { + console.log("[NetworkStats] First check _id:", checks[0]._id); + console.log("[NetworkStats] Last check _id:", checks[checks.length - 1]._id); + console.log( + "[NetworkStats] Sample check structure:", + JSON.stringify(checks[0], null, 2) + ); + } + const sorted = [...(checks || [])].sort((a, b) => new Date(a._id) - new Date(b._id)); const series = []; let prev = null; for (const check of sorted) { + console.log(`[NetworkStats] Processing check: ${check._id}`); const eth = (check.net || []).find((iface) => iface.name === "en0"); if (!eth) { + console.log("[NetworkStats] No en0 interface found in check:", check._id); prev = check; continue; } + + console.log(`[NetworkStats] Found en0 interface in check ${check._id}:`, eth); + if (prev) { + console.log(`[NetworkStats] Have previous check: ${prev._id}`); const prevEth = (prev.net || []).find((iface) => iface.name === "en0"); const t1 = new Date(check._id); const t0 = new Date(prev._id); + console.log(`[NetworkStats] Time difference: ${t1 - t0}ms`); + if (!prevEth || isNaN(t1) || isNaN(t0)) { + console.log("[NetworkStats] Skipping - invalid prev data or time"); prev = check; continue; } + const dt = (t1 - t0) / 1000; + console.log(`[NetworkStats] Delta time: ${dt}s`); + if (dt > 0) { - series.push({ - time: check._id, - bytesPerSec: (eth.bytesSent - prevEth.bytesSent) / dt, - packetsPerSec: (eth.packetsSent - prevEth.packetsSent) / dt, - errors: (eth.errIn ?? 0) + (eth.errOut ?? 0), - drops: (eth.dropIn ?? 0) + (eth.dropOut ?? 0), + const bytesField = eth.avgBytesSent; + const prevBytesField = prevEth.avgBytesSent; + + console.log(`[NetworkStats] Bytes comparison:`, { + current: bytesField, + previous: prevBytesField, + diff: bytesField - prevBytesField, }); + + if (bytesField !== undefined && prevBytesField !== undefined) { + const dataPoint = { + _id: check._id, // Use _id instead of time to match AreaChartBoxes + bytesPerSec: (bytesField - prevBytesField) / dt, + packetsPerSec: (eth.avgPacketsSent - prevEth.avgPacketsSent) / dt, + errors: (eth.avgErrIn ?? 0) + (eth.avgErrOut ?? 0), + drops: 0, // Skip drops for now since we don't have avgDropIn/Out + }; + console.log(`[NetworkStats] Adding data point:`, dataPoint); + series.push(dataPoint); + } else { + console.warn("[NetworkStats] Missing bytes fields:", { eth, prevEth }); + } + } else { + console.log("[NetworkStats] Skipping - zero or negative time delta"); } + } else { + console.log("[NetworkStats] No previous check yet, setting as prev"); } prev = check; } + console.log(`[NetworkStats] Generated ${series.length} time series data points`); + + // If we only have one check, create a single data point with absolute values + if (series.length === 0 && sorted.length === 1) { + const check = sorted[0]; + const eth = (check.net || []).find((iface) => iface.name === "en0"); + if (eth) { + console.log( + "[NetworkStats] Only one data point available, showing absolute values" + ); + series.push({ + _id: check._id, // Use _id instead of time to match AreaChartBoxes + bytesPerSec: eth.avgBytesSent || 0, // Show absolute value instead of rate + packetsPerSec: eth.avgPacketsSent || 0, // Show absolute value instead of rate + errors: (eth.avgErrIn ?? 0) + (eth.avgErrOut ?? 0), + drops: 0, + }); + } + } + + if (series.length > 0) { + console.log("[NetworkStats] Sample series data:", series[0]); + } return series; } - -function getXAxisFormatter(checks) { - if (!checks || checks.length === 0) return (val) => val; - const sorted = [...checks].sort((a, b) => new Date(a._id) - new Date(b._id)); - const first = new Date(sorted[0]._id); - const last = new Date(sorted[sorted.length - 1]._id); - const diffDays = (last - first) / (1000 * 60 * 60 * 24); - - return diffDays > 2 - ? (val) => - new Date(val).toLocaleDateString(undefined, { month: "short", day: "numeric" }) - : (val) => - new Date(val).toLocaleTimeString(undefined, { - hour: "2-digit", - minute: "2-digit", - hour12: false, - }); -}