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
This commit is contained in:
Yunus M 2023-12-01 17:08:24 +05:30 committed by GitHub
parent b616dca52d
commit 3e29161fea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 95 additions and 128 deletions

View File

@ -107,48 +107,8 @@ function RightContainer({
} }
/> />
{/* <TextContainer>
<Typography>Stacked Graphs :</Typography>
<Switch
checked={stacked}
onChange={(): void => {
setStacked((value) => !value);
}}
/>
</TextContainer> */}
{/* <Title light={'true'}>Fill Opacity: </Title> */}
{/* <Slider
value={parseInt(opacity, 10)}
marks={{
0: '0',
33: '33',
66: '66',
100: '100',
}}
onChange={(number): void => onChangeHandler(setOpacity, number.toString())}
step={1}
/> */}
{/* <Title light={'true'}>Null/Zero values: </Title>
<NullButtonContainer>
{nullValueButtons.map((button) => (
<Button
type={button.check === selectedNullZeroValue ? 'primary' : 'default'}
key={button.name}
onClick={(): void =>
onChangeHandler(setSelectedNullZeroValue, button.check)
}
>
{button.name}
</Button>
))}
</NullButtonContainer> */}
<Space style={{ marginTop: 10 }} direction="vertical"> <Space style={{ marginTop: 10 }} direction="vertical">
<Typography>Fill span gaps</Typography> <Typography>Fill gaps</Typography>
<Switch <Switch
checked={isFillSpans} checked={isFillSpans}

View File

@ -29,6 +29,8 @@ const generateTooltipContent = (
): HTMLElement => { ): HTMLElement => {
const container = document.createElement('div'); const container = document.createElement('div');
container.classList.add('tooltip-container'); container.classList.add('tooltip-container');
const overlay = document.getElementById('overlay');
let tooltipCount = 0;
let tooltipTitle = ''; let tooltipTitle = '';
const formattedData: Record<string, UplotTooltipDataProps> = {}; const formattedData: Record<string, UplotTooltipDataProps> = {};
@ -49,28 +51,40 @@ const generateTooltipContent = (
const { metric = {}, queryName = '', legend = '' } = const { metric = {}, queryName = '', legend = '' } =
seriesList[index - 1] || {}; seriesList[index - 1] || {};
const value = data[index][idx];
const label = getLabelName(metric, queryName || '', legend || ''); const label = getLabelName(metric, queryName || '', legend || '');
const value = data[index][idx] || 0; if (value) {
const tooltipValue = getToolTipValue(value, yAxisUnit); const tooltipValue = getToolTipValue(value, yAxisUnit);
const dataObj = { const dataObj = {
show: item.show || false, show: item.show || false,
color: colors[(index - 1) % colors.length], color: colors[(index - 1) % colors.length],
label, label,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
focus: item?._focus || false, focus: item?._focus || false,
value, value,
tooltipValue, tooltipValue,
textContent: `${label} : ${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< const sortedData: Record<
string, string,
UplotTooltipDataProps UplotTooltipDataProps
@ -116,8 +130,6 @@ const generateTooltipContent = (
}); });
} }
const overlay = document.getElementById('overlay');
if (overlay && overlay.style.display === 'none') { if (overlay && overlay.style.display === 'none') {
overlay.style.display = 'block'; overlay.style.display = 'block';
} }

View File

@ -1,44 +1,65 @@
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { QueryData } from 'types/api/widgets/getQuery';
// eslint-disable-next-line sonarjs/cognitive-complexity function getXAxisTimestamps(seriesList: QueryData[]): number[] {
function fillMissingTimestamps( const timestamps = new Set();
sortedTimestamps: number[],
subsetArray: any[],
fillSpans: boolean | undefined,
): any[] {
const filledArray = [];
let subsetIndex = 0; seriesList.forEach((series: { values: [number, string][] }) => {
// eslint-disable-next-line no-restricted-syntax series.values.forEach((value) => {
for (const timestamp of sortedTimestamps) { timestamps.add(value[0]);
if ( });
subsetIndex < subsetArray.length && });
timestamp === subsetArray[subsetIndex][0]
) {
// Timestamp is present in subsetArray
const seriesPointData = subsetArray[subsetIndex];
if ( const timestampsArr: number[] | unknown[] = Array.from(timestamps) || [];
seriesPointData && // eslint-disable-next-line @typescript-eslint/ban-ts-comment
Array.isArray(seriesPointData) && // @ts-ignore
seriesPointData.length > 0 && return timestampsArr.sort((a, b) => a - b);
seriesPointData[1] !== 'NaN' }
) {
filledArray.push(subsetArray[subsetIndex]);
} else {
const value = fillSpans ? 0 : null;
filledArray.push([seriesPointData[0], value]);
}
subsetIndex += 1; function fillMissingXAxisTimestamps(
} else { timestampArr: number[],
// Timestamp is missing in subsetArray, fill with [timestamp, 0] 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; 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 = ( export const getUPlotChartData = (
@ -46,43 +67,12 @@ export const getUPlotChartData = (
fillSpans?: boolean, fillSpans?: boolean,
): any[] => { ): any[] => {
const seriesList = apiResponse?.data?.result || []; const seriesList = apiResponse?.data?.result || [];
const uPlotData = []; const timestampArr = getXAxisTimestamps(seriesList);
const yAxisValuesArr = fillMissingXAxisTimestamps(
// this helps us identify the series with the max number of values and helps define the x axis - timestamps timestampArr,
const xSeries = seriesList.reduce( seriesList,
(maxObj, currentObj) => fillSpans || false,
currentObj.values.length > maxObj.values.length ? currentObj : maxObj,
seriesList[0],
); );
// sort seriesList return [timestampArr, ...yAxisValuesArr];
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;
}; };

View File

@ -42,6 +42,11 @@ body {
border-radius: 50%; border-radius: 50%;
} }
} }
&.u-off {
text-decoration: line-through;
text-decoration-thickness: 3px;
}
} }
} }