Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [Security Solution] Restores Alerts table local storage persistence and the Remove Column action (#114742) #115301

Merged
merged 1 commit into from
Oct 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export const alertsStackByOptions: AlertsStackByOption[] = [
{ text: 'signal.rule.name', value: 'signal.rule.name' },
{ text: 'source.ip', value: 'source.ip' },
{ text: 'user.name', value: 'user.name' },
{ text: 'process.name', value: 'process.name' },
{ text: 'file.name', value: 'file.name' },
{ text: 'hash.sha256', value: 'hash.sha256' },
];

export const DEFAULT_STACK_BY_FIELD = 'signal.rule.name';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ export type AlertsStackByField =
| 'signal.rule.type'
| 'signal.rule.name'
| 'source.ip'
| 'user.name';
| 'user.name'
| 'process.name'
| 'file.name'
| 'hash.sha256';
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export const {
setSelected,
setTGridSelectAll,
toggleDetailPanel,
updateColumnOrder,
updateColumns,
updateColumnWidth,
updateIsLoading,
updateItemsPerPage,
updateItemsPerPageOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import {
removeColumn,
upsertColumn,
applyDeltaToColumnWidth,
updateColumnOrder,
updateColumns,
updateColumnWidth,
updateItemsPerPage,
updateSort,
} from './actions';
Expand Down Expand Up @@ -168,4 +170,35 @@ describe('epicLocalStorage', () => {
);
await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled());
});

it('persists updates to the column order to local storage', async () => {
shallow(
<TestProviders store={store}>
<QueryTabContentComponent {...props} />
</TestProviders>
);
store.dispatch(
updateColumnOrder({
columnIds: ['event.severity', '@timestamp', 'event.category'],
id: 'test',
})
);
await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled());
});

it('persists updates to the column width to local storage', async () => {
shallow(
<TestProviders store={store}>
<QueryTabContentComponent {...props} />
</TestProviders>
);
store.dispatch(
updateColumnWidth({
columnId: 'event.severity',
id: 'test',
width: 123,
})
);
await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled());
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
applyDeltaToColumnWidth,
setExcludedRowRendererIds,
updateColumns,
updateColumnOrder,
updateColumnWidth,
updateItemsPerPage,
updateSort,
} from './actions';
Expand All @@ -30,6 +32,8 @@ const timelineActionTypes = [
upsertColumn.type,
applyDeltaToColumnWidth.type,
updateColumns.type,
updateColumnOrder.type,
updateColumnWidth.type,
updateItemsPerPage.type,
updateSort.type,
setExcludedRowRendererIds.type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
id: 0,
items: [
{
icon: <EuiIcon type="eyeClosed" size="s" />,
name: i18n.HIDE_COLUMN,
icon: <EuiIcon type="cross" size="s" />,
name: i18n.REMOVE_COLUMN,
onClick: () => {
dispatch(tGridActions.removeColumn({ id: timelineId, columnId: header.id }));
handleClosePopOverTrigger();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ describe('helpers', () => {
describe('getColumnHeaders', () => {
// additional properties used by `EuiDataGrid`:
const actions = {
showHide: false,
showSortAsc: true,
showSortDesc: true,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { allowSorting } from '../helpers';
const defaultActions: EuiDataGridColumnActions = {
showSortAsc: true,
showSortDesc: true,
showHide: false,
};

const getAllBrowserFields = (browserFields: BrowserFields): Array<Partial<BrowserField>> =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ export const FULL_SCREEN = i18n.translate('xpack.timelines.timeline.fullScreenBu
defaultMessage: 'Full screen',
});

export const HIDE_COLUMN = i18n.translate('xpack.timelines.timeline.hideColumnLabel', {
defaultMessage: 'Hide column',
});

export const SORT_AZ = i18n.translate('xpack.timelines.timeline.sortAZLabel', {
defaultMessage: 'Sort A-Z',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
*/

import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';

import { BodyComponent, StatefulBodyProps } from '.';
import { Sort } from './sort';
import { REMOVE_COLUMN } from './column_headers/translations';
import { Direction } from '../../../../common/search_strategy';
import { useMountAppended } from '../../utils/use_mount_appended';
import { defaultHeaders, mockBrowserFields, mockTimelineData, TestProviders } from '../../../mock';
Expand Down Expand Up @@ -273,4 +275,57 @@ describe('Body', () => {
.find((c) => c.id === 'signal.rule.risk_score')?.cellActions
).toBeUndefined();
});

test('it does NOT render switches for hiding columns in the `EuiDataGrid` `Columns` popover', async () => {
render(
<TestProviders>
<BodyComponent {...props} />
</TestProviders>
);

// Click the `EuidDataGrid` `Columns` button to open the popover:
fireEvent.click(screen.getByTestId('dataGridColumnSelectorButton'));

// `EuiDataGrid` renders switches for hiding in the `Columns` popover when `showColumnSelector.allowHide` is `true`
const switches = await screen.queryAllByRole('switch');

expect(switches.length).toBe(0); // no switches are rendered, because `allowHide` is `false`
});

test('it dispatches the `REMOVE_COLUMN` action when a user clicks `Remove column` in the column header popover', async () => {
render(
<TestProviders>
<BodyComponent {...props} />
</TestProviders>
);

// click the `@timestamp` column header to display the popover
fireEvent.click(screen.getByText('@timestamp'));

// click the `Remove column` action in the popover
fireEvent.click(await screen.getByText(REMOVE_COLUMN));

expect(mockDispatch).toBeCalledWith({
payload: { columnId: '@timestamp', id: 'timeline-test' },
type: 'x-pack/timelines/t-grid/REMOVE_COLUMN',
});
});

test('it dispatches the `UPDATE_COLUMN_WIDTH` action when a user resizes a column', async () => {
render(
<TestProviders>
<BodyComponent {...props} />
</TestProviders>
);

// simulate resizing the column
fireEvent.mouseDown(screen.getAllByTestId('dataGridColumnResizer')[0]);
fireEvent.mouseMove(screen.getAllByTestId('dataGridColumnResizer')[0]);
fireEvent.mouseUp(screen.getAllByTestId('dataGridColumnResizer')[0]);

expect(mockDispatch).toBeCalledWith({
payload: { columnId: '@timestamp', id: 'timeline-test', width: NaN },
type: 'x-pack/timelines/t-grid/UPDATE_COLUMN_WIDTH',
});
});
});
52 changes: 43 additions & 9 deletions x-pack/plugins/timelines/public/components/t_grid/body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import { ViewSelection } from '../event_rendered_view/selector';
import { EventRenderedView } from '../event_rendered_view';
import { useDataGridHeightHack } from './height_hack';
import { Filter } from '../../../../../../../src/plugins/data/public';
import { REMOVE_COLUMN } from './column_headers/translations';

const StatefulAlertStatusBulkActions = lazy(
() => import('../toolbar/bulk_actions/alert_status_bulk_actions')
Expand Down Expand Up @@ -497,7 +498,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
showFullScreenSelector: false,
}
: {
showColumnSelector: { allowHide: true, allowReorder: true },
showColumnSelector: { allowHide: false, allowReorder: true },
showSortSelector: true,
showFullScreenSelector: true,
}),
Expand Down Expand Up @@ -559,13 +560,32 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
[columnHeaders, dispatch, id, loadPage]
);

const [visibleColumns, setVisibleColumns] = useState(() =>
columnHeaders.map(({ id: cid }) => cid)
); // initializes to the full set of columns
const visibleColumns = useMemo(() => columnHeaders.map(({ id: cid }) => cid), [columnHeaders]); // the full set of columns

useEffect(() => {
setVisibleColumns(columnHeaders.map(({ id: cid }) => cid));
}, [columnHeaders]);
const onColumnResize = useCallback(
({ columnId, width }: { columnId: string; width: number }) => {
dispatch(
tGridActions.updateColumnWidth({
columnId,
id,
width,
})
);
},
[dispatch, id]
);

const onSetVisibleColumns = useCallback(
(newVisibleColumns: string[]) => {
dispatch(
tGridActions.updateColumnOrder({
columnIds: newVisibleColumns,
id,
})
);
},
[dispatch, id]
);

const setEventsLoading = useCallback<SetEventsLoading>(
({ eventIds, isLoading: loading }) => {
Expand Down Expand Up @@ -654,6 +674,19 @@ export const BodyComponent = React.memo<StatefulBodyProps>(

return {
...header,
actions: {
...header.actions,
additional: [
{
iconType: 'cross',
label: REMOVE_COLUMN,
onClick: () => {
dispatch(tGridActions.removeColumn({ id, columnId: header.id }));
},
size: 'xs',
},
],
},
...(hasCellActions(header.id)
? {
cellActions:
Expand All @@ -663,7 +696,7 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
: {}),
};
}),
[columnHeaders, defaultCellActions, browserFields, data, pageSize, id]
[columnHeaders, defaultCellActions, browserFields, data, pageSize, id, dispatch]
);

const renderTGridCellValue = useMemo(() => {
Expand Down Expand Up @@ -761,14 +794,15 @@ export const BodyComponent = React.memo<StatefulBodyProps>(
data-test-subj="body-data-grid"
aria-label={i18n.TGRID_BODY_ARIA_LABEL}
columns={columnsWithCellActions}
columnVisibility={{ visibleColumns, setVisibleColumns }}
columnVisibility={{ visibleColumns, setVisibleColumns: onSetVisibleColumns }}
gridStyle={gridStyle}
leadingControlColumns={leadingTGridControlColumns}
trailingControlColumns={trailingTGridControlColumns}
toolbarVisibility={toolbarVisibility}
rowCount={totalItems}
renderCellValue={renderTGridCellValue}
sorting={{ columns: sortingColumns, onSort }}
onColumnResize={onColumnResize}
pagination={{
pageIndex: activePage,
pageSize,
Expand Down
11 changes: 11 additions & 0 deletions x-pack/plugins/timelines/public/store/t_grid/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ export const applyDeltaToColumnWidth = actionCreator<{
delta: number;
}>('APPLY_DELTA_TO_COLUMN_WIDTH');

export const updateColumnOrder = actionCreator<{
columnIds: string[];
id: string;
}>('UPDATE_COLUMN_ORDER');

export const updateColumnWidth = actionCreator<{
columnId: string;
id: string;
width: number;
}>('UPDATE_COLUMN_WIDTH');

export type ToggleDetailPanel = TimelineExpandedDetailType & {
tabType?: TimelineTabs;
timelineId: string;
Expand Down
Loading