[Security Solutions][Timeline] Added createFrom in action to hide (#98144)

* added createFrom in action to hide

* prettier configured

* tests to check timeline modal table actions

* test changes and contant extract

* removed unused dependency

* prevent adding empty column to timeline table when no action need

* test updated

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Sergi Massaneda 2021-04-29 10:22:15 +02:00 committed by GitHub
parent 42d361c644
commit 3f48479376
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 41 deletions

View file

@ -6,14 +6,38 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { mount, shallow } from 'enzyme';
import { QueryBarDefineRule } from './index';
import { useFormFieldMock } from '../../../../common/mock';
import {
TestProviders,
useFormFieldMock,
mockOpenTimelineQueryResults,
} from '../../../../common/mock';
import { mockHistory, Router } from '../../../../cases/components/__mock__/router';
import { useGetAllTimeline, getAllTimeline } from '../../../../timelines/containers/all';
jest.mock('../../../../common/lib/kibana');
jest.mock('../../../../timelines/containers/all', () => {
const originalModule = jest.requireActual('../../../../timelines/containers/all');
return {
...originalModule,
useGetAllTimeline: jest.fn(),
};
});
describe('QueryBarDefineRule', () => {
beforeEach(() => {
((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({
fetchAllTimeline: jest.fn(),
timelines: getAllTimeline('', mockOpenTimelineQueryResults.timeline ?? []),
loading: false,
totalCount: mockOpenTimelineQueryResults.totalCount,
refetch: jest.fn(),
});
});
it('renders correctly', () => {
const Component = () => {
const field = useFormFieldMock();
@ -32,7 +56,35 @@ describe('QueryBarDefineRule', () => {
);
};
const wrapper = shallow(<Component />);
expect(wrapper.dive().find('[data-test-subj="query-bar-define-rule"]')).toHaveLength(1);
});
it('renders import query from saved timeline modal actions hidden correctly', () => {
const Component = () => {
const field = useFormFieldMock();
return (
<QueryBarDefineRule
browserFields={{}}
isLoading={false}
indexPattern={{ fields: [], title: 'title' }}
onCloseTimelineSearch={jest.fn()}
openTimelineSearch={true}
dataTestSubj="query-bar-define-rule"
idAria="idAria"
field={field}
/>
);
};
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<Component />
</Router>
</TestProviders>
);
expect(wrapper.find('[data-test-subj="open-duplicate"]').exists()).toBeFalsy();
expect(wrapper.find('[data-test-subj="create-from-template"]').exists()).toBeFalsy();
});
});

View file

@ -6,7 +6,7 @@
*/
import { EuiFormRow, EuiMutationObserver } from '@elastic/eui';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { Subscription } from 'rxjs';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
@ -50,6 +50,8 @@ interface QueryBarDefineRuleProps {
onValidityChange?: (arg: boolean) => void;
}
const actionTimelineToHide: ActionTimelineToShow[] = ['duplicate', 'createFrom'];
const StyledEuiFormRow = styled(EuiFormRow)`
.kbnTypeahead__items {
max-height: 45vh !important;
@ -253,8 +255,6 @@ export const QueryBarDefineRule = ({
}
};
const actionTimelineToHide = useMemo<ActionTimelineToShow[]>(() => ['duplicate'], []);
return (
<>
<StyledEuiFormRow

View file

@ -12,11 +12,38 @@ import { waitFor } from '@testing-library/react';
import { AddTimelineButton } from './';
import { useKibana } from '../../../../common/lib/kibana';
import { TimelineId } from '../../../../../common/types/timeline';
import { mockOpenTimelineQueryResults, TestProviders } from '../../../../common/mock';
import { mockHistory, Router } from '../../../../cases/components/__mock__/router';
import { getAllTimeline, useGetAllTimeline } from '../../../containers/all';
jest.mock('../../../../common/lib/kibana', () => ({
useKibana: jest.fn(),
useUiSetting$: jest.fn().mockReturnValue([]),
}));
jest.mock('../../open_timeline/use_timeline_status', () => {
const originalModule = jest.requireActual('../../open_timeline/use_timeline_status');
return {
...originalModule,
useTimelineStatus: jest.fn().mockReturnValue({
timelineStatus: 'active',
templateTimelineFilter: [],
installPrepackagedTimelines: jest.fn(),
}),
};
});
jest.mock('../../../../common/lib/kibana', () => {
const originalModule = jest.requireActual('../../../../common/lib/kibana');
return {
...originalModule,
useKibana: jest.fn(),
useUiSetting$: jest.fn().mockReturnValue([]),
};
});
jest.mock('../../../containers/all', () => {
const originalModule = jest.requireActual('../../../containers/all');
return {
...originalModule,
useGetAllTimeline: jest.fn(),
};
});
jest.mock('../../timeline/properties/new_template_timeline', () => ({
NewTemplateTimeline: jest.fn(() => <div data-test-subj="create-template-btn" />),
@ -35,8 +62,7 @@ jest.mock('../../../../common/components/inspect', () => ({
InspectButtonContainer: jest.fn(({ children }) => <div>{children}</div>),
}));
// FLAKY: https://github.com/elastic/kibana/issues/96691
describe.skip('AddTimelineButton', () => {
describe('AddTimelineButton', () => {
let wrapper: ReactWrapper;
const props = {
timelineId: TimelineId.active,
@ -67,24 +93,24 @@ describe.skip('AddTimelineButton', () => {
});
test('it renders create timeline btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy()
);
});
test('it renders create timeline template btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy()
);
});
test('it renders Open timeline btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy()
);
});
});
@ -113,24 +139,86 @@ describe.skip('AddTimelineButton', () => {
});
test('it renders create timeline btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy()
);
});
test('it renders create timeline template btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy()
);
});
test('it renders Open timeline btn', async () => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy()
);
});
});
describe('open modal', () => {
beforeEach(() => {
(useKibana as jest.Mock).mockReturnValue({
services: {
application: {
getUrlForApp: jest.fn(),
capabilities: {
siem: {
crud: true,
},
},
},
},
});
((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({
fetchAllTimeline: jest.fn(),
timelines: getAllTimeline('', mockOpenTimelineQueryResults.timeline ?? []),
loading: false,
totalCount: mockOpenTimelineQueryResults.totalCount,
refetch: jest.fn(),
});
wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<AddTimelineButton {...props} />
</Router>
</TestProviders>
);
});
afterEach(() => {
(useKibana as jest.Mock).mockReset();
});
it('should render timelines table', async () => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="open-timeline-button"]').first().simulate('click');
await waitFor(() => {
expect(wrapper.find('[data-test-subj="timelines-table"]').exists()).toBeTruthy();
});
});
it('should render correct actions', async () => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy()
);
wrapper.find('[data-test-subj="open-timeline-button"]').first().simulate('click');
await waitFor(() => {
expect(wrapper.find('[data-test-subj="open-duplicate"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="create-from-template"]').exists()).toBeFalsy();
});
});
});
});

View file

@ -10,6 +10,7 @@ import React, { useCallback, useMemo, useState } from 'react';
import { OpenTimelineModalButton } from '../../open_timeline/open_timeline_modal/open_timeline_modal_button';
import { OpenTimelineModal } from '../../open_timeline/open_timeline_modal';
import { ActionTimelineToShow } from '../../open_timeline/types';
import * as i18n from '../../timeline/properties/translations';
import { NewTimeline } from '../../timeline/properties/helpers';
import { NewTemplateTimeline } from '../../timeline/properties/new_template_timeline';
@ -20,6 +21,8 @@ interface AddTimelineButtonComponentProps {
export const ADD_TIMELINE_BUTTON_CLASS_NAME = 'add-timeline-button';
const actionTimelineToHide: ActionTimelineToShow[] = ['createFrom'];
const AddTimelineButtonComponent: React.FC<AddTimelineButtonComponentProps> = ({ timelineId }) => {
const [showActions, setShowActions] = useState(false);
const [showTimelineModal, setShowTimelineModal] = useState(false);
@ -83,7 +86,9 @@ const AddTimelineButtonComponent: React.FC<AddTimelineButtonComponentProps> = ({
</EuiPopover>
</EuiFlexItem>
{showTimelineModal ? <OpenTimelineModal onClose={onCloseTimelineModal} /> : null}
{showTimelineModal ? (
<OpenTimelineModal onClose={onCloseTimelineModal} hideActions={actionTimelineToHide} />
) : null}
</>
);
};

View file

@ -83,13 +83,15 @@ export const getTimelinesTableColumns = ({
}),
...getExtendedColumns(showExtendedColumns),
...getIconHeaderColumns({ timelineType }),
...getActionsColumns({
actionTimelineToShow,
deleteTimelines,
enableExportTimelineDownloader,
onOpenDeleteTimelineModal,
onOpenTimeline,
}),
...(actionTimelineToShow.length
? getActionsColumns({
actionTimelineToShow,
deleteTimelines,
enableExportTimelineDownloader,
onOpenDeleteTimelineModal,
onOpenTimeline,
})
: []),
];
};