From 664706ff9fa133fe4eb21db94bde4347bcfa703e Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 23 Nov 2021 15:47:50 -0500 Subject: [PATCH] [Security Solution][Investigations] Fix for histogram not rendering data in some cases (#118868) (#119533) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Jan Monschke --- .../public/common/components/charts/barchart.tsx | 8 ++++++-- .../charts/draggable_legend_item.test.tsx | 9 +++++++++ .../components/charts/draggable_legend_item.tsx | 15 ++++++++++++++- .../common/components/charts/translation.ts | 4 ++++ .../alerts_histogram_panel/alerts_histogram.tsx | 9 +++++++-- .../alerts_histogram_panel/helpers.tsx | 2 +- 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/charts/barchart.tsx b/x-pack/plugins/security_solution/public/common/components/charts/barchart.tsx index 20ab5cca89a76..b60382481e9d6 100644 --- a/x-pack/plugins/security_solution/public/common/components/charts/barchart.tsx +++ b/x-pack/plugins/security_solution/public/common/components/charts/barchart.tsx @@ -8,7 +8,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useMemo } from 'react'; import { Chart, BarSeries, Axis, Position, ScaleType, Settings } from '@elastic/charts'; -import { getOr, get, isNumber } from 'lodash/fp'; +import { getOr, get, isNumber, isEmpty } from 'lodash/fp'; import deepmerge from 'deepmerge'; import uuid from 'uuid'; import styled from 'styled-components'; @@ -18,6 +18,7 @@ import { escapeDataProviderId } from '../drag_and_drop/helpers'; import { useTimeZone } from '../../lib/kibana'; import { defaultLegendColors } from '../matrix_histogram/utils'; import { useThrottledResizeObserver } from '../utils'; +import { EMPTY_VALUE_LABEL } from '../charts/translation'; import { ChartPlaceHolder } from './chart_place_holder'; import { @@ -32,6 +33,7 @@ import { } from './common'; import { DraggableLegend } from './draggable_legend'; import { LegendItem } from './draggable_legend_item'; +import type { ChartData } from './common'; const LegendFlexItem = styled(EuiFlexItem)` overview: hidden; @@ -50,7 +52,9 @@ const checkIfAnyValidSeriesExist = ( data.some(checkIfAllTheDataInTheSeriesAreValid); const yAccessors = ['y']; -const splitSeriesAccessors = ['g']; +const splitSeriesAccessors = [ + (datum: ChartData) => (isEmpty(datum.g) ? EMPTY_VALUE_LABEL : datum.g), +]; // Bar chart rotation: https://ela.st/chart-rotations export const BarChartBaseComponent = ({ diff --git a/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.test.tsx b/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.test.tsx index 17b70a9903590..9d1dde39d8cc0 100644 --- a/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.test.tsx @@ -59,4 +59,13 @@ describe('DraggableLegendItem', () => { wrapper.find(`[data-test-subj="legend-item-${legendItem.dataProviderId}"]`).prop('hideTopN') ).toEqual(true); }); + + it('renders the empty value label when the value is empty', () => { + wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="value-wrapper-empty"]').first().exists()).toBeTruthy(); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.tsx b/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.tsx index 0cf580db67237..3182189a52e2a 100644 --- a/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.tsx +++ b/x-pack/plugins/security_solution/public/common/components/charts/draggable_legend_item.tsx @@ -7,8 +7,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiHealth, EuiText } from '@elastic/eui'; import React from 'react'; +import { isEmpty } from 'lodash/fp'; import { DefaultDraggable } from '../draggables'; +import { EMPTY_VALUE_LABEL } from './translation'; export interface LegendItem { color?: string; @@ -18,6 +20,15 @@ export interface LegendItem { value: string; } +/** + * Renders the value or a placeholder in case the value is empty + */ +const ValueWrapper = React.memo<{ value?: string | null }>(({ value }) => + isEmpty(value) ? {EMPTY_VALUE_LABEL} : <>{value} +); + +ValueWrapper.displayName = 'ValueWrapper'; + const DraggableLegendItemComponent: React.FC<{ legendItem: LegendItem; }> = ({ legendItem }) => { @@ -41,7 +52,9 @@ const DraggableLegendItemComponent: React.FC<{ isDraggable={false} timelineId={timelineId} value={value} - /> + > + + diff --git a/x-pack/plugins/security_solution/public/common/components/charts/translation.ts b/x-pack/plugins/security_solution/public/common/components/charts/translation.ts index a527a85f62c71..15dbb05f7c7b9 100644 --- a/x-pack/plugins/security_solution/public/common/components/charts/translation.ts +++ b/x-pack/plugins/security_solution/public/common/components/charts/translation.ts @@ -20,3 +20,7 @@ export const DATA_NOT_AVAILABLE_TITLE = i18n.translate( defaultMessage: 'Chart Data Not Available', } ); + +export const EMPTY_VALUE_LABEL = i18n.translate('xpack.securitySolution.chart.emptyValueLabel', { + defaultMessage: 'empty value', +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.tsx index d09d33ce5aded..d71330d45861c 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.tsx @@ -15,11 +15,13 @@ import { } from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, EuiProgress } from '@elastic/eui'; import React, { useMemo } from 'react'; +import { isEmpty } from 'lodash/fp'; -import { useTheme, UpdateDateRange } from '../../../../common/components/charts/common'; +import { useTheme, UpdateDateRange, ChartData } from '../../../../common/components/charts/common'; import { histogramDateTimeFormatter } from '../../../../common/components/utils'; import { DraggableLegend } from '../../../../common/components/charts/draggable_legend'; import { LegendItem } from '../../../../common/components/charts/draggable_legend_item'; +import { EMPTY_VALUE_LABEL } from '../../../../common/components/charts/translation'; import type { HistogramData } from './types'; @@ -55,7 +57,10 @@ export const AlertsHistogram = React.memo( const yAxisId = 'alertsHistogramAxisY'; const id = 'alertsHistogram'; const yAccessors = useMemo(() => ['y'], []); - const splitSeriesAccessors = useMemo(() => ['g'], []); + const splitSeriesAccessors = useMemo( + () => [(datum: ChartData) => (isEmpty(datum.g) ? EMPTY_VALUE_LABEL : datum.g)], + [] + ); const tickFormat = useMemo(() => histogramDateTimeFormatter([from, to]), [from, to]); return ( diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx index e5534900a3784..5c3808843aae7 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx @@ -5,9 +5,9 @@ * 2.0. */ +import { isEmpty } from 'lodash/fp'; import moment from 'moment'; -import { isEmpty } from 'lodash/fp'; import type { HistogramData, AlertsAggregation, AlertsBucket, AlertsGroupBucket } from './types'; import type { AlertSearchResponse } from '../../../containers/detection_engine/alerts/types'; import type { AlertsStackByField } from '../common/types';