Skip to content

Commit

Permalink
[RAM] Bring back toggle column on alert table (#168158)
Browse files Browse the repository at this point in the history
## Summary
 
FIX -> #155243


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: PhilippeOberti <philippe.oberti@elastic.co>
  • Loading branch information
XavierM and PhilippeOberti committed Oct 7, 2023
1 parent e9777f6 commit 44a9d28
Show file tree
Hide file tree
Showing 26 changed files with 445 additions and 80 deletions.
5 changes: 2 additions & 3 deletions x-pack/examples/triggers_actions_ui_example/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
TriggersAndActionsUIPublicPluginSetup,
TriggersAndActionsUIPublicPluginStart,
} from '@kbn/triggers-actions-ui-plugin/public';
import { TypeRegistry } from '@kbn/triggers-actions-ui-plugin/public/application/type_registry';
import { AlertTableConfigRegistry } from '@kbn/triggers-actions-ui-plugin/public/application/alert_table_config_registry';
import {
AlertsTableConfigurationRegistry,
AlertsTableFlyoutBaseProps,
Expand Down Expand Up @@ -81,8 +81,7 @@ export class TriggersActionsUiExamplePlugin
) {
const {
alertsTableConfigurationRegistry,
}: { alertsTableConfigurationRegistry: TypeRegistry<AlertsTableConfigurationRegistry> } =
triggersActionsUi;
}: { alertsTableConfigurationRegistry: AlertTableConfigRegistry } = triggersActionsUi;

const columns: EuiDataGridColumn[] = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const registerCellActions = (
investigateInNewTimeline: createInvestigateInNewTimelineCellActionFactory({ store, services }),
showTopN: createShowTopNCellActionFactory({ services }),
copyToClipboard: createCopyToClipboardCellActionFactory({ services }),
toggleColumn: createToggleColumnCellActionFactory({ store }),
toggleColumn: createToggleColumnCellActionFactory({ store, services }),
};

const registerCellActionsTrigger = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@

import type { SecurityAppStore } from '../../../common/store/types';
import { TableId, dataTableActions } from '@kbn/securitysolution-data-table';
import { createToggleColumnCellActionFactory } from './toggle_column';

import type { CellActionExecutionContext } from '@kbn/cell-actions';

import { createToggleColumnCellActionFactory } from './toggle_column';
import { mockGlobalState } from '../../../common/mock';
import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock';

const services = createStartServicesMock();
const mockAlertConfigGetActions = jest.fn();
services.triggersActionsUi.alertsTableConfigurationRegistry.getActions = mockAlertConfigGetActions;
const mockToggleColumn = jest.fn();
mockAlertConfigGetActions.mockImplementation(() => ({
toggleColumn: mockToggleColumn,
}));

const mockDispatch = jest.fn();
const mockGetState = jest.fn().mockReturnValue(mockGlobalState);
Expand All @@ -34,7 +43,7 @@ const context = {
} as unknown as CellActionExecutionContext;

describe('createToggleColumnCellActionFactory', () => {
const toggleColumnActionFactory = createToggleColumnCellActionFactory({ store });
const toggleColumnActionFactory = createToggleColumnCellActionFactory({ store, services });
const toggleColumnAction = toggleColumnActionFactory({ id: 'testAction' });

beforeEach(() => {
Expand Down Expand Up @@ -71,6 +80,10 @@ describe('createToggleColumnCellActionFactory', () => {
});

describe('execute', () => {
afterEach(() => {
mockToggleColumn.mockClear();
mockAlertConfigGetActions.mockClear();
});
it('should remove column', async () => {
await toggleColumnAction.execute(context);
expect(mockDispatch).toHaveBeenCalledWith(
Expand Down Expand Up @@ -99,5 +112,29 @@ describe('createToggleColumnCellActionFactory', () => {
})
);
});

it('should call triggersActionsUi.alertsTableConfigurationRegistry to add a column in alert', async () => {
const name = 'fake-field-name';
await toggleColumnAction.execute({
...context,
data: [{ ...context.data[0], field: { ...context.data[0].field, name } }],
metadata: {
scopeId: TableId.alertsOnAlertsPage,
},
});
expect(mockAlertConfigGetActions).toHaveBeenCalledWith('securitySolution-alerts-page');
expect(mockToggleColumn).toHaveBeenCalledWith(name);
});

it('should call triggersActionsUi.alertsTableConfigurationRegistry to remove a column in alert', async () => {
await toggleColumnAction.execute({
...context,
metadata: {
scopeId: TableId.alertsOnAlertsPage,
},
});
expect(mockAlertConfigGetActions).toHaveBeenCalledWith('securitySolution-alerts-page');
expect(mockToggleColumn).toHaveBeenCalledWith(fieldName);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { timelineSelectors } from '../../../timelines/store/timeline';
import { DEFAULT_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants';
import type { SecurityCellAction } from '../../types';
import { SecurityCellActionType } from '../../constants';
import type { StartServices } from '../../../types';
import { getAlertConfigIdByScopeId } from '../../../common/lib/triggers_actions_ui/alert_table_scope_config';

const ICON = 'listAdd';
const COLUMN_TOGGLE = i18n.translate('xpack.securitySolution.actions.toggleColumnToggle.label', {
Expand All @@ -33,7 +35,13 @@ const NESTED_COLUMN = (field: string) =>
});

export const createToggleColumnCellActionFactory = createCellActionFactory(
({ store }: { store: SecurityAppStore }): CellActionTemplate<SecurityCellAction> => ({
({
store,
services,
}: {
store: SecurityAppStore;
services: StartServices;
}): CellActionTemplate<SecurityCellAction> => ({
type: SecurityCellActionType.TOGGLE_COLUMN,
getIconType: () => ICON,
getDisplayName: () => COLUMN_TOGGLE,
Expand All @@ -60,6 +68,14 @@ export const createToggleColumnCellActionFactory = createCellActionFactory(
return;
}

const alertTableConfigurationId = getAlertConfigIdByScopeId(scopeId);
if (alertTableConfigurationId) {
services.triggersActionsUi.alertsTableConfigurationRegistry
.getActions(alertTableConfigurationId)
.toggleColumn(field.name);
return;
}

const selector = isTimelineScope(scopeId)
? timelineSelectors.getTimelineByIdSelector()
: dataTableSelectors.getTableByIdSelector();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { TableId } from '@kbn/securitysolution-data-table';
import { ALERTS_TABLE_REGISTRY_CONFIG_IDS } from '../../../../common/constants';
import { getAlertConfigIdByScopeId } from './alert_table_scope_config';

describe('getAlertConfigIdByScopeId', () => {
it('should return an alert configuration ID when the scope is valid', async () => {
expect(getAlertConfigIdByScopeId(TableId.alertsOnAlertsPage)).toEqual(
ALERTS_TABLE_REGISTRY_CONFIG_IDS.ALERTS_PAGE
);
expect(getAlertConfigIdByScopeId(TableId.alertsOnRuleDetailsPage)).toEqual(
ALERTS_TABLE_REGISTRY_CONFIG_IDS.RULE_DETAILS
);
expect(getAlertConfigIdByScopeId(TableId.alertsOnCasePage)).toEqual(
ALERTS_TABLE_REGISTRY_CONFIG_IDS.CASE
);
expect(getAlertConfigIdByScopeId(TableId.alertsRiskInputs)).toEqual(
ALERTS_TABLE_REGISTRY_CONFIG_IDS.RISK_INPUTS
);
});

it('should return undefined when the scope is NOT valid', async () => {
expect(getAlertConfigIdByScopeId(TableId.test)).toEqual(undefined);
expect(getAlertConfigIdByScopeId('hereWeGo')).toEqual(undefined);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { TableId } from '@kbn/securitysolution-data-table';
import { ALERTS_TABLE_REGISTRY_CONFIG_IDS } from '../../../../common/constants';

type PickKey<T, K extends keyof T> = Extract<keyof T, K>;
type KeysAlertTableId = PickKey<
typeof TableId,
'alertsOnAlertsPage' | 'alertsOnRuleDetailsPage' | 'alertsOnCasePage' | 'alertsRiskInputs'
>;

type ValuesAlertTableId = typeof TableId[KeysAlertTableId];

type KeysAlertTableConfiguration = keyof typeof ALERTS_TABLE_REGISTRY_CONFIG_IDS;
type ValuesAlertTableConfiguration =
typeof ALERTS_TABLE_REGISTRY_CONFIG_IDS[KeysAlertTableConfiguration];

const ScopeIdLinkToAlertTableConfiguration: Record<
ValuesAlertTableId,
ValuesAlertTableConfiguration
> = {
[TableId.alertsOnAlertsPage]: ALERTS_TABLE_REGISTRY_CONFIG_IDS.ALERTS_PAGE,
[TableId.alertsOnRuleDetailsPage]: ALERTS_TABLE_REGISTRY_CONFIG_IDS.RULE_DETAILS,
[TableId.alertsOnCasePage]: ALERTS_TABLE_REGISTRY_CONFIG_IDS.CASE,
[TableId.alertsRiskInputs]: ALERTS_TABLE_REGISTRY_CONFIG_IDS.RISK_INPUTS,
};

export const getAlertConfigIdByScopeId = (scopeId: string) => {
if (ScopeIdLinkToAlertTableConfiguration[scopeId as ValuesAlertTableId]) {
return ScopeIdLinkToAlertTableConfiguration[scopeId as ValuesAlertTableId];
}
return undefined;
};
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s
value: user,
}}
mode={CellActionsMode.HOVER_RIGHT}
triggerId={SecurityCellActionsTrigger.DEFAULT} // TODO use SecurityCellActionsTrigger.DETAILS_FLYOUT when https://github.com/elastic/kibana/issues/155243 is fixed
visibleCellActions={5} // TODO use 6 when https://github.com/elastic/kibana/issues/155243 is fixed
triggerId={SecurityCellActionsTrigger.DETAILS_FLYOUT}
visibleCellActions={6}
sourcererScopeId={getSourcererScopeId(scopeId)}
metadata={{ scopeId }}
showActionTooltips
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s
field: 'host.name',
}}
mode={CellActionsMode.HOVER_RIGHT}
triggerId={SecurityCellActionsTrigger.DEFAULT} // TODO use SecurityCellActionsTrigger.DETAILS_FLYOUT when https://github.com/elastic/kibana/issues/155243 is fixed
visibleCellActions={5} // TODO use 6 when https://github.com/elastic/kibana/issues/155243 is fixed
triggerId={SecurityCellActionsTrigger.DETAILS_FLYOUT}
visibleCellActions={6}
sourcererScopeId={getSourcererScopeId(scopeId)}
metadata={{ scopeId }}
showActionTooltips
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ const columns: Array<EuiBasicTableColumn<HighlightedFieldsTableRow>> = [
value: description.values,
}}
mode={CellActionsMode.HOVER_RIGHT}
triggerId={SecurityCellActionsTrigger.DEFAULT} // TODO use SecurityCellActionsTrigger.DETAILS_FLYOUT when https://github.com/elastic/kibana/issues/155243 is fixed
visibleCellActions={5} // TODO use 6 when https://github.com/elastic/kibana/issues/155243 is fixed
triggerId={SecurityCellActionsTrigger.DETAILS_FLYOUT}
visibleCellActions={6}
sourcererScopeId={getSourcererScopeId(description.scopeId)}
metadata={{ scopeId: description.scopeId }}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ export const DocumentSeverity: FC = memo(() => {
value: alertSeverity,
}}
mode={CellActionsMode.HOVER_RIGHT}
triggerId={SecurityCellActionsTrigger.DEFAULT} // TODO use SecurityCellActionsTrigger.DETAILS_FLYOUT when https://github.com/elastic/kibana/issues/155243 is fixed
visibleCellActions={5} // TODO use 6 when https://github.com/elastic/kibana/issues/155243 is fixed
triggerId={SecurityCellActionsTrigger.DETAILS_FLYOUT}
visibleCellActions={6}
sourcererScopeId={getSourcererScopeId(scopeId)}
metadata={{ scopeId }}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ export const DocumentStatus: FC = () => {
value: statusData.values[0],
}}
mode={CellActionsMode.HOVER_RIGHT}
triggerId={SecurityCellActionsTrigger.DEFAULT} // TODO use SecurityCellActionsTrigger.DETAILS_FLYOUT when https://github.com/elastic/kibana/issues/155243 is fixed
visibleCellActions={5} // TODO use 6 when https://github.com/elastic/kibana/issues/155243 is fixed
triggerId={SecurityCellActionsTrigger.DETAILS_FLYOUT}
visibleCellActions={6}
sourcererScopeId={getSourcererScopeId(scopeId)}
metadata={{ scopeId }}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const getColumns: ColumnsProvider = ({
}}
triggerId={SecurityCellActionsTrigger.DETAILS_FLYOUT}
mode={CellActionsMode.HOVER_RIGHT}
visibleCellActions={3}
visibleCellActions={6}
sourcererScopeId={getSourcererScopeId(scopeId)}
metadata={{ scopeId, isObjectArray: data.isObjectArray }}
>
Expand All @@ -96,7 +96,7 @@ export const getColumns: ColumnsProvider = ({
* Table view displayed in the document details expandable flyout right section
*/
export const TableTab: FC = memo(() => {
const { browserFields, dataFormattedForFieldBrowser, eventId } = useRightPanelContext();
const { browserFields, dataFormattedForFieldBrowser, eventId, scopeId } = useRightPanelContext();

return (
<EventFieldsBrowser
Expand All @@ -105,7 +105,7 @@ export const TableTab: FC = memo(() => {
eventId={eventId}
isDraggable={false}
timelineTabType={TimelineTabs.query}
scopeId={'alert-details-flyout'}
scopeId={scopeId}
isReadOnly={false}
columnsProvider={getColumns}
/>
Expand Down

0 comments on commit 44a9d28

Please sign in to comment.