From 56a54261ede8ba671ca0906412015943ae6bd67a Mon Sep 17 00:00:00 2001 From: christineweng <18648970+christineweng@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:09:18 -0500 Subject: [PATCH] [Security Solution][Alert Details] Alerts KPI clean up (#189837) ## Summary Removed unused components (those that were replaced by Len Embeddable) and cleaned up jest test console errors. No UI change from this PR. ![image](https://github.com/user-attachments/assets/18afd3cb-796a-42ec-8e98-9110494d7fb4) ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../alerts_count_panel/alerts_count.test.tsx | 218 --------------- .../alerts_count_panel/alerts_count.tsx | 95 ------- .../alerts_count_panel/columns.test.tsx | 77 ----- .../alerts_count_panel/columns.tsx | 112 -------- .../alerts_count_panel/helpers.test.tsx | 132 --------- .../alerts_count_panel/helpers.tsx | 67 ----- .../alerts_kpis/alerts_count_panel/index.tsx | 3 - .../mocks/mock_response_empty_field0.ts | 35 --- .../mocks/mock_response_multi_group.ts | 61 ---- .../mocks/mock_response_single_group.ts | 146 ---------- .../alerts_histogram.test.tsx | 78 ------ .../alerts_histogram.tsx | 127 --------- .../alerts_histogram_panel/helpers.test.tsx | 19 +- .../alerts_histogram_panel/helpers.tsx | 100 ------- .../alerts_histogram_panel/index.test.tsx | 264 ++++++++---------- .../alerts_histogram_panel/mock_data.ts | 78 ------ .../alerts_histogram_panel/types.ts | 38 --- .../alerts_summary_charts_panel/index.tsx | 3 +- .../use_summary_chart_data.test.tsx | 8 +- .../alerts_local_storage/index.test.tsx | 5 - .../chart_panels/chart_collapse/index.tsx | 5 +- .../alerts_kpis/chart_panels/index.test.tsx | 11 +- 22 files changed, 132 insertions(+), 1550 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_empty_field0.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_multi_group.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_single_group.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/types.ts diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.test.tsx deleted file mode 100644 index 3740c7b2ef7df..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.test.tsx +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { shallow, mount } from 'enzyme'; - -import { AlertsCount } from './alerts_count'; -import type { AlertSearchResponse } from '../../../containers/detection_engine/alerts/types'; -import { TestProviders } from '../../../../common/mock'; -import { DragDropContextWrapper } from '../../../../common/components/drag_and_drop/drag_drop_context_wrapper'; -import { mockBrowserFields } from '../../../../common/containers/source/mock'; -import type { AlertsCountAggregation } from './types'; -import { emptyStackByField0Response } from './mocks/mock_response_empty_field0'; -import { - buckets as oneGroupByResponseBuckets, - mockMultiGroupResponse, -} from './mocks/mock_response_multi_group'; -import { - buckets as twoGroupByResponseBuckets, - singleGroupResponse, -} from './mocks/mock_response_single_group'; - -jest.mock('../../../../common/lib/kibana'); -const mockDispatch = jest.fn(); - -jest.mock('react-router-dom', () => { - const actual = jest.requireActual('react-router-dom'); - return { ...actual, useLocation: jest.fn().mockReturnValue({ pathname: '' }) }; -}); - -jest.mock('react-redux', () => { - const original = jest.requireActual('react-redux'); - return { - ...original, - useDispatch: () => mockDispatch, - }; -}); - -describe('AlertsCount', () => { - it('renders correctly', () => { - const wrapper = shallow( - } - loading={false} - stackByField0={'test_selected_field'} - stackByField1={undefined} - /> - ); - - expect(wrapper.find('[data-test-subj="alertsCountTable"]').exists()).toBeTruthy(); - }); - - it('renders the expected table body message when stackByField0 is an empty string', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="alertsCountTable"] tbody').text()).toEqual( - 'No items found' - ); - }); - - describe('one group by field', () => { - oneGroupByResponseBuckets.forEach((bucket, i) => { - it(`renders the expected stackByField0 column text for bucket '${bucket.key}'`, () => { - const wrapper = mount( - - - - - - ); - - expect( - wrapper - .find(`[data-test-subj="stackByField0Key"] div.euiTableCellContent`) - .hostNodes() - .at(i) - .text() - ).toEqual(bucket.key); - }); - }); - - oneGroupByResponseBuckets.forEach((bucket, i) => { - it(`renders the expected doc_count column value for bucket '${bucket.key}'`, () => { - const wrapper = mount( - - - - - - ); - - expect( - wrapper - .find(`[data-test-subj="doc_count"] div.euiTableCellContent`) - .hostNodes() - .at(i) - .text() - ).toEqual(`${bucket.doc_count}`); - }); - }); - }); - - describe('two group by fields: stackByField0 column', () => { - let resultRow = 0; - - twoGroupByResponseBuckets.forEach((bucket) => { - bucket.stackByField1.buckets.forEach((b) => { - it(`renders the expected stackByField0 column text for stackByField0: '${bucket.key}', stackByField1 '${b.key}'`, () => { - const wrapper = mount( - - - - - - ); - - expect( - wrapper - .find(`[data-test-subj="stackByField0Key"] div.euiTableCellContent`) - .hostNodes() - .at(resultRow++) - .text() - ).toEqual(bucket.key); - }); - }); - }); - }); - - describe('two group by fields: stackByField1 column', () => { - let resultRow = 0; - - twoGroupByResponseBuckets.forEach((bucket) => { - bucket.stackByField1.buckets.forEach((b, i) => { - it(`renders the expected stackByField1 column text for stackByField0: '${bucket.key}', stackByField1 '${b.key}'`, () => { - const wrapper = mount( - - - - - - ); - - expect( - wrapper - .find(`[data-test-subj="stackByField1Key"] div.euiTableCellContent`) - .hostNodes() - .at(resultRow++) - .text() - ).toEqual(b.key); - }); - }); - }); - }); - - describe('two group by fields: stackByField1DocCount column', () => { - let resultRow = 0; - - twoGroupByResponseBuckets.forEach((bucket) => { - bucket.stackByField1.buckets.forEach((b, i) => { - it(`renders the expected doc_count column value for stackByField0: '${bucket.key}', stackByField1 '${b.key}'`, () => { - const wrapper = mount( - - - - - - ); - - expect( - wrapper - .find(`[data-test-subj="stackByField1DocCount"] div.euiTableCellContent`) - .hostNodes() - .at(resultRow++) - .text() - ).toEqual(`${b.doc_count}`); - }); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx deleted file mode 100644 index c83650b8e15d8..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/alerts_count.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiInMemoryTable } from '@elastic/eui'; -import { isEmpty } from 'lodash/fp'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { useUiSetting$ } from '../../../../common/lib/kibana'; -import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; -import type { AlertsCountAggregation } from './types'; -import type { AlertSearchResponse } from '../../../containers/detection_engine/alerts/types'; -import { - getMaxRiskSubAggregations, - getUpToMaxBuckets, -} from '../alerts_treemap_panel/alerts_treemap/lib/helpers'; -import { getFlattenedBuckets } from '../alerts_treemap_panel/alerts_treemap/lib/flatten/get_flattened_buckets'; -import type { FlattenedBucket, RawBucket } from '../alerts_treemap_panel/alerts_treemap/types'; -import { - getMultiGroupAlertsCountTableColumns, - getSingleGroupByAlertsCountTableColumns, -} from './columns'; -import { DEFAULT_STACK_BY_FIELD0_SIZE } from './helpers'; - -interface AlertsCountProps { - loading: boolean; - data: AlertSearchResponse; - stackByField0: string; - stackByField1: string | undefined; -} - -const Wrapper = styled.div` - margin-top: -${({ theme }) => theme.eui.euiSizeS}; -`; - -export const AlertsCountComponent: React.FC = ({ - data, - loading, - stackByField0, - stackByField1, -}) => { - const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); - - const tableColumns = useMemo( - () => - isEmpty(stackByField1?.trim()) - ? getSingleGroupByAlertsCountTableColumns({ - defaultNumberFormat, - stackByField0, - }) - : getMultiGroupAlertsCountTableColumns({ - defaultNumberFormat, - stackByField0, - stackByField1, - }), - [defaultNumberFormat, stackByField0, stackByField1] - ); - - const buckets: RawBucket[] = useMemo( - () => - getUpToMaxBuckets({ - buckets: data.aggregations?.stackByField0?.buckets, - maxItems: DEFAULT_STACK_BY_FIELD0_SIZE, - }), - [data.aggregations?.stackByField0?.buckets] - ); - - const maxRiskSubAggregations = useMemo(() => getMaxRiskSubAggregations(buckets), [buckets]); - - const items: FlattenedBucket[] = useMemo( - () => - isEmpty(stackByField1?.trim()) - ? buckets - : getFlattenedBuckets({ - buckets, - maxRiskSubAggregations, - stackByField0, - }), - [buckets, maxRiskSubAggregations, stackByField0, stackByField1] - ); - - return ( - - - - ); -}; - -AlertsCountComponent.displayName = 'AlertsCountComponent'; - -export const AlertsCount = React.memo(AlertsCountComponent); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.test.tsx deleted file mode 100644 index c5600fe7eda94..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.test.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { omit } from 'lodash/fp'; -import { - getMultiGroupAlertsCountTableColumns, - getSingleGroupByAlertsCountTableColumns, -} from './columns'; - -describe('columns', () => { - const defaultNumberFormat = '0,0.[000]'; - const stackByField0 = 'kibana.alert.rule.name'; - - describe('getMultiGroupAlertsCountTableColumns', () => { - const stackByField1 = 'host.name'; - - test('it returns the expected columns', () => { - expect( - getMultiGroupAlertsCountTableColumns({ - defaultNumberFormat, - stackByField0, - stackByField1, - }).map((x) => omit('render', x)) - ).toEqual([ - { - 'data-test-subj': 'stackByField0Key', - field: 'key', - name: 'Top 1000 values of kibana.alert.rule.name', - truncateText: false, - }, - { - 'data-test-subj': 'stackByField1Key', - field: 'stackByField1Key', - name: 'Top 1000 values of host.name', - truncateText: false, - }, - { - 'data-test-subj': 'stackByField1DocCount', - dataType: 'number', - field: 'stackByField1DocCount', - name: 'Count of records', - sortable: true, - textOnly: true, - }, - ]); - }); - }); - - describe('getSingleGroupByAlertsCountTableColumns', () => { - test('it returns the expected columns', () => { - expect( - getSingleGroupByAlertsCountTableColumns({ defaultNumberFormat, stackByField0 }).map((x) => - omit('render', x) - ) - ).toEqual([ - { - 'data-test-subj': 'stackByField0Key', - field: 'key', - name: 'kibana.alert.rule.name', - truncateText: false, - }, - { - 'data-test-subj': 'doc_count', - dataType: 'number', - field: 'doc_count', - name: 'Count of records', - sortable: true, - textOnly: true, - }, - ]); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.tsx deleted file mode 100644 index 9b9e3081d2fe5..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/columns.tsx +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { EuiBasicTableColumn } from '@elastic/eui'; -import numeral from '@elastic/numeral'; - -import { TableId } from '@kbn/securitysolution-data-table'; -import type { FlattenedBucket } from '../alerts_treemap_panel/alerts_treemap/types'; -import { DefaultDraggable } from '../../../../common/components/draggables'; -import type { GenericBuckets } from '../../../../../common/search_strategy/common'; -import * as i18n from './translations'; -import { DEFAULT_STACK_BY_FIELD0_SIZE, DEFAULT_STACK_BY_FIELD1_SIZE } from './helpers'; - -export const getSingleGroupByAlertsCountTableColumns = ({ - defaultNumberFormat, - stackByField0, -}: { - defaultNumberFormat: string; - stackByField0: string; -}): Array> => [ - { - 'data-test-subj': 'stackByField0Key', - field: 'key', - name: stackByField0, - render: function DraggableStackOptionField(value: string) { - return ( - - ); - }, - truncateText: false, - }, - { - 'data-test-subj': 'doc_count', - dataType: 'number', - field: 'doc_count', - name: i18n.COUNT_TABLE_COLUMN_TITLE, - render: (item: string) => numeral(item).format(defaultNumberFormat), - sortable: true, - textOnly: true, - }, -]; - -export const getMultiGroupAlertsCountTableColumns = ({ - defaultNumberFormat, - stackByField0, - stackByField1, -}: { - defaultNumberFormat: string; - stackByField0: string; - stackByField1: string | undefined; -}): Array> => [ - { - 'data-test-subj': 'stackByField0Key', - field: 'key', - name: i18n.COLUMN_LABEL({ fieldName: stackByField0, topN: DEFAULT_STACK_BY_FIELD0_SIZE }), - render: function DraggableStackOptionField(value: string) { - return ( - - ); - }, - truncateText: false, - }, - { - 'data-test-subj': 'stackByField1Key', - field: 'stackByField1Key', - name: i18n.COLUMN_LABEL({ fieldName: stackByField1 ?? '', topN: DEFAULT_STACK_BY_FIELD1_SIZE }), - render: function DraggableStackOptionField(value: string) { - return ( - - ); - }, - truncateText: false, - }, - { - 'data-test-subj': 'stackByField1DocCount', - dataType: 'number', - field: 'stackByField1DocCount', - name: i18n.COUNT_TABLE_COLUMN_TITLE, - render: (item: string) => numeral(item).format(defaultNumberFormat), - sortable: true, - textOnly: true, - }, -]; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.test.tsx deleted file mode 100644 index e651f17d59157..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.test.tsx +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getAlertsCountQuery } from './helpers'; - -const stackByField0 = 'kibana.alert.rule.name'; -const stackByField1 = 'host.name'; -const from = '2022-07-08T06:00:00.000Z'; -const to = '2022-07-09T05:59:59.999Z'; -const additionalFilters = [ - { - bool: { - must: [], - filter: [ - { - term: { - 'kibana.alert.workflow_status': 'open', - }, - }, - ], - should: [], - must_not: [ - { - exists: { - field: 'kibana.alert.building_block_type', - }, - }, - ], - }, - }, -]; -const runtimeMappings = {}; - -describe('helpers', () => { - describe('getAlertsCountQuery', () => { - test('it returns the expected query when stackByField1 is specified', () => { - expect( - getAlertsCountQuery({ - additionalFilters, - from, - runtimeMappings, - stackByField0, - stackByField1, - to, - }) - ).toEqual({ - size: 0, - aggs: { - stackByField0: { - terms: { field: 'kibana.alert.rule.name', order: { _count: 'desc' }, size: 1000 }, - aggs: { - stackByField1: { - terms: { field: 'host.name', order: { _count: 'desc' }, size: 1000 }, - }, - }, - }, - }, - query: { - bool: { - filter: [ - { - bool: { - must: [], - filter: [{ term: { 'kibana.alert.workflow_status': 'open' } }], - should: [], - must_not: [{ exists: { field: 'kibana.alert.building_block_type' } }], - }, - }, - { - range: { - '@timestamp': { - gte: '2022-07-08T06:00:00.000Z', - lte: '2022-07-09T05:59:59.999Z', - }, - }, - }, - ], - }, - }, - runtime_mappings: {}, - }); - }); - - test('it returns the expected query when stackByField1 is `undefined`', () => { - expect( - getAlertsCountQuery({ - additionalFilters, - from, - runtimeMappings, - stackByField0, - stackByField1: undefined, - to, - }) - ).toEqual({ - size: 0, - aggs: { - stackByField0: { - terms: { field: 'kibana.alert.rule.name', order: { _count: 'desc' }, size: 1000 }, - aggs: {}, - }, - }, - query: { - bool: { - filter: [ - { - bool: { - must: [], - filter: [{ term: { 'kibana.alert.workflow_status': 'open' } }], - should: [], - must_not: [{ exists: { field: 'kibana.alert.building_block_type' } }], - }, - }, - { - range: { - '@timestamp': { - gte: '2022-07-08T06:00:00.000Z', - lte: '2022-07-09T05:59:59.999Z', - }, - }, - }, - ], - }, - }, - runtime_mappings: {}, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx deleted file mode 100644 index 1537d1f1fd212..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { getOptionalSubAggregation } from '../alerts_treemap_panel/alerts_treemap/query'; - -export const DEFAULT_STACK_BY_FIELD0_SIZE = 1000; -export const DEFAULT_STACK_BY_FIELD1_SIZE = 1000; - -export const getAlertsCountQuery = ({ - additionalFilters = [], - from, - runtimeMappings, - stackByField0, - stackByField1, - to, -}: { - additionalFilters: Array<{ - bool: { filter: unknown[]; should: unknown[]; must_not: unknown[]; must: unknown[] }; - }>; - from: string; - runtimeMappings?: MappingRuntimeFields; - stackByField0: string; - stackByField1: string | undefined; - to: string; -}) => { - return { - size: 0, - aggs: { - stackByField0: { - terms: { - field: stackByField0, - order: { - _count: 'desc', - }, - size: DEFAULT_STACK_BY_FIELD0_SIZE, - }, - aggs: { - ...getOptionalSubAggregation({ - stackByField1, - stackByField1Size: DEFAULT_STACK_BY_FIELD1_SIZE, - }), - }, - }, - }, - query: { - bool: { - filter: [ - ...additionalFilters, - { - range: { - '@timestamp': { - gte: from, - lte: to, - }, - }, - }, - ], - }, - }, - runtime_mappings: runtimeMappings, - }; -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx index 18ba80752c398..a9d9821601d25 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx @@ -9,13 +9,10 @@ import type { EuiComboBox } from '@elastic/eui'; import type { Action } from '@kbn/ui-actions-plugin/public'; import React, { memo, useMemo } from 'react'; import { v4 as uuidv4 } from 'uuid'; - import type { Filter } from '@kbn/es-query'; import { useGlobalTime } from '../../../../common/containers/use_global_time'; import { HeaderSection } from '../../../../common/components/header_section'; - import { InspectButtonContainer } from '../../../../common/components/inspect'; - import * as i18n from './translations'; import { KpiPanel } from '../common/components'; import { FieldSelection } from '../../../../common/components/field_selection'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_empty_field0.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_empty_field0.ts deleted file mode 100644 index a2d9d92cd75a6..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_empty_field0.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { AlertSearchResponse } from '../../../../containers/detection_engine/alerts/types'; -import type { AlertsCountAggregation } from '../types'; - -export const emptyStackByField0Response: AlertSearchResponse = { - took: 0, - timeout: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: { - value: 87, - relation: 'eq', - }, - max_score: null, - hits: [], - }, - aggregations: { - stackByField0: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [], - }, - }, -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_multi_group.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_multi_group.ts deleted file mode 100644 index 730fded03f88b..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_multi_group.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { AlertSearchResponse } from '../../../../containers/detection_engine/alerts/types'; -import type { AlertsCountAggregation } from '../types'; - -export const buckets = [ - { - key: 'matches everything', - doc_count: 34, - }, - { - key: 'EQL process sequence', - doc_count: 28, - }, - { - key: 'Endpoint Security', - doc_count: 19, - }, - { - key: 'mimikatz process started', - doc_count: 5, - }, - { - key: 'Threshold rule', - doc_count: 1, - }, -]; - -/** - * A mock response to a request containing multiple group by fields - */ -export const mockMultiGroupResponse: AlertSearchResponse = { - took: 0, - timeout: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: { - value: 87, - relation: 'eq', - }, - max_score: null, - hits: [], - }, - aggregations: { - stackByField0: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets, - }, - }, -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_single_group.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_single_group.ts deleted file mode 100644 index e7c0f982be03b..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/mocks/mock_response_single_group.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { AlertSearchResponse } from '../../../../containers/detection_engine/alerts/types'; -import type { AlertsCountAggregation } from '../types'; - -export const buckets = [ - { - key: 'matches everything', - doc_count: 34, - stackByField1: { - buckets: [ - { - key: 'Host-k8iyfzraq9', - doc_count: 12, - }, - { - key: 'Host-ao1a4wu7vn', - doc_count: 10, - }, - { - key: 'Host-3fbljiq8rj', - doc_count: 7, - }, - { - key: 'Host-r4y6xi92ob', - doc_count: 5, - }, - ], - }, - }, - { - key: 'EQL process sequence', - doc_count: 28, - stackByField1: { - sum_other_doc_count: 0, - buckets: [ - { - key: 'Host-k8iyfzraq9', - doc_count: 10, - }, - { - key: 'Host-ao1a4wu7vn', - doc_count: 7, - }, - { - key: 'Host-3fbljiq8rj', - doc_count: 5, - }, - { - key: 'Host-r4y6xi92ob', - doc_count: 3, - }, - ], - }, - }, - { - key: 'Endpoint Security', - doc_count: 19, - stackByField1: { - sum_other_doc_count: 0, - buckets: [ - { - key: 'Host-ao1a4wu7vn', - doc_count: 11, - }, - { - key: 'Host-3fbljiq8rj', - doc_count: 6, - }, - { - key: 'Host-k8iyfzraq9', - doc_count: 1, - }, - { - key: 'Host-r4y6xi92ob', - doc_count: 1, - }, - ], - }, - }, - { - key: 'mimikatz process started', - doc_count: 5, - stackByField1: { - sum_other_doc_count: 0, - buckets: [ - { - key: 'Host-k8iyfzraq9', - doc_count: 3, - }, - { - key: 'Host-3fbljiq8rj', - doc_count: 1, - }, - { - key: 'Host-r4y6xi92ob', - doc_count: 1, - }, - ], - }, - }, - { - key: 'Threshold rule', - doc_count: 1, - stackByField1: { - sum_other_doc_count: 0, - buckets: [ - { - key: 'Host-r4y6xi92ob', - doc_count: 1, - }, - ], - }, - }, -]; - -export const singleGroupResponse: AlertSearchResponse = { - took: 0, - timeout: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: { - value: 87, - relation: 'eq', - }, - max_score: null, - hits: [], - }, - aggregations: { - stackByField0: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets, - }, - }, -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.test.tsx deleted file mode 100644 index 4b64a214bd02b..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.test.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount, shallow } from 'enzyme'; - -import { AlertsHistogram } from './alerts_histogram'; -import { TestProviders } from '../../../../common/mock'; - -jest.mock('../../../../common/lib/kibana'); - -const legendItems = [ - { - color: '#1EA593', - count: 77, - dataProviderId: - 'draggable-legend-item-2f890398-548e-4604-b2de-525f0eecd124-kibana_alert_rule_name-matches everything', - field: 'kibana.alert.rule.name', - value: 'matches everything', - }, - { - color: '#2B70F7', - count: 56, - dataProviderId: - 'draggable-legend-item-07aca01b-d334-424d-98c0-6d6bc9f8a886-kibana_alert_rule_name-Endpoint Security', - field: 'kibana.alert.rule.name', - value: 'Endpoint Security', - }, -]; - -const defaultProps = { - legendItems, - loading: false, - data: [], - from: '2020-07-07T08:20:18.966Z', - to: '2020-07-08T08:20:18.966Z', - updateDateRange: jest.fn(), -}; - -describe('AlertsHistogram', () => { - it('renders correctly', () => { - const wrapper = shallow(); - - expect(wrapper.find('Chart').exists()).toBeTruthy(); - }); - - it('renders a legend with the default width', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="draggable-legend"]').first()).toHaveStyleRule( - 'min-width', - '165px' - ); - }); - - it('renders a legend with the specified `legendWidth`', () => { - const legendMinWidth = 1234; - - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="draggable-legend"]').first()).toHaveStyleRule( - 'min-width', - `${legendMinWidth}px` - ); - }); -}); 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 deleted file mode 100644 index 83052e4e5a2f1..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/alerts_histogram.tsx +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { ChartSizeArray } from '@elastic/charts'; -import { i18n } from '@kbn/i18n'; -import { - Axis, - Chart, - HistogramBarSeries, - Position, - Settings, - ScaleType, - LegendValue, -} from '@elastic/charts'; -import { EuiFlexGroup, EuiFlexItem, EuiProgress } from '@elastic/eui'; -import React, { useMemo } from 'react'; - -import type { UpdateDateRange, ChartData } from '../../../../common/components/charts/common'; -import { useThemes } from '../../../../common/components/charts/common'; -import { histogramDateTimeFormatter } from '../../../../common/components/utils'; -import { hasValueToDisplay } from '../../../../common/utils/validators'; -import { DraggableLegend } from '../../../../common/components/charts/draggable_legend'; -import type { LegendItem } from '../../../../common/components/charts/draggable_legend_item'; -import { EMPTY_VALUE_LABEL } from '../../../../common/components/charts/translation'; - -import type { HistogramData } from './types'; - -const DEFAULT_CHART_HEIGHT = 174; - -interface AlertsHistogramProps { - chartHeight?: number; - from: string; - legendItems: LegendItem[]; - legendPosition?: Position; - legendMinWidth?: number; - loading: boolean; - showLegend?: boolean; - to: string; - data: HistogramData[]; - updateDateRange: UpdateDateRange; -} -export const AlertsHistogram = React.memo( - ({ - chartHeight = DEFAULT_CHART_HEIGHT, - data, - from, - legendItems, - legendPosition = Position.Right, - legendMinWidth, - loading, - showLegend, - to, - updateDateRange, - }) => { - const { baseTheme, theme } = useThemes(); - const chartSize: ChartSizeArray = useMemo(() => ['100%', chartHeight], [chartHeight]); - const xAxisId = 'alertsHistogramAxisX'; - const yAxisId = 'alertsHistogramAxisY'; - const id = 'alertsHistogram'; - const yAccessors = useMemo(() => ['y'], []); - const splitSeriesAccessors = useMemo( - () => [(datum: ChartData) => (hasValueToDisplay(datum.g) ? datum.g : EMPTY_VALUE_LABEL)], - [] - ); - const tickFormat = useMemo(() => histogramDateTimeFormatter([from, to]), [from, to]); - - return ( - <> - {loading && ( - - )} - - - - - - - - - - - - - - - {legendItems.length > 0 && ( - - )} - - - - ); - } -); - -AlertsHistogram.displayName = 'AlertsHistogram'; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx index 519a7975c5891..2599b10b93a48 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.test.tsx @@ -7,12 +7,7 @@ import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import type { Embeddable } from '@kbn/embeddable-plugin/public'; -import { - createResetGroupByFieldAction, - formatAlertsData, - showInitialLoadingSpinner, -} from './helpers'; -import { result, textResult, stackedByBooleanField, stackedByTextField } from './mock_data'; +import { createResetGroupByFieldAction, showInitialLoadingSpinner } from './helpers'; import type { LensDataTableEmbeddable } from '../../../../common/components/visualization_actions/types'; describe('helpers', () => { @@ -43,18 +38,6 @@ describe('helpers', () => { }); }); -describe('formatAlertsData', () => { - test('stack by a boolean field', () => { - const res = formatAlertsData(stackedByBooleanField); - expect(res).toEqual(result); - }); - - test('stack by a text field', () => { - const res = formatAlertsData(stackedByTextField); - expect(res).toEqual(textResult); - }); -}); - describe('createResetGroupByFieldAction', () => { let action: Action; const embeddable = { 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 cbeb7e9c3d0a5..8757316038b4a 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,95 +5,11 @@ * 2.0. */ -import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { isEmpty } from 'lodash/fp'; -import moment from 'moment'; - import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import type { Embeddable } from '@kbn/embeddable-plugin/public'; -import type { HistogramData, AlertsAggregation, AlertsBucket, AlertsGroupBucket } from './types'; -import type { AlertSearchResponse } from '../../../containers/detection_engine/alerts/types'; import { RESET_GROUP_BY_FIELDS } from '../../../../common/components/chart_settings_popover/configurations/default/translations'; import type { LensDataTableEmbeddable } from '../../../../common/components/visualization_actions/types'; -const EMPTY_ALERTS_DATA: HistogramData[] = []; - -export const formatAlertsData = (alertsData: AlertSearchResponse<{}, AlertsAggregation> | null) => { - const groupBuckets: AlertsGroupBucket[] = - alertsData?.aggregations?.alertsByGrouping?.buckets ?? []; - return groupBuckets.reduce( - (acc, { key_as_string: keyAsString, key: group, alerts }) => { - const alertsBucket: AlertsBucket[] = alerts.buckets ?? []; - - return [ - ...acc, - // eslint-disable-next-line @typescript-eslint/naming-convention - ...alertsBucket.map(({ key, doc_count }: AlertsBucket) => ({ - x: key, - y: doc_count, - g: keyAsString ?? group.toString(), - })), - ]; - }, - EMPTY_ALERTS_DATA - ); -}; - -export const getAlertsHistogramQuery = ( - stackByField: string, - from: string, - to: string, - additionalFilters: Array<{ - bool: { filter: unknown[]; should: unknown[]; must_not: unknown[]; must: unknown[] }; - }>, - runtimeMappings?: MappingRuntimeFields -) => { - return { - aggs: { - alertsByGrouping: { - terms: { - field: stackByField, - order: { - _count: 'desc', - }, - size: 10, - }, - aggs: { - alerts: { - date_histogram: { - field: '@timestamp', - fixed_interval: `${Math.floor(moment(to).diff(moment(from)) / 32)}ms`, - min_doc_count: 0, - extended_bounds: { - min: from, - max: to, - }, - }, - }, - }, - }, - }, - query: { - bool: { - filter: [ - ...additionalFilters, - { - range: { - '@timestamp': { - gte: from, - lte: to, - }, - }, - }, - ], - }, - }, - runtime_mappings: runtimeMappings, - _source: false, - size: 0, - }; -}; - /** * Returns `true` when the alerts histogram initial loading spinner should be shown * @@ -108,22 +24,6 @@ export const showInitialLoadingSpinner = ({ isLoadingAlerts: boolean; }): boolean => isInitialLoading && isLoadingAlerts; -export const parseFilterQuery = (query?: string) => { - try { - return query != null && !isEmpty(query) ? JSON.parse(query) : {}; - } catch { - return {}; - } -}; - -export const buildFilterQuery = (query?: string) => { - try { - return isEmpty(query) ? [] : [parseFilterQuery(query)]; - } catch { - return []; - } -}; - interface CreateResetGroupByFieldActionProps { callback?: () => void; order?: number; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx index 18b51365b0429..8a14499740444 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { mount } from 'enzyme'; import type { Filter } from '@kbn/es-query'; @@ -75,8 +75,6 @@ jest.mock('../../../../common/lib/kibana', () => { jest.mock('../../../../common/components/visualization_actions/visualization_embeddable'); -jest.mock('../../../../common/hooks/use_experimental_features'); - jest.mock('../../../../common/components/visualization_actions/use_visualization_response', () => { const original = jest.requireActual( '../../../../common/components/visualization_actions/use_visualization_response' @@ -371,30 +369,26 @@ describe('AlertsHistogramPanel', () => { }); describe('Query', () => { - it('it render with a illegal KQL', async () => { - await act(async () => { - jest.mock('@kbn/es-query', () => ({ - buildEsQuery: jest.fn().mockImplementation(() => { - throw new Error('Something went wrong'); - }), - })); - const props = { ...defaultProps, query: { query: 'host.name: "', language: 'kql' } }; - const wrapper = mount( - - - - ); + it('it render with a illegal KQL', () => { + jest.mock('@kbn/es-query', () => ({ + buildEsQuery: jest.fn().mockImplementation(() => { + throw new Error('Something went wrong'); + }), + })); + const props = { ...defaultProps, query: { query: 'host.name: "', language: 'kql' } }; + const wrapper = mount( + + + + ); - await waitFor(() => { - expect(wrapper.find('[data-test-subj="alerts-histogram-panel"]').exists()).toBeTruthy(); - }); - wrapper.unmount(); - }); + expect(wrapper.find('[data-test-subj="alerts-histogram-panel"]').exists()).toBeTruthy(); + wrapper.unmount(); }); }); describe('Filters', () => { - it('filters props is valid, alerts query include filter', async () => { + it('filters props is valid, alerts query include filter', () => { const statusFilter: Filter = { meta: { alias: null, @@ -423,119 +417,103 @@ describe('AlertsHistogramPanel', () => { ); - await waitFor(() => { - expect( - (VisualizationEmbeddable as unknown as jest.Mock).mock.calls[0][0].timerange - ).toEqual({ - from: '2020-07-07T08:20:18.966Z', - to: '2020-07-08T08:20:18.966Z', - }); - expect( - (VisualizationEmbeddable as unknown as jest.Mock).mock.calls[0][0].extraOptions.filters - ).toEqual(props.filters); + expect((VisualizationEmbeddable as unknown as jest.Mock).mock.calls[0][0].timerange).toEqual({ + from: '2020-07-07T08:20:18.966Z', + to: '2020-07-08T08:20:18.966Z', }); + expect( + (VisualizationEmbeddable as unknown as jest.Mock).mock.calls[0][0].extraOptions.filters + ).toEqual(props.filters); wrapper.unmount(); }); }); describe('toggle button', () => { describe('When setIsExpanded is available', () => { - it('toggles', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click'); - expect(mockSetIsExpanded).toBeCalledWith(false); - expect(mockSetToggle).not.toBeCalled(); - }); + it('toggles', () => { + const wrapper = mount( + + + + ); + + wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click'); + expect(mockSetIsExpanded).toBeCalledWith(false); + expect(mockSetToggle).not.toBeCalled(); + wrapper.unmount(); }); it('when isExpanded is true, render histogram panel', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(true); - expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( - true - ); - }); + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(true); + expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( + true + ); + wrapper.unmount(); }); it('when isExpanded is false, hide histogram panel', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(false); - expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( - false - ); - }); + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(false); + expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( + false + ); + wrapper.unmount(); }); }); describe('When setIsExpanded is not available, use toggleQuery', () => { - beforeEach(() => { - mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle }); - }); const props = { ...defaultProps, setIsExpanded: undefined }; it('toggles', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click'); - expect(mockSetToggle).toBeCalledWith(false); - }); + const wrapper = mount( + + + + ); + wrapper.find('[data-test-subj="query-toggle-header"]').first().simulate('click'); + expect(mockSetToggle).toBeCalledWith(false); + wrapper.unmount(); }); - it('when toggleStatus is true, render', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(true); - expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( - true - ); - }); + it('when toggleStatus is true, render', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(true); + expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( + true + ); + wrapper.unmount(); }); it('when toggleStatus is false, hide', async () => { mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle }); - await act(async () => { - const wrapper = mount( - - - - ); - expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(false); - expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( - false - ); - }); + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="panelFlexGroup"]').exists()).toEqual(false); + expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toEqual( + false + ); + wrapper.unmount(); }); }); }); describe('VisualizationEmbeddable', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - test('it renders the header with alerts count', () => { const wrapper = mount( @@ -552,50 +530,49 @@ describe('AlertsHistogramPanel', () => { }, ], }); + wrapper.setProps({ filters: [] }); wrapper.update(); expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).text()).toContain('999'); + wrapper.unmount(); }); - it('renders LensEmbeddable', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - expect( - wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists() - ).toBeTruthy(); - }); + it('renders LensEmbeddable', () => { + const wrapper = mount( + + + + ); + expect(wrapper.find('[data-test-subj="embeddable-matrix-histogram"]').exists()).toBeTruthy(); + wrapper.unmount(); }); - it('renders LensEmbeddable with provided height', async () => { - await act(async () => { - mount( - - - - ); - expect((VisualizationEmbeddable as unknown as jest.Mock).mock.calls[0][0].height).toEqual( - 155 - ); - }); + it('renders LensEmbeddable with provided height', () => { + const wrapper = mount( + + + + ); + + expect((VisualizationEmbeddable as unknown as jest.Mock).mock.calls[0][0].height).toEqual( + 155 + ); + wrapper.unmount(); }); - it('should render correct subtitle with alert count', async () => { - await act(async () => { - const wrapper = mount( - - - - ); - expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).text()).toContain('999'); - }); + it('should render correct subtitle with alert count', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).text()).toContain('999'); + wrapper.unmount(); }); - it('should render correct subtitle with empty string', async () => { + it('should render correct subtitle with empty string', () => { (useVisualizationResponse as jest.Mock).mockReturnValue({ responses: [ { @@ -605,15 +582,14 @@ describe('AlertsHistogramPanel', () => { ], loading: false, }); + const wrapper = mount( + + + + ); - await act(async () => { - const wrapper = mount( - - - - ); - expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).text()).toEqual(''); - }); + expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).text()).toEqual(''); + wrapper.unmount(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/mock_data.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/mock_data.ts index e2ab1a3ae9f84..df6f4e1573554 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/mock_data.ts +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/mock_data.ts @@ -4,84 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -export const stackedByBooleanField = { - took: 1, - timed_out: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { - total: { - value: 3, - relation: 'eq', - }, - hits: [], - }, - timeout: false, - aggregations: { - alertsByGrouping: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 1, - key_as_string: 'true', - doc_count: 2683, - alerts: { - buckets: [ - { key_as_string: '2022-05-10T15:34:48.075Z', key: 1652196888075, doc_count: 0 }, - { key_as_string: '2022-05-10T16:19:48.074Z', key: 1652199588074, doc_count: 0 }, - { key_as_string: '2022-05-10T17:04:48.073Z', key: 1652202288073, doc_count: 0 }, - ], - }, - }, - ], - }, - }, -}; - -export const result = [ - { x: 1652196888075, y: 0, g: 'true' }, - { x: 1652199588074, y: 0, g: 'true' }, - { x: 1652202288073, y: 0, g: 'true' }, -]; - -export const stackedByTextField = { - took: 1, - timeout: false, - _shards: { total: 1, successful: 1, skipped: 0, failed: 0 }, - hits: { - total: { - value: 3, - relation: 'eq', - }, - hits: [], - }, - aggregations: { - alertsByGrouping: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'MacBook-Pro.local', - doc_count: 2706, - alerts: { - buckets: [ - { key_as_string: '2022-05-10T15:34:48.075Z', key: 1652196888075, doc_count: 0 }, - { key_as_string: '2022-05-10T16:19:48.074Z', key: 1652199588074, doc_count: 0 }, - { key_as_string: '2022-05-10T17:04:48.073Z', key: 1652202288073, doc_count: 0 }, - ], - }, - }, - ], - }, - }, -}; - -export const textResult = [ - { x: 1652196888075, y: 0, g: 'MacBook-Pro.local' }, - { x: 1652199588074, y: 0, g: 'MacBook-Pro.local' }, - { x: 1652202288073, y: 0, g: 'MacBook-Pro.local' }, -]; - export const mockAlertSearchResponse = { took: 1, timed_out: false, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/types.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/types.ts deleted file mode 100644 index ba0205577aa3a..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/types.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface HistogramData { - x: number; - y: number; - g: string; -} - -export interface AlertsAggregation { - alertsByGrouping: { - buckets: AlertsGroupBucket[]; - }; -} - -export interface AlertsBucket { - key_as_string: string; - key: number; - doc_count: number; -} - -export interface AlertsGroupBucket { - key: string | number; - key_as_string?: string; - alerts: { - buckets: AlertsBucket[]; - }; - doc_count: number; -} - -export interface AlertsTotal { - value: number; - relation: string; -} diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/index.tsx index 2cc5cda85436b..791f8eb9dc1ce 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/index.tsx @@ -19,7 +19,8 @@ import type { GroupBySelection } from '../alerts_progress_bar_panel/types'; import type { AddFilterProps } from '../common/types'; const StyledFlexGroup = styled(EuiFlexGroup)` - @media only screen and (min-width: ${({ theme }) => theme.eui.euiBreakpoints.l}); + @media only screen and (min-width: ${({ theme }) => theme.eui.euiBreakpoints.l}) { + } `; const StyledFlexItem = styled(EuiFlexItem)` diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data.test.tsx index 4949fa9a2855f..22dd8da0e1101 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_summary_charts_panel/use_summary_chart_data.test.tsx @@ -14,7 +14,6 @@ import * as aggregations from './aggregations'; import * as severityMock from '../severity_level_panel/mock_data'; import * as alertRuleMock from '../alerts_by_rule_panel/mock_rule_data'; import * as alertsGroupingMock from '../alerts_progress_bar_panel/mock_data'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; const from = '2022-04-05T12:00:00.000Z'; const to = '2022-04-08T12:00:00.000Z'; @@ -50,9 +49,6 @@ jest.mock('../../../../common/containers/use_global_time', () => { }; }); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; -jest.mock('../../../../common/hooks/use_experimental_features'); - describe('getAlertsQuery', () => { test('it returns the expected severity query', () => { expect( @@ -167,7 +163,7 @@ describe('get summary charts data', () => { }); }); - describe('get alerts by type data', () => { + describe('get alerts by rule data', () => { beforeEach(() => { jest.clearAllMocks(); mockDateNow.mockReturnValue(dateNow); @@ -175,7 +171,6 @@ describe('get summary charts data', () => { }); it('should return correct default values', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); const { result } = renderUseSummaryChartData({ aggregations: aggregations.alertRuleAggregations, }); @@ -195,7 +190,6 @@ describe('get summary charts data', () => { }); it('should return parsed alerts by type items', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); mockUseQueryAlerts.mockReturnValue({ ...defaultUseQueryAlertsReturn, data: alertRuleMock.mockAlertsData, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/alerts_local_storage/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/alerts_local_storage/index.test.tsx index 6fd125dd24092..303b85a40e6ee 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/alerts_local_storage/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/alerts_local_storage/index.test.tsx @@ -10,10 +10,6 @@ import React from 'react'; import { useAlertsLocalStorage } from '.'; import { TestProviders } from '../../../../../common/mock'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; - -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; -jest.mock('../../../../../common/hooks/use_experimental_features'); describe('useAlertsLocalStorage', () => { const wrapper = ({ children }: { children: React.ReactNode }) => ( @@ -21,7 +17,6 @@ describe('useAlertsLocalStorage', () => { ); test('it returns the expected defaults', () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); const { result } = renderHook(() => useAlertsLocalStorage(), { wrapper }); const defaults = Object.fromEntries( diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/chart_collapse/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/chart_collapse/index.tsx index dbeea09315331..0539b7f7615d6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/chart_collapse/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/chart_collapse/index.tsx @@ -50,7 +50,8 @@ const combinedAggregations = (groupBySelection: GroupBySelection) => { const StyledEuiFlexGroup = styled(EuiFlexGroup)` margin-top: ${({ theme }) => theme.eui.euiSizeXS}; - @media only screen and (min-width: ${({ theme }) => theme.eui.euiBreakpoints.l}); + @media only screen and (min-width: ${({ theme }) => theme.eui.euiBreakpoints.l}) { + } `; const SeverityWrapper = styled(EuiFlexItem)` @@ -105,7 +106,7 @@ export const ChartCollapse: React.FC = ({ }); }, [data]); const groupBy = useMemo(() => getGroupByLabel(groupBySelection), [groupBySelection]); - // className="eui-alignMiddle" + return ( {!isLoading && ( diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx index 2b75252f3d578..668f323d147cb 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/chart_panels/index.test.tsx @@ -16,7 +16,6 @@ import { mockBrowserFields } from '../../../../common/containers/source/mock'; import { useSourcererDataView } from '../../../../sourcerer/containers'; import { TestProviders } from '../../../../common/mock'; import { ChartPanels } from '.'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useQueryToggle } from '../../../../common/containers/query_toggle'; import { LensEmbeddable } from '../../../../common/components/visualization_actions/lens_embeddable'; import { createResetGroupByFieldAction } from '../alerts_histogram_panel/helpers'; @@ -27,6 +26,11 @@ jest.mock('../../../../sourcerer/containers'); jest.mock('../../../../common/components/visualization_actions/lens_embeddable'); jest.mock('../../../../common/components/page/use_refetch_by_session', () => ({ useRefetchByRestartingSession: jest.fn().mockReturnValue({ + session: { + current: { + start: jest.fn(), + }, + }, searchSessionId: 'mockSearchSessionId', refetchByRestartingSession: jest.fn(), }), @@ -63,9 +67,6 @@ jest.mock('../../../../common/lib/kibana', () => { }; }); -const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; -jest.mock('../../../../common/hooks/use_experimental_features'); - const mockSetToggle = jest.fn(); const mockUseQueryToggle = useQueryToggle as jest.Mock; jest.mock('../../../../common/containers/query_toggle'); @@ -163,7 +164,6 @@ describe('ChartPanels', () => { }); test('when toggle is true, renders the chart selector tabs', async () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: mockSetToggle }); render( @@ -177,7 +177,6 @@ describe('ChartPanels', () => { }); test('when toggle is false, renders the chart collapse', async () => { - mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: mockSetToggle }); render(