From 3e29161fead6e0508c80105de85410deeadc2b74 Mon Sep 17 00:00:00 2001 From: Yunus M Date: Fri, 1 Dec 2023 17:08:24 +0530 Subject: [PATCH] fix: update logic for handling data for uplot charts (#4131) * fix: update logic for handling data for uplot charts * fix: hide tooltip if no tooltip values present * fix: remove console log --- .../NewWidget/RightContainer/index.tsx | 42 +----- .../src/lib/uPlotLib/plugins/tooltipPlugin.ts | 44 +++--- .../lib/uPlotLib/utils/getUplotChartData.ts | 132 ++++++++---------- frontend/src/styles.scss | 5 + 4 files changed, 95 insertions(+), 128 deletions(-) diff --git a/frontend/src/container/NewWidget/RightContainer/index.tsx b/frontend/src/container/NewWidget/RightContainer/index.tsx index d8f650f083..023dd584b2 100644 --- a/frontend/src/container/NewWidget/RightContainer/index.tsx +++ b/frontend/src/container/NewWidget/RightContainer/index.tsx @@ -107,48 +107,8 @@ function RightContainer({ } /> - {/* - Stacked Graphs : - { - setStacked((value) => !value); - }} - /> - */} - - {/* Fill Opacity: */} - - {/* onChangeHandler(setOpacity, number.toString())} - step={1} - /> */} - - {/* Null/Zero values: - - - {nullValueButtons.map((button) => ( - - ))} - */} - - Fill span gaps + Fill gaps { const container = document.createElement('div'); container.classList.add('tooltip-container'); + const overlay = document.getElementById('overlay'); + let tooltipCount = 0; let tooltipTitle = ''; const formattedData: Record = {}; @@ -49,28 +51,40 @@ const generateTooltipContent = ( const { metric = {}, queryName = '', legend = '' } = seriesList[index - 1] || {}; + const value = data[index][idx]; const label = getLabelName(metric, queryName || '', legend || ''); - const value = data[index][idx] || 0; - const tooltipValue = getToolTipValue(value, yAxisUnit); + if (value) { + const tooltipValue = getToolTipValue(value, yAxisUnit); - const dataObj = { - show: item.show || false, - color: colors[(index - 1) % colors.length], - label, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - focus: item?._focus || false, - value, - tooltipValue, - textContent: `${label} : ${tooltipValue}`, - }; + const dataObj = { + show: item.show || false, + color: colors[(index - 1) % colors.length], + label, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + focus: item?._focus || false, + value, + tooltipValue, + textContent: `${label} : ${tooltipValue}`, + }; - formattedData[label] = dataObj; + tooltipCount += 1; + formattedData[label] = dataObj; + } } }); } + // Show tooltip only if atleast only series has a value at the hovered timestamp + if (tooltipCount <= 0) { + if (overlay && overlay.style.display === 'block') { + overlay.style.display = 'none'; + } + + return container; + } + const sortedData: Record< string, UplotTooltipDataProps @@ -116,8 +130,6 @@ const generateTooltipContent = ( }); } - const overlay = document.getElementById('overlay'); - if (overlay && overlay.style.display === 'none') { overlay.style.display = 'block'; } diff --git a/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts b/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts index be4bfb59e5..d1f5a7ffbc 100644 --- a/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts +++ b/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts @@ -1,44 +1,65 @@ import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; +import { QueryData } from 'types/api/widgets/getQuery'; -// eslint-disable-next-line sonarjs/cognitive-complexity -function fillMissingTimestamps( - sortedTimestamps: number[], - subsetArray: any[], - fillSpans: boolean | undefined, -): any[] { - const filledArray = []; +function getXAxisTimestamps(seriesList: QueryData[]): number[] { + const timestamps = new Set(); - let subsetIndex = 0; - // eslint-disable-next-line no-restricted-syntax - for (const timestamp of sortedTimestamps) { - if ( - subsetIndex < subsetArray.length && - timestamp === subsetArray[subsetIndex][0] - ) { - // Timestamp is present in subsetArray - const seriesPointData = subsetArray[subsetIndex]; + seriesList.forEach((series: { values: [number, string][] }) => { + series.values.forEach((value) => { + timestamps.add(value[0]); + }); + }); - if ( - seriesPointData && - Array.isArray(seriesPointData) && - seriesPointData.length > 0 && - seriesPointData[1] !== 'NaN' - ) { - filledArray.push(subsetArray[subsetIndex]); - } else { - const value = fillSpans ? 0 : null; - filledArray.push([seriesPointData[0], value]); - } + const timestampsArr: number[] | unknown[] = Array.from(timestamps) || []; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return timestampsArr.sort((a, b) => a - b); +} - subsetIndex += 1; - } else { - // Timestamp is missing in subsetArray, fill with [timestamp, 0] +function fillMissingXAxisTimestamps( + timestampArr: number[], + data: any[], + fillSpans: boolean, +): any { + // Generate a set of all timestamps in the range + const allTimestampsSet = new Set(timestampArr); + const processedData = JSON.parse(JSON.stringify(data)); + + // Fill missing timestamps with null values + processedData.forEach((entry: { values: (number | null)[][] }) => { + const existingTimestamps = new Set(entry.values.map((value) => value[0])); + + const missingTimestamps = Array.from(allTimestampsSet).filter( + (timestamp) => !existingTimestamps.has(timestamp), + ); + + missingTimestamps.forEach((timestamp) => { const value = fillSpans ? 0 : null; - filledArray.push([timestamp, value]); - } - } - return filledArray; + entry.values.push([timestamp, value]); + }); + + entry.values.forEach((v) => { + if (Number.isNaN(v[1])) { + const replaceValue = fillSpans ? 0 : 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 @typescript-eslint/ban-ts-comment + // @ts-ignore + entry.values.sort((a, b) => a[0] - b[0]); + }); + + return processedData.map((entry: { values: [number, string][] }) => + entry.values.map((value) => value[1]), + ); } export const getUPlotChartData = ( @@ -46,43 +67,12 @@ export const getUPlotChartData = ( fillSpans?: boolean, ): any[] => { const seriesList = apiResponse?.data?.result || []; - const uPlotData = []; - - // this helps us identify the series with the max number of values and helps define the x axis - timestamps - const xSeries = seriesList.reduce( - (maxObj, currentObj) => - currentObj.values.length > maxObj.values.length ? currentObj : maxObj, - seriesList[0], + const timestampArr = getXAxisTimestamps(seriesList); + const yAxisValuesArr = fillMissingXAxisTimestamps( + timestampArr, + seriesList, + fillSpans || false, ); - // sort seriesList - for (let index = 0; index < seriesList.length; index += 1) { - seriesList[index]?.values?.sort((a, b) => a[0] - b[0]); - } - - const timestampArr = xSeries?.values?.map((v) => v[0]); - - // timestamp - uPlotData.push(timestampArr); - - // for each series, push the values - seriesList.forEach((series) => { - const updatedSeries = fillMissingTimestamps( - timestampArr, - series?.values || [], - fillSpans, - ); - - const seriesData = - updatedSeries?.map((v) => { - if (v[1] === null) { - return v[1]; - } - return parseFloat(v[1]); - }) || []; - - uPlotData.push(seriesData); - }); - - return uPlotData; + return [timestampArr, ...yAxisValuesArr]; }; diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 8efda895d4..6712b4c59a 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -42,6 +42,11 @@ body { border-radius: 50%; } } + + &.u-off { + text-decoration: line-through; + text-decoration-thickness: 3px; + } } }