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

[RAC] Updates Alerts table cell actions #116446

Merged
merged 10 commits into from
Nov 2, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) =>
Expand All @@ -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);
Original file line number Diff line number Diff line change
Expand Up @@ -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',
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ({
Expand Down
15 changes: 5 additions & 10 deletions x-pack/test/functional/services/observability/alerts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -216,15 +212,14 @@ export function ObservabilityAlertsCommonProvider({
getQueryBar,
clearQueryBar,
closeAlertsFlyout,
filterForValueButtonExists,
getAlertsFlyout,
getAlertsFlyoutDescriptionListDescriptions,
getAlertsFlyoutDescriptionListTitles,
getAlertsFlyoutOrFail,
getAlertsFlyoutTitle,
getAlertsFlyoutViewInAppButtonOrFail,
getCopyToClipboardButton,
getFilterForValueButton,
copyToClipboardButtonExists,
getNoDataPageOrFail,
getNoDataStateOrFail,
getTableCells,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down