From ed54239a9f6b8c0a77e53b3180c441e0c9a74203 Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:50:50 +0200 Subject: [PATCH] Alerting: Dont show 1 firing series when no data in Expressions PreviewSummary (#76981) * Dont show 1 firing series when no data in Expressions PreviewSummary * Add comment to make clear we need to filter out undefineds for firing count * Move logic to a new getGroupedByStateAndSeriesCount method and added test to it --- .../expressions/Expression.test.tsx | 75 ++++++++++++++++++- .../components/expressions/Expression.tsx | 21 ++++-- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/public/app/features/alerting/unified/components/expressions/Expression.test.tsx b/public/app/features/alerting/unified/components/expressions/Expression.test.tsx index 326cd6a7acd..3c502ac4370 100644 --- a/public/app/features/alerting/unified/components/expressions/Expression.test.tsx +++ b/public/app/features/alerting/unified/components/expressions/Expression.test.tsx @@ -1,11 +1,11 @@ -import { screen, render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { times } from 'lodash'; import React from 'react'; import { DataFrame, toDataFrame } from '@grafana/data'; -import { ExpressionResult } from './Expression'; +import { ExpressionResult, getGroupedByStateAndSeriesCount } from './Expression'; describe('TestResult', () => { it('should be able to render', () => { @@ -82,3 +82,74 @@ function makeSeries(n: number) { }) ); } + +describe('getGroupedByStateAndSeriesCount', () => { + it('should group series by state correctly and count the number of series', () => { + const series: DataFrame[] = [ + toDataFrame({ fields: [{ name: 'value', values: [1] }] }), + toDataFrame({ fields: [{ name: 'value', values: [undefined] }] }), + toDataFrame({ fields: [{ name: 'value', values: [0] }] }), + toDataFrame({ fields: [{ name: 'value', values: [2] }] }), + toDataFrame({ fields: [{ name: 'value', values: [undefined] }] }), + ]; + + const { groupedByState, seriesCount } = getGroupedByStateAndSeriesCount(series); + + expect(groupedByState['firing']).toEqual([series[0], series[3]]); + expect(groupedByState['inactive']).toEqual([series[2]]); + expect(seriesCount).toEqual(3); + }); + + it('should return empty group state and zero series count when input array is empty', () => { + const series: DataFrame[] = []; + + const { groupedByState, seriesCount } = getGroupedByStateAndSeriesCount(series); + + expect(groupedByState).toEqual({ + firing: [], + inactive: [], + }); + expect(seriesCount).toEqual(0); + }); + + it('should return zero series count and empty group state when all series have undefined values', () => { + const series = [ + toDataFrame({ fields: [{ name: 'value', values: [undefined] }] }), + toDataFrame({ fields: [{ name: 'value', values: [undefined] }] }), + ]; + + const { groupedByState, seriesCount } = getGroupedByStateAndSeriesCount(series); + + expect(groupedByState['firing']).toEqual([]); + expect(groupedByState['inactive']).toEqual([]); + expect(seriesCount).toEqual(0); + }); + + it('should group all series by inactive state when all series have zero values', () => { + const series = [ + toDataFrame({ fields: [{ name: 'value', values: [0] }] }), + toDataFrame({ fields: [{ name: 'value', values: [0] }] }), + toDataFrame({ fields: [{ name: 'value', values: [0] }] }), + ]; + + const { groupedByState, seriesCount } = getGroupedByStateAndSeriesCount(series); + + expect(groupedByState['firing']).toEqual([]); + expect(groupedByState['inactive']).toEqual(series); + expect(seriesCount).toEqual(series.length); + }); + + it('should group all series by Firing state when all series have non-zero values', () => { + const series = [ + toDataFrame({ fields: [{ name: 'value', values: [1] }] }), + toDataFrame({ fields: [{ name: 'value', values: [2] }] }), + toDataFrame({ fields: [{ name: 'value', values: [3] }] }), + ]; + + const { groupedByState, seriesCount } = getGroupedByStateAndSeriesCount(series); + + expect(groupedByState['firing']).toEqual(series); + expect(groupedByState['inactive']).toEqual([]); + expect(seriesCount).toEqual(series.length); + }); +}); diff --git a/public/app/features/alerting/unified/components/expressions/Expression.tsx b/public/app/features/alerting/unified/components/expressions/Expression.tsx index f6849d41a0a..efc5bbd6b8b 100644 --- a/public/app/features/alerting/unified/components/expressions/Expression.tsx +++ b/public/app/features/alerting/unified/components/expressions/Expression.tsx @@ -60,14 +60,10 @@ export const Expression: FC = ({ const isLoading = data && Object.values(data).some((d) => Boolean(d) && d.state === LoadingState.Loading); const hasResults = Array.isArray(data?.series) && !isLoading; const series = data?.series ?? []; - const seriesCount = series.length; const alertCondition = isAlertCondition ?? false; - const groupedByState = { - [PromAlertingRuleState.Firing]: series.filter((serie) => getSeriesValue(serie) !== 0), - [PromAlertingRuleState.Inactive]: series.filter((serie) => getSeriesValue(serie) === 0), - }; + const { seriesCount, groupedByState } = getGroupedByStateAndSeriesCount(series); const renderExpressionType = useCallback( (query: ExpressionQuery) => { @@ -236,6 +232,21 @@ export const PreviewSummary: FC<{ firing: number; normal: number; isCondition: b return {`${seriesCount} series`}; }; +export function getGroupedByStateAndSeriesCount(series: DataFrame[]) { + const noDataSeries = series.filter((serie) => getSeriesValue(serie) === undefined).length; + const groupedByState = { + // we need to filter out series with no data (undefined) or zero value + [PromAlertingRuleState.Firing]: series.filter( + (serie) => getSeriesValue(serie) !== undefined && getSeriesValue(serie) !== 0 + ), + [PromAlertingRuleState.Inactive]: series.filter((serie) => getSeriesValue(serie) === 0), + }; + + const seriesCount = series.length - noDataSeries; + + return { groupedByState, seriesCount }; +} + interface HeaderProps { refId: string; queryType: ExpressionQueryType;