Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Detections Engine] Add Alert actions to the Timeline #73228

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
599599b
[Detections Engine] Add Alert actions to the Timeline
patrykkopycinski Jul 26, 2020
74610a1
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Jul 26, 2020
f2b5dd0
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 18, 2020
08abda3
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 19, 2020
6526e38
update unit tests
patrykkopycinski Aug 19, 2020
e56a0e9
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 19, 2020
c55285d
fix unit tests
patrykkopycinski Aug 19, 2020
2cfad92
Update index.test.tsx
patrykkopycinski Aug 19, 2020
7e5bb0c
Merge branch 'master' into feat/alert-actions-timeline
elasticmachine Aug 24, 2020
ccf64f9
cleanup
patrykkopycinski Aug 24, 2020
046b2fa
Merge branch 'master' into feat/alert-actions-timeline
elasticmachine Aug 24, 2020
6e26432
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 24, 2020
ca35772
add missing fields
patrykkopycinski Aug 24, 2020
ad034af
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 25, 2020
796398b
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 25, 2020
bc3be47
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 26, 2020
703e63d
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 26, 2020
7e8b506
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 27, 2020
c67ecec
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 27, 2020
a059c38
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 27, 2020
c2f903d
PR comments
patrykkopycinski Aug 27, 2020
107faf7
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 29, 2020
a819ae8
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 29, 2020
6ab3200
types
patrykkopycinski Aug 31, 2020
fc2a02f
update row alert status
patrykkopycinski Aug 31, 2020
1a34aab
Merge branch 'master' of github.com:elastic/kibana into feat/alert-ac…
patrykkopycinski Aug 31, 2020
12f17f6
Merge branch 'master' into feat/alert-actions-timeline
elasticmachine Sep 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion x-pack/plugins/security_solution/public/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { EuiErrorBoundary } from '@elastic/eui';
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';

import { ManageUserInfo } from '../detections/components/user_info';
import { DEFAULT_DARK_MODE, APP_NAME } from '../../common/constants';
import { ErrorToastDispatcher } from '../common/components/error_toast_dispatcher';
import { MlCapabilitiesProvider } from '../common/components/ml/permissions/ml_capabilities_provider';
Expand All @@ -28,6 +29,7 @@ import { ManageGlobalTimeline } from '../timelines/components/manage_timeline';
import { StartServices } from '../types';
import { PageRouter } from './routes';
import { ManageSource } from '../common/containers/sourcerer';

interface StartAppComponent extends AppFrontendLibs {
children: React.ReactNode;
history: History;
Expand Down Expand Up @@ -57,7 +59,9 @@ const StartAppComponent: FC<StartAppComponent> = ({ children, apolloClient, hist
<ManageSource>
<ThemeProvider theme={theme}>
<MlCapabilitiesProvider>
<PageRouter history={history}>{children}</PageRouter>
<ManageUserInfo>
<PageRouter history={history}>{children}</PageRouter>
</ManageUserInfo>
</MlCapabilitiesProvider>
</ThemeProvider>
</ManageSource>
Expand Down
7 changes: 6 additions & 1 deletion x-pack/plugins/security_solution/public/app/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React, { useMemo } from 'react';
import styled from 'styled-components';

import { TimelineId } from '../../../common/types/timeline';
import { DragDropContextWrapper } from '../../common/components/drag_and_drop/drag_drop_context_wrapper';
import { Flyout } from '../../timelines/components/flyout';
import { HeaderGlobal } from '../../common/components/header_global';
Expand All @@ -17,6 +18,7 @@ import { useWithSource } from '../../common/containers/source';
import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline';
import { navTabs } from './home_navigations';
import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index';
import { useUserInfo } from '../../detections/components/user_info';

const SecuritySolutionAppWrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -52,6 +54,9 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
const [showTimeline] = useShowTimeline();
const { browserFields, indexPattern, indicesExist } = useWithSource('default', indexToAdd);

// side effect: this will attempt to create the signals index if it doesn't exist
useUserInfo();
Copy link
Contributor

@andrew-goldstein andrew-goldstein Aug 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider adding a comment like:

useUserInfo(); // side effect: this will attempt to create the signals index if it doesn't exist


return (
<SecuritySolutionAppWrapper>
<HeaderGlobal />
Expand All @@ -62,7 +67,7 @@ const HomePageComponent: React.FC<HomePageProps> = ({ children }) => {
{indicesExist && showTimeline && (
<>
<AutoSaveWarningMsg />
<Flyout timelineId="timeline-1" usersViewing={usersViewing} />
<Flyout timelineId={TimelineId.active} usersViewing={usersViewing} />
</>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
*/

import React, { useEffect, useMemo } from 'react';
import { useDispatch } from 'react-redux';

import { Filter } from '../../../../../../../src/plugins/data/public';
import { TimelineIdLiteral } from '../../../../common/types/timeline';
import { StatefulEventsViewer } from '../events_viewer';
import { alertsDefaultModel } from './default_headers';
import { useManageTimeline } from '../../../timelines/components/manage_timeline';
import { getInvestigateInResolverAction } from '../../../timelines/components/timeline/body/helpers';
import * as i18n from './translations';
import { useKibana } from '../../lib/kibana';

Expand Down Expand Up @@ -68,7 +66,6 @@ const AlertsTableComponent: React.FC<Props> = ({
startDate,
pageFilters = [],
}) => {
const dispatch = useDispatch();
const alertsFilter = useMemo(() => [...defaultAlertsFilters, ...pageFilters], [pageFilters]);
const { filterManager } = useKibana().services.data.query;
const { initializeTimeline } = useManageTimeline();
Expand All @@ -80,12 +77,12 @@ const AlertsTableComponent: React.FC<Props> = ({
filterManager,
defaultModel: alertsDefaultModel,
footerText: i18n.TOTAL_COUNT_OF_ALERTS,
timelineRowActions: () => [getInvestigateInResolverAction({ dispatch, timelineId })],
title: i18n.ALERTS_TABLE_TITLE,
unit: i18n.UNIT,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<StatefulEventsViewer
pageFilters={alertsFilter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import * as i18n from './translations';
import { MatrixHistogramOption, MatrixHisrogramConfigs } from '../matrix_histogram/types';
import { MatrixHistogramOption, MatrixHistogramConfigs } from '../matrix_histogram/types';
import { HistogramType } from '../../../graphql/types';

export const alertsStackByOptions: MatrixHistogramOption[] = [
Expand All @@ -21,7 +21,7 @@ export const alertsStackByOptions: MatrixHistogramOption[] = [

const DEFAULT_STACK_BY = 'event.module';

export const histogramConfigs: MatrixHisrogramConfigs = {
export const histogramConfigs: MatrixHistogramConfigs = {
defaultStackByOption:
alertsStackByOptions.find((o) => o.text === DEFAULT_STACK_BY) ?? alertsStackByOptions[1],
errorMessage: i18n.ERROR_FETCHING_ALERTS_DATA,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import * as i18n from './translations';
import { useUiSetting$ } from '../../lib/kibana';
import { MatrixHistogramContainer } from '../matrix_histogram';
import { histogramConfigs } from './histogram_configs';
import { MatrixHisrogramConfigs } from '../matrix_histogram/types';
import { MatrixHistogramConfigs } from '../matrix_histogram/types';
const ID = 'alertsOverTimeQuery';

export const AlertsView = ({
Expand All @@ -38,7 +38,7 @@ export const AlertsView = ({
[]
);
const { globalFullScreen } = useFullScreen();
const alertsHistogramConfigs: MatrixHisrogramConfigs = useMemo(
const alertsHistogramConfigs: MatrixHistogramConfigs = useMemo(
() => ({
...histogramConfigs,
subtitle: getSubtitle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ const utilityBar = (refetch: inputsModel.Refetch, totalCount: number) => (
<div data-test-subj="mock-utility-bar" />
);

const exceptionsModal = (refetch: inputsModel.Refetch) => (
<div data-test-subj="mock-exceptions-modal" />
);

const eventsViewerDefaultProps = {
browserFields: {},
columns: [],
Expand Down Expand Up @@ -464,42 +460,4 @@ describe('EventsViewer', () => {
});
});
});

describe('exceptions modal', () => {
test('it renders exception modal if "exceptionsModal" callback exists', async () => {
const wrapper = mount(
<TestProviders>
<MockedProvider mocks={mockEventViewerResponse} addTypename={false}>
<EventsViewer
{...eventsViewerDefaultProps}
exceptionsModal={exceptionsModal}
graphEventId=""
/>
</MockedProvider>
</TestProviders>
);

await waitFor(() => {
wrapper.update();

expect(wrapper.find(`[data-test-subj="mock-exceptions-modal"]`).exists()).toBeTruthy();
});
});

test('it does not render exception modal if "exceptionModal" callback does not exist', async () => {
const wrapper = mount(
<TestProviders>
<MockedProvider mocks={mockEventViewerResponse} addTypename={false}>
<EventsViewer {...eventsViewerDefaultProps} graphEventId="" />
</MockedProvider>
</TestProviders>
);

await waitFor(() => {
wrapper.update();

expect(wrapper.find(`[data-test-subj="mock-exceptions-modal"]`).exists()).toBeFalsy();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ interface Props {
utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode;
// If truthy, the graph viewer (Resolver) is showing
graphEventId: string | undefined;
exceptionsModal?: (refetch: inputsModel.Refetch) => React.ReactNode;
}

const EventsViewerComponent: React.FC<Props> = ({
Expand All @@ -135,7 +134,6 @@ const EventsViewerComponent: React.FC<Props> = ({
toggleColumn,
utilityBar,
graphEventId,
exceptionsModal,
}) => {
const { globalFullScreen } = useFullScreen();
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
Expand Down Expand Up @@ -261,7 +259,6 @@ const EventsViewerComponent: React.FC<Props> = ({
</HeaderFilterGroupWrapper>
)}
</HeaderSection>
{exceptionsModal && exceptionsModal(refetch)}
{utilityBar && !resolverIsShowing(graphEventId) && (
<UtilityBar>{utilityBar?.(refetch, totalCountMinusDeleted)}</UtilityBar>
)}
Expand All @@ -280,6 +277,7 @@ const EventsViewerComponent: React.FC<Props> = ({
docValueFields={docValueFields}
id={id}
isEventViewer={true}
refetch={refetch}
sort={sort}
toggleColumn={toggleColumn}
/>
Expand Down Expand Up @@ -338,6 +336,5 @@ export const EventsViewer = React.memo(
prevProps.start === nextProps.start &&
prevProps.sort === nextProps.sort &&
prevProps.utilityBar === nextProps.utilityBar &&
prevProps.graphEventId === nextProps.graphEventId &&
prevProps.exceptionsModal === nextProps.exceptionsModal
prevProps.graphEventId === nextProps.graphEventId
);
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export interface OwnProps {
headerFilterGroup?: React.ReactNode;
pageFilters?: Filter[];
utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode;
exceptionsModal?: (refetch: inputsModel.Refetch) => React.ReactNode;
}

type Props = OwnProps & PropsFromRedux;
Expand Down Expand Up @@ -75,7 +74,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
utilityBar,
// If truthy, the graph viewer (Resolver) is showing
graphEventId,
exceptionsModal,
}) => {
const [
{ docValueFields, browserFields, indexPatterns, isLoading: isLoadingIndexPattern },
Expand Down Expand Up @@ -158,7 +156,6 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
toggleColumn={toggleColumn}
utilityBar={utilityBar}
graphEventId={graphEventId}
exceptionsModal={exceptionsModal}
/>
</InspectButtonContainer>
</FullScreenContainer>
Expand Down Expand Up @@ -223,7 +220,6 @@ type PropsFromRedux = ConnectedProps<typeof connector>;
export const StatefulEventsViewer = connector(
React.memo(
StatefulEventsViewerComponent,
// eslint-disable-next-line complexity
(prevProps, nextProps) =>
prevProps.id === nextProps.id &&
deepEqual(prevProps.columns, nextProps.columns) &&
Expand All @@ -244,7 +240,6 @@ export const StatefulEventsViewer = connector(
prevProps.showCheckboxes === nextProps.showCheckboxes &&
prevProps.start === nextProps.start &&
prevProps.utilityBar === nextProps.utilityBar &&
prevProps.graphEventId === nextProps.graphEventId &&
prevProps.exceptionsModal === nextProps.exceptionsModal
prevProps.graphEventId === nextProps.graphEventId
)
);
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface AddExceptionModalBaseProps {

export interface AddExceptionModalProps extends AddExceptionModalBaseProps {
onCancel: () => void;
onConfirm: (didCloseAlert: boolean) => void;
onConfirm: (didCloseAlert: boolean, didBulkCloseAlert: boolean) => void;
onRuleChange?: () => void;
alertStatus?: Status;
}
Expand Down Expand Up @@ -137,8 +137,8 @@ export const AddExceptionModal = memo(function AddExceptionModal({
);
const onSuccess = useCallback(() => {
addSuccess(i18n.ADD_EXCEPTION_SUCCESS);
onConfirm(shouldCloseAlert);
}, [addSuccess, onConfirm, shouldCloseAlert]);
onConfirm(shouldCloseAlert, shouldBulkCloseAlert);
}, [addSuccess, onConfirm, shouldBulkCloseAlert, shouldCloseAlert]);

const [{ isLoading: addExceptionIsLoading }, addOrUpdateExceptionItems] = useAddOrUpdateException(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface MatrixHistogramOption {
export type GetSubTitle = (count: number) => string;
export type GetTitle = (matrixHistogramOption: MatrixHistogramOption) => string;

export interface MatrixHisrogramConfigs {
export interface MatrixHistogramConfigs {
defaultStackByOption: MatrixHistogramOption;
errorMessage: string;
hideHistogramIfEmpty?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as H from 'history';
import { Query, Filter } from '../../../../../../../src/plugins/data/public';
import { url } from '../../../../../../../src/plugins/kibana_utils/public';

import { TimelineId } from '../../../../common/types/timeline';
import { SecurityPageName } from '../../../app/types';
import { inputsSelectors, State } from '../../store';
import { UrlInputsModel } from '../../store/inputs/model';
Expand Down Expand Up @@ -122,7 +123,7 @@ export const makeMapStateToProps = () => {
const { linkTo: globalLinkTo, timerange: globalTimerange } = inputState.global;
const { linkTo: timelineLinkTo, timerange: timelineTimerange } = inputState.timeline;

const flyoutTimeline = getTimeline(state, 'timeline-1');
const flyoutTimeline = getTimeline(state, TimelineId.active);
const timeline =
flyoutTimeline != null
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as i18n from './translations';
import {
MatrixHistogramOption,
MatrixHisrogramConfigs,
MatrixHistogramConfigs,
} from '../../../components/matrix_histogram/types';
import { HistogramType } from '../../../../graphql/types';

Expand All @@ -19,7 +19,7 @@ export const anomaliesStackByOptions: MatrixHistogramOption[] = [

const DEFAULT_STACK_BY = i18n.ANOMALIES_STACK_BY_JOB_ID;

export const histogramConfigs: MatrixHisrogramConfigs = {
export const histogramConfigs: MatrixHistogramConfigs = {
defaultStackByOption:
anomaliesStackByOptions.find((o) => o.text === DEFAULT_STACK_BY) ?? anomaliesStackByOptions[0],
errorMessage: i18n.ERROR_FETCHING_ANOMALIES_DATA,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
import { FilterStateStore } from '../../../../../../src/plugins/data/common/es_query/filters/meta_filter';

import { TimelineType, TimelineStatus } from '../../../common/types/timeline';
import { TimelineId, TimelineType, TimelineStatus } from '../../../common/types/timeline';

import { OpenTimelineResult } from '../../timelines/components/open_timeline/types';
import {
Expand Down Expand Up @@ -2227,7 +2227,7 @@ export const defaultTimelineProps: CreateTimelineProps = {
filters: [],
highlightedDropAndProviderId: '',
historyIds: [],
id: 'timeline-1',
id: TimelineId.active,
isFavorite: false,
isLive: false,
isLoading: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
} from '../../../common/mock/';
import { CreateTimeline, UpdateTimelineLoading } from './types';
import { Ecs } from '../../../graphql/types';
import { TimelineType, TimelineStatus } from '../../../../common/types/timeline';
import { TimelineId, TimelineType, TimelineStatus } from '../../../../common/types/timeline';

jest.mock('apollo-client');

Expand Down Expand Up @@ -67,7 +67,10 @@ describe('alert actions', () => {
});

expect(updateTimelineIsLoading).toHaveBeenCalledTimes(1);
expect(updateTimelineIsLoading).toHaveBeenCalledWith({ id: 'timeline-1', isLoading: true });
expect(updateTimelineIsLoading).toHaveBeenCalledWith({
id: TimelineId.active,
isLoading: true,
});
});

test('it invokes createTimeline with designated timeline template if "timelineTemplate" exists', async () => {
Expand Down Expand Up @@ -313,9 +316,12 @@ describe('alert actions', () => {
updateTimelineIsLoading,
});

expect(updateTimelineIsLoading).toHaveBeenCalledWith({ id: 'timeline-1', isLoading: true });
expect(updateTimelineIsLoading).toHaveBeenCalledWith({
id: 'timeline-1',
id: TimelineId.active,
isLoading: true,
});
expect(updateTimelineIsLoading).toHaveBeenCalledWith({
id: TimelineId.active,
isLoading: false,
});
expect(createTimeline).toHaveBeenCalledTimes(1);
Expand Down
Loading