Skip to content

Commit

Permalink
[Security Solution] flyout UI adjustment (#108192) (#108677)
Browse files Browse the repository at this point in the history
* styling

* fix hover actions

* init overflow button for flyout

* init overflow button

* topN btn

* remove popover from topN

* fix tests

* fix unit test

* add use hover action items hook

* fix for code review

Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Angela Chuang <[email protected]>
  • Loading branch information
kibanamachine and angorayc authored Aug 16, 2021
1 parent 1218000 commit 5e0a92f
Show file tree
Hide file tree
Showing 24 changed files with 741 additions and 227 deletions.
4 changes: 4 additions & 0 deletions x-pack/plugins/security_solution/cypress/screens/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export const ID_FIELD = '[data-test-subj="timeline"] [data-test-subj="field-name

export const ID_TOGGLE_FIELD = '[data-test-subj="toggle-field-_id"]';

export const ID_HOVER_ACTION_OVERFLOW_BTN = '[data-test-subj="more-actions-_id"]';

export const LOCKED_ICON = '[data-test-subj="timeline-date-picker-lock-button"]';

export const UNLOCKED_ICON = '[data-test-subj="timeline-date-picker-unlock-button"]';
Expand Down Expand Up @@ -266,3 +268,5 @@ export const TIMELINE_TAB_CONTENT_PINNED = '[data-test-subj="timeline-tab-conten

export const TIMELINE_TAB_CONTENT_GRAPHS_NOTES =
'[data-test-subj="timeline-tab-content-graph-notes"]';

export const TIMESTAMP_HOVER_ACTION_OVERFLOW_BTN = '[data-test-subj="more-actions-@timestamp"]';
17 changes: 17 additions & 0 deletions x-pack/plugins/security_solution/cypress/tasks/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ID_FIELD,
ID_HEADER_FIELD,
ID_TOGGLE_FIELD,
ID_HOVER_ACTION_OVERFLOW_BTN,
NOTES_TAB_BUTTON,
NOTES_TEXT_AREA,
OPEN_TIMELINE_ICON,
Expand Down Expand Up @@ -63,6 +64,7 @@ import {
TIMELINE_CREATE_TEMPLATE_FROM_TIMELINE_BTN,
TIMELINE_COLLAPSED_ITEMS_BTN,
TIMELINE_TAB_CONTENT_EQL,
TIMESTAMP_HOVER_ACTION_OVERFLOW_BTN,
} from '../screens/timeline';
import { REFRESH_BUTTON, TIMELINE } from '../screens/timelines';

Expand Down Expand Up @@ -188,7 +190,14 @@ export const attachTimelineToExistingCase = () => {
cy.get(ATTACH_TIMELINE_TO_EXISTING_CASE_ICON).click({ force: true });
};

const clickIdHoverActionOverflowButton = () => {
cy.get(ID_HOVER_ACTION_OVERFLOW_BTN).should('exist');

cy.get(ID_HOVER_ACTION_OVERFLOW_BTN).click({ force: true });
};

export const clickIdToggleField = () => {
clickIdHoverActionOverflowButton();
cy.get(ID_HEADER_FIELD).should('not.exist');

cy.get(ID_TOGGLE_FIELD).click({
Expand Down Expand Up @@ -293,7 +302,15 @@ export const unpinFirstEvent = () => {
cy.get(PIN_EVENT).first().click({ force: true });
};

const clickTimestampHoverActionOverflowButton = () => {
cy.get(TIMESTAMP_HOVER_ACTION_OVERFLOW_BTN).should('exist');

cy.get(TIMESTAMP_HOVER_ACTION_OVERFLOW_BTN).click({ force: true });
};

export const clickTimestampToggleField = () => {
clickTimestampHoverActionOverflowButton();

cy.get(TIMESTAMP_TOGGLE_FIELD).should('exist');

cy.get(TIMESTAMP_TOGGLE_FIELD).click({ force: true });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { TestProviders } from '../../mock';
import { useMountAppended } from '../../utils/use_mount_appended';
import { mockBrowserFields } from '../../containers/source/mock';
import { EventFieldsData } from './types';
import { get } from 'lodash/fp';

jest.mock('../../lib/kibana');
interface Column {
Expand Down Expand Up @@ -78,13 +79,13 @@ describe('getColumns', () => {
});
});

describe('add to timeline', () => {
test('it renders an add to timeline button', () => {
describe('overflow button', () => {
test('it renders an overflow button', () => {
const wrapper = mount(
<TestProviders>{actionsColumn.render(testValue, testData)}</TestProviders>
) as ReactWrapper;

expect(wrapper.find('[data-test-subj="hover-actions-add-timeline"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="more-actions-agent.id"]').exists()).toBeTruthy();
});
});

Expand All @@ -95,8 +96,32 @@ describe('getColumns', () => {
) as ReactWrapper;

expect(
wrapper.find('[data-test-subj="hover-actions-toggle-column"]').exists()
).toBeTruthy();
get(['items', 0, 'key'], wrapper.find('[data-test-subj="more-actions-agent.id"]').props())
).toEqual('hover-actions-toggle-column');
});
});

describe('add to timeline', () => {
test('it renders an add to timeline button', () => {
const wrapper = mount(
<TestProviders>{actionsColumn.render(testValue, testData)}</TestProviders>
) as ReactWrapper;

expect(
get(['items', 1, 'key'], wrapper.find('[data-test-subj="more-actions-agent.id"]').props())
).toEqual('hover-actions-add-timeline');
});
});

describe('topN', () => {
test('it renders a show topN button', () => {
const wrapper = mount(
<TestProviders>{actionsColumn.render(testValue, testData)}</TestProviders>
) as ReactWrapper;

expect(
get(['items', 2, 'key'], wrapper.find('[data-test-subj="more-actions-agent.id"]').props())
).toEqual('hover-actions-show-top-n');
});
});

Expand All @@ -106,7 +131,9 @@ describe('getColumns', () => {
<TestProviders>{actionsColumn.render(testValue, testData)}</TestProviders>
) as ReactWrapper;

expect(wrapper.find('[data-test-subj="hover-actions-copy-button"]').exists()).toBeTruthy();
expect(
get(['items', 3, 'key'], wrapper.find('[data-test-subj="more-actions-agent.id"]').props())
).toEqual('hover-actions-copy-button');
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { EventFieldsBrowser } from './event_fields_browser';
import { mockBrowserFields } from '../../containers/source/mock';
import { useMountAppended } from '../../utils/use_mount_appended';
import { TimelineTabs } from '../../../../common/types/timeline';
import { get } from 'lodash/fp';

jest.mock('../../lib/kibana');

Expand Down Expand Up @@ -116,7 +117,7 @@ describe('EventFieldsBrowser', () => {
expect(wrapper.find('[data-test-subj="hover-actions-filter-out"]').exists()).toBeTruthy();
});

test('it renders an add to timeline button', () => {
test('it renders an overflow button', () => {
const wrapper = mount(
<TestProviders>
<EventFieldsBrowser
Expand All @@ -129,7 +130,7 @@ describe('EventFieldsBrowser', () => {
</TestProviders>
);

expect(wrapper.find('[data-test-subj="hover-actions-add-timeline"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="more-actions-@timestamp"]').exists()).toBeTruthy();
});

test('it renders a column toggle button', () => {
Expand All @@ -146,8 +147,26 @@ describe('EventFieldsBrowser', () => {
);

expect(
wrapper.find('[data-test-subj="hover-actions-toggle-column"]').first().exists()
).toBeTruthy();
get(['items', 0, 'key'], wrapper.find('[data-test-subj="more-actions-@timestamp"]').props())
).toEqual('hover-actions-toggle-column');
});

test('it renders an add to timeline button', () => {
const wrapper = mount(
<TestProviders>
<EventFieldsBrowser
browserFields={mockBrowserFields}
data={mockDetailItemData}
eventId={eventId}
timelineId="test"
timelineTabType={TimelineTabs.query}
/>
</TestProviders>
);

expect(
get(['items', 1, 'key'], wrapper.find('[data-test-subj="more-actions-@timestamp"]').props())
).toEqual('hover-actions-add-timeline');
});

test('it renders a copy button', () => {
Expand All @@ -163,7 +182,9 @@ describe('EventFieldsBrowser', () => {
</TestProviders>
);

expect(wrapper.find('[data-test-subj="hover-actions-copy-button"]').exists()).toBeTruthy();
expect(
get(['items', 2, 'key'], wrapper.find('[data-test-subj="more-actions-@timestamp"]').props())
).toEqual('hover-actions-copy-button');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,13 @@ const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)`
font-size: ${({ theme }) => theme.eui.euiFontSizeXS};
font-family: ${({ theme }) => theme.eui.euiCodeFontFamily};
.eventFieldsTable__hoverActionButtons {
&:focus-within {
.timelines__hoverActionButton,
.securitySolution__hoverActionButton {
opacity: 1;
}
.hoverActions-active {
.timelines__hoverActionButton,
.securitySolution__hoverActionButton {
opacity: 1;
}
}
&:hover {
.timelines__hoverActionButton,
.securitySolution__hoverActionButton {
Expand All @@ -110,9 +109,6 @@ const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)`
opacity: 0;
} */
opacity: 0;
&:focus {
opacity: 1;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ export const getSummaryColumns = (
name: '',
},
{
className: 'flyoutOverviewDescription',
field: 'description',
truncateText: false,
render: DescriptionComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ export const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)`
.euiTableHeaderCell .euiTableCellContent {
padding: 0;
}
.flyoutOverviewDescription {
.hoverActions-active {
.timelines__hoverActionButton,
.securitySolution__hoverActionButton {
opacity: 1;
}
}
&:hover {
.timelines__hoverActionButton,
.securitySolution__hoverActionButton {
opacity: 1;
}
}
}
`;

export const SummaryViewComponent: React.FC<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,16 @@ export const ActionCell: React.FC<Props> = React.memo(
});
}, []);

const closeTopN = useCallback(() => {
setShowTopN(false);
}, []);

return (
<HoverActions
closeTopN={closeTopN}
dataType={data.type}
dataProvider={actionCellConfig?.dataProvider}
enableOverflowButton={true}
field={data.field}
goGetTimelineId={setGoGetTimelineId}
isObjectArray={data.isObjectArray}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import React, { useMemo } from 'react';
import { EuiButtonEmpty, EuiButtonIcon, EuiPopover, EuiToolTip } from '@elastic/eui';
import { EuiButtonEmpty, EuiButtonIcon, EuiContextMenuItem, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { StatefulTopN } from '../../top_n';
import { TimelineId } from '../../../../../common/types/timeline';
Expand All @@ -24,7 +24,7 @@ const SHOW_TOP = (fieldName: string) =>

interface Props {
/** `Component` is only used with `EuiDataGrid`; the grid keeps a reference to `Component` for show / hide functionality */
Component?: typeof EuiButtonEmpty | typeof EuiButtonIcon;
Component?: typeof EuiButtonEmpty | typeof EuiButtonIcon | typeof EuiContextMenuItem;
field: string;
onClick: () => void;
onFilterAdded?: () => void;
Expand Down Expand Up @@ -64,6 +64,7 @@ export const ShowTopNButton: React.FC<Props> = React.memo(
<Component
aria-label={SHOW_TOP(field)}
data-test-subj="show-top-field"
icon="visBarVertical"
iconType="visBarVertical"
onClick={onClick}
title={SHOW_TOP(field)}
Expand All @@ -84,17 +85,15 @@ export const ShowTopNButton: React.FC<Props> = React.memo(
);

return showTopN ? (
<EuiPopover button={button} isOpen={showTopN} closePopover={onClick}>
<StatefulTopN
browserFields={browserFields}
field={field}
indexPattern={indexPattern}
onFilterAdded={onFilterAdded}
timelineId={timelineId ?? undefined}
toggleTopN={onClick}
value={value}
/>
</EuiPopover>
<StatefulTopN
browserFields={browserFields}
field={field}
indexPattern={indexPattern}
onFilterAdded={onFilterAdded}
timelineId={timelineId ?? undefined}
toggleTopN={onClick}
value={value}
/>
) : showTooltip ? (
<EuiToolTip
content={
Expand Down
Loading

0 comments on commit 5e0a92f

Please sign in to comment.