From ea478144627545795ffeb72a194c7bf87281e99a Mon Sep 17 00:00:00 2001 From: PhilippeOberti Date: Mon, 21 Oct 2024 16:03:26 -0500 Subject: [PATCH 1/3] [Security Solution][Alert details] - refactor UI on insights --- .../components/correlations_overview.test.tsx | 58 +++-- .../components/correlations_overview.tsx | 2 +- .../insights_summary_row.stories.tsx | 77 ------ .../components/insights_summary_row.test.tsx | 53 +---- .../right/components/insights_summary_row.tsx | 78 ++---- .../components/prevalence_overview.test.tsx | 34 +-- .../right/components/prevalence_overview.tsx | 14 +- .../related_alerts_by_ancestry.test.tsx | 103 ++++++-- .../components/related_alerts_by_ancestry.tsx | 73 +++++- ...lated_alerts_by_same_source_event.test.tsx | 110 +++++++-- .../related_alerts_by_same_source_event.tsx | 75 +++++- .../related_alerts_by_session.test.tsx | 103 ++++++-- .../components/related_alerts_by_session.tsx | 73 +++++- .../right/components/related_cases.test.tsx | 103 ++++++-- .../right/components/related_cases.tsx | 77 +++++- .../components/suppressed_alerts.test.tsx | 104 +++++--- .../right/components/suppressed_alerts.tsx | 77 ++++-- .../right/components/test_ids.ts | 20 +- .../threat_intelligence_overview.test.tsx | 222 ++++++++++++------ .../threat_intelligence_overview.tsx | 130 +++++++--- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - ...ert_details_right_panel_overview_tab.cy.ts | 27 +-- .../alert_details_right_panel_overview_tab.ts | 8 +- 25 files changed, 1128 insertions(+), 496 deletions(-) delete mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx index f4a97b7deed11..c187631f7abb2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx @@ -22,6 +22,7 @@ import { CORRELATIONS_RELATED_CASES_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, } from './test_ids'; import { useShowRelatedAlertsByAncestry } from '../../shared/hooks/use_show_related_alerts_by_ancestry'; @@ -58,17 +59,32 @@ const TITLE_LINK_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(CORRELATIO const TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(CORRELATIONS_TEST_ID); const TITLE_TEXT_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(CORRELATIONS_TEST_ID); -const SUPPRESSED_ALERTS_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); -const RELATED_ALERTS_BY_ANCESTRY_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const SUPPRESSED_ALERTS_TEXT_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( + CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID +); +const SUPPRESSED_ALERTS_VALUE_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID +); +const RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID +); +const RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); -const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); -const RELATED_ALERTS_BY_SESSION_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( + CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID +); +const RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID +); +const RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID ); -const RELATED_CASES_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const RELATED_CASES_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const RELATED_CASES_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const panelContextValue = { eventId: 'event id', @@ -193,11 +209,16 @@ describe('', () => { }); const { getByTestId, queryByText } = render(renderCorrelationsOverview(panelContextValue)); - expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(RELATED_CASES_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SUPPRESSED_ALERTS_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_CASES_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RELATED_CASES_VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(SUPPRESSED_ALERTS_TEXT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(SUPPRESSED_ALERTS_VALUE_TEST_ID)).toBeInTheDocument(); expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); @@ -215,11 +236,18 @@ describe('', () => { jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); const { getByText, queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); - expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect( + queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID) + ).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_CASES_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(RELATED_CASES_VALUE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SUPPRESSED_ALERTS_TEXT_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SUPPRESSED_ALERTS_VALUE_TEST_ID)).not.toBeInTheDocument(); expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx index c2494b4cde675..9ab130cfc2de1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx @@ -134,7 +134,7 @@ export const CorrelationsOverview: React.FC = () => { data-test-subj={CORRELATIONS_TEST_ID} > {canShowAtLeastOneInsight ? ( - + {showSuppressedAlerts && ( )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.tsx deleted file mode 100644 index eb76108d6b215..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.stories.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 React from 'react'; -import type { Story } from '@storybook/react'; -import { css } from '@emotion/react'; -import { InsightsSummaryRow } from './insights_summary_row'; - -export default { - component: InsightsSummaryRow, - title: 'Flyout/InsightsSummaryRow', -}; - -const wrapper = (children: React.ReactNode) => ( -
- {children} -
-); - -export const Default: Story = () => - wrapper( - - ); - -export const InvalidColor: Story = () => - wrapper( - - ); - -export const NoColor: Story = () => - wrapper(); - -export const LongText: Story = () => - wrapper( - - ); - -export const LongNumber: Story = () => - wrapper( - - ); - -export const Loading: Story = () => - wrapper(); - -export const Error: Story = () => - wrapper(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx index 3e10e83332a97..ac3a6cb0f958d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx @@ -11,9 +11,8 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { InsightsSummaryRow } from './insights_summary_row'; const testId = 'test'; -const iconTestId = `${testId}Icon`; +const textTestId = `${testId}Text`; const valueTestId = `${testId}Value`; -const colorTestId = `${testId}Color`; const loadingTestId = `${testId}Loading`; describe('', () => { @@ -21,62 +20,36 @@ describe('', () => { const { getByTestId } = render( {'value for this'}} color={'rgb(189,39,30)'} data-test-subj={testId} /> ); - expect(getByTestId(iconTestId)).toBeInTheDocument(); - expect(getByTestId(valueTestId)).toHaveTextContent('1 this is a test for red'); - expect(getByTestId(colorTestId)).toBeInTheDocument(); + expect(getByTestId(textTestId)).toHaveTextContent('this is a test for red'); + expect(getByTestId(valueTestId)).toHaveTextContent('value for this'); }); it('should render loading skeletton if loading is true', () => { const { getByTestId } = render( - + {'value for this'}} + data-test-subj={testId} + /> ); expect(getByTestId(loadingTestId)).toBeInTheDocument(); }); it('should only render null when error is true', () => { - const { container } = render(); - - expect(container).toBeEmptyDOMElement(); - }); - - it('should handle big number in a compact notation', () => { - const { getByTestId } = render( - - - + const { container } = render( + {'value for this'}} /> ); - expect(getByTestId(valueTestId)).toHaveTextContent('160k this is a test for red'); - }); - - it(`should not show the colored dot if color isn't provided`, () => { - const { queryByTestId } = render( - - - - ); - - expect(queryByTestId(colorTestId)).not.toBeInTheDocument(); + expect(container).toBeEmptyDOMElement(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx index 23f838f5068bb..3f51f682b9d18 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx @@ -9,15 +9,13 @@ import type { ReactElement, VFC } from 'react'; import React from 'react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { - EuiIcon, - EuiFlexGroup, - EuiFlexItem, - EuiHealth, - EuiSkeletonText, - useEuiTheme, -} from '@elastic/eui'; -import { FormattedCount } from '../../../../common/components/formatted_number'; +import type { EuiBadgeProps } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui'; + +const LOADING = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel', + { defaultMessage: 'Loading' } +); export interface InsightsSummaryRowProps { /** @@ -29,22 +27,17 @@ export interface InsightsSummaryRowProps { */ error?: boolean; /** - * Icon to display on the left side of each row + * Text corresponding of the number of results/entries */ - icon: string; + text: string | ReactElement; /** * Number of results/entries found */ - value?: number; - /** - * Text corresponding of the number of results/entries - */ - text: string | ReactElement; + value: ReactElement; /** - * Optional parameter for now, will be used to display a dot on the right side - * (corresponding to some sort of severity?) + * Decides the color of the badge */ - color?: string; // TODO remove optional when we have guidance on what the colors will actually be + color?: EuiBadgeProps['color']; /** * Prefix data-test-subj because this component will be used in multiple places */ @@ -54,19 +47,15 @@ export interface InsightsSummaryRowProps { /** * Panel showing summary information as an icon, a count and text as well as a severity colored dot. * Should be used for Entities, Threat intelligence, Prevalence, Correlations and Results components under the Insights section. - * The colored dot is currently optional but will ultimately be mandatory (waiting on PM and UIUX). */ export const InsightsSummaryRow: VFC = ({ loading = false, error = false, - icon, value, text, - color, + color = 'hollow', 'data-test-subj': dataTestSubj, }) => { - const { euiTheme } = useEuiTheme(); - const loadingDataTestSubj = `${dataTestSubj}Loading`; if (loading) { return ( @@ -74,13 +63,7 @@ export const InsightsSummaryRow: VFC = ({ lines={1} size="m" isLoading={loading} - contentAriaLabel={i18n.translate( - 'xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel', - { - defaultMessage: 'Loading insights for {value}', - values: { value }, - } - )} + contentAriaLabel={LOADING} data-test-subj={loadingDataTestSubj} /> ); @@ -90,9 +73,8 @@ export const InsightsSummaryRow: VFC = ({ return null; } - const iconDataTestSubj = `${dataTestSubj}Icon`; + const textDataTestSubj = `${dataTestSubj}Text`; const valueDataTestSubj = `${dataTestSubj}Value`; - const colorDataTestSubj = `${dataTestSubj}Color`; return ( = ({ alignItems={'center'} responsive={false} > - - - = ({ overflow: hidden; `} > - {value && } {text} + {text} + + + {value} - {color && ( - - - - )} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx index a47ed04c85b5a..527b9830b3948 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx @@ -8,7 +8,11 @@ import { render } from '@testing-library/react'; import { TestProviders } from '../../../../common/mock'; import { DocumentDetailsContext } from '../../shared/context'; -import { PREVALENCE_TEST_ID } from './test_ids'; +import { + PREVALENCE_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, + SUMMARY_ROW_VALUE_TEST_ID, +} from './test_ids'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInsightsTab } from '../../left'; import React from 'react'; @@ -149,21 +153,19 @@ describe('', () => { expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Prevalence'); - const iconDataTestSubj1 = `${PREVALENCE_TEST_ID}${field1}Icon`; - const valueDataTestSubj1 = `${PREVALENCE_TEST_ID}${field1}Value`; - expect(getByTestId(iconDataTestSubj1)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj1)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj1)).toHaveTextContent('field1, value1 is uncommon'); - - const iconDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Icon`; - const valueDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Value`; - expect(getByTestId(iconDataTestSubj2)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj2)).toBeInTheDocument(); - expect(getByTestId(valueDataTestSubj2)).toHaveTextContent('field2, value2,value22 is uncommon'); - - const iconDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Icon`; - const valueDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Value`; - expect(queryByTestId(iconDataTestSubj3)).not.toBeInTheDocument(); + const textDataTestSubj1 = SUMMARY_ROW_TEXT_TEST_ID(`${PREVALENCE_TEST_ID}${field1}`); + const valueDataTestSubj1 = SUMMARY_ROW_VALUE_TEST_ID(`${PREVALENCE_TEST_ID}${field1}`); + expect(getByTestId(textDataTestSubj1)).toHaveTextContent('field1, value1'); + expect(getByTestId(valueDataTestSubj1)).toHaveTextContent('Uncommon'); + + const textDataTestSubj2 = SUMMARY_ROW_TEXT_TEST_ID(`${PREVALENCE_TEST_ID}${field2}`); + const valueDataTestSubj2 = SUMMARY_ROW_VALUE_TEST_ID(`${PREVALENCE_TEST_ID}${field2}`); + expect(getByTestId(textDataTestSubj2)).toHaveTextContent('field2, value2'); + expect(getByTestId(valueDataTestSubj2)).toHaveTextContent('Uncommon'); + + const textDataTestSubj3 = SUMMARY_ROW_TEXT_TEST_ID(`${PREVALENCE_TEST_ID}${field3}`); + const valueDataTestSubj3 = SUMMARY_ROW_VALUE_TEST_ID(`${PREVALENCE_TEST_ID}${field3}`); + expect(queryByTestId(textDataTestSubj3)).not.toBeInTheDocument(); expect(queryByTestId(valueDataTestSubj3)).not.toBeInTheDocument(); expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx index 96ee603607742..d64007fc6ded6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx @@ -7,7 +7,7 @@ import type { FC } from 'react'; import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '@kbn/security-solution-common'; @@ -19,6 +19,13 @@ import { LeftPanelInsightsTab } from '../../left'; import { PREVALENCE_TAB_ID } from '../../left/components/prevalence_details'; import { InsightsSummaryRow } from './insights_summary_row'; +const UNCOMMON = ( + +); + const PERCENTAGE_THRESHOLD = 0.1; // we show the prevalence if its value is below 10% const DEFAULT_FROM = 'now-30d'; const DEFAULT_TO = 'now'; @@ -104,11 +111,10 @@ export const PrevalenceOverview: FC = () => { content={{ loading, error }} data-test-subj={PREVALENCE_TEST_ID} > - + {uncommonData.length > 0 ? ( uncommonData.map((d) => ( { values={{ field: d.field, value: d.values.toString() }} /> } + value={{UNCOMMON}} + color={'warning'} data-test-subj={`${PREVALENCE_TEST_ID}${d.field}`} key={`${PREVALENCE_TEST_ID}${d.field}`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx index 5aad641c6e400..57b8ab2ad27db 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx @@ -9,21 +9,32 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, + CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID, } from './test_ids'; import { RelatedAlertsByAncestry } from './related_alerts_by_ancestry'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_ancestry'); +const mockOpenLeftPanel = jest.fn(); const documentId = 'documentId'; const indices = ['indices']; const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID @@ -37,7 +48,30 @@ const renderRelatedAlertsByAncestry = () => ); describe('', () => { - it('should render many related alerts correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related alert correctly', () => { + (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsByAncestry(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by ancestry'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + }); + + it('should render multiple related alerts correctly', () => { (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ loading: false, error: false, @@ -45,26 +79,20 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsByAncestry(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 alerts related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by ancestry'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); }); - it('should render single related alerts correctly', () => { + it('should render big number of related alerts correctly', () => { (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2000, }); const { getByTestId } = renderRelatedAlertsByAncestry(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 alert related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by ancestry'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); }); it('should render loading skeleton', () => { @@ -85,4 +113,49 @@ describe('', () => { const { container } = renderRelatedAlertsByAncestry(); expect(container).toBeEmptyDOMElement(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsByAncestry(); + getByTestId(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); + + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + isPreviewMode: true, + }); + (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsByAncestry(); + const button = getByTestId(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID); + + expect(button).toHaveAttribute('disabled'); + + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx index 2e628ba61a7be..fff5459a566f0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx @@ -5,13 +5,27 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { useDocumentDetailsContext } from '../../shared/context'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; import { InsightsSummaryRow } from './insights_summary_row'; -import { CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID } from './test_ids'; +import { + CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID, + CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, +} from './test_ids'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; -const ICON = 'warning'; +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.entities.relatedAlertsByAncestry.buttonLabel', + { defaultMessage: 'Related alerts by ancestry' } +); export interface RelatedAlertsByAncestryProps { /** @@ -36,26 +50,63 @@ export const RelatedAlertsByAncestry: React.VFC = indices, scopeId, }) => { + const { eventId, indexName, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + const { loading, error, dataCount } = useFetchRelatedAlertsByAncestry({ documentId, indices, scopeId, }); - const text = ( - + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, indexName, openLeftPanel, scopeId]); + + const text = useMemo( + () => ( + + ), + [dataCount] + ); + + const value = useMemo( + () => ( + + + + ), + [dataCount, isPreviewMode, onClick] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx index d52d547397789..194809e040cad 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx @@ -9,20 +9,31 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, + CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID, } from './test_ids'; import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; import { RelatedAlertsBySameSourceEvent } from './related_alerts_by_same_source_event'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_same_source_event'); +const mockOpenLeftPanel = jest.fn(); const originalEventId = 'originalEventId'; const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID( +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( @@ -40,7 +51,30 @@ const renderRelatedAlertsBySameSourceEvent = () => ); describe('', () => { - it('should render many related alerts correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related alert correctly', () => { + (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by source event'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + }); + + it('should render multiple related alerts correctly', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ loading: false, error: false, @@ -48,26 +82,20 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); }); - it('should render single related alerts correctly', () => { + it('should render big number of related alerts correctly', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2000, }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 alert related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); }); it('should render loading skeleton', () => { @@ -87,10 +115,52 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('0 alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('0'); + }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ + loading: false, + error: true, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); + getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); + + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + isPreviewMode: true, + }); + (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ + loading: false, + error: true, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); + const button = getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID); + + expect(button).toHaveAttribute('disabled'); + + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx index 0c1550dbb8692..e91d9c450bde9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx @@ -5,13 +5,27 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { + CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID, + CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, +} from './test_ids'; import { InsightsSummaryRow } from './insights_summary_row'; -import { CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID } from './test_ids'; +import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; -const ICON = 'warning'; +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.entities.relatedAlertsBySameSourceEvent.buttonLabel', + { defaultMessage: 'Related alerts by ancestry' } +); export interface RelatedAlertsBySameSourceEventProps { /** @@ -31,24 +45,61 @@ export const RelatedAlertsBySameSourceEvent: React.VFC { + const { eventId, indexName, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + const { loading, dataCount } = useFetchRelatedAlertsBySameSourceEvent({ originalEventId, scopeId, }); - const text = ( - + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, indexName, openLeftPanel, scopeId]); + + const text = useMemo( + () => ( + + ), + [dataCount] + ); + + const value = useMemo( + () => ( + + + + ), + [dataCount, isPreviewMode, onClick] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx index 96ab397229420..7ab039f92e0fb 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx @@ -9,20 +9,31 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, + CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID, } from './test_ids'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_session'); +const mockOpenLeftPanel = jest.fn(); +const eventId = 'eventId'; +const indexName = 'indexName'; const entityId = 'entityId'; const scopeId = 'scopeId'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); @@ -34,7 +45,30 @@ const renderRelatedAlertsBySession = () => ); describe('', () => { - it('should render many related alerts correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related alerts correctly', () => { + (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySession(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by session'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + }); + + it('should render multiple related alerts correctly', () => { (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ loading: false, error: false, @@ -42,26 +76,20 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsBySession(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 alerts related by session'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by session'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); }); - it('should render single related alerts correctly', () => { + it('should render big number of related alerts correctly', () => { (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2000, }); const { getByTestId } = renderRelatedAlertsBySession(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 alert related by session'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by session'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); }); it('should render loading skeleton', () => { @@ -82,4 +110,49 @@ describe('', () => { const { container } = renderRelatedAlertsBySession(); expect(container).toBeEmptyDOMElement(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySession(); + getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); + + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + isPreviewMode: true, + }); + (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedAlertsBySession(); + const button = getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID); + + expect(button).toHaveAttribute('disabled'); + + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx index 4b41389137fad..dd6f96d1c6793 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx @@ -5,13 +5,27 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { i18n } from '@kbn/i18n'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; import { InsightsSummaryRow } from './insights_summary_row'; -import { CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID } from './test_ids'; +import { + CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID, + CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, +} from './test_ids'; +import { useDocumentDetailsContext } from '../../shared/context'; -const ICON = 'warning'; +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.entities.relatedAlertsBySession.buttonLabel', + { defaultMessage: 'Related alerts by session' } +); export interface RelatedAlertsBySessionProps { /** @@ -31,25 +45,62 @@ export const RelatedAlertsBySession: React.VFC = ({ entityId, scopeId, }) => { + const { eventId, indexName, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + const { loading, error, dataCount } = useFetchRelatedAlertsBySession({ entityId, scopeId, }); - const text = ( - + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, indexName, openLeftPanel, scopeId]); + + const text = useMemo( + () => ( + + ), + [dataCount] + ); + + const value = useMemo( + () => ( + + + + ), + [dataCount, isPreviewMode, onClick] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx index 3d20e6399af38..75a70fbbbb399 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx @@ -10,18 +10,29 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { CORRELATIONS_RELATED_CASES_TEST_ID, - SUMMARY_ROW_ICON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, + CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID, } from './test_ids'; import { RelatedCases } from './related_cases'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../../shared/hooks/use_fetch_related_cases'); +const mockOpenLeftPanel = jest.fn(); const eventId = 'eventId'; +const indexName = 'indexName'; +const scopeId = 'scopeId'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); @@ -33,7 +44,30 @@ const renderRelatedCases = () => ); describe('', () => { - it('should render many related cases correctly', () => { + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + }); + + it('should render single related case correctly', () => { + (useFetchRelatedCases as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedCases(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related case'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + }); + + it('should render multiple related cases correctly', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ loading: false, error: false, @@ -41,26 +75,20 @@ describe('', () => { }); const { getByTestId } = renderRelatedCases(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 related cases'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related cases'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); }); - it('should render single related case correctly', () => { + it('should render big number of related cases correctly', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ loading: false, error: false, - dataCount: 1, + dataCount: 2000, }); const { getByTestId } = renderRelatedCases(); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 related case'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related cases'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); }); it('should render loading skeleton', () => { @@ -81,4 +109,49 @@ describe('', () => { const { container } = renderRelatedCases(); expect(container).toBeEmptyDOMElement(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + (useFetchRelatedCases as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedCases(); + getByTestId(CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); + + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + indexName, + scopeId, + isPreviewMode: true, + }); + (useFetchRelatedCases as jest.Mock).mockReturnValue({ + loading: false, + error: false, + dataCount: 1, + }); + + const { getByTestId } = renderRelatedCases(); + const button = getByTestId(CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID); + + expect(button).toHaveAttribute('disabled'); + + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx index d45cc971dc046..5cc14ff2b0b17 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx @@ -5,13 +5,27 @@ * 2.0. */ -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { + CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID, + CORRELATIONS_RELATED_CASES_TEST_ID, +} from './test_ids'; import { InsightsSummaryRow } from './insights_summary_row'; -import { CORRELATIONS_RELATED_CASES_TEST_ID } from './test_ids'; +import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; -const ICON = 'warning'; +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.entities.relatedCases.buttonLabel', + { defaultMessage: 'Related cases' } +); export interface RelatedCasesProps { /** @@ -21,25 +35,62 @@ export interface RelatedCasesProps { } /** - * + * Show related cases in summary row */ export const RelatedCases: React.VFC = ({ eventId }) => { + const { indexName, scopeId, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + const { loading, error, dataCount } = useFetchRelatedCases({ eventId }); - const text = ( - + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, indexName, openLeftPanel, scopeId]); + + const text = useMemo( + () => ( + + ), + [dataCount] + ); + + const value = useMemo( + () => ( + + + + ), + [dataCount, isPreviewMode, onClick] ); return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx index b5954c251c014..18ce6d871bf21 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx @@ -9,15 +9,27 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { - SUMMARY_ROW_ICON_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, + CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID, } from './test_ids'; import { SuppressedAlerts } from './suppressed_alerts'; import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); +jest.mock('../../../../../common/detection_engine/utils', () => ({ + isSuppressionRuleInGA: jest.fn().mockReturnValue(false), +})); + +const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); const renderSuppressedAlerts = (alertSuppressionCount: number) => @@ -27,34 +39,30 @@ const renderSuppressedAlerts = (alertSuppressionCount: number) => ); -jest.mock('../../../../../common/detection_engine/utils', () => ({ - isSuppressionRuleInGA: jest.fn().mockReturnValue(false), -})); - +const mockOpenLeftPanel = jest.fn(); +const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; const isSuppressionRuleInGAMock = isSuppressionRuleInGA as jest.Mock; describe('', () => { - it('should render zero suppressed alert correctly', () => { - const { getByTestId } = renderSuppressedAlerts(0); - - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('0 suppressed alert'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect( - getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) - ).toBeInTheDocument(); + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); }); it('should render single suppressed alert correctly', () => { const { getByTestId } = renderSuppressedAlerts(1); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('1 suppressed alert'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alert'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); expect( getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) ).toBeInTheDocument(); @@ -63,14 +71,15 @@ describe('', () => { it('should render multiple suppressed alerts row correctly', () => { const { getByTestId } = renderSuppressedAlerts(2); - expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); - const value = getByTestId(VALUE_TEST_ID); - expect(value).toBeInTheDocument(); - expect(value).toHaveTextContent('2 suppressed alerts'); - expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect( - getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) - ).toBeInTheDocument(); + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alerts'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); + }); + + it('should render big number of suppressed alerts row correctly', () => { + const { getByTestId } = renderSuppressedAlerts(2000); + + expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alerts'); + expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); }); it('should not render Technical Preview badge if rule type is in GA', () => { @@ -81,4 +90,39 @@ describe('', () => { queryByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) ).not.toBeInTheDocument(); }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + const { getByTestId } = renderSuppressedAlerts(1); + getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); + + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: true, + }); + + const { getByTestId } = renderSuppressedAlerts(1); + const button = getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID); + + expect(button).toHaveAttribute('disabled'); + + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx index a8cd147a4ac14..c20945c47acbf 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx @@ -5,18 +5,25 @@ * 2.0. */ -import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiBetaBadge } from '@elastic/eui'; +import React, { useCallback, useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiBetaBadge, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { i18n } from '@kbn/i18n'; -import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { FormattedCount } from '../../../../common/components/formatted_number'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { InsightsSummaryRow } from './insights_summary_row'; import { CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, + CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID, } from './test_ids'; -import { InsightsSummaryRow } from './insights_summary_row'; +import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; const SUPPRESSED_ALERTS_COUNT_TECHNICAL_PREVIEW = i18n.translate( 'xpack.securitySolution.flyout.right.overview.insights.suppressedAlertsCountTechnicalPreview', @@ -24,6 +31,10 @@ const SUPPRESSED_ALERTS_COUNT_TECHNICAL_PREVIEW = i18n.translate( defaultMessage: 'Technical Preview', } ); +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.entities.suppressedAlerts.buttonLabel', + { defaultMessage: 'Suppressed alerts' } +); export interface SuppressedAlertsProps { /** @@ -43,21 +54,57 @@ export const SuppressedAlerts: React.VFC = ({ alertSuppressionCount, ruleType, }) => { + const { eventId, indexName, scopeId, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: CORRELATIONS_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, indexName, openLeftPanel, scopeId]); + + const text = useMemo( + () => ( + + ), + [alertSuppressionCount] + ); + + const value = useMemo( + () => ( + + + + ), + [alertSuppressionCount, isPreviewMode, onClick] + ); + return ( - } + text={text} + value={value} data-test-subj={CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID} key={`correlation-row-suppressed-alerts`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts index e649c578bf487..ce4660f12db27 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts @@ -104,7 +104,7 @@ export const INSIGHTS_CONTENT_TEST_ID = INSIGHTS_TEST_ID + CONTENT_TEST_ID; /* Summary row */ export const SUMMARY_ROW_LOADING_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Loading`; -export const SUMMARY_ROW_ICON_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Icon`; +export const SUMMARY_ROW_TEXT_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Text`; export const SUMMARY_ROW_VALUE_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Value`; /* Entities */ @@ -146,21 +146,39 @@ export const ENTITIES_HOST_OVERVIEW_VULNERABILITIES_TEST_ID = /* Threat intelligence */ export const INSIGHTS_THREAT_INTELLIGENCE_TEST_ID = `${PREFIX}InsightsThreatIntelligence` as const; +export const INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID = + `${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}ThreatMatches` as const; +export const INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID = + `${INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID}Button` as const; +export const INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID = + `${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}EnrichedWithThreatIntelligence` as const; +export const INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID = + `${INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID}Button` as const; /* Correlations */ export const CORRELATIONS_TEST_ID = `${PREFIX}Correlations` as const; export const CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID = `${CORRELATIONS_TEST_ID}SuppressedAlerts` as const; +export const CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID = + `${CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID}Button` as const; export const CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID = `${CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID}TechnicalPreview` as const; export const CORRELATIONS_RELATED_CASES_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedCases` as const; +export const CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID = + `${CORRELATIONS_RELATED_CASES_TEST_ID}Button` as const; export const CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedAlertsBySession` as const; +export const CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID = + `${CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID}Button` as const; export const CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedAlertsBySameSourceEvent` as const; +export const CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID = + `${CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID}Button` as const; export const CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedAlertsByAncestry` as const; +export const CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID = + `${CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID}Button` as const; /* Insights Prevalence */ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx index af92283b781b5..2a465607a386d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx @@ -6,18 +6,25 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; -import { useExpandableFlyoutApi, type ExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { DocumentDetailsContext } from '../../shared/context'; -import { TestProviders } from '../../../../common/mock'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useDocumentDetailsContext } from '../../shared/context'; import { ThreatIntelligenceOverview } from './threat_intelligence_overview'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInsightsTab } from '../../left'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; -import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; import { - EXPANDABLE_PANEL_CONTENT_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID, + SUMMARY_ROW_TEXT_TEST_ID, + SUMMARY_ROW_VALUE_TEST_ID, +} from './test_ids'; +import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, @@ -25,6 +32,8 @@ import { EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, } from '@kbn/security-solution-common'; +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); jest.mock('../hooks/use_fetch_threat_intelligence'); const TOGGLE_ICON_TEST_ID = EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID( @@ -39,32 +48,45 @@ const TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID( const TITLE_TEXT_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID( INSIGHTS_THREAT_INTELLIGENCE_TEST_ID ); -const CONTENT_TEST_ID = EXPANDABLE_PANEL_CONTENT_TEST_ID(INSIGHTS_THREAT_INTELLIGENCE_TEST_ID); const LOADING_TEST_ID = EXPANDABLE_PANEL_LOADING_TEST_ID(INSIGHTS_THREAT_INTELLIGENCE_TEST_ID); +const THREAT_MATCHES_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID +); +const THREAT_MATCHES_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID +); +const ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID +); +const ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID +); -const panelContextValue = { - eventId: 'event id', - indexName: 'indexName', - dataFormattedForFieldBrowser: [], -} as unknown as DocumentDetailsContext; - -jest.mock('@kbn/expandable-flyout'); +const mockOpenLeftPanel = jest.fn(); +const eventId = 'eventId'; +const indexName = 'indexName'; +const scopeId = 'scopeId'; +const dataFormattedForFieldBrowser = ['scopeId']; -const renderThreatIntelligenceOverview = (contextValue: DocumentDetailsContext) => ( - - +const renderThreatIntelligenceOverview = () => + render( + - - -); - -const flyoutContextValue = { - openLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutApi; + + ); describe('', () => { - beforeAll(() => { - jest.mocked(useExpandableFlyoutApi).mockReturnValue(flyoutContextValue); + beforeEach(() => { + jest.clearAllMocks(); + + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + dataFormattedForFieldBrowser, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); }); it('should render wrapper component', () => { @@ -72,9 +94,7 @@ describe('', () => { loading: false, }); - const { getByTestId, queryByTestId } = render( - renderThreatIntelligenceOverview(panelContextValue) - ); + const { getByTestId, queryByTestId } = renderThreatIntelligenceOverview(); expect(queryByTestId(TOGGLE_ICON_TEST_ID)).not.toBeInTheDocument(); expect(getByTestId(TITLE_ICON_TEST_ID)).toBeInTheDocument(); @@ -82,14 +102,19 @@ describe('', () => { expect(queryByTestId(TITLE_TEXT_TEST_ID)).not.toBeInTheDocument(); }); - it('should not render link if isPrenviewMode is true', () => { + it('should not render link if isPreviewMode is true', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + dataFormattedForFieldBrowser, + isPreviewMode: true, + }); (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, }); - const { getByTestId, queryByTestId } = render( - renderThreatIntelligenceOverview({ ...panelContextValue, isPreviewMode: true }) - ); + const { getByTestId, queryByTestId } = renderThreatIntelligenceOverview(); expect(queryByTestId(TOGGLE_ICON_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(TITLE_ICON_TEST_ID)).not.toBeInTheDocument(); @@ -104,13 +129,15 @@ describe('', () => { threatEnrichmentsCount: 1, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Threat intelligence'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('1 threat match detected'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '1 field enriched with threat intelligence' + expect(getByTestId(THREAT_MATCHES_TEXT_TEST_ID)).toHaveTextContent('Threat match detected'); + expect(getByTestId(THREAT_MATCHES_VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID)).toHaveTextContent( + 'Field enriched with threat intelligence' ); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE_TEST_ID)).toHaveTextContent('1'); }); it('should render 2 matches detected and 2 fields enriched', () => { @@ -120,73 +147,120 @@ describe('', () => { threatEnrichmentsCount: 2, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Threat intelligence'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('2 threat matches detected'); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '2 fields enriched with threat intelligence' + expect(getByTestId(THREAT_MATCHES_TEXT_TEST_ID)).toHaveTextContent('Threat matches detected'); + expect(getByTestId(THREAT_MATCHES_VALUE_TEST_ID)).toHaveTextContent('2'); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID)).toHaveTextContent( + 'Fields enriched with threat intelligence' ); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE_TEST_ID)).toHaveTextContent('2'); }); - it('should render 0 fields enriched', () => { + it('should render loading', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ - loading: false, - threatMatchesCount: 1, - threatEnrichmentsCount: 0, + loading: true, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '0 fields enriched with threat intelligence' - ); + expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); - it('should render 0 matches detected', () => { + it('should navigate to left section Insights tab when clicking on button', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, - threatMatchesCount: 0, - threatEnrichmentsCount: 2, + threatMatchesCount: 1, + threatEnrichmentsCount: 1, }); + const { getByTestId } = renderThreatIntelligenceOverview(); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); - - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('0 threat matches detected'); + getByTestId(TITLE_LINK_TEST_ID).click(); + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: THREAT_INTELLIGENCE_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); }); - it('should render loading', () => { + it('should open the expanded section to the correct tab when the number is clicked', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ - loading: true, + loading: false, + threatMatchesCount: 1, + threatEnrichmentsCount: 1, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = renderThreatIntelligenceOverview(); + getByTestId(INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID).click(); - expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: THREAT_INTELLIGENCE_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + + getByTestId( + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID + ).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: THREAT_INTELLIGENCE_TAB_ID, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); }); - it('should navigate to left section Insights tab when clicking on button', () => { + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + dataFormattedForFieldBrowser, + isPreviewMode: true, + }); (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, threatMatchesCount: 1, threatEnrichmentsCount: 1, }); - const { getByTestId } = render( - - - - - + + const { getByTestId } = renderThreatIntelligenceOverview(); + const threatMatchesButton = getByTestId( + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID + ); + const enrichedWithThreatIntelligenceButton = getByTestId( + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID ); - getByTestId(TITLE_LINK_TEST_ID).click(); - expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ - id: DocumentDetailsLeftPanelKey, - path: { tab: LeftPanelInsightsTab, subTab: THREAT_INTELLIGENCE_TAB_ID }, - params: { - id: panelContextValue.eventId, - indexName: panelContextValue.indexName, - }, - }); + expect(threatMatchesButton).toHaveAttribute('disabled'); + expect(enrichedWithThreatIntelligenceButton).toHaveAttribute('disabled'); + + threatMatchesButton.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + + enrichedWithThreatIntelligenceButton.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx index 10b23ecfc2340..1ab487a8967a3 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx @@ -7,18 +7,46 @@ import type { FC } from 'react'; import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '@kbn/security-solution-common'; +import { i18n } from '@kbn/i18n'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { InsightsSummaryRow } from './insights_summary_row'; import { useDocumentDetailsContext } from '../../shared/context'; -import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; +import { + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID, + INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID, +} from './test_ids'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInsightsTab } from '../../left'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; +const TITLE = ( + +); +const TOOLTIP = ( + +); +const THREAT_MATCHES_BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.threatIntelligence.threatMatches.buttonLabel', + { defaultMessage: 'Threat matches' } +); +const ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.threatIntelligence.enrichedWithThreatIntelligence.buttonLabel', + { defaultMessage: 'Enriched with threat intelligence' } +); + /** * Threat intelligence section under Insights section, overview tab. * The component fetches the necessary data, then pass it down to the InsightsSubSection component for loading and error state, @@ -53,26 +81,72 @@ export const ThreatIntelligenceOverview: FC = () => { !isPreviewMode ? { callback: goToThreatIntelligenceTab, - tooltip: ( - - ), + tooltip: TOOLTIP, } : undefined, [isPreviewMode, goToThreatIntelligenceTab] ); + const threatMatchCountText = useMemo( + () => ( + + ), + [threatMatchesCount] + ); + + const threatMatchCountValue = useMemo( + () => ( + + {threatMatchesCount} + + ), + [goToThreatIntelligenceTab, isPreviewMode, threatMatchesCount] + ); + + const threatEnrichmentsCountText = useMemo( + () => ( + + ), + [threatEnrichmentsCount] + ); + + const threatEnrichmentsCountValue = useMemo( + () => ( + + {threatEnrichmentsCount} + + ), + [goToThreatIntelligenceTab, isPreviewMode, threatEnrichmentsCount] + ); + return ( - ), + title: TITLE, link, iconType: !isPreviewMode ? 'arrowStart' : undefined, }} @@ -81,32 +155,18 @@ export const ThreatIntelligenceOverview: FC = () => { > - } - data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} + text={threatMatchCountText} + value={threatMatchCountValue} + data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID} /> - } - data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} + text={threatEnrichmentsCountText} + value={threatEnrichmentsCountValue} + data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID} /> diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index b408251126660..7f8596a3dcddf 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -38763,7 +38763,6 @@ "xpack.securitySolution.flyout.right.insights.entities.noDataDescription": "Les informations de l'hôte et de l'utilisateur ne sont pas disponibles pour cette alerte.", "xpack.securitySolution.flyout.right.insights.entities.suppressedAlertTechnicalPreviewTooltip": "Cette fonctionnalité est en version d'évaluation technique et pourra être modifiée ou retirée complètement dans une future version. Elastic s'efforcera de corriger tout problème, mais les fonctionnalités des versions d'évaluation technique ne sont pas soumises aux SLA de support des fonctionnalités officielles en disponibilité générale.", "xpack.securitySolution.flyout.right.insights.entities.userLoadingAriaLabel": "aperçu de l'utilisateur", - "xpack.securitySolution.flyout.right.insights.insightSummaryButtonIconAriaLabel": "Icône de ligne de résumé d'informations", "xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel": "Chargement des informations pour {value}", "xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription": "Aucune donnée de prévalence disponible.", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle": "Prévalence", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9831cfa07e6d3..4ff7491ed6b4c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -38506,7 +38506,6 @@ "xpack.securitySolution.flyout.right.insights.entities.noDataDescription": "このアラートでは、ホストとユーザーの情報は利用できません。", "xpack.securitySolution.flyout.right.insights.entities.suppressedAlertTechnicalPreviewTooltip": "この機能はテクニカルプレビュー中であり、将来のリリースでは変更されたり完全に削除されたりする場合があります。Elasticはすべての問題の修正に努めますが、テクニカルプレビュー中の機能には正式なGA機能のサポートSLAが適用されません。", "xpack.securitySolution.flyout.right.insights.entities.userLoadingAriaLabel": "ユーザー概要", - "xpack.securitySolution.flyout.right.insights.insightSummaryButtonIconAriaLabel": "インサイト概要行アイコン", "xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel": "{value}のインサイトを読み込み中", "xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription": "発生率データはありません。", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle": "発生率", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a7ae5366d9762..5fbaf48cef1cf 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -38551,7 +38551,6 @@ "xpack.securitySolution.flyout.right.insights.entities.noDataDescription": "主机和用户信息对此告警不可用。", "xpack.securitySolution.flyout.right.insights.entities.suppressedAlertTechnicalPreviewTooltip": "此功能处于技术预览状态,在未来版本中可能会更改或完全移除。Elastic 将努力修复任何问题,但处于技术预览状态的功能不受正式 GA 功能支持 SLA 的约束。", "xpack.securitySolution.flyout.right.insights.entities.userLoadingAriaLabel": "用户概览", - "xpack.securitySolution.flyout.right.insights.insightSummaryButtonIconAriaLabel": "洞见摘要行图标", "xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel": "正在加载 {value} 的洞见", "xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription": "无普及性数据可用。", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle": "普及率", diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts index 6b451801a58c5..87dd30b293f0d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -27,7 +27,6 @@ import { DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_SECTION_HEADER, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_MITRE_ATTACK_DETAILS, @@ -43,6 +42,8 @@ import { DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_HOST_OVERVIEW_LINK, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_USER_OVERVIEW_LINK, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_SESSION_PREVIEW_NO_DATA, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_VALUE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE, } from '../../../../screens/expandable_flyout/alert_details_right_panel_overview_tab'; import { navigateToCorrelationsDetails, @@ -348,14 +349,12 @@ describe( 'Threat intelligence' ); - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) - .eq(0) - .should('have.text', '0 threat matches detected'); // TODO work on getting proper IoC data to get proper data here - - // field with threat enrichement - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) - .eq(1) - .should('have.text', '0 fields enriched with threat intelligence'); // TODO work on getting proper IoC data to get proper data here + cy.get( + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_VALUE + ).should('have.text', '0'); // TODO work on getting proper IoC data to get proper data here + cy.get( + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE + ).should('have.text', '0'); // TODO work on getting proper IoC data to get proper data here cy.log('should navigate to left panel Threat Intelligence tab'); @@ -385,19 +384,19 @@ describe( ); // cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_SUPPRESSED_ALERTS) // .should('be.visible') - // .and('have.text', '1 suppressed alert'); // TODO populate rule with alert suppression + // .and('have.text', '1'); // TODO populate rule with alert suppression cy.get( DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_ANCESTRY - ).should('have.text', '1 alert related by ancestry'); + ).should('have.text', '1'); cy.get( DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_SAME_SOURCE_EVENT - ).should('have.text', '1 alert related by source event'); + ).should('have.text', '1'); cy.get( DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_SESSION - ).should('have.text', '1 alert related by session'); + ).should('have.text', '1'); cy.get( DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_CASES - ).should('have.text', '1 related case'); + ).should('have.text', '1'); cy.log('should navigate to left panel Correlations tab'); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts index 676dec4aaeab1..dc04e6ca3041c 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts @@ -77,8 +77,12 @@ export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_USER_OVERVIEW_LINK = getDataTe export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER = getDataTestSubjectSelector('securitySolutionFlyoutInsightsThreatIntelligenceTitleLink'); -export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES = - getDataTestSubjectSelector('securitySolutionFlyoutInsightsThreatIntelligenceValue'); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_VALUE = + getDataTestSubjectSelector('securitySolutionFlyoutInsightsThreatIntelligenceThreatMatchesValue'); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE = + getDataTestSubjectSelector( + 'securitySolutionFlyoutInsightsThreatIntelligenceEnrichedWithThreatIntelligenceValue' + ); /* Insights Correlations */ From 8e0fca8f0bb1ec35472aaf80974b19dadbaf8cbb Mon Sep 17 00:00:00 2001 From: PhilippeOberti Date: Mon, 28 Oct 2024 18:23:25 -0500 Subject: [PATCH 2/3] combining logic within insights_summary_row.tsx --- .../right/components/insights_summary_row.tsx | 72 ++++++++++++++++--- .../right/components/prevalence_overview.tsx | 10 ++- .../components/related_alerts_by_ancestry.tsx | 58 ++------------- .../related_alerts_by_same_source_event.tsx | 56 ++------------- .../components/related_alerts_by_session.tsx | 56 ++------------- .../right/components/related_cases.tsx | 56 ++------------- .../right/components/suppressed_alerts.tsx | 51 ++----------- .../threat_intelligence_overview.tsx | 53 ++------------ 8 files changed, 94 insertions(+), 318 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx index 3f51f682b9d18..a889ebca16e90 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx @@ -6,16 +6,27 @@ */ import type { ReactElement, VFC } from 'react'; +import { useCallback } from 'react'; +import { useMemo } from 'react'; import React from 'react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import type { EuiBadgeProps } from '@elastic/eui'; +import { EuiButtonEmpty } from '@elastic/eui'; import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; +import { FormattedCount } from '../../../../common/components/formatted_number'; const LOADING = i18n.translate( 'xpack.securitySolution.flyout.right.insights.insightSummaryLoadingAriaLabel', { defaultMessage: 'Loading' } ); +const BUTTON = i18n.translate( + 'xpack.securitySolution.flyout.right.insights.insightSummaryButtonAriaLabel', + { defaultMessage: 'Click to see more details' } +); export interface InsightsSummaryRowProps { /** @@ -33,11 +44,11 @@ export interface InsightsSummaryRowProps { /** * Number of results/entries found */ - value: ReactElement; + value: number | ReactElement; /** - * Decides the color of the badge + * Optional parameter used to know which subtab to navigate to when the user clicks on the button */ - color?: EuiBadgeProps['color']; + expandedSubTab?: string; /** * Prefix data-test-subj because this component will be used in multiple places */ @@ -45,7 +56,9 @@ export interface InsightsSummaryRowProps { } /** - * Panel showing summary information as an icon, a count and text as well as a severity colored dot. + * Panel showing summary information. + * The default display is a text on the left and a count on the right, displayed with a clickable EuiBadge. + * The left and right section can accept a ReactElement to allow for more complex display. * Should be used for Entities, Threat intelligence, Prevalence, Correlations and Results components under the Insights section. */ export const InsightsSummaryRow: VFC = ({ @@ -53,10 +66,53 @@ export const InsightsSummaryRow: VFC = ({ error = false, value, text, - color = 'hollow', + expandedSubTab, 'data-test-subj': dataTestSubj, }) => { - const loadingDataTestSubj = `${dataTestSubj}Loading`; + const { eventId, indexName, scopeId, isPreviewMode } = useDocumentDetailsContext(); + const { openLeftPanel } = useExpandableFlyoutApi(); + + const onClick = useCallback(() => { + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: expandedSubTab, + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }, [eventId, expandedSubTab, indexName, openLeftPanel, scopeId]); + + const buttonDataTestSubj = useMemo(() => `${dataTestSubj}Button`, [dataTestSubj]); + const button = useMemo( + () => ( + <> + {typeof value === 'number' ? ( + + + + + + ) : ( + value + )} + + ), + [buttonDataTestSubj, isPreviewMode, onClick, value] + ); + + const loadingDataTestSubj = useMemo(() => `${dataTestSubj}Loading`, [dataTestSubj]); if (loading) { return ( = ({ {text} - {value} + {button} ); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx index d64007fc6ded6..adb660f67ce72 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx @@ -116,14 +116,12 @@ export const PrevalenceOverview: FC = () => { uncommonData.map((d) => ( + <> + {d.field} + {','} {d.values.toString()} + } value={{UNCOMMON}} - color={'warning'} data-test-subj={`${PREVALENCE_TEST_ID}${d.field}`} key={`${PREVALENCE_TEST_ID}${d.field}`} /> diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx index fff5459a566f0..4b225d5595883 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.tsx @@ -5,27 +5,12 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedCount } from '../../../../common/components/formatted_number'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; -import { useDocumentDetailsContext } from '../../shared/context'; +import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; import { InsightsSummaryRow } from './insights_summary_row'; -import { - CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID, - CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, -} from './test_ids'; -import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; - -const BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.entities.relatedAlertsByAncestry.buttonLabel', - { defaultMessage: 'Related alerts by ancestry' } -); +import { CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID } from './test_ids'; export interface RelatedAlertsByAncestryProps { /** @@ -50,30 +35,12 @@ export const RelatedAlertsByAncestry: React.VFC = indices, scopeId, }) => { - const { eventId, indexName, isPreviewMode } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - const { loading, error, dataCount } = useFetchRelatedAlertsByAncestry({ documentId, indices, scopeId, }); - const onClick = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { - tab: LeftPanelInsightsTab, - subTab: CORRELATIONS_TAB_ID, - }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, indexName, openLeftPanel, scopeId]); - const text = useMemo( () => ( = [dataCount] ); - const value = useMemo( - () => ( - - - - ), - [dataCount, isPreviewMode, onClick] - ); - return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx index e91d9c450bde9..dade35ca75546 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx @@ -5,28 +5,13 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedCount } from '../../../../common/components/formatted_number'; -import { useDocumentDetailsContext } from '../../shared/context'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; -import { - CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID, - CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, -} from './test_ids'; +import { CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID } from './test_ids'; import { InsightsSummaryRow } from './insights_summary_row'; import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; -const BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.entities.relatedAlertsBySameSourceEvent.buttonLabel', - { defaultMessage: 'Related alerts by ancestry' } -); - export interface RelatedAlertsBySameSourceEventProps { /** * Value of the kibana.alert.original_event.id field @@ -45,29 +30,11 @@ export const RelatedAlertsBySameSourceEvent: React.VFC { - const { eventId, indexName, isPreviewMode } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - const { loading, dataCount } = useFetchRelatedAlertsBySameSourceEvent({ originalEventId, scopeId, }); - const onClick = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { - tab: LeftPanelInsightsTab, - subTab: CORRELATIONS_TAB_ID, - }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, indexName, openLeftPanel, scopeId]); - const text = useMemo( () => ( ( - - - - ), - [dataCount, isPreviewMode, onClick] - ); - return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx index dd6f96d1c6793..9037ebca232a0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.tsx @@ -5,27 +5,12 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { i18n } from '@kbn/i18n'; -import { FormattedCount } from '../../../../common/components/formatted_number'; -import { LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; import { InsightsSummaryRow } from './insights_summary_row'; -import { - CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID, - CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, -} from './test_ids'; -import { useDocumentDetailsContext } from '../../shared/context'; - -const BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.entities.relatedAlertsBySession.buttonLabel', - { defaultMessage: 'Related alerts by session' } -); +import { CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID } from './test_ids'; export interface RelatedAlertsBySessionProps { /** @@ -45,29 +30,11 @@ export const RelatedAlertsBySession: React.VFC = ({ entityId, scopeId, }) => { - const { eventId, indexName, isPreviewMode } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - const { loading, error, dataCount } = useFetchRelatedAlertsBySession({ entityId, scopeId, }); - const onClick = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { - tab: LeftPanelInsightsTab, - subTab: CORRELATIONS_TAB_ID, - }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, indexName, openLeftPanel, scopeId]); - const text = useMemo( () => ( = ({ [dataCount] ); - const value = useMemo( - () => ( - - - - ), - [dataCount, isPreviewMode, onClick] - ); - return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx index 5cc14ff2b0b17..8a01b21799d86 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.tsx @@ -5,28 +5,13 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedCount } from '../../../../common/components/formatted_number'; -import { useDocumentDetailsContext } from '../../shared/context'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; -import { - CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID, - CORRELATIONS_RELATED_CASES_TEST_ID, -} from './test_ids'; +import { CORRELATIONS_RELATED_CASES_TEST_ID } from './test_ids'; import { InsightsSummaryRow } from './insights_summary_row'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; -const BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.entities.relatedCases.buttonLabel', - { defaultMessage: 'Related cases' } -); - export interface RelatedCasesProps { /** * Id of the document @@ -38,26 +23,8 @@ export interface RelatedCasesProps { * Show related cases in summary row */ export const RelatedCases: React.VFC = ({ eventId }) => { - const { indexName, scopeId, isPreviewMode } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - const { loading, error, dataCount } = useFetchRelatedCases({ eventId }); - const onClick = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { - tab: LeftPanelInsightsTab, - subTab: CORRELATIONS_TAB_ID, - }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, indexName, openLeftPanel, scopeId]); - const text = useMemo( () => ( = ({ eventId }) => { [dataCount] ); - const value = useMemo( - () => ( - - - - ), - [dataCount, isPreviewMode, onClick] - ); - return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx index c20945c47acbf..c7eb50aeb383a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.tsx @@ -5,23 +5,17 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiBetaBadge, EuiButtonEmpty } from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiBetaBadge } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { i18n } from '@kbn/i18n'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { FormattedCount } from '../../../../common/components/formatted_number'; -import { useDocumentDetailsContext } from '../../shared/context'; -import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; -import { LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { InsightsSummaryRow } from './insights_summary_row'; import { CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, - CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID, } from './test_ids'; import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; @@ -31,10 +25,6 @@ const SUPPRESSED_ALERTS_COUNT_TECHNICAL_PREVIEW = i18n.translate( defaultMessage: 'Technical Preview', } ); -const BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.entities.suppressedAlerts.buttonLabel', - { defaultMessage: 'Suppressed alerts' } -); export interface SuppressedAlertsProps { /** @@ -54,24 +44,6 @@ export const SuppressedAlerts: React.VFC = ({ alertSuppressionCount, ruleType, }) => { - const { eventId, indexName, scopeId, isPreviewMode } = useDocumentDetailsContext(); - const { openLeftPanel } = useExpandableFlyoutApi(); - - const onClick = useCallback(() => { - openLeftPanel({ - id: DocumentDetailsLeftPanelKey, - path: { - tab: LeftPanelInsightsTab, - subTab: CORRELATIONS_TAB_ID, - }, - params: { - id: eventId, - indexName, - scopeId, - }, - }); - }, [eventId, indexName, openLeftPanel, scopeId]); - const text = useMemo( () => ( = ({ [alertSuppressionCount] ); - const value = useMemo( - () => ( - - - - ), - [alertSuppressionCount, isPreviewMode, onClick] - ); - return ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx index 1ab487a8967a3..0a737a973ea2d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx @@ -7,19 +7,16 @@ import type { FC } from 'react'; import React, { useCallback, useMemo } from 'react'; -import { EuiButtonEmpty, EuiFlexGroup } from '@elastic/eui'; +import { EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '@kbn/security-solution-common'; -import { i18n } from '@kbn/i18n'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { InsightsSummaryRow } from './insights_summary_row'; import { useDocumentDetailsContext } from '../../shared/context'; import { - INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_TEST_ID, - INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID, } from './test_ids'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; @@ -38,14 +35,6 @@ const TOOLTIP = ( defaultMessage="Show all threat intelligence" /> ); -const THREAT_MATCHES_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.threatIntelligence.threatMatches.buttonLabel', - { defaultMessage: 'Threat matches' } -); -const ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.right.insights.threatIntelligence.enrichedWithThreatIntelligence.buttonLabel', - { defaultMessage: 'Enriched with threat intelligence' } -); /** * Threat intelligence section under Insights section, overview tab. @@ -98,22 +87,6 @@ export const ThreatIntelligenceOverview: FC = () => { [threatMatchesCount] ); - const threatMatchCountValue = useMemo( - () => ( - - {threatMatchesCount} - - ), - [goToThreatIntelligenceTab, isPreviewMode, threatMatchesCount] - ); - const threatEnrichmentsCountText = useMemo( () => ( { [threatEnrichmentsCount] ); - const threatEnrichmentsCountValue = useMemo( - () => ( - - {threatEnrichmentsCount} - - ), - [goToThreatIntelligenceTab, isPreviewMode, threatEnrichmentsCount] - ); - return ( { > From 2b34b9b1359e4ae745b80be42b0177922341b85a Mon Sep 17 00:00:00 2001 From: PhilippeOberti Date: Tue, 29 Oct 2024 17:56:47 -0500 Subject: [PATCH 3/3] fix Jest and Cypress tests --- .../components/correlations_overview.test.tsx | 14 +- .../components/insights_summary_row.test.tsx | 128 ++++++++++++++++-- .../right/components/insights_summary_row.tsx | 33 ++--- .../related_alerts_by_ancestry.test.tsx | 45 +----- ...lated_alerts_by_same_source_event.test.tsx | 47 +------ .../related_alerts_by_session.test.tsx | 45 +----- .../right/components/related_cases.test.tsx | 45 +----- .../components/suppressed_alerts.test.tsx | 35 +---- .../right/components/test_ids.ts | 15 +- .../threat_intelligence_overview.test.tsx | 54 ++------ .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../alert_details_right_panel_overview_tab.ts | 14 +- 14 files changed, 182 insertions(+), 296 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx index c187631f7abb2..71292b73a68e0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx @@ -22,8 +22,8 @@ import { CORRELATIONS_RELATED_CASES_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, SUMMARY_ROW_TEXT_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, } from './test_ids'; import { useShowRelatedAlertsByAncestry } from '../../shared/hooks/use_show_related_alerts_by_ancestry'; import { useShowRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_show_related_alerts_by_same_source_event'; @@ -59,32 +59,32 @@ const TITLE_LINK_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(CORRELATIO const TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(CORRELATIONS_TEST_ID); const TITLE_TEXT_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(CORRELATIONS_TEST_ID); -const SUPPRESSED_ALERTS_TEXT_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const SUPPRESSED_ALERTS_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID ); -const SUPPRESSED_ALERTS_VALUE_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( +const SUPPRESSED_ALERTS_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID ); const RELATED_ALERTS_BY_ANCESTRY_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); -const RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_ANCESTRY_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); -const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_SAME_SOURCE_EVENT_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); const RELATED_ALERTS_BY_SESSION_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID ); -const RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const RELATED_ALERTS_BY_SESSION_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID ); const RELATED_CASES_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); -const RELATED_CASES_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const RELATED_CASES_VALUE_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const panelContextValue = { eventId: 'event id', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx index ac3a6cb0f958d..2a721e317781e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.test.tsx @@ -9,30 +9,39 @@ import React from 'react'; import { render } from '@testing-library/react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { InsightsSummaryRow } from './insights_summary_row'; +import { useDocumentDetailsContext } from '../../shared/context'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; +import { LeftPanelInsightsTab } from '../../left'; + +jest.mock('@kbn/expandable-flyout'); +jest.mock('../../shared/context'); + +const mockOpenLeftPanel = jest.fn(); +const scopeId = 'scopeId'; +const eventId = 'eventId'; +const indexName = 'indexName'; const testId = 'test'; const textTestId = `${testId}Text`; +const buttonTestId = `${testId}Button`; const valueTestId = `${testId}Value`; const loadingTestId = `${testId}Loading`; describe('', () => { - it('should render by default', () => { - const { getByTestId } = render( - - {'value for this'}} - color={'rgb(189,39,30)'} - data-test-subj={testId} - /> - - ); + beforeEach(() => { + jest.clearAllMocks(); - expect(getByTestId(textTestId)).toHaveTextContent('this is a test for red'); - expect(getByTestId(valueTestId)).toHaveTextContent('value for this'); + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: false, + }); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); }); - it('should render loading skeletton if loading is true', () => { + it('should render loading skeleton if loading is true', () => { const { getByTestId } = render( ', () => { expect(container).toBeEmptyDOMElement(); }); + + it('should render the value component', () => { + const { getByTestId, queryByTestId } = render( + + {'value for this'}} + data-test-subj={testId} + /> + + ); + + expect(getByTestId(textTestId)).toHaveTextContent('this is a test for red'); + expect(getByTestId(valueTestId)).toHaveTextContent('value for this'); + expect(queryByTestId(buttonTestId)).not.toBeInTheDocument(); + }); + + it('should render the value as EuiBadge and EuiButtonEmpty', () => { + const { getByTestId, queryByTestId } = render( + + + + ); + + expect(getByTestId(textTestId)).toHaveTextContent('this is a test for red'); + expect(getByTestId(buttonTestId)).toHaveTextContent('2'); + expect(queryByTestId(valueTestId)).not.toBeInTheDocument(); + }); + + it('should render big numbers formatted correctly', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId(buttonTestId)).toHaveTextContent('2k'); + }); + + it('should open the expanded section to the correct tab when the number is clicked', () => { + const { getByTestId } = render( + + + + ); + getByTestId(buttonTestId).click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { + tab: LeftPanelInsightsTab, + subTab: 'subTab', + }, + params: { + id: eventId, + indexName, + scopeId, + }, + }); + }); + + it('should disabled the click when in preview mode', () => { + (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, + indexName, + scopeId, + isPreviewMode: true, + }); + + const { getByTestId } = render( + + + + ); + const button = getByTestId(buttonTestId); + + expect(button).toHaveAttribute('disabled'); + + button.click(); + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx index a889ebca16e90..56a19d2eca965 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_summary_row.tsx @@ -6,13 +6,10 @@ */ import type { ReactElement, VFC } from 'react'; -import { useCallback } from 'react'; -import { useMemo } from 'react'; -import React from 'react'; +import React, { useMemo, useCallback } from 'react'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui'; +import { EuiBadge, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { useDocumentDetailsContext } from '../../shared/context'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; @@ -87,9 +84,14 @@ export const InsightsSummaryRow: VFC = ({ }); }, [eventId, expandedSubTab, indexName, openLeftPanel, scopeId]); - const buttonDataTestSubj = useMemo(() => `${dataTestSubj}Button`, [dataTestSubj]); - const button = useMemo( - () => ( + const textDataTestSubj = useMemo(() => `${dataTestSubj}Text`, [dataTestSubj]); + const loadingDataTestSubj = useMemo(() => `${dataTestSubj}Loading`, [dataTestSubj]); + + const button = useMemo(() => { + const buttonDataTestSubj = `${dataTestSubj}Button`; + const valueDataTestSubj = `${dataTestSubj}Value`; + + return ( <> {typeof value === 'number' ? ( @@ -105,14 +107,12 @@ export const InsightsSummaryRow: VFC = ({ ) : ( - value +
{value}
)} - ), - [buttonDataTestSubj, isPreviewMode, onClick, value] - ); + ); + }, [dataTestSubj, isPreviewMode, onClick, value]); - const loadingDataTestSubj = useMemo(() => `${dataTestSubj}Loading`, [dataTestSubj]); if (loading) { return ( = ({ return null; } - const textDataTestSubj = `${dataTestSubj}Text`; - const valueDataTestSubj = `${dataTestSubj}Value`; - return ( = ({ > {text} - - {button} - + {button} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx index 57b8ab2ad27db..38efe27b16ea9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_ancestry.test.tsx @@ -10,10 +10,9 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_TEXT_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, - CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { RelatedAlertsByAncestry } from './related_alerts_by_ancestry'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; @@ -35,7 +34,7 @@ const eventId = 'eventId'; const indexName = 'indexName'; const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); @@ -54,6 +53,7 @@ describe('', () => { (useDocumentDetailsContext as jest.Mock).mockReturnValue({ eventId, indexName, + scopeId, isPreviewMode: false, }); (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); @@ -68,7 +68,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsByAncestry(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); it('should render multiple related alerts correctly', () => { @@ -80,19 +80,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsByAncestry(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); - }); - - it('should render big number of related alerts correctly', () => { - (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 2000, - }); - - const { getByTestId } = renderRelatedAlertsByAncestry(); - expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by ancestry'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -122,7 +110,7 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsByAncestry(); - getByTestId(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID).click(); + getByTestId(BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -137,25 +125,4 @@ describe('', () => { }, }); }); - - it('should disabled the click when in preview mode', () => { - (useDocumentDetailsContext as jest.Mock).mockReturnValue({ - eventId, - indexName, - isPreviewMode: true, - }); - (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 1, - }); - - const { getByTestId } = renderRelatedAlertsByAncestry(); - const button = getByTestId(CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID); - - expect(button).toHaveAttribute('disabled'); - - button.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx index 194809e040cad..80e7c99a60917 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx @@ -10,10 +10,9 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_TEXT_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, - CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; import { RelatedAlertsBySameSourceEvent } from './related_alerts_by_same_source_event'; @@ -36,7 +35,7 @@ const indexName = 'indexName'; const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( @@ -57,6 +56,7 @@ describe('', () => { (useDocumentDetailsContext as jest.Mock).mockReturnValue({ eventId, indexName, + scopeId, isPreviewMode: false, }); (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); @@ -71,7 +71,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); it('should render multiple related alerts correctly', () => { @@ -83,19 +83,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); - }); - - it('should render big number of related alerts correctly', () => { - (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 2000, - }); - - const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -116,7 +104,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by source event'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('0'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('0'); }); it('should open the expanded section to the correct tab when the number is clicked', () => { @@ -127,7 +115,7 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID).click(); + getByTestId(BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -142,25 +130,4 @@ describe('', () => { }, }); }); - - it('should disabled the click when in preview mode', () => { - (useDocumentDetailsContext as jest.Mock).mockReturnValue({ - eventId, - indexName, - isPreviewMode: true, - }); - (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ - loading: false, - error: true, - dataCount: 1, - }); - - const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); - const button = getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID); - - expect(button).toHaveAttribute('disabled'); - - button.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx index 7ab039f92e0fb..4aeeef1feb8b1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_session.test.tsx @@ -10,10 +10,9 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_TEXT_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, - CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; @@ -34,7 +33,7 @@ const entityId = 'entityId'; const scopeId = 'scopeId'; const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID); const renderRelatedAlertsBySession = () => @@ -51,6 +50,7 @@ describe('', () => { (useDocumentDetailsContext as jest.Mock).mockReturnValue({ eventId, indexName, + scopeId, isPreviewMode: false, }); (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); @@ -65,7 +65,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsBySession(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alert related by session'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); it('should render multiple related alerts correctly', () => { @@ -77,19 +77,7 @@ describe('', () => { const { getByTestId } = renderRelatedAlertsBySession(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by session'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); - }); - - it('should render big number of related alerts correctly', () => { - (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 2000, - }); - - const { getByTestId } = renderRelatedAlertsBySession(); - expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Alerts related by session'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -119,7 +107,7 @@ describe('', () => { }); const { getByTestId } = renderRelatedAlertsBySession(); - getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID).click(); + getByTestId(BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -134,25 +122,4 @@ describe('', () => { }, }); }); - - it('should disabled the click when in preview mode', () => { - (useDocumentDetailsContext as jest.Mock).mockReturnValue({ - eventId, - indexName, - isPreviewMode: true, - }); - (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 1, - }); - - const { getByTestId } = renderRelatedAlertsBySession(); - const button = getByTestId(CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID); - - expect(button).toHaveAttribute('disabled'); - - button.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx index 75a70fbbbb399..e55d0e109d1d7 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_cases.test.tsx @@ -12,8 +12,7 @@ import { CORRELATIONS_RELATED_CASES_TEST_ID, SUMMARY_ROW_TEXT_TEST_ID, SUMMARY_ROW_LOADING_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, - CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { RelatedCases } from './related_cases'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; @@ -33,7 +32,7 @@ const indexName = 'indexName'; const scopeId = 'scopeId'; const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(CORRELATIONS_RELATED_CASES_TEST_ID); const renderRelatedCases = () => @@ -48,6 +47,7 @@ describe('', () => { jest.clearAllMocks(); (useDocumentDetailsContext as jest.Mock).mockReturnValue({ + eventId, indexName, scopeId, isPreviewMode: false, @@ -64,7 +64,7 @@ describe('', () => { const { getByTestId } = renderRelatedCases(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related case'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); }); it('should render multiple related cases correctly', () => { @@ -76,19 +76,7 @@ describe('', () => { const { getByTestId } = renderRelatedCases(); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related cases'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); - }); - - it('should render big number of related cases correctly', () => { - (useFetchRelatedCases as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 2000, - }); - - const { getByTestId } = renderRelatedCases(); - expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Related cases'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading skeleton', () => { @@ -118,7 +106,7 @@ describe('', () => { }); const { getByTestId } = renderRelatedCases(); - getByTestId(CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID).click(); + getByTestId(BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -133,25 +121,4 @@ describe('', () => { }, }); }); - - it('should disabled the click when in preview mode', () => { - (useDocumentDetailsContext as jest.Mock).mockReturnValue({ - indexName, - scopeId, - isPreviewMode: true, - }); - (useFetchRelatedCases as jest.Mock).mockReturnValue({ - loading: false, - error: false, - dataCount: 1, - }); - - const { getByTestId } = renderRelatedCases(); - const button = getByTestId(CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID); - - expect(button).toHaveAttribute('disabled'); - - button.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx index 18ce6d871bf21..331283e194ed0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/suppressed_alerts.test.tsx @@ -10,10 +10,9 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_TEXT_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, - CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, } from './test_ids'; import { SuppressedAlerts } from './suppressed_alerts'; import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; @@ -30,7 +29,7 @@ jest.mock('../../../../../common/detection_engine/utils', () => ({ })); const TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); -const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); +const BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID(CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); const renderSuppressedAlerts = (alertSuppressionCount: number) => render( @@ -62,7 +61,7 @@ describe('', () => { const { getByTestId } = renderSuppressedAlerts(1); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alert'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('1'); expect( getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) ).toBeInTheDocument(); @@ -72,14 +71,7 @@ describe('', () => { const { getByTestId } = renderSuppressedAlerts(2); expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alerts'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2'); - }); - - it('should render big number of suppressed alerts row correctly', () => { - const { getByTestId } = renderSuppressedAlerts(2000); - - expect(getByTestId(TEXT_TEST_ID)).toHaveTextContent('Suppressed alerts'); - expect(getByTestId(VALUE_TEST_ID)).toHaveTextContent('2k'); + expect(getByTestId(BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should not render Technical Preview badge if rule type is in GA', () => { @@ -93,7 +85,7 @@ describe('', () => { it('should open the expanded section to the correct tab when the number is clicked', () => { const { getByTestId } = renderSuppressedAlerts(1); - getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID).click(); + getByTestId(BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -108,21 +100,4 @@ describe('', () => { }, }); }); - - it('should disabled the click when in preview mode', () => { - (useDocumentDetailsContext as jest.Mock).mockReturnValue({ - eventId, - indexName, - scopeId, - isPreviewMode: true, - }); - - const { getByTestId } = renderSuppressedAlerts(1); - const button = getByTestId(CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID); - - expect(button).toHaveAttribute('disabled'); - - button.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts index ce4660f12db27..959f8f106bb08 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts @@ -106,6 +106,7 @@ export const INSIGHTS_CONTENT_TEST_ID = INSIGHTS_TEST_ID + CONTENT_TEST_ID; export const SUMMARY_ROW_LOADING_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Loading`; export const SUMMARY_ROW_TEXT_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Text`; export const SUMMARY_ROW_VALUE_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Value`; +export const SUMMARY_ROW_BUTTON_TEST_ID = (dataTestSubj: string) => `${dataTestSubj}Button`; /* Entities */ @@ -148,37 +149,23 @@ export const ENTITIES_HOST_OVERVIEW_VULNERABILITIES_TEST_ID = export const INSIGHTS_THREAT_INTELLIGENCE_TEST_ID = `${PREFIX}InsightsThreatIntelligence` as const; export const INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID = `${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}ThreatMatches` as const; -export const INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID = - `${INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID}Button` as const; export const INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID = `${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}EnrichedWithThreatIntelligence` as const; -export const INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID = - `${INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID}Button` as const; /* Correlations */ export const CORRELATIONS_TEST_ID = `${PREFIX}Correlations` as const; export const CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID = `${CORRELATIONS_TEST_ID}SuppressedAlerts` as const; -export const CORRELATIONS_SUPPRESSED_ALERTS_BUTTON_TEST_ID = - `${CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID}Button` as const; export const CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID = `${CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID}TechnicalPreview` as const; export const CORRELATIONS_RELATED_CASES_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedCases` as const; -export const CORRELATIONS_RELATED_CASES_BUTTON_TEST_ID = - `${CORRELATIONS_RELATED_CASES_TEST_ID}Button` as const; export const CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedAlertsBySession` as const; -export const CORRELATIONS_RELATED_ALERTS_BY_SESSION_BUTTON_TEST_ID = - `${CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID}Button` as const; export const CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedAlertsBySameSourceEvent` as const; -export const CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_BUTTON_TEST_ID = - `${CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID}Button` as const; export const CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID = `${CORRELATIONS_TEST_ID}RelatedAlertsByAncestry` as const; -export const CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_BUTTON_TEST_ID = - `${CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID}Button` as const; /* Insights Prevalence */ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx index 2a465607a386d..f451862e0990e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx @@ -16,13 +16,11 @@ import { LeftPanelInsightsTab } from '../../left'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; import { - INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_TEST_ID, - INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID, INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID, + SUMMARY_ROW_BUTTON_TEST_ID, SUMMARY_ROW_TEXT_TEST_ID, - SUMMARY_ROW_VALUE_TEST_ID, } from './test_ids'; import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, @@ -52,13 +50,13 @@ const LOADING_TEST_ID = EXPANDABLE_PANEL_LOADING_TEST_ID(INSIGHTS_THREAT_INTELLI const THREAT_MATCHES_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID ); -const THREAT_MATCHES_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const THREAT_MATCHES_BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_TEST_ID ); const ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID = SUMMARY_ROW_TEXT_TEST_ID( INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID ); -const ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( +const ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID = SUMMARY_ROW_BUTTON_TEST_ID( INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_TEST_ID ); @@ -133,11 +131,11 @@ describe('', () => { expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Threat intelligence'); expect(getByTestId(THREAT_MATCHES_TEXT_TEST_ID)).toHaveTextContent('Threat match detected'); - expect(getByTestId(THREAT_MATCHES_VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(THREAT_MATCHES_BUTTON_TEST_ID)).toHaveTextContent('1'); expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID)).toHaveTextContent( 'Field enriched with threat intelligence' ); - expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE_TEST_ID)).toHaveTextContent('1'); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID)).toHaveTextContent('1'); }); it('should render 2 matches detected and 2 fields enriched', () => { @@ -151,11 +149,11 @@ describe('', () => { expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Threat intelligence'); expect(getByTestId(THREAT_MATCHES_TEXT_TEST_ID)).toHaveTextContent('Threat matches detected'); - expect(getByTestId(THREAT_MATCHES_VALUE_TEST_ID)).toHaveTextContent('2'); + expect(getByTestId(THREAT_MATCHES_BUTTON_TEST_ID)).toHaveTextContent('2'); expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_TEXT_TEST_ID)).toHaveTextContent( 'Fields enriched with threat intelligence' ); - expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE_TEST_ID)).toHaveTextContent('2'); + expect(getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID)).toHaveTextContent('2'); }); it('should render loading', () => { @@ -199,7 +197,7 @@ describe('', () => { }); const { getByTestId } = renderThreatIntelligenceOverview(); - getByTestId(INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID).click(); + getByTestId(THREAT_MATCHES_BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -214,9 +212,7 @@ describe('', () => { }, }); - getByTestId( - INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID - ).click(); + getByTestId(ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID).click(); expect(mockOpenLeftPanel).toHaveBeenCalledWith({ id: DocumentDetailsLeftPanelKey, @@ -231,36 +227,4 @@ describe('', () => { }, }); }); - - it('should disabled the click when in preview mode', () => { - (useDocumentDetailsContext as jest.Mock).mockReturnValue({ - eventId, - indexName, - scopeId, - dataFormattedForFieldBrowser, - isPreviewMode: true, - }); - (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ - loading: false, - threatMatchesCount: 1, - threatEnrichmentsCount: 1, - }); - - const { getByTestId } = renderThreatIntelligenceOverview(); - const threatMatchesButton = getByTestId( - INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_BUTTON_TEST_ID - ); - const enrichedWithThreatIntelligenceButton = getByTestId( - INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_BUTTON_TEST_ID - ); - - expect(threatMatchesButton).toHaveAttribute('disabled'); - expect(enrichedWithThreatIntelligenceButton).toHaveAttribute('disabled'); - - threatMatchesButton.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - - enrichedWithThreatIntelligenceButton.click(); - expect(mockOpenLeftPanel).not.toHaveBeenCalled(); - }); }); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 7f8596a3dcddf..c5889c61f56a4 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -38767,7 +38767,6 @@ "xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription": "Aucune donnée de prévalence disponible.", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle": "Prévalence", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTooltip": "Afficher toutes les prévalences", - "xpack.securitySolution.flyout.right.insights.prevalence.rowDescription": "{field}, {value} est inhabituel", "xpack.securitySolution.flyout.right.insights.sectionTitle": "Informations exploitables", "xpack.securitySolution.flyout.right.insights.threatIntelligence.threatEnrichmentDescription": "{count, plural, one {champ enrichi} other {champs enrichis}} avec Threat Intelligence", "xpack.securitySolution.flyout.right.insights.threatIntelligence.threatIntelligenceTitle": "Threat Intelligence", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4ff7491ed6b4c..9fb18fd43079c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -38510,7 +38510,6 @@ "xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription": "発生率データはありません。", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle": "発生率", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTooltip": "すべての発生率を表示", - "xpack.securitySolution.flyout.right.insights.prevalence.rowDescription": "{field}、{value}は共通していません", "xpack.securitySolution.flyout.right.insights.sectionTitle": "インサイト", "xpack.securitySolution.flyout.right.insights.threatIntelligence.threatEnrichmentDescription": "{count, plural, other {フィールド}}はヒートインテリジェンスでエンリッチされています", "xpack.securitySolution.flyout.right.insights.threatIntelligence.threatIntelligenceTitle": "脅威インテリジェンス", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 5fbaf48cef1cf..3da2131e48b7a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -38555,7 +38555,6 @@ "xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription": "无普及性数据可用。", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle": "普及率", "xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTooltip": "显示所有普及率", - "xpack.securitySolution.flyout.right.insights.prevalence.rowDescription": "{field},{value} 不常见", "xpack.securitySolution.flyout.right.insights.sectionTitle": "洞见", "xpack.securitySolution.flyout.right.insights.threatIntelligence.threatEnrichmentDescription": "{count, plural, other {个字段}}已使用威胁情报扩充", "xpack.securitySolution.flyout.right.insights.threatIntelligence.threatIntelligenceTitle": "威胁情报", diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts index dc04e6ca3041c..2d267bee721dc 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_right_panel_overview_tab.ts @@ -78,10 +78,10 @@ export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_USER_OVERVIEW_LINK = getDataTe export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER = getDataTestSubjectSelector('securitySolutionFlyoutInsightsThreatIntelligenceTitleLink'); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_THREAT_MATCHES_VALUE = - getDataTestSubjectSelector('securitySolutionFlyoutInsightsThreatIntelligenceThreatMatchesValue'); + getDataTestSubjectSelector('securitySolutionFlyoutInsightsThreatIntelligenceThreatMatchesButton'); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_ENRICHED_WITH_THREAT_INTELLIGENCE_VALUE = getDataTestSubjectSelector( - 'securitySolutionFlyoutInsightsThreatIntelligenceEnrichedWithThreatIntelligenceValue' + 'securitySolutionFlyoutInsightsThreatIntelligenceEnrichedWithThreatIntelligenceButton' ); /* Insights Correlations */ @@ -89,17 +89,17 @@ export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_E export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER = getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsTitleLink'); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_SUPPRESSED_ALERTS = - getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsSuppressedAlertsValue'); + getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsSuppressedAlertsButton'); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_ANCESTRY = - getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsRelatedAlertsByAncestryValue'); + getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsRelatedAlertsByAncestryButton'); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_SAME_SOURCE_EVENT = getDataTestSubjectSelector( - 'securitySolutionFlyoutCorrelationsRelatedAlertsBySameSourceEventValue' + 'securitySolutionFlyoutCorrelationsRelatedAlertsBySameSourceEventButton' ); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_ALERTS_BY_SESSION = - getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsRelatedAlertsBySessionValue'); + getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsRelatedAlertsBySessionButton'); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES_RELATED_CASES = - getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsRelatedCasesValue'); + getDataTestSubjectSelector('securitySolutionFlyoutCorrelationsRelatedCasesButton'); /* Insights Prevalence */