Skip to content

Commit

Permalink
[Security Solution][Alert details] - move footer components to flyout…
Browse files Browse the repository at this point in the history
… folder (elastic#189289)
  • Loading branch information
PhilippeOberti authored Aug 6, 2024
1 parent bb97741 commit a048ad1
Show file tree
Hide file tree
Showing 29 changed files with 557 additions and 604 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/osquery/cypress/e2e/all/alerts_cases.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('Alert Event Details - Cases', { tags: ['@ess', '@serverless'] }, () =>
it('runs osquery against alert and creates a new case', () => {
const [caseName, caseDescription] = generateRandomStringName(2);
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('securitySolutionFlyoutFooterDropdownButton').click();
cy.getBySel('osquery-action-item').click();
cy.contains(/^\d+ agen(t|ts) selected/);
cy.getBySel('globalLoadingIndicator').should('not.exist');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe(
it('should be able to run live query and add to timeline', () => {
const TIMELINE_NAME = 'Untitled timeline';
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('securitySolutionFlyoutFooterDropdownButton').click();
cy.getBySel('osquery-action-item').click();
cy.contains('1 agent selected.');
selectAllAgents();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe(

it('should be able to run take action query against all enrolled agents', () => {
cy.getBySel('expand-event').first().click();
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('securitySolutionFlyoutFooterDropdownButton').click();
cy.getBySel('osquery-action-item').click();
cy.getBySel('agentSelection').within(() => {
cy.getBySel('comboBoxClearButton').click();
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/osquery/cypress/tasks/live_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export const checkActionItemsInResults = ({
};

export const takeOsqueryActionWithParams = () => {
cy.getBySel('take-action-dropdown-btn').click();
cy.getBySel('securitySolutionFlyoutFooterDropdownButton').click();
cy.getBySel('osquery-action-item').click();
selectAllAgents();
inputQuery("SELECT * FROM os_version where name='{{host.os.name}}';", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,3 @@ export const ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS = i18n
defaultMessage: 'Show only threat indicator alerts',
}
);

export const TAKE_ACTION = i18n.translate(
'xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle',
{
defaultMessage: 'Take action',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
EndpointIsolateSuccess,
HostIsolationPanel,
} from '../../../common/components/endpoint/host_isolation';
import { useHostIsolationTools } from '../../../timelines/components/side_panel/event_details/use_host_isolation_tools';
import { useHostIsolation } from '../shared/hooks/use_host_isolation';
import { useIsolateHostPanelContext } from './context';
import { FlyoutBody } from '../../shared/components/flyout_body';

Expand All @@ -26,8 +26,7 @@ export const PanelContent: FC = () => {
const { dataFormattedForFieldBrowser, eventId, scopeId, indexName, isolateAction } =
useIsolateHostPanelContext();

const { isIsolateActionSuccessBannerVisible, handleIsolationActionSuccess } =
useHostIsolationTools();
const { isIsolateActionSuccessBannerVisible, handleIsolationActionSuccess } = useHostIsolation();

const { alertId, hostName } = useBasicDataFromDetailsData(dataFormattedForFieldBrowser);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useRuleDetailsLink } from '../../shared/hooks/use_rule_details_link';
import { DocumentStatus } from './status';
import { DocumentSeverity } from './severity';
import { RiskScore } from './risk_score';
import { useRefetchByScope } from '../../../../timelines/components/side_panel/event_details/flyout/use_refetch_by_scope';
import { useRefetchByScope } from '../hooks/use_refetch_by_scope';
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
import { useDocumentDetailsContext } from '../../shared/context';
import { PreferenceFormattedDate } from '../../../../common/components/formatted_date';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,58 @@ import React from 'react';
import type { ReactWrapper } from 'enzyme';
import { mount } from 'enzyme';
import { waitFor } from '@testing-library/react';

import type { TakeActionDropdownProps } from '.';
import { TakeActionDropdown } from '.';
import { generateAlertDetailsDataMock } from '../../../common/components/event_details/__mocks__';
import { getDetectionAlertMock } from '../../../common/mock/mock_detection_alerts';
import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy';
import { TimelineId } from '../../../../common/types/timeline';
import { TestProviders } from '../../../common/mock';
import { mockTimelines } from '../../../common/mock/mock_timelines_plugin';
import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock';
import { useHttp, useKibana } from '../../../common/lib/kibana';
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
import type { TakeActionDropdownProps } from './take_action_dropdown';
import { TakeActionDropdown } from './take_action_dropdown';
import { generateAlertDetailsDataMock } from '../../../../common/components/event_details/__mocks__';
import { getDetectionAlertMock } from '../../../../common/mock/mock_detection_alerts';
import { TimelineId } from '../../../../../common/types/timeline';
import { TestProviders } from '../../../../common/mock';
import { mockTimelines } from '../../../../common/mock/mock_timelines_plugin';
import { createStartServicesMock } from '../../../../common/lib/kibana/kibana_react.mock';
import { useHttp, useKibana } from '../../../../common/lib/kibana';
import { mockCasesContract } from '@kbn/cases-plugin/public/mocks';
import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../common/components/user_privileges/user_privileges_context';
import { useUserPrivileges } from '../../../common/components/user_privileges';
import { getUserPrivilegesMockDefaultValue } from '../../../common/components/user_privileges/__mocks__';
import { allCasesPermissions } from '../../../cases_test_utils';
import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../../common/components/user_privileges/user_privileges_context';
import { useUserPrivileges } from '../../../../common/components/user_privileges';
import { getUserPrivilegesMockDefaultValue } from '../../../../common/components/user_privileges/__mocks__';
import { allCasesPermissions } from '../../../../cases_test_utils';
import {
ALERT_ASSIGNEES_CONTEXT_MENU_ITEM_TITLE,
ALERT_TAGS_CONTEXT_MENU_ITEM_TITLE,
} from '../../../common/components/toolbar/bulk_actions/translations';
} from '../../../../common/components/toolbar/bulk_actions/translations';
import { FLYOUT_FOOTER_DEOPDOEN_BUTTON_TEST_ID } from '../test_ids';

jest.mock('../../../common/components/endpoint/host_isolation');
jest.mock('../../../common/components/endpoint/responder');
jest.mock('../../../common/components/user_privileges');
jest.mock('../../../../common/components/endpoint/host_isolation');
jest.mock('../../../../common/components/endpoint/responder');
jest.mock('../../../../common/components/user_privileges');

jest.mock('../user_info', () => ({
jest.mock('../../../../detections/components/user_info', () => ({
useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]),
}));

jest.mock('../../../common/lib/kibana');
jest.mock('../../../common/components/guided_onboarding_tour/tour_step');
jest.mock('../../../../common/lib/kibana');
jest.mock('../../../../common/components/guided_onboarding_tour/tour_step');

jest.mock('../../containers/detection_engine/alerts/use_alerts_privileges', () => ({
useAlertsPrivileges: jest.fn().mockReturnValue({ hasIndexWrite: true, hasKibanaCRUD: true }),
}));
jest.mock('../../../cases/components/use_insert_timeline');
jest.mock(
'../../../../detections/containers/detection_engine/alerts/use_alerts_privileges',
() => ({
useAlertsPrivileges: jest.fn().mockReturnValue({ hasIndexWrite: true, hasKibanaCRUD: true }),
})
);
jest.mock('../../../../cases/components/use_insert_timeline');

jest.mock('../../../common/hooks/use_app_toasts', () => ({
jest.mock('../../../../common/hooks/use_app_toasts', () => ({
useAppToasts: jest.fn().mockReturnValue({
addError: jest.fn(),
}),
}));

jest.mock('../../../common/hooks/use_license', () => ({
jest.mock('../../../../common/hooks/use_license', () => ({
useLicense: jest.fn().mockReturnValue({ isPlatinumPlus: () => true, isEnterprise: () => false }),
}));

jest.mock(
'../../../common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status',
'../../../../common/components/endpoint/host_isolation/from_alerts/use_host_isolation_status',
() => {
return {
useEndpointHostIsolationStatus: jest.fn().mockReturnValue({
Expand All @@ -74,11 +77,10 @@ describe('take action dropdown', () => {

beforeEach(() => {
defaultProps = {
detailsData: generateAlertDetailsDataMock() as TimelineEventsDetailsItem[],
ecsData: getDetectionAlertMock(),
dataFormattedForFieldBrowser: generateAlertDetailsDataMock() as TimelineEventsDetailsItem[],
dataAsNestedObject: getDetectionAlertMock(),
handleOnEventClosed: jest.fn(),
isHostIsolationPanelOpen: false,
loadingEventDetails: false,
onAddEventFilterClick: jest.fn(),
onAddExceptionTypeClick: jest.fn(),
onAddIsolationStatusClick: jest.fn(),
Expand Down Expand Up @@ -125,7 +127,9 @@ describe('take action dropdown', () => {
<TakeActionDropdown {...defaultProps} />
</TestProviders>
);
expect(wrapper.find('[data-test-subj="take-action-dropdown-btn"]').exists()).toBeTruthy();
expect(
wrapper.find(`[data-test-subj="${FLYOUT_FOOTER_DEOPDOEN_BUTTON_TEST_ID}"]`).exists()
).toBeTruthy();
});

test('should render takeActionButton with correct text', () => {
Expand All @@ -134,9 +138,9 @@ describe('take action dropdown', () => {
<TakeActionDropdown {...defaultProps} />
</TestProviders>
);
expect(wrapper.find('[data-test-subj="take-action-dropdown-btn"]').first().text()).toEqual(
'Take action'
);
expect(
wrapper.find(`[data-test-subj="${FLYOUT_FOOTER_DEOPDOEN_BUTTON_TEST_ID}"]`).first().text()
).toEqual('Take action');
});

describe('should render take action items', () => {
Expand All @@ -148,7 +152,9 @@ describe('take action dropdown', () => {
<TakeActionDropdown {...defaultProps} />
</TestProviders>
);
wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click');
wrapper
.find(`button[data-test-subj="${FLYOUT_FOOTER_DEOPDOEN_BUTTON_TEST_ID}"]`)
.simulate('click');
});
test('should render "Add to existing case"', async () => {
await waitFor(() => {
Expand Down Expand Up @@ -243,8 +249,8 @@ describe('take action dropdown', () => {
describe('for Endpoint related actions', () => {
/** Removes the detail data that is used to determine if data is for an Alert */
const setAlertDetailsDataMockToEvent = () => {
if (defaultProps.detailsData) {
defaultProps.detailsData = defaultProps.detailsData
if (defaultProps.dataFormattedForFieldBrowser) {
defaultProps.dataFormattedForFieldBrowser = defaultProps.dataFormattedForFieldBrowser
.map((obj) => {
if (obj.field === 'kibana.alert.rule.uuid') {
return null;
Expand All @@ -261,34 +267,36 @@ describe('take action dropdown', () => {
})
.filter((obj) => obj) as TimelineEventsDetailsItem[];
} else {
expect(defaultProps.detailsData).toBeInstanceOf(Object);
expect(defaultProps.dataFormattedForFieldBrowser).toBeInstanceOf(Object);
}
};

const setAgentTypeOnAlertDetailsDataMock = (agentType: string = 'endpoint') => {
if (defaultProps.detailsData) {
defaultProps.detailsData = defaultProps.detailsData.map((obj) => {
if (obj.field === 'agent.type') {
return {
category: 'agent',
field: 'agent.type',
values: [agentType],
originalValue: [agentType],
};
}
if (obj.field === 'agent.id') {
return {
category: 'agent',
field: 'agent.id',
values: ['123'],
originalValue: ['123'],
};
}
if (defaultProps.dataFormattedForFieldBrowser) {
defaultProps.dataFormattedForFieldBrowser = defaultProps.dataFormattedForFieldBrowser.map(
(obj) => {
if (obj.field === 'agent.type') {
return {
category: 'agent',
field: 'agent.type',
values: [agentType],
originalValue: [agentType],
};
}
if (obj.field === 'agent.id') {
return {
category: 'agent',
field: 'agent.id',
values: ['123'],
originalValue: ['123'],
};
}

return obj;
}) as TimelineEventsDetailsItem[];
return obj;
}
) as TimelineEventsDetailsItem[];
} else {
expect(defaultProps.detailsData).toBeInstanceOf(Object);
expect(defaultProps.dataFormattedForFieldBrowser).toBeInstanceOf(Object);
}
};

Expand All @@ -297,14 +305,14 @@ describe('take action dropdown', () => {
agentType: string = 'endpoint',
agentId: string = '123'
) => {
if (defaultProps.ecsData) {
defaultProps.ecsData.agent = {
if (defaultProps.dataAsNestedObject) {
defaultProps.dataAsNestedObject.agent = {
// @ts-expect-error Ecs definition for agent seems to be missing properties
id: agentId,
type: [agentType],
};
} else {
expect(defaultProps.ecsData).toBeInstanceOf(Object);
expect(defaultProps.dataAsNestedObject).toBeInstanceOf(Object);
}
};

Expand All @@ -316,7 +324,9 @@ describe('take action dropdown', () => {
<TakeActionDropdown {...defaultProps} />
</TestProviders>
);
wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click');
wrapper
.find(`button[data-test-subj="${FLYOUT_FOOTER_DEOPDOEN_BUTTON_TEST_ID}"]`)
.simulate('click');

return wrapper;
};
Expand Down
Loading

0 comments on commit a048ad1

Please sign in to comment.