[RAC] Updates Alerts table cell actions (#116446)

* Adds Filter Out button to alert table cell flyout

* Adds translations

* Fixes capitalization of labels

* Removes unused declarations and imports

* Fixes and adds functional tests for Alerts table action buttons

* Addresses review comments

* Fixes Alert table cell actions functional tests

* Removes Filter out action for now

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Claudio Procida 2021-11-02 17:43:24 +01:00 committed by GitHub
parent e53771df2d
commit c149fe6f92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 20 additions and 66 deletions

View file

@ -7,58 +7,16 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { ObservabilityPublicPluginsStart } from '../..';
import { getMappedNonEcsValue } from './render_cell_value';
import FilterForValueButton from './filter_for_value';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { TimelineNonEcsData } from '../../../../timelines/common/search_strategy';
import { TGridCellAction } from '../../../../timelines/common/types/timeline';
import { getPageRowIndex, TimelinesUIStart } from '../../../../timelines/public';
import { getPageRowIndex } from '../../../../timelines/public';
export const FILTER_FOR_VALUE = i18n.translate('xpack.observability.hoverActions.filterForValue', {
defaultMessage: 'Filter for value',
});
/** a hook to eliminate the verbose boilerplate required to use common services */
const useKibanaServices = () => {
const { timelines } = useKibana<{ timelines: TimelinesUIStart }>().services;
const {
services: {
data: {
query: { filterManager },
},
},
} = useKibana<ObservabilityPublicPluginsStart>();
return { timelines, filterManager };
};
/** actions common to all cells (e.g. copy to clipboard) */
const commonCellActions: TGridCellAction[] = [
({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) =>
({ rowIndex, columnId, Component }) => {
const { timelines } = useKibanaServices();
const value = getMappedNonEcsValue({
data: data[getPageRowIndex(rowIndex, pageSize)],
fieldName: columnId,
});
return (
<>
{timelines.getHoverActions().getCopyButton({
Component,
field: columnId,
isHoverAction: false,
ownFocus: false,
showTooltip: false,
value,
})}
</>
);
},
];
/** actions for adding filters to the search bar */
const buildFilterCellActions = (addToQuery: (value: string) => void): TGridCellAction[] => [
({ data, pageSize }: { data: TimelineNonEcsData[][]; pageSize: number }) =>
@ -80,7 +38,5 @@ const buildFilterCellActions = (addToQuery: (value: string) => void): TGridCellA
];
/** returns the default actions shown in `EuiDataGrid` cells */
export const getDefaultCellActions = ({ addToQuery }: { addToQuery: (value: string) => void }) => [
...buildFilterCellActions(addToQuery),
...commonCellActions,
];
export const getDefaultCellActions = ({ addToQuery }: { addToQuery: (value: string) => void }) =>
buildFilterCellActions(addToQuery);

View file

@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n';
export const filterForValueButtonLabel = i18n.translate(
'xpack.observability.hoverActions.filterForValueButtonLabel',
{
defaultMessage: 'Filter for value',
defaultMessage: 'Filter in',
}
);

View file

@ -146,7 +146,14 @@ const EuiDataGridContainer = styled.div<{ hideLastPage: boolean }>`
}
`;
const FIELDS_WITHOUT_CELL_ACTIONS = ['@timestamp', 'signal.rule.risk_score', 'signal.reason'];
// TODO: accept extra list of column ids without actions from callsites
const FIELDS_WITHOUT_CELL_ACTIONS = [
'@timestamp',
'signal.rule.risk_score',
'signal.reason',
'kibana.alert.duration.us',
'kibana.alert.reason',
];
const hasCellActions = (columnId?: string) =>
columnId && FIELDS_WITHOUT_CELL_ACTIONS.indexOf(columnId) < 0;
const transformControlColumns = ({

View file

@ -16,7 +16,7 @@ const DATE_WITH_DATA = {
};
const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout';
const COPY_TO_CLIPBOARD_BUTTON_SELECTOR = 'copy-to-clipboard';
const FILTER_FOR_VALUE_BUTTON_SELECTOR = 'filter-for-value';
const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel';
const ACTION_COLUMN_INDEX = 1;
@ -149,16 +149,12 @@ export function ObservabilityAlertsCommonProvider({
// Cell actions
const copyToClipboardButtonExists = async () => {
return await testSubjects.exists(COPY_TO_CLIPBOARD_BUTTON_SELECTOR);
};
const getCopyToClipboardButton = async () => {
return await testSubjects.find(COPY_TO_CLIPBOARD_BUTTON_SELECTOR);
const filterForValueButtonExists = async () => {
return await testSubjects.exists(FILTER_FOR_VALUE_BUTTON_SELECTOR);
};
const getFilterForValueButton = async () => {
return await testSubjects.find('filter-for-value');
return await testSubjects.find(FILTER_FOR_VALUE_BUTTON_SELECTOR);
};
const openActionsMenuForRow = async (rowIndex: number) => {
@ -216,15 +212,14 @@ export function ObservabilityAlertsCommonProvider({
getQueryBar,
clearQueryBar,
closeAlertsFlyout,
filterForValueButtonExists,
getAlertsFlyout,
getAlertsFlyoutDescriptionListDescriptions,
getAlertsFlyoutDescriptionListTitles,
getAlertsFlyoutOrFail,
getAlertsFlyoutTitle,
getAlertsFlyoutViewInAppButtonOrFail,
getCopyToClipboardButton,
getFilterForValueButton,
copyToClipboardButtonExists,
getNoDataPageOrFail,
getNoDataStateOrFail,
getTableCells,

View file

@ -189,19 +189,15 @@ export default ({ getService }: FtrProviderContext) => {
await alertStatusCell.moveMouseTo();
await retry.waitFor(
'cell actions visible',
async () => await observability.alerts.common.copyToClipboardButtonExists()
async () => await observability.alerts.common.filterForValueButtonExists()
);
});
});
afterEach(async () => {
await observability.alerts.common.clearQueryBar();
});
it('Copy button works', async () => {
// NOTE: We don't have access to the clipboard in a headless environment,
// so we'll just check the button is clickable in the functional tests.
await (await observability.alerts.common.getCopyToClipboardButton()).click();
// Reset the query bar by hiding the dropdown
await observability.alerts.common.submitQuery('');
});
it('Filter for value works', async () => {