diff --git a/Client/src/App.jsx b/Client/src/App.jsx index 03c406a6c..82c8203a8 100644 --- a/Client/src/App.jsx +++ b/Client/src/App.jsx @@ -10,6 +10,7 @@ import Register from "./Pages/Auth/Register/Register"; import Account from "./Pages/Account"; import Monitors from "./Pages/Monitors/Home"; import CreateMonitor from "./Pages/Monitors/CreateMonitor"; +import CreateInfrastructureMonitor from "./Pages/Infrastructure/CreateMonitor"; import Incidents from "./Pages/Incidents"; import Status from "./Pages/Status"; import Integrations from "./Pages/Integrations"; @@ -39,7 +40,7 @@ import { getAppSettings } from "./Features/Settings/settingsSlice"; import { logger } from "./Utils/Logger"; // Import the logger import { networkService } from "./main"; import { Infrastructure } from "./Pages/Infrastructure"; -import InfrastructureDetails from "./Pages/Infrastructure/details"; +import InfrastructureDetails from "./Pages/Infrastructure/Details"; function App() { const AdminCheckedRegister = withAdminCheck(Register); const MonitorsWithAdminProp = withAdminProp(Monitors); @@ -129,7 +130,10 @@ function App() { path="infrastructure" element={} /> - + } + /> } diff --git a/Client/src/Components/Charts/AreaChart/data.js b/Client/src/Components/Charts/AreaChart/data.js deleted file mode 100644 index 43efd165d..000000000 --- a/Client/src/Components/Charts/AreaChart/data.js +++ /dev/null @@ -1,59 +0,0 @@ -const ObjectId = (string) => string; -const ISODate = (string) => string; - -// Helper to generate random percentage between 0.1 and 1.0 -const randomPercent = () => Number((Math.random() * 0.9 + 0.1).toFixed(2)); - -// Create base timestamp and increment by 5 minutes for each entry -const baseTime = new Date("2024-11-15T07:00:00.000Z"); -const checks = Array.from({ length: 20 }, (_, index) => { - const timestamp = new Date(baseTime.getTime() + index * 5 * 60 * 1000); - - return { - _id: ObjectId(`6736f4f449e23954c8b89a${index.toString(16).padStart(2, "0")}`), - monitorId: ObjectId("6736e6c2939f02e0ca519465"), - status: true, - responseTime: Math.floor(Math.random() * 50) + 80, // Random between 80-130ms - statusCode: 200, - message: "OK", - cpu: { - physical_core: 0, - logical_core: 0, - frequency: 0, - temperature: 0, - free_percent: 0, - usage_percent: randomPercent(), - _id: ObjectId(`6736f4f449e23954c8b89b${index.toString(16).padStart(2, "0")}`), - }, - memory: { - total_bytes: 0, - available_bytes: 0, - used_bytes: 0, - usage_percent: randomPercent(), - _id: ObjectId(`6736f4f449e23954c8b89c${index.toString(16).padStart(2, "0")}`), - }, - disk: [ - { - read_speed_bytes: 0, - write_speed_bytes: 0, - total_bytes: 0, - free_bytes: 0, - usage_percent: randomPercent(), - _id: ObjectId(`6736f4f449e23954c8b89d${index.toString(16).padStart(2, "0")}`), - }, - ], - host: { - os: "", - platform: "", - kernel_version: "", - _id: ObjectId(`6736f4f449e23954c8b89e${index.toString(16).padStart(2, "0")}`), - }, - errors: [], - expiry: ISODate(new Date(timestamp.getTime() + 24 * 60 * 60 * 1000).toISOString()), - createdAt: ISODate(timestamp.toISOString()), - updatedAt: ISODate(timestamp.toISOString()), - __v: 0, - }; -}); - -export default checks; diff --git a/Client/src/Components/Charts/AreaChart/index.jsx b/Client/src/Components/Charts/AreaChart/index.jsx index 4aa507940..d05dbb14a 100644 --- a/Client/src/Components/Charts/AreaChart/index.jsx +++ b/Client/src/Components/Charts/AreaChart/index.jsx @@ -10,7 +10,7 @@ import { import { createGradient } from "../Utils/gradientUtils"; import PropTypes from "prop-types"; import { useTheme } from "@mui/material"; - +import { useId } from "react"; /** * CustomAreaChart component for rendering an area chart with optional gradient and custom ticks. * @@ -83,13 +83,16 @@ const CustomAreaChart = ({ gradientStartColor, gradientEndColor, customTooltip, + height = "100%", }) => { const theme = useTheme(); - const gradientId = `gradient-${Math.random().toString(36).slice(2, 9)}`; + const uniqueId = useId(); + const gradientId = `gradient-${uniqueId}`; return ( - {customTooltip ? ( { // Calculate the length of the stroke for the circle - const circumference = 2 * Math.PI * radius; - const totalSize = radius * 2 + strokeWidth * 2; // This is the total size of the SVG, needed for the viewBox - const strokeLength = (progress / 100) * circumference; + const { circumference, totalSize, strokeLength } = useMemo( + () => ({ + circumference: 2 * Math.PI * radius, + totalSize: radius * 2 + strokeWidth * 2, + strokeLength: (progress / 100) * (2 * Math.PI * radius), + }), + [radius, strokeWidth, progress] + ); const [offset, setOffset] = useState(circumference); const theme = useTheme(); diff --git a/Client/src/Components/Charts/Utils/chartUtils.jsx b/Client/src/Components/Charts/Utils/chartUtils.jsx index ad673e472..043203525 100644 --- a/Client/src/Components/Charts/Utils/chartUtils.jsx +++ b/Client/src/Components/Charts/Utils/chartUtils.jsx @@ -74,6 +74,22 @@ PercentTick.propTypes = { index: PropTypes.number, }; +/** + * Converts a decimal value to a formatted percentage string. + * + * @param {number} value - The decimal value to convert (e.g., 0.75) + * @returns {string} Formatted percentage string (e.g., "75.00%") or original input if not a number + * + * @example + * getFormattedPercentage(0.7543) // Returns "75.43%" + * getFormattedPercentage(1) // Returns "100.00%" + * getFormattedPercentage("test") // Returns "test" + */ +const getFormattedPercentage = (value) => { + if (typeof value !== "number") return value; + return `${(value * 100).toFixed(2)}.%`; +}; + /** * Custom tooltip component for displaying infrastructure data. * @@ -146,8 +162,8 @@ export const InfrastructureTooltip = ({ sx={{ opacity: 0.8 }} > {yIdx >= 0 - ? `${yLabel} ${payload[0].payload[hardwareType][yIdx][metric] * 100}%` - : `${yLabel} ${payload[0].payload[hardwareType][metric] * 100}%`} + ? `${yLabel} ${getFormattedPercentage(payload[0].payload[hardwareType][yIdx][metric])}` + : `${yLabel} ${getFormattedPercentage(payload[0].payload[hardwareType][metric])}`} diff --git a/Client/src/Components/Inputs/Checkbox/index.jsx b/Client/src/Components/Inputs/Checkbox/index.jsx index a0348dedf..2f89d86df 100644 --- a/Client/src/Components/Inputs/Checkbox/index.jsx +++ b/Client/src/Components/Inputs/Checkbox/index.jsx @@ -40,7 +40,6 @@ const Checkbox = ({ /* TODO move sizes to theme */ const sizes = { small: "14px", medium: "16px", large: "18px" }; const theme = useTheme(); - return ( } @@ -66,7 +66,6 @@ const Checkbox = ({ sx={{ borderRadius: theme.shape.borderRadius, p: theme.spacing(2.5), - m: theme.spacing(-2.5), "& .MuiButtonBase-root": { width: theme.spacing(10), p: 0, @@ -90,7 +89,7 @@ const Checkbox = ({ Checkbox.propTypes = { id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, + label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, size: PropTypes.oneOf(["small", "medium", "large"]), isChecked: PropTypes.bool.isRequired, value: PropTypes.string, diff --git a/Client/src/Components/Inputs/Field/index.css b/Client/src/Components/Inputs/Field/index.css index 2d251e4bf..33196b3b9 100644 --- a/Client/src/Components/Inputs/Field/index.css +++ b/Client/src/Components/Inputs/Field/index.css @@ -1,6 +1,15 @@ .field { - min-width: 250px; + min-width: var(--env-var-width-3); } + +.field-infrastructure-alert { + max-width: var(--env-var-width-4); +} + +.field-infrastructure-alert .MuiInputBase-root:has(input) { + height: var(--env-var-height-2); +} + .field h3.MuiTypography-root, .field h5.MuiTypography-root, .field input, @@ -14,7 +23,7 @@ padding-right: var(--env-var-spacing-1-minus); } .field .MuiInputBase-root:has(input) { - height: 34px; + height: var(--env-var-height-2); } .field .MuiInputBase-root:has(.MuiInputAdornment-root) { padding-right: var(--env-var-spacing-1-minus); diff --git a/Client/src/Components/Inputs/Field/index.jsx b/Client/src/Components/Inputs/Field/index.jsx index 0e558c197..d1eab532d 100644 --- a/Client/src/Components/Inputs/Field/index.jsx +++ b/Client/src/Components/Inputs/Field/index.jsx @@ -46,6 +46,7 @@ const Field = forwardRef( error, disabled, hidden, + className }, ref ) => { @@ -56,7 +57,7 @@ const Field = forwardRef( return ( - {error && ( + { error && (