Skip to content

Commit

Permalink
Expandable flyout context (#165662)
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippeOberti authored Sep 13, 2023
1 parent b425081 commit 170024d
Show file tree
Hide file tree
Showing 61 changed files with 502 additions and 832 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,11 @@
*/

import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
import { css } from '@emotion/react';
import React, { createContext, memo, useContext, useMemo } from 'react';
import { EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';

import { useTimelineEventsDetails } from '../../timelines/containers/details';
import { getAlertIndexAlias } from '../../timelines/components/side_panel/event_details/helpers';
import { useSpaceId } from '../../common/hooks/use_space_id';
import { useRouteSpy } from '../../common/utils/route/use_route_spy';
import { SecurityPageName } from '../../../common/constants';
import { SourcererScopeName } from '../../common/store/sourcerer/model';
import { useSourcererDataView } from '../../common/containers/sourcerer';
import { useEventDetails } from '../shared/hooks/use_event_details';
import { FlyoutError } from '../shared/components/flyout_error';
import { FlyoutLoading } from '../shared/components/flyout_loading';
import type { IsolateHostPanelProps } from '.';

export interface IsolateHostPanelContext {
Expand All @@ -35,7 +29,7 @@ export interface IsolateHostPanelContext {
/**
* An array of field objects with category and value
*/
dataFormattedForFieldBrowser: TimelineEventsDetailsItem[] | null;
dataFormattedForFieldBrowser: TimelineEventsDetailsItem[];
/**
* Isolate action, either 'isolateHost' or 'unisolateHost'
*/
Expand All @@ -55,26 +49,11 @@ export type IsolateHostPanelProviderProps = {

export const IsolateHostPanelProvider = memo(
({ id, indexName, scopeId, isolateAction, children }: IsolateHostPanelProviderProps) => {
const currentSpaceId = useSpaceId();
// TODO Replace getAlertIndexAlias way to retrieving the eventIndex with the GET /_alias
// https://github.com/elastic/kibana/issues/113063
const eventIndex = indexName ? getAlertIndexAlias(indexName, currentSpaceId) ?? indexName : '';
const [{ pageName }] = useRouteSpy();
const sourcererScope =
pageName === SecurityPageName.detections
? SourcererScopeName.detections
: SourcererScopeName.default;
const sourcererDataView = useSourcererDataView(sourcererScope);
const [loading, dataFormattedForFieldBrowser] = useTimelineEventsDetails({
indexName: eventIndex,
eventId: id ?? '',
runtimeMappings: sourcererDataView.runtimeMappings,
skip: !id,
});
const { dataFormattedForFieldBrowser, loading } = useEventDetails({ eventId: id, indexName });

const contextValue = useMemo(
() =>
id && indexName && scopeId && isolateAction
id && indexName && scopeId && isolateAction && dataFormattedForFieldBrowser
? {
eventId: id,
indexName,
Expand All @@ -87,16 +66,11 @@ export const IsolateHostPanelProvider = memo(
);

if (loading) {
return (
<EuiFlexItem
css={css`
align-items: center;
justify-content: center;
`}
>
<EuiLoadingSpinner size="xxl" />
</EuiFlexItem>
);
return <FlyoutLoading />;
}

if (!contextValue) {
return <FlyoutError />;
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import '@testing-library/jest-dom';
import { LeftPanelContext } from '../context';
import { TestProviders } from '../../../common/mock';
import { AnalyzeGraph } from './analyze_graph';
import { ANALYZE_GRAPH_ERROR_TEST_ID, ANALYZER_GRAPH_TEST_ID } from './test_ids';
import { ANALYZER_GRAPH_TEST_ID } from './test_ids';

jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
Expand Down Expand Up @@ -45,21 +45,4 @@ describe('<AnalyzeGraph />', () => {
);
expect(wrapper.getByTestId(ANALYZER_GRAPH_TEST_ID)).toBeInTheDocument();
});

it('should render error message on null eventId', () => {
const contextValue = {
eventId: null,
} as unknown as LeftPanelContext;

const wrapper = render(
<TestProviders>
<LeftPanelContext.Provider value={contextValue}>
<AnalyzeGraph />
</LeftPanelContext.Provider>
</TestProviders>
);
expect(wrapper.getByTestId(ANALYZE_GRAPH_ERROR_TEST_ID)).toBeInTheDocument();
expect(wrapper.getByText('Unable to display analyzer')).toBeInTheDocument();
expect(wrapper.getByText('There was an error displaying analyzer')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@

import type { FC } from 'react';
import React, { useMemo } from 'react';
import { EuiEmptyPrompt } from '@elastic/eui';

import { ANALYZER_ERROR_MESSAGE } from './translations';
import { useLeftPanelContext } from '../context';
import { ANALYZE_GRAPH_ERROR_TEST_ID, ANALYZER_GRAPH_TEST_ID } from './test_ids';
import { ANALYZER_GRAPH_TEST_ID } from './test_ids';
import { Resolver } from '../../../resolver/view';
import { useTimelineDataFilters } from '../../../timelines/containers/use_timeline_data_filters';
import { ERROR_TITLE, ERROR_MESSAGE } from '../../shared/translations';
import { isActiveTimeline } from '../../../helpers';

export const ANALYZE_GRAPH_ID = 'analyze_graph';
Expand All @@ -30,18 +27,6 @@ export const AnalyzeGraph: FC = () => {
);
const filters = useMemo(() => ({ from, to }), [from, to]);

if (!eventId) {
return (
<EuiEmptyPrompt
iconType="error"
color="danger"
title={<h2>{ERROR_TITLE(ANALYZER_ERROR_MESSAGE)}</h2>}
body={<p>{ERROR_MESSAGE(ANALYZER_ERROR_MESSAGE)}</p>}
data-test-subj={ANALYZE_GRAPH_ERROR_TEST_ID}
/>
);
}

return (
<div data-test-subj={ANALYZER_GRAPH_TEST_ID}>
<Resolver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,12 @@ describe('<InvestigationGuide />', () => {
expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument();
});

it('should render null when dataFormattedForFieldBrowser is null', () => {
const mockContext = {
...mockContextValue,
dataFormattedForFieldBrowser: null,
};
(useInvestigationGuide as jest.Mock).mockReturnValue({
loading: false,
error: false,
});
const { container } = render(renderInvestigationGuide(mockContext));
expect(container).toBeEmptyDOMElement();
});

it('should render null useInvestigationGuide errors out', () => {
it('should render no data message when useInvestigationGuide errors out', () => {
(useInvestigationGuide as jest.Mock).mockReturnValue({
loading: false,
error: true,
});
const { container } = render(renderInvestigationGuide());
expect(container).toBeEmptyDOMElement();
const { getByTestId } = render(renderInvestigationGuide());
expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ export const InvestigationGuide: React.FC = () => {
dataFormattedForFieldBrowser,
});

if (!dataFormattedForFieldBrowser || error) {
return null;
}

if (loading) {
return (
<EuiFlexGroup
Expand All @@ -45,7 +41,7 @@ export const InvestigationGuide: React.FC = () => {

return (
<>
{basicAlertData.ruleId && ruleNote ? (
{!error && basicAlertData.ruleId && ruleNote ? (
<InvestigationGuideView
basicData={basicAlertData}
ruleNote={ruleNote}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import {
PREVALENCE_DETAILS_LOADING_TEST_ID,
PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID,
PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID,
PREVALENCE_DETAILS_TABLE_TEST_ID,
PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID,
Expand Down Expand Up @@ -218,7 +218,7 @@ describe('PrevalenceDetails', () => {
expect(getByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).toBeInTheDocument();
});

it('should render error if call errors out', () => {
it('should render no data message if call errors out', () => {
(usePrevalence as jest.Mock).mockReturnValue({
loading: false,
error: true,
Expand All @@ -231,66 +231,6 @@ describe('PrevalenceDetails', () => {
</LeftPanelContext.Provider>
);

expect(getByTestId(PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID)).toBeInTheDocument();
});

it('should render error if event is null', () => {
const contextValue = {
...panelContextValue,
eventId: null,
} as unknown as LeftPanelContext;
(usePrevalence as jest.Mock).mockReturnValue({
loading: false,
error: true,
data: [],
});

const { getByTestId } = render(
<LeftPanelContext.Provider value={contextValue}>
<PrevalenceDetails />
</LeftPanelContext.Provider>
);

expect(getByTestId(PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID)).toBeInTheDocument();
});

it('should render error if dataFormattedForFieldBrowser is null', () => {
const contextValue = {
...panelContextValue,
dataFormattedForFieldBrowser: null,
};
(usePrevalence as jest.Mock).mockReturnValue({
loading: false,
error: true,
data: [],
});

const { getByTestId } = render(
<LeftPanelContext.Provider value={contextValue}>
<PrevalenceDetails />
</LeftPanelContext.Provider>
);

expect(getByTestId(PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID)).toBeInTheDocument();
});

it('should render error if browserFields is null', () => {
const contextValue = {
...panelContextValue,
browserFields: null,
};
(usePrevalence as jest.Mock).mockReturnValue({
loading: false,
error: true,
data: [],
});

const { getByTestId } = render(
<LeftPanelContext.Provider value={contextValue}>
<PrevalenceDetails />
</LeftPanelContext.Provider>
);

expect(getByTestId(PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID)).toBeInTheDocument();
expect(getByTestId(`${PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID}Error`)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import React, { useMemo, useState } from 'react';
import type { EuiBasicTableColumn, OnTimeChangeProps } from '@elastic/eui';
import {
EuiCallOut,
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiInMemoryTable,
Expand All @@ -28,10 +27,8 @@ import { useLicense } from '../../../common/hooks/use_license';
import { InvestigateInTimelineButton } from '../../../common/components/event_details/table/investigate_in_timeline_button';
import type { PrevalenceData } from '../../shared/hooks/use_prevalence';
import { usePrevalence } from '../../shared/hooks/use_prevalence';
import { ERROR_MESSAGE, ERROR_TITLE } from '../../shared/translations';
import {
HOST_TITLE,
PREVALENCE_ERROR_MESSAGE,
PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE,
PREVALENCE_TABLE_COUNT_COLUMN_TITLE,
PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE,
Expand All @@ -49,7 +46,6 @@ import {
PREVALENCE_DETAILS_LOADING_TEST_ID,
PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID,
PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID,
PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID,
Expand Down Expand Up @@ -208,8 +204,7 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [
* Prevalence table displayed in the document details expandable flyout left section under the Insights tab
*/
export const PrevalenceDetails: React.FC = () => {
const { browserFields, dataFormattedForFieldBrowser, eventId, investigationFields } =
useLeftPanelContext();
const { dataFormattedForFieldBrowser, investigationFields } = useLeftPanelContext();

const isPlatinumPlus = useLicense().isPlatinumPlus();

Expand Down Expand Up @@ -273,18 +268,6 @@ export const PrevalenceDetails: React.FC = () => {
);
}

if (!eventId || !dataFormattedForFieldBrowser || !browserFields || error) {
return (
<EuiEmptyPrompt
iconType="error"
color="danger"
title={<h2>{ERROR_TITLE(PREVALENCE_ERROR_MESSAGE)}</h2>}
body={<p>{ERROR_MESSAGE(PREVALENCE_ERROR_MESSAGE)}</p>}
data-test-subj={PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID}
/>
);
}

const upsell = (
<>
<EuiCallOut data-test-subj={`${PREVALENCE_DETAILS_TABLE_TEST_ID}UpSell`}>
Expand All @@ -309,7 +292,7 @@ export const PrevalenceDetails: React.FC = () => {

return (
<>
{!isPlatinumPlus && upsell}
{!error && !isPlatinumPlus && upsell}
<EuiPanel>
<EuiSuperDatePicker
start={start}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface SuppressedAlertsProps {
/**
* An object with top level fields from the ECS object
*/
dataAsNestedObject: Ecs | null;
dataAsNestedObject: Ecs;
/**
* Value of the kibana.alert.suppression.doc_count field
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,6 @@ export const RELATED_USERS_TOOL_TIP = (hostName: string) =>
values: { hostName },
});

export const PREVALENCE_ERROR_MESSAGE = i18n.translate(
'xpack.securitySolution.flyout.prevalenceErrorMessage',
{
defaultMessage: 'prevalence',
}
);

export const PREVALENCE_NO_DATA_MESSAGE = i18n.translate(
'xpack.securitySolution.flyout.prevalenceNoDataMessage',
{
Expand Down
Loading

0 comments on commit 170024d

Please sign in to comment.