diff --git a/client/src/Components/v2/design-elements/Gauge.tsx b/client/src/Components/v2/design-elements/Gauge.tsx new file mode 100644 index 000000000..34c57487d --- /dev/null +++ b/client/src/Components/v2/design-elements/Gauge.tsx @@ -0,0 +1,106 @@ +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; + +import { useTheme } from "@mui/material/styles"; +import { useMemo, useState, useEffect } from "react"; +import { getInfraGaugeColor } from "@/Utils/MonitorUtils"; + +const MINIMUM_VALUE = 0; +const MAXIMUM_VALUE = 100; + +export const Gauge = ({ + isLoading = false, + progress = 0, + radius = 70, + strokeWidth = 15, + precision = 1, + unit = "%", +}: { + isLoading?: boolean; + progress?: number; + radius?: number; + strokeWidth?: number; + precision?: number; + unit?: string; +}) => { + const theme = useTheme(); + const progressWithinRange = Math.max(MINIMUM_VALUE, Math.min(progress, MAXIMUM_VALUE)); + + // Calculate the length of the stroke for the circle + 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); + useEffect(() => { + setOffset(circumference); + const timer = setTimeout(() => { + setOffset(circumference - strokeLength); + }, 100); + + return () => clearTimeout(timer); + }, [progress, circumference, strokeLength]); + + const fillColor = getInfraGaugeColor(progressWithinRange, theme); + + if (isLoading) { + return; + } + + return ( + + + + + + + + {`${progressWithinRange.toFixed(precision)}${unit}`} + + + ); +}; diff --git a/client/src/Components/v2/design-elements/index.tsx b/client/src/Components/v2/design-elements/index.tsx index 6ebffc624..000dab1b2 100644 --- a/client/src/Components/v2/design-elements/index.tsx +++ b/client/src/Components/v2/design-elements/index.tsx @@ -15,3 +15,4 @@ export { default as Icon } from "./Icon"; export * from "./Tooltip"; export * from "./StatBox"; export * from "./BaseChart"; +export * from "./Gauge"; diff --git a/client/src/Components/v2/monitors/ControlsFilter.tsx b/client/src/Components/v2/monitors/ControlsFilter.tsx index d7eecefb5..34eedd190 100644 --- a/client/src/Components/v2/monitors/ControlsFilter.tsx +++ b/client/src/Components/v2/monitors/ControlsFilter.tsx @@ -11,6 +11,7 @@ const statuses = ["up", "down"]; const states = ["active", "paused"]; export const ControlsFilter = ({ + showTypes = true, selectedTypes, setSelectedTypes, selectedStatus, @@ -19,8 +20,9 @@ export const ControlsFilter = ({ setSelectedState, onClearFilters, }: { - selectedTypes: MonitorType[]; - setSelectedTypes: React.Dispatch>; + showTypes?: boolean; + selectedTypes?: MonitorType[]; + setSelectedTypes?: React.Dispatch>; selectedStatus: string; setSelectedStatus: React.Dispatch>; selectedState: string; @@ -30,27 +32,29 @@ export const ControlsFilter = ({ const theme = useTheme(); const isSmall = useMediaQuery(theme.breakpoints.down("md")); const isFilterActive = - selectedTypes.length > 0 || selectedStatus !== "" || selectedState !== ""; + (selectedTypes?.length ?? 0) > 0 || selectedStatus !== "" || selectedState !== ""; return ( - + {showTypes && setSelectedTypes && ( + + )}