[RAC] Actions popovers UI unification (#109221)
* popover padding size unified * remove panels from all context menus * action items order changed * cases menu items test fixed * translations and small changes * remove components not used anywhere Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Angela Chuang <yi-chun.chuang@elastic.co>
This commit is contained in:
parent
ec7889a938
commit
64dff78dce
|
@ -33,7 +33,7 @@ import {
|
||||||
EuiDataGridColumn,
|
EuiDataGridColumn,
|
||||||
EuiFlexGroup,
|
EuiFlexGroup,
|
||||||
EuiFlexItem,
|
EuiFlexItem,
|
||||||
EuiContextMenu,
|
EuiContextMenuPanel,
|
||||||
EuiPopover,
|
EuiPopover,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
@ -212,11 +212,8 @@ function ObservabilityActions({
|
||||||
onUpdateFailure: onAlertStatusUpdated,
|
onUpdateFailure: onAlertStatusUpdated,
|
||||||
});
|
});
|
||||||
|
|
||||||
const actionsPanels = useMemo(() => {
|
const actionsMenuItems = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
content: [
|
|
||||||
timelines.getAddToExistingCaseButton({
|
timelines.getAddToExistingCaseButton({
|
||||||
event,
|
event,
|
||||||
casePermissions,
|
casePermissions,
|
||||||
|
@ -230,8 +227,6 @@ function ObservabilityActions({
|
||||||
onClose: afterCaseSelection,
|
onClose: afterCaseSelection,
|
||||||
}),
|
}),
|
||||||
...(alertPermissions.crud ? statusActionItems : []),
|
...(alertPermissions.crud ? statusActionItems : []),
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}, [afterCaseSelection, casePermissions, timelines, event, statusActionItems, alertPermissions]);
|
}, [afterCaseSelection, casePermissions, timelines, event, statusActionItems, alertPermissions]);
|
||||||
|
|
||||||
|
@ -255,6 +250,7 @@ function ObservabilityActions({
|
||||||
aria-label="View alert in app"
|
aria-label="View alert in app"
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
{actionsMenuItems.length > 0 && (
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<EuiPopover
|
<EuiPopover
|
||||||
button={
|
button={
|
||||||
|
@ -272,9 +268,10 @@ function ObservabilityActions({
|
||||||
panelPaddingSize="none"
|
panelPaddingSize="none"
|
||||||
anchorPosition="downLeft"
|
anchorPosition="downLeft"
|
||||||
>
|
>
|
||||||
<EuiContextMenu panels={actionsPanels} initialPanelId={0} />
|
<EuiContextMenuPanel size="s" items={actionsMenuItems} />
|
||||||
</EuiPopover>
|
</EuiPopover>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
)}
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -19,6 +19,14 @@ export const mockTimelines = {
|
||||||
.fn()
|
.fn()
|
||||||
.mockReturnValue(<div data-test-subj="add-to-case-action">{'Add to case'}</div>),
|
.mockReturnValue(<div data-test-subj="add-to-case-action">{'Add to case'}</div>),
|
||||||
getAddToCaseAction: jest.fn(),
|
getAddToCaseAction: jest.fn(),
|
||||||
getAddToExistingCaseButton: jest.fn(),
|
getAddToExistingCaseButton: jest.fn().mockReturnValue(
|
||||||
getAddToNewCaseButton: jest.fn(),
|
<div key="add-to-existing-case-action" data-test-subj="add-to-existing-case-action">
|
||||||
|
{'Add to existing case'}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
getAddToNewCaseButton: jest.fn().mockReturnValue(
|
||||||
|
<div key="add-to-new-case-action" data-test-subj="add-to-new-case-action">
|
||||||
|
{'Add to new case'}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,36 +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 { EuiContextMenuItem } from '@elastic/eui';
|
|
||||||
import React from 'react';
|
|
||||||
import * as i18n from '../translations';
|
|
||||||
|
|
||||||
interface AddEndpointExceptionProps {
|
|
||||||
onClick: () => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddEndpointExceptionComponent: React.FC<AddEndpointExceptionProps> = ({
|
|
||||||
onClick,
|
|
||||||
disabled,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<EuiContextMenuItem
|
|
||||||
key="add-endpoint-exception-menu-item"
|
|
||||||
aria-label={i18n.ACTION_ADD_ENDPOINT_EXCEPTION}
|
|
||||||
data-test-subj="add-endpoint-exception-menu-item"
|
|
||||||
id="addEndpointException"
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled}
|
|
||||||
size="s"
|
|
||||||
>
|
|
||||||
{i18n.ACTION_ADD_ENDPOINT_EXCEPTION}
|
|
||||||
</EuiContextMenuItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AddEndpointException = React.memo(AddEndpointExceptionComponent);
|
|
|
@ -1,32 +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 { EuiContextMenuItem } from '@elastic/eui';
|
|
||||||
import React from 'react';
|
|
||||||
import * as i18n from '../translations';
|
|
||||||
|
|
||||||
interface AddEventFilterProps {
|
|
||||||
onClick: () => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddEventFilterComponent: React.FC<AddEventFilterProps> = ({ onClick, disabled }) => {
|
|
||||||
return (
|
|
||||||
<EuiContextMenuItem
|
|
||||||
key="add-event-filter-menu-item"
|
|
||||||
aria-label={i18n.ACTION_ADD_EVENT_FILTER}
|
|
||||||
data-test-subj="add-event-filter-menu-item"
|
|
||||||
id="addEventFilter"
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
{i18n.ACTION_ADD_EVENT_FILTER}
|
|
||||||
</EuiContextMenuItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AddEventFilter = React.memo(AddEventFilterComponent);
|
|
|
@ -1,33 +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 { EuiContextMenuItem } from '@elastic/eui';
|
|
||||||
import React from 'react';
|
|
||||||
import * as i18n from '../translations';
|
|
||||||
|
|
||||||
interface AddExceptionProps {
|
|
||||||
disabled?: boolean;
|
|
||||||
onClick: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddExceptionComponent: React.FC<AddExceptionProps> = ({ disabled, onClick }) => {
|
|
||||||
return (
|
|
||||||
<EuiContextMenuItem
|
|
||||||
key="add-exception-menu-item"
|
|
||||||
aria-label={i18n.ACTION_ADD_EXCEPTION}
|
|
||||||
data-test-subj="add-exception-menu-item"
|
|
||||||
id="addException"
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled}
|
|
||||||
size="s"
|
|
||||||
>
|
|
||||||
{i18n.ACTION_ADD_EXCEPTION}
|
|
||||||
</EuiContextMenuItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AddException = React.memo(AddExceptionComponent);
|
|
|
@ -56,7 +56,8 @@ jest.mock('../../../../common/lib/kibana', () => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const actionMenuButton = '[data-test-subj="timeline-context-menu-button"] button';
|
const actionMenuButton = '[data-test-subj="timeline-context-menu-button"] button';
|
||||||
const addToCaseButton = '[data-test-subj="attach-alert-to-case-button"]';
|
const addToExistingCaseButton = '[data-test-subj="add-to-existing-case-action"]';
|
||||||
|
const addToNewCaseButton = '[data-test-subj="add-to-new-case-action"]';
|
||||||
|
|
||||||
describe('InvestigateInResolverAction', () => {
|
describe('InvestigateInResolverAction', () => {
|
||||||
test('it render AddToCase context menu item if timelineId === TimelineId.detectionsPage', () => {
|
test('it render AddToCase context menu item if timelineId === TimelineId.detectionsPage', () => {
|
||||||
|
@ -65,7 +66,8 @@ describe('InvestigateInResolverAction', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find(actionMenuButton).simulate('click');
|
wrapper.find(actionMenuButton).simulate('click');
|
||||||
expect(wrapper.find(addToCaseButton).first().exists()).toEqual(true);
|
expect(wrapper.find(addToExistingCaseButton).first().exists()).toEqual(true);
|
||||||
|
expect(wrapper.find(addToNewCaseButton).first().exists()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it render AddToCase context menu item if timelineId === TimelineId.detectionsRulesDetailsPage', () => {
|
test('it render AddToCase context menu item if timelineId === TimelineId.detectionsRulesDetailsPage', () => {
|
||||||
|
@ -77,7 +79,8 @@ describe('InvestigateInResolverAction', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapper.find(actionMenuButton).simulate('click');
|
wrapper.find(actionMenuButton).simulate('click');
|
||||||
expect(wrapper.find(addToCaseButton).first().exists()).toEqual(true);
|
expect(wrapper.find(addToExistingCaseButton).first().exists()).toEqual(true);
|
||||||
|
expect(wrapper.find(addToNewCaseButton).first().exists()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it render AddToCase context menu item if timelineId === TimelineId.active', () => {
|
test('it render AddToCase context menu item if timelineId === TimelineId.active', () => {
|
||||||
|
@ -86,7 +89,8 @@ describe('InvestigateInResolverAction', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find(actionMenuButton).simulate('click');
|
wrapper.find(actionMenuButton).simulate('click');
|
||||||
expect(wrapper.find(addToCaseButton).first().exists()).toEqual(true);
|
expect(wrapper.find(addToExistingCaseButton).first().exists()).toEqual(true);
|
||||||
|
expect(wrapper.find(addToNewCaseButton).first().exists()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it does NOT render AddToCase context menu item when timelineId is not in the allowed list', () => {
|
test('it does NOT render AddToCase context menu item when timelineId is not in the allowed list', () => {
|
||||||
|
@ -94,6 +98,7 @@ describe('InvestigateInResolverAction', () => {
|
||||||
wrappingComponent: TestProviders,
|
wrappingComponent: TestProviders,
|
||||||
});
|
});
|
||||||
wrapper.find(actionMenuButton).simulate('click');
|
wrapper.find(actionMenuButton).simulate('click');
|
||||||
expect(wrapper.find(addToCaseButton).first().exists()).toEqual(false);
|
expect(wrapper.find(addToExistingCaseButton).first().exists()).toEqual(false);
|
||||||
|
expect(wrapper.find(addToNewCaseButton).first().exists()).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,16 +7,11 @@
|
||||||
|
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { EuiButtonIcon, EuiContextMenu, EuiPopover, EuiToolTip } from '@elastic/eui';
|
import { EuiButtonIcon, EuiContextMenuPanel, EuiPopover, EuiToolTip } from '@elastic/eui';
|
||||||
import { indexOf } from 'lodash';
|
import { indexOf } from 'lodash';
|
||||||
|
|
||||||
import { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types';
|
import { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types';
|
||||||
import { get, getOr } from 'lodash/fp';
|
import { get, getOr } from 'lodash/fp';
|
||||||
import {
|
|
||||||
EuiContextMenuPanelDescriptor,
|
|
||||||
EuiContextMenuPanelItemDescriptor,
|
|
||||||
} from '@elastic/eui/src/components/context_menu/context_menu';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { buildGetAlertByIdQuery } from '../../../../common/components/exceptions/helpers';
|
import { buildGetAlertByIdQuery } from '../../../../common/components/exceptions/helpers';
|
||||||
import { EventsTdContent } from '../../../../timelines/components/timeline/styles';
|
import { EventsTdContent } from '../../../../timelines/components/timeline/styles';
|
||||||
import { DEFAULT_ICON_BUTTON_WIDTH } from '../../../../timelines/components/timeline/helpers';
|
import { DEFAULT_ICON_BUTTON_WIDTH } from '../../../../timelines/components/timeline/helpers';
|
||||||
|
@ -54,11 +49,6 @@ interface AlertContextMenuProps {
|
||||||
onRuleChange?: () => void;
|
onRuleChange?: () => void;
|
||||||
timelineId: string;
|
timelineId: string;
|
||||||
}
|
}
|
||||||
export const NestedWrapper = styled.span`
|
|
||||||
button.euiContextMenuItem {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
|
const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
|
||||||
ariaLabel = i18n.MORE_ACTIONS,
|
ariaLabel = i18n.MORE_ACTIONS,
|
||||||
|
@ -99,27 +89,18 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
const hasWritePermissions = useGetUserCasesPermissions()?.crud ?? false;
|
const hasWritePermissions = useGetUserCasesPermissions()?.crud ?? false;
|
||||||
const addToCaseAction = useMemo(
|
const addToCaseActionItems = useMemo(
|
||||||
() =>
|
() =>
|
||||||
[
|
[
|
||||||
TimelineId.detectionsPage,
|
TimelineId.detectionsPage,
|
||||||
TimelineId.detectionsRulesDetailsPage,
|
TimelineId.detectionsRulesDetailsPage,
|
||||||
TimelineId.active,
|
TimelineId.active,
|
||||||
].includes(timelineId as TimelineId) && hasWritePermissions
|
].includes(timelineId as TimelineId) && hasWritePermissions
|
||||||
? {
|
? [
|
||||||
actionItem: [
|
|
||||||
{
|
|
||||||
name: i18n.ACTION_ADD_TO_CASE,
|
|
||||||
panel: 2,
|
|
||||||
'data-test-subj': 'attach-alert-to-case-button',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
content: [
|
|
||||||
timelinesUi.getAddToExistingCaseButton(addToCaseActionProps),
|
timelinesUi.getAddToExistingCaseButton(addToCaseActionProps),
|
||||||
timelinesUi.getAddToNewCaseButton(addToCaseActionProps),
|
timelinesUi.getAddToNewCaseButton(addToCaseActionProps),
|
||||||
],
|
]
|
||||||
}
|
: [],
|
||||||
: { actionItem: [], content: [] },
|
|
||||||
[addToCaseActionProps, hasWritePermissions, timelineId, timelinesUi]
|
[addToCaseActionProps, hasWritePermissions, timelineId, timelinesUi]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -179,7 +160,7 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
|
||||||
onAddEventFilterClick,
|
onAddEventFilterClick,
|
||||||
} = useEventFilterModal();
|
} = useEventFilterModal();
|
||||||
|
|
||||||
const { actionItems } = useAlertsActions({
|
const { actionItems: statusActionItems } = useAlertsActions({
|
||||||
alertStatus,
|
alertStatus,
|
||||||
eventId: ecsRowData?._id,
|
eventId: ecsRowData?._id,
|
||||||
indexName: ecsRowData?._index ?? '',
|
indexName: ecsRowData?._index ?? '',
|
||||||
|
@ -201,57 +182,43 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
|
||||||
closePopover();
|
closePopover();
|
||||||
}, [closePopover, onAddEventFilterClick]);
|
}, [closePopover, onAddEventFilterClick]);
|
||||||
|
|
||||||
const { exceptionActions } = useExceptionActions({
|
const { exceptionActionItems } = useExceptionActions({
|
||||||
isEndpointAlert,
|
isEndpointAlert,
|
||||||
onAddExceptionTypeClick: handleOnAddExceptionTypeClick,
|
onAddExceptionTypeClick: handleOnAddExceptionTypeClick,
|
||||||
});
|
});
|
||||||
const investigateInResolverAction = useInvestigateInResolverContextItem({
|
const investigateInResolverActionItems = useInvestigateInResolverContextItem({
|
||||||
timelineId,
|
timelineId,
|
||||||
ecsData: ecsRowData,
|
ecsData: ecsRowData,
|
||||||
onClose: afterItemSelection,
|
onClose: afterItemSelection,
|
||||||
});
|
});
|
||||||
const eventFilterAction = useEventFilterAction({
|
const { eventFilterActionItems } = useEventFilterAction({
|
||||||
onAddEventFilterClick: handleOnAddEventFilterClick,
|
onAddEventFilterClick: handleOnAddEventFilterClick,
|
||||||
});
|
});
|
||||||
const items: EuiContextMenuPanelItemDescriptor[] = useMemo(
|
const items: React.ReactElement[] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
!isEvent && ruleId
|
!isEvent && ruleId
|
||||||
? [
|
? [
|
||||||
...investigateInResolverAction,
|
...investigateInResolverActionItems,
|
||||||
...addToCaseAction.actionItem,
|
...addToCaseActionItems,
|
||||||
...actionItems.map((aI) => ({ name: <NestedWrapper>{aI}</NestedWrapper> })),
|
...statusActionItems,
|
||||||
...exceptionActions,
|
...exceptionActionItems,
|
||||||
]
|
]
|
||||||
: [...investigateInResolverAction, ...addToCaseAction.actionItem, eventFilterAction],
|
: [...investigateInResolverActionItems, ...addToCaseActionItems, ...eventFilterActionItems],
|
||||||
[
|
[
|
||||||
actionItems,
|
statusActionItems,
|
||||||
addToCaseAction.actionItem,
|
addToCaseActionItems,
|
||||||
eventFilterAction,
|
eventFilterActionItems,
|
||||||
exceptionActions,
|
exceptionActionItems,
|
||||||
investigateInResolverAction,
|
investigateInResolverActionItems,
|
||||||
isEvent,
|
isEvent,
|
||||||
ruleId,
|
ruleId,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const panels: EuiContextMenuPanelDescriptor[] = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
items,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: i18n.ACTION_ADD_TO_CASE,
|
|
||||||
content: addToCaseAction.content,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[addToCaseAction.content, items]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{timelinesUi.getAddToCaseAction(addToCaseActionProps)}
|
{timelinesUi.getAddToCaseAction(addToCaseActionProps)}
|
||||||
|
{items.length > 0 && (
|
||||||
<div key="actions-context-menu">
|
<div key="actions-context-menu">
|
||||||
<EventsTdContent textAlign="center" width={DEFAULT_ICON_BUTTON_WIDTH}>
|
<EventsTdContent textAlign="center" width={DEFAULT_ICON_BUTTON_WIDTH}>
|
||||||
<EuiPopover
|
<EuiPopover
|
||||||
|
@ -263,10 +230,11 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps> = ({
|
||||||
anchorPosition="downLeft"
|
anchorPosition="downLeft"
|
||||||
repositionOnScroll
|
repositionOnScroll
|
||||||
>
|
>
|
||||||
<EuiContextMenu size="s" initialPanelId={0} panels={panels} />
|
<EuiContextMenuPanel size="s" items={items} />
|
||||||
</EuiPopover>
|
</EuiPopover>
|
||||||
</EventsTdContent>
|
</EventsTdContent>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
{exceptionModalType != null &&
|
{exceptionModalType != null &&
|
||||||
ruleId != null &&
|
ruleId != null &&
|
||||||
ruleName != null &&
|
ruleName != null &&
|
||||||
|
|
|
@ -1,36 +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 { EuiContextMenuItem } from '@elastic/eui';
|
|
||||||
import React from 'react';
|
|
||||||
import { FILTER_ACKNOWLEDGED } from '../../alerts_filter_group';
|
|
||||||
import * as i18n from '../../translations';
|
|
||||||
|
|
||||||
interface AcknowledgedAlertStatusProps {
|
|
||||||
onClick: () => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AcknowledgedAlertStatusComponent: React.FC<AcknowledgedAlertStatusProps> = ({
|
|
||||||
onClick,
|
|
||||||
disabled,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<EuiContextMenuItem
|
|
||||||
key="acknowledged-alert"
|
|
||||||
aria-label={i18n.ACTION_ACKNOWLEDGED_ALERT}
|
|
||||||
data-test-subj="acknowledged-alert-status"
|
|
||||||
id={FILTER_ACKNOWLEDGED}
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
{i18n.ACTION_ACKNOWLEDGED_ALERT}
|
|
||||||
</EuiContextMenuItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AcknowledgedAlertStatus = React.memo(AcknowledgedAlertStatusComponent);
|
|
|
@ -1,33 +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 { EuiContextMenuItem } from '@elastic/eui';
|
|
||||||
import React from 'react';
|
|
||||||
import { FILTER_CLOSED } from '../../alerts_filter_group';
|
|
||||||
import * as i18n from '../../translations';
|
|
||||||
|
|
||||||
interface CloseAlertActionProps {
|
|
||||||
onClick: () => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CloseAlertActionComponent: React.FC<CloseAlertActionProps> = ({ onClick, disabled }) => {
|
|
||||||
return (
|
|
||||||
<EuiContextMenuItem
|
|
||||||
key="close-alert"
|
|
||||||
aria-label={i18n.ACTION_CLOSE_ALERT}
|
|
||||||
data-test-subj="close-alert-status"
|
|
||||||
id={FILTER_CLOSED}
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
{i18n.ACTION_CLOSE_ALERT}
|
|
||||||
</EuiContextMenuItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CloseAlertAction = React.memo(CloseAlertActionComponent);
|
|
|
@ -1,33 +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 { EuiContextMenuItem } from '@elastic/eui';
|
|
||||||
import React from 'react';
|
|
||||||
import { FILTER_OPEN } from '../../alerts_filter_group';
|
|
||||||
import * as i18n from '../../translations';
|
|
||||||
|
|
||||||
interface OpenAlertStatusProps {
|
|
||||||
onClick: () => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OpenAlertStatusComponent: React.FC<OpenAlertStatusProps> = ({ onClick, disabled }) => {
|
|
||||||
return (
|
|
||||||
<EuiContextMenuItem
|
|
||||||
key="open-alert"
|
|
||||||
aria-label={i18n.ACTION_OPEN_ALERT}
|
|
||||||
data-test-subj="open-alert-status"
|
|
||||||
id={FILTER_OPEN}
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
{i18n.ACTION_OPEN_ALERT}
|
|
||||||
</EuiContextMenuItem>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const OpenAlertStatus = React.memo(OpenAlertStatusComponent);
|
|
|
@ -5,8 +5,9 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { EuiContextMenuItem } from '@elastic/eui';
|
||||||
import { get } from 'lodash/fp';
|
import { get } from 'lodash/fp';
|
||||||
import {
|
import {
|
||||||
setActiveTabTimeline,
|
setActiveTabTimeline,
|
||||||
|
@ -44,9 +45,12 @@ export const useInvestigateInResolverContextItem = ({
|
||||||
return isDisabled
|
return isDisabled
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
{
|
<EuiContextMenuItem
|
||||||
name: ACTION_INVESTIGATE_IN_RESOLVER,
|
key="investigate-in-resolver-action-item"
|
||||||
onClick: handleClick,
|
data-test-subj="investigate-in-resolver-action-item"
|
||||||
},
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{ACTION_INVESTIGATE_IN_RESOLVER}
|
||||||
|
</EuiContextMenuItem>,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,26 +5,13 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import { EuiContextMenuItem } from '@elastic/eui';
|
||||||
import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types';
|
import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types';
|
||||||
|
|
||||||
import { useUserData } from '../../user_info';
|
import { useUserData } from '../../user_info';
|
||||||
import { ACTION_ADD_ENDPOINT_EXCEPTION, ACTION_ADD_EXCEPTION } from '../translations';
|
import { ACTION_ADD_ENDPOINT_EXCEPTION, ACTION_ADD_EXCEPTION } from '../translations';
|
||||||
|
|
||||||
interface ExceptionActions {
|
|
||||||
name: string;
|
|
||||||
onClick: () => void;
|
|
||||||
disabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseExceptionActions {
|
|
||||||
disabledAddEndpointException: boolean;
|
|
||||||
disabledAddException: boolean;
|
|
||||||
exceptionActions: ExceptionActions[];
|
|
||||||
handleEndpointExceptionModal: () => void;
|
|
||||||
handleDetectionExceptionModal: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseExceptionActionProps {
|
interface UseExceptionActionProps {
|
||||||
isEndpointAlert: boolean;
|
isEndpointAlert: boolean;
|
||||||
onAddExceptionTypeClick: (type: ExceptionListType) => void;
|
onAddExceptionTypeClick: (type: ExceptionListType) => void;
|
||||||
|
@ -33,7 +20,7 @@ interface UseExceptionActionProps {
|
||||||
export const useExceptionActions = ({
|
export const useExceptionActions = ({
|
||||||
isEndpointAlert,
|
isEndpointAlert,
|
||||||
onAddExceptionTypeClick,
|
onAddExceptionTypeClick,
|
||||||
}: UseExceptionActionProps): UseExceptionActions => {
|
}: UseExceptionActionProps) => {
|
||||||
const [{ canUserCRUD, hasIndexWrite }] = useUserData();
|
const [{ canUserCRUD, hasIndexWrite }] = useUserData();
|
||||||
|
|
||||||
const handleDetectionExceptionModal = useCallback(() => {
|
const handleDetectionExceptionModal = useCallback(() => {
|
||||||
|
@ -47,20 +34,25 @@ export const useExceptionActions = ({
|
||||||
const disabledAddEndpointException = !canUserCRUD || !hasIndexWrite || !isEndpointAlert;
|
const disabledAddEndpointException = !canUserCRUD || !hasIndexWrite || !isEndpointAlert;
|
||||||
const disabledAddException = !canUserCRUD || !hasIndexWrite;
|
const disabledAddException = !canUserCRUD || !hasIndexWrite;
|
||||||
|
|
||||||
const exceptionActions = useMemo(
|
const exceptionActionItems = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
<EuiContextMenuItem
|
||||||
name: ACTION_ADD_ENDPOINT_EXCEPTION,
|
key="add-endpoint-exception-menu-item"
|
||||||
onClick: handleEndpointExceptionModal,
|
data-test-subj="add-endpoint-exception-menu-item"
|
||||||
disabled: disabledAddEndpointException,
|
disabled={disabledAddEndpointException}
|
||||||
[`data-test-subj`]: 'add-endpoint-exception-menu-item',
|
onClick={handleEndpointExceptionModal}
|
||||||
},
|
>
|
||||||
{
|
{ACTION_ADD_ENDPOINT_EXCEPTION}
|
||||||
name: ACTION_ADD_EXCEPTION,
|
</EuiContextMenuItem>,
|
||||||
onClick: handleDetectionExceptionModal,
|
|
||||||
disabled: disabledAddException,
|
<EuiContextMenuItem
|
||||||
[`data-test-subj`]: 'add-exception-menu-item',
|
key="add-exception-menu-item"
|
||||||
},
|
data-test-subj="add-exception-menu-item"
|
||||||
|
disabled={disabledAddException}
|
||||||
|
onClick={handleDetectionExceptionModal}
|
||||||
|
>
|
||||||
|
{ACTION_ADD_EXCEPTION}
|
||||||
|
</EuiContextMenuItem>,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
disabledAddEndpointException,
|
disabledAddEndpointException,
|
||||||
|
@ -70,11 +62,5 @@ export const useExceptionActions = ({
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return { exceptionActionItems };
|
||||||
disabledAddEndpointException,
|
|
||||||
disabledAddException,
|
|
||||||
exceptionActions,
|
|
||||||
handleEndpointExceptionModal,
|
|
||||||
handleDetectionExceptionModal,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
import { EuiContextMenuItem } from '@elastic/eui';
|
||||||
import { ACTION_ADD_EVENT_FILTER } from '../translations';
|
import { ACTION_ADD_EVENT_FILTER } from '../translations';
|
||||||
|
|
||||||
export const useEventFilterAction = ({
|
export const useEventFilterAction = ({
|
||||||
|
@ -13,12 +14,17 @@ export const useEventFilterAction = ({
|
||||||
}: {
|
}: {
|
||||||
onAddEventFilterClick: () => void;
|
onAddEventFilterClick: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const eventFilterActions = useMemo(
|
const eventFilterActionItems = useMemo(
|
||||||
() => ({
|
() => [
|
||||||
name: ACTION_ADD_EVENT_FILTER,
|
<EuiContextMenuItem
|
||||||
onClick: onAddEventFilterClick,
|
key="add-event-filter-menu-item"
|
||||||
}),
|
data-test-subj="add-event-filter-menu-item"
|
||||||
|
onClick={onAddEventFilterClick}
|
||||||
|
>
|
||||||
|
{ACTION_ADD_EVENT_FILTER}
|
||||||
|
</EuiContextMenuItem>,
|
||||||
|
],
|
||||||
[onAddEventFilterClick]
|
[onAddEventFilterClick]
|
||||||
);
|
);
|
||||||
return eventFilterActions;
|
return { eventFilterActionItems };
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import { EuiContextMenuItem } from '@elastic/eui';
|
||||||
import { useKibana } from '../../../../common/lib/kibana';
|
import { useKibana } from '../../../../common/lib/kibana';
|
||||||
|
|
||||||
import { TimelineId } from '../../../../../common/types/timeline';
|
import { TimelineId } from '../../../../../common/types/timeline';
|
||||||
|
@ -102,18 +103,21 @@ export const useInvestigateInTimeline = ({
|
||||||
updateTimelineIsLoading,
|
updateTimelineIsLoading,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const investigateInTimelineAction = showInvestigateInTimelineAction
|
const investigateInTimelineActionItems = showInvestigateInTimelineAction
|
||||||
? [
|
? [
|
||||||
{
|
<EuiContextMenuItem
|
||||||
name: ACTION_INVESTIGATE_IN_TIMELINE,
|
key="investigate-in-timeline-action-item"
|
||||||
onClick: investigateInTimelineAlertClick,
|
data-test-subj="investigate-in-timeline-action-item"
|
||||||
disabled: isFetchingAlertEcs,
|
disabled={isFetchingAlertEcs === true}
|
||||||
},
|
onClick={investigateInTimelineAlertClick}
|
||||||
|
>
|
||||||
|
{ACTION_INVESTIGATE_IN_TIMELINE}
|
||||||
|
</EuiContextMenuItem>,
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
investigateInTimelineAction,
|
investigateInTimelineActionItems,
|
||||||
investigateInTimelineAlertClick,
|
investigateInTimelineAlertClick,
|
||||||
showInvestigateInTimelineAction,
|
showInvestigateInTimelineAction,
|
||||||
};
|
};
|
||||||
|
|
|
@ -185,13 +185,6 @@ export const ACTION_ADD_EVENT_FILTER = i18n.translate(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ACTION_ADD_TO_CASE = i18n.translate(
|
|
||||||
'xpack.securitySolution.detectionEngine.alerts.actions.addToCase',
|
|
||||||
{
|
|
||||||
defaultMessage: 'Add to case',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const ACTION_ADD_ENDPOINT_EXCEPTION = i18n.translate(
|
export const ACTION_ADD_ENDPOINT_EXCEPTION = i18n.translate(
|
||||||
'xpack.securitySolution.detectionEngine.alerts.actions.addEndpointException',
|
'xpack.securitySolution.detectionEngine.alerts.actions.addEndpointException',
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
import { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import { EuiContextMenuItem } from '@elastic/eui';
|
||||||
import type { TimelineEventsDetailsItem } from '../../../../common';
|
import type { TimelineEventsDetailsItem } from '../../../../common';
|
||||||
import { isIsolationSupported } from '../../../../common/endpoint/service/host_isolation/utils';
|
import { isIsolationSupported } from '../../../../common/endpoint/service/host_isolation/utils';
|
||||||
import { HostStatus } from '../../../../common/endpoint/types';
|
import { HostStatus } from '../../../../common/endpoint/types';
|
||||||
|
@ -89,11 +90,14 @@ export const useHostIsolationAction = ({
|
||||||
isolationSupported &&
|
isolationSupported &&
|
||||||
isHostIsolationPanelOpen === false
|
isHostIsolationPanelOpen === false
|
||||||
? [
|
? [
|
||||||
{
|
<EuiContextMenuItem
|
||||||
name: isolateHostTitle,
|
key="isolate-host-action-item"
|
||||||
onClick: isolateHostHandler,
|
data-test-subj="isolate-host-action-item"
|
||||||
disabled: loadingHostIsolationStatus || agentStatus === HostStatus.UNENROLLED,
|
disabled={loadingHostIsolationStatus || agentStatus === HostStatus.UNENROLLED}
|
||||||
},
|
onClick={isolateHostHandler}
|
||||||
|
>
|
||||||
|
{isolateHostTitle}
|
||||||
|
</EuiContextMenuItem>,
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
[
|
[
|
||||||
|
|
|
@ -1,18 +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 { ACTION_ADD_TO_CASE } from '../alerts_table/translations';
|
|
||||||
|
|
||||||
export const addToCaseActionItem = (timelineId: string | null | undefined) =>
|
|
||||||
['detections-page', 'detections-rules-details-page', 'timeline-1'].includes(timelineId ?? '')
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
name: ACTION_ADD_TO_CASE,
|
|
||||||
panel: 2,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [];
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useCallback, useMemo } from 'react';
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
import { EuiContextMenu, EuiContextMenuPanel, EuiButton, EuiPopover } from '@elastic/eui';
|
import { EuiContextMenuPanel, EuiButton, EuiPopover } from '@elastic/eui';
|
||||||
import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types';
|
import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types';
|
||||||
|
|
||||||
import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations';
|
import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations';
|
||||||
|
@ -15,13 +15,10 @@ import { TimelineEventsDetailsItem, TimelineNonEcsData } from '../../../../commo
|
||||||
import { useExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions';
|
import { useExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions';
|
||||||
import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions';
|
import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions';
|
||||||
import { useInvestigateInTimeline } from '../alerts_table/timeline_actions/use_investigate_in_timeline';
|
import { useInvestigateInTimeline } from '../alerts_table/timeline_actions/use_investigate_in_timeline';
|
||||||
import { ACTION_ADD_TO_CASE } from '../alerts_table/translations';
|
|
||||||
import { useGetUserCasesPermissions, useKibana } from '../../../common/lib/kibana';
|
import { useGetUserCasesPermissions, useKibana } from '../../../common/lib/kibana';
|
||||||
import { useInsertTimeline } from '../../../cases/components/use_insert_timeline';
|
import { useInsertTimeline } from '../../../cases/components/use_insert_timeline';
|
||||||
import { addToCaseActionItem } from './helpers';
|
|
||||||
import { useEventFilterAction } from '../alerts_table/timeline_actions/use_event_filter_action';
|
import { useEventFilterAction } from '../alerts_table/timeline_actions/use_event_filter_action';
|
||||||
import { useHostIsolationAction } from '../host_isolation/use_host_isolation_action';
|
import { useHostIsolationAction } from '../host_isolation/use_host_isolation_action';
|
||||||
import { CHANGE_ALERT_STATUS } from './translations';
|
|
||||||
import { getFieldValue } from '../host_isolation/helpers';
|
import { getFieldValue } from '../host_isolation/helpers';
|
||||||
import type { Ecs } from '../../../../common/ecs';
|
import type { Ecs } from '../../../../common/ecs';
|
||||||
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||||
|
@ -121,7 +118,7 @@ export const TakeActionDropdown = React.memo(
|
||||||
[onAddIsolationStatusClick]
|
[onAddIsolationStatusClick]
|
||||||
);
|
);
|
||||||
|
|
||||||
const hostIsolationAction = useHostIsolationAction({
|
const hostIsolationActionItems = useHostIsolationAction({
|
||||||
closePopover: closePopoverHandler,
|
closePopover: closePopoverHandler,
|
||||||
detailsData,
|
detailsData,
|
||||||
onAddIsolationStatusClick: handleOnAddIsolationStatusClick,
|
onAddIsolationStatusClick: handleOnAddIsolationStatusClick,
|
||||||
|
@ -136,7 +133,7 @@ export const TakeActionDropdown = React.memo(
|
||||||
[onAddExceptionTypeClick]
|
[onAddExceptionTypeClick]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { exceptionActions } = useExceptionActions({
|
const { exceptionActionItems } = useExceptionActions({
|
||||||
isEndpointAlert,
|
isEndpointAlert,
|
||||||
onAddExceptionTypeClick: handleOnAddExceptionTypeClick,
|
onAddExceptionTypeClick: handleOnAddExceptionTypeClick,
|
||||||
});
|
});
|
||||||
|
@ -146,7 +143,7 @@ export const TakeActionDropdown = React.memo(
|
||||||
setIsPopoverOpen(false);
|
setIsPopoverOpen(false);
|
||||||
}, [onAddEventFilterClick]);
|
}, [onAddEventFilterClick]);
|
||||||
|
|
||||||
const eventFilterActions = useEventFilterAction({
|
const { eventFilterActionItems } = useEventFilterAction({
|
||||||
onAddEventFilterClick: handleOnAddEventFilterClick,
|
onAddEventFilterClick: handleOnAddEventFilterClick,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -154,7 +151,7 @@ export const TakeActionDropdown = React.memo(
|
||||||
closePopoverHandler();
|
closePopoverHandler();
|
||||||
}, [closePopoverHandler]);
|
}, [closePopoverHandler]);
|
||||||
|
|
||||||
const { actionItems } = useAlertsActions({
|
const { actionItems: statusActionItems } = useAlertsActions({
|
||||||
alertStatus: actionsData.alertStatus,
|
alertStatus: actionsData.alertStatus,
|
||||||
eventId: actionsData.eventId,
|
eventId: actionsData.eventId,
|
||||||
indexName,
|
indexName,
|
||||||
|
@ -163,7 +160,7 @@ export const TakeActionDropdown = React.memo(
|
||||||
closePopover: closePopoverAndFlyout,
|
closePopover: closePopoverAndFlyout,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { investigateInTimelineAction } = useInvestigateInTimeline({
|
const { investigateInTimelineActionItems } = useInvestigateInTimeline({
|
||||||
alertIds,
|
alertIds,
|
||||||
ecsRowData: ecsData,
|
ecsRowData: ecsData,
|
||||||
onInvestigateInTimelineAlertClick: closePopoverHandler,
|
onInvestigateInTimelineAlertClick: closePopoverHandler,
|
||||||
|
@ -172,15 +169,9 @@ export const TakeActionDropdown = React.memo(
|
||||||
const alertsActionItems = useMemo(
|
const alertsActionItems = useMemo(
|
||||||
() =>
|
() =>
|
||||||
!isEvent && actionsData.ruleId
|
!isEvent && actionsData.ruleId
|
||||||
? [
|
? [...statusActionItems, ...exceptionActionItems]
|
||||||
{
|
: eventFilterActionItems,
|
||||||
name: CHANGE_ALERT_STATUS,
|
[eventFilterActionItems, exceptionActionItems, statusActionItems, isEvent, actionsData.ruleId]
|
||||||
panel: 1,
|
|
||||||
},
|
|
||||||
...exceptionActions,
|
|
||||||
]
|
|
||||||
: [eventFilterActions],
|
|
||||||
[eventFilterActions, exceptionActions, isEvent, actionsData.ruleId]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const addToCaseProps = useMemo(() => {
|
const addToCaseProps = useMemo(() => {
|
||||||
|
@ -197,55 +188,35 @@ export const TakeActionDropdown = React.memo(
|
||||||
}
|
}
|
||||||
}, [afterCaseSelection, casePermissions, ecsData, insertTimelineHook]);
|
}, [afterCaseSelection, casePermissions, ecsData, insertTimelineHook]);
|
||||||
|
|
||||||
const panels = useMemo(() => {
|
const addToCasesActionItems = useMemo(
|
||||||
if (tGridEnabled) {
|
() =>
|
||||||
return [
|
addToCaseProps &&
|
||||||
{
|
['detections-page', 'detections-rules-details-page', 'timeline-1'].includes(
|
||||||
id: 0,
|
timelineId ?? ''
|
||||||
items: [
|
)
|
||||||
|
? [
|
||||||
|
timelinesUi.getAddToExistingCaseButton(addToCaseProps),
|
||||||
|
timelinesUi.getAddToNewCaseButton(addToCaseProps),
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
[timelinesUi, addToCaseProps, timelineId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const items: React.ReactElement[] = useMemo(
|
||||||
|
() => [
|
||||||
|
...(tGridEnabled ? addToCasesActionItems : []),
|
||||||
...alertsActionItems,
|
...alertsActionItems,
|
||||||
...addToCaseActionItem(timelineId),
|
...hostIsolationActionItems,
|
||||||
...hostIsolationAction,
|
...investigateInTimelineActionItems,
|
||||||
...investigateInTimelineAction,
|
|
||||||
],
|
],
|
||||||
},
|
[
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: CHANGE_ALERT_STATUS,
|
|
||||||
content: <EuiContextMenuPanel size="s" items={actionItems} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: ACTION_ADD_TO_CASE,
|
|
||||||
content: [
|
|
||||||
<>{addToCaseProps && timelinesUi.getAddToExistingCaseButton(addToCaseProps)}</>,
|
|
||||||
<>{addToCaseProps && timelinesUi.getAddToNewCaseButton(addToCaseProps)}</>,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
items: [...alertsActionItems, ...hostIsolationAction, ...investigateInTimelineAction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: CHANGE_ALERT_STATUS,
|
|
||||||
content: <EuiContextMenuPanel size="s" items={actionItems} />,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
addToCaseProps,
|
|
||||||
alertsActionItems,
|
|
||||||
hostIsolationAction,
|
|
||||||
investigateInTimelineAction,
|
|
||||||
timelineId,
|
|
||||||
timelinesUi,
|
|
||||||
actionItems,
|
|
||||||
tGridEnabled,
|
tGridEnabled,
|
||||||
]);
|
alertsActionItems,
|
||||||
|
addToCasesActionItems,
|
||||||
|
hostIsolationActionItems,
|
||||||
|
investigateInTimelineActionItems,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
const takeActionButton = useMemo(() => {
|
const takeActionButton = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
@ -255,10 +226,10 @@ export const TakeActionDropdown = React.memo(
|
||||||
);
|
);
|
||||||
}, [togglePopoverHandler]);
|
}, [togglePopoverHandler]);
|
||||||
|
|
||||||
return panels[0].items?.length && !loadingEventDetails ? (
|
return items.length && !loadingEventDetails ? (
|
||||||
<>
|
<>
|
||||||
<EuiPopover
|
<EuiPopover
|
||||||
id="hostIsolationTakeActionPanel"
|
id="AlertTakeActionPanel"
|
||||||
button={takeActionButton}
|
button={takeActionButton}
|
||||||
isOpen={isPopoverOpen}
|
isOpen={isPopoverOpen}
|
||||||
closePopover={closePopoverHandler}
|
closePopover={closePopoverHandler}
|
||||||
|
@ -266,7 +237,7 @@ export const TakeActionDropdown = React.memo(
|
||||||
anchorPosition="downLeft"
|
anchorPosition="downLeft"
|
||||||
repositionOnScroll
|
repositionOnScroll
|
||||||
>
|
>
|
||||||
<EuiContextMenu size="s" initialPanelId={0} panels={panels} />
|
<EuiContextMenuPanel size="s" items={items} />
|
||||||
</EuiPopover>
|
</EuiPopover>
|
||||||
</>
|
</>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
|
@ -33,8 +33,9 @@ const AddToCaseActionComponent: React.FC<AddToCaseActionProps> = ({
|
||||||
<EuiContextMenuItem
|
<EuiContextMenuItem
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
data-test-subj="attach-alert-to-case-button"
|
data-test-subj="attach-alert-to-case-button"
|
||||||
size="s"
|
|
||||||
onClick={addExistingCaseClick}
|
onClick={addExistingCaseClick}
|
||||||
|
// needs forced size="s" since it is lazy loaded and the EuiContextMenuPanel can not initialize the size
|
||||||
|
size="s"
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
>
|
>
|
||||||
{i18n.ACTION_ADD_EXISTING_CASE}
|
{i18n.ACTION_ADD_EXISTING_CASE}
|
||||||
|
|
|
@ -34,8 +34,9 @@ const AddToCaseActionComponent: React.FC<AddToCaseActionProps> = ({
|
||||||
<EuiContextMenuItem
|
<EuiContextMenuItem
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
data-test-subj="attach-alert-to-case-button"
|
data-test-subj="attach-alert-to-case-button"
|
||||||
size="s"
|
|
||||||
onClick={addNewCaseClick}
|
onClick={addNewCaseClick}
|
||||||
|
// needs forced size="s" since it is lazy loaded and the EuiContextMenuPanel can not initialize the size
|
||||||
|
size="s"
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
>
|
>
|
||||||
{i18n.ACTION_ADD_NEW_CASE}
|
{i18n.ACTION_ADD_NEW_CASE}
|
||||||
|
|
|
@ -96,7 +96,7 @@ const BulkActionsComponent: React.FC<BulkActionsProps> = ({
|
||||||
<EuiPopover
|
<EuiPopover
|
||||||
isOpen={isActionsPopoverOpen}
|
isOpen={isActionsPopoverOpen}
|
||||||
anchorPosition="upCenter"
|
anchorPosition="upCenter"
|
||||||
panelPaddingSize="s"
|
panelPaddingSize="none"
|
||||||
button={
|
button={
|
||||||
<EuiButtonEmpty
|
<EuiButtonEmpty
|
||||||
aria-label="selectedShowBulkActions"
|
aria-label="selectedShowBulkActions"
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const BULK_ACTION_OPEN_SELECTED = i18n.translate(
|
||||||
export const BULK_ACTION_CLOSE_SELECTED = i18n.translate(
|
export const BULK_ACTION_CLOSE_SELECTED = i18n.translate(
|
||||||
'xpack.timelines.timeline.closeSelectedTitle',
|
'xpack.timelines.timeline.closeSelectedTitle',
|
||||||
{
|
{
|
||||||
defaultMessage: 'Close selected',
|
defaultMessage: 'Mark as closed',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,6 @@ export const useStatusBulkActionItems = ({
|
||||||
key="open"
|
key="open"
|
||||||
data-test-subj="open-alert-status"
|
data-test-subj="open-alert-status"
|
||||||
onClick={() => onClickUpdate(FILTER_OPEN)}
|
onClick={() => onClickUpdate(FILTER_OPEN)}
|
||||||
size="s"
|
|
||||||
>
|
>
|
||||||
{i18n.BULK_ACTION_OPEN_SELECTED}
|
{i18n.BULK_ACTION_OPEN_SELECTED}
|
||||||
</EuiContextMenuItem>
|
</EuiContextMenuItem>
|
||||||
|
@ -139,7 +138,6 @@ export const useStatusBulkActionItems = ({
|
||||||
key="acknowledge"
|
key="acknowledge"
|
||||||
data-test-subj="acknowledged-alert-status"
|
data-test-subj="acknowledged-alert-status"
|
||||||
onClick={() => onClickUpdate(FILTER_ACKNOWLEDGED)}
|
onClick={() => onClickUpdate(FILTER_ACKNOWLEDGED)}
|
||||||
size="s"
|
|
||||||
>
|
>
|
||||||
{i18n.BULK_ACTION_ACKNOWLEDGED_SELECTED}
|
{i18n.BULK_ACTION_ACKNOWLEDGED_SELECTED}
|
||||||
</EuiContextMenuItem>
|
</EuiContextMenuItem>
|
||||||
|
@ -151,7 +149,6 @@ export const useStatusBulkActionItems = ({
|
||||||
key="close"
|
key="close"
|
||||||
data-test-subj="close-alert-status"
|
data-test-subj="close-alert-status"
|
||||||
onClick={() => onClickUpdate(FILTER_CLOSED)}
|
onClick={() => onClickUpdate(FILTER_CLOSED)}
|
||||||
size="s"
|
|
||||||
>
|
>
|
||||||
{i18n.BULK_ACTION_CLOSE_SELECTED}
|
{i18n.BULK_ACTION_CLOSE_SELECTED}
|
||||||
</EuiContextMenuItem>
|
</EuiContextMenuItem>
|
||||||
|
|
Loading…
Reference in a new issue