diff --git a/frontend/src/lib/uPlotLib/utils/dataUtils.ts b/frontend/src/lib/uPlotLib/utils/dataUtils.ts new file mode 100644 index 0000000000..653a72c44a --- /dev/null +++ b/frontend/src/lib/uPlotLib/utils/dataUtils.ts @@ -0,0 +1,51 @@ +/** + * Checks if a value is invalid for plotting + * + * @param value - The value to check + * @returns true if the value is invalid (should be replaced with null), false otherwise + */ +export function isInvalidPlotValue(value: unknown): boolean { + // Check for null or undefined + if (value === null || value === undefined) { + return true; + } + + // Handle number checks + if (typeof value === 'number') { + // Check for NaN, Infinity, -Infinity + return !Number.isFinite(value); + } + + // Handle string values + if (typeof value === 'string') { + // Check for string representations of infinity + if (['+Inf', '-Inf', 'Infinity', '-Infinity', 'NaN'].includes(value)) { + return true; + } + + // Try to parse the string as a number + const numValue = parseFloat(value); + + // If parsing failed or resulted in a non-finite number, it's invalid + if (Number.isNaN(numValue) || !Number.isFinite(numValue)) { + return true; + } + } + + // Value is valid for plotting + return false; +} + +export function normalizePlotValue(value: unknown): number | null { + if (isInvalidPlotValue(value)) { + return null; + } + + // Convert string numbers to actual numbers + if (typeof value === 'string') { + return parseFloat(value); + } + + // Already a valid number + return value as number; +} diff --git a/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts b/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts index 1e224da05a..9a55248b50 100644 --- a/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts +++ b/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts @@ -4,6 +4,7 @@ import { cloneDeep, isUndefined } from 'lodash-es'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { QueryData } from 'types/api/widgets/getQuery'; +import { normalizePlotValue } from './dataUtils'; import { generateColor } from './generateColor'; function getXAxisTimestamps(seriesList: QueryData[]): number[] { @@ -43,16 +44,8 @@ function fillMissingXAxisTimestamps(timestampArr: number[], data: any[]): any { }); entry.values.forEach((v) => { - if (Number.isNaN(v[1])) { - const replaceValue = null; - // eslint-disable-next-line no-param-reassign - v[1] = replaceValue; - } else if (v[1] !== null) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line no-param-reassign - v[1] = parseFloat(v[1]); - } + // eslint-disable-next-line no-param-reassign + v[1] = normalizePlotValue(v[1]); }); // eslint-disable-next-line @typescript-eslint/ban-ts-comment