[Security Solution] Disable renderer hover actions in the Rules preview flyout (#141546)

## [Security Solution] Disable hover actions on renderers in the Rules preview flyout

This PR addresses issue <https://github.com/elastic/kibana/issues/141026> by disabling hover actions on renderers in the  _Rules preview_ flyout, per the Before and After screenshots below:

### Before

![before](https://user-images.githubusercontent.com/4459398/191833235-ed9974d8-3d31-4da1-8db6-e5c500003f6b.png)

_Above: Before the fix, actions were displayed when hovering over a rendered field in the Rules preview flyout_

### After

![after](https://user-images.githubusercontent.com/4459398/191833522-427649ab-9670-48df-8a87-1980fe8e4070.png)

_Above: After the fix, actions are NOT displayed when hovering over a rendered field in the Rules preview flyout_
This commit is contained in:
Andrew Macri 2022-09-27 14:15:53 -06:00 committed by GitHub
parent 504d8c4c70
commit f571f80827
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 3 deletions

View file

@ -5,16 +5,24 @@
* 2.0.
*/
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { shallow } from 'enzyme';
import React from 'react';
import type { DraggableStateSnapshot, DraggingStyle } from 'react-beautiful-dnd';
import { waitFor } from '@testing-library/react';
import '../../mock/match_media';
import { TimelineId } from '../../../../common/types';
import { mockBrowserFields } from '../../containers/source/mock';
import { TestProviders } from '../../mock';
import { mockDataProviders } from '../../../timelines/components/timeline/data_providers/mock/mock_data_providers';
import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../../../timelines/components/row_renderers_browser/constants';
import { DragDropContextWrapper } from './drag_drop_context_wrapper';
import { ConditionalPortal, DraggableWrapper, getStyle } from './draggable_wrapper';
import {
ConditionalPortal,
disableHoverActions,
DraggableWrapper,
getStyle,
} from './draggable_wrapper';
import { useMountAppended } from '../../utils/use_mount_appended';
jest.mock('../../lib/kibana');
@ -27,6 +35,26 @@ jest.mock('@elastic/eui', () => {
};
});
const timelineIdsWithHoverActions = [
undefined,
TimelineId.active,
TimelineId.alternateTest,
TimelineId.casePage,
TimelineId.detectionsPage,
TimelineId.detectionsRulesDetailsPage,
TimelineId.hostsPageEvents,
TimelineId.hostsPageSessions,
TimelineId.kubernetesPageSessions,
TimelineId.networkPageEvents,
TimelineId.test,
TimelineId.usersPageEvents,
];
const timelineIdsNoHoverActions = [
TimelineId.rulePreview,
ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID,
];
describe('DraggableWrapper', () => {
const dataProvider = mockDataProviders[0];
const message = 'draggable wrapper content';
@ -36,6 +64,15 @@ describe('DraggableWrapper', () => {
jest.useFakeTimers();
});
afterEach(() => {
const portal = document.querySelector('[data-euiportal="true"]');
if (portal != null) {
portal.innerHTML = '';
}
jest.useRealTimers();
});
describe('rendering', () => {
test('it renders against the snapshot', () => {
const wrapper = shallow(
@ -103,6 +140,56 @@ describe('DraggableWrapper', () => {
expect(wrapper.find('[data-test-subj="hover-actions-copy-button"]').exists()).toBe(true);
});
});
timelineIdsWithHoverActions.forEach((timelineId) => {
test(`it renders hover actions (by default) when 'isDraggable' is false and timelineId is '${timelineId}'`, async () => {
const isDraggable = false;
const { container } = render(
<TestProviders>
<DragDropContextWrapper browserFields={mockBrowserFields}>
<DraggableWrapper
dataProvider={dataProvider}
isDraggable={isDraggable}
render={() => message}
timelineId={timelineId}
/>
</DragDropContextWrapper>
</TestProviders>
);
fireEvent.mouseEnter(container.querySelector('[data-test-subj="withHoverActionsButton"]')!);
await waitFor(() => {
expect(screen.getByTestId('hover-actions-copy-button')).toBeInTheDocument();
});
});
});
timelineIdsNoHoverActions.forEach((timelineId) => {
test(`it does NOT render hover actions when 'isDraggable' is false and timelineId is '${timelineId}'`, async () => {
const isDraggable = false;
const { container } = render(
<TestProviders>
<DragDropContextWrapper browserFields={mockBrowserFields}>
<DraggableWrapper
dataProvider={dataProvider}
isDraggable={isDraggable}
render={() => message}
timelineId={timelineId}
/>
</DragDropContextWrapper>
</TestProviders>
);
fireEvent.mouseEnter(container.querySelector('[data-test-subj="withHoverActionsButton"]')!);
await waitFor(() => {
expect(screen.queryByTestId('hover-actions-copy-button')).not.toBeInTheDocument();
});
});
});
});
describe('text truncation styling', () => {
@ -192,4 +279,18 @@ describe('ConditionalPortal', () => {
expect(getStyle(style, snapshot)).toHaveProperty('transitionDuration', '0.00000001s');
});
});
describe('disableHoverActions', () => {
timelineIdsNoHoverActions.forEach((timelineId) =>
test(`it returns true when timelineId is ${timelineId}`, () => {
expect(disableHoverActions(timelineId)).toBe(true);
})
);
timelineIdsWithHoverActions.forEach((timelineId) =>
test(`it returns false when timelineId is ${timelineId}`, () => {
expect(disableHoverActions(timelineId)).toBe(false);
})
);
});
});

View file

@ -18,6 +18,7 @@ import { Draggable, Droppable } from 'react-beautiful-dnd';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { TimelineId } from '../../../../common/types';
import { dragAndDropActions } from '../../store/drag_and_drop';
import type { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';
import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../../../timelines/components/row_renderers_browser/constants';
@ -108,6 +109,9 @@ interface Props {
onFilterAdded?: () => void;
}
export const disableHoverActions = (timelineId: string | undefined): boolean =>
[TimelineId.rulePreview, ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID].includes(timelineId ?? '');
/**
* Wraps a draggable component to handle registration / unregistration of the
* data provider associated with the item being dropped
@ -370,7 +374,7 @@ const DraggableWrapperComponent: React.FC<Props> = ({
<WithHoverActions
alwaysShow={showTopN || hoverActionsOwnFocus}
closePopOverTrigger={closePopOverTrigger}
hoverContent={hoverContent}
hoverContent={disableHoverActions(timelineId) ? undefined : hoverContent}
onCloseRequested={onCloseRequested}
render={renderContent}
/>