[RAM] Replace alerts list with table in rule details page (#172302)

Closes #168472

## Summary

Replaces the old alerts list with the alerts table in the rule details
page, only for supported rule types.

<img width="1464" alt="image"
src="e556438a-3c01-4460-bfa8-2ff32d15a077">


### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [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
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))

---------

Co-authored-by: Xavier Mouligneau <xavier.mouligneau@elastic.co>
Co-authored-by: Maryam Saeidi <maryam.saeidi@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Umberto Pepato 2023-12-08 09:35:40 +01:00 committed by GitHub
parent 2ada7f8153
commit 7803c45878
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 496 additions and 39 deletions

View file

@ -24,6 +24,7 @@ export const AlertConsumers = {
SIEM: 'siem',
UPTIME: 'uptime',
ML: 'ml',
STACK_ALERTS: 'stackAlerts',
} as const;
export type AlertConsumers = typeof AlertConsumers[keyof typeof AlertConsumers];
export type STATUS_VALUES = 'open' | 'acknowledged' | 'closed' | 'in-progress'; // TODO: remove 'in-progress' after migration to 'acknowledged'

View file

@ -29,8 +29,7 @@ export type DeprecatedCellValueElementProps = EuiDataGridCellValueElementProps &
isTimeline?: boolean; // Default cell renderer is used for both the alert table and timeline. This allows us to cheaply separate concerns
linkValues: string[] | undefined;
rowRenderers?: DeprecatedRowRenderer[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setFlyoutAlert?: (data: any) => void;
setFlyoutAlert?: (alertId: string) => void;
scopeId: string;
truncate?: boolean;
key?: string;

View file

@ -0,0 +1,10 @@
/*
* 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 { AlertConsumers } from '@kbn/rule-data-utils';
export const ALERT_TABLE_GENERIC_CONFIG_ID = `${AlertConsumers.STACK_ALERTS}-generic-alert-table`;

View file

@ -13,3 +13,4 @@ export const BASE_TRIGGERS_ACTIONS_UI_API_PATH = '/internal/triggers_actions_ui'
export * from './parse_interval';
export * from './experimental_features';
export * from './normalized_field_types';
export * from './alert_config';

View file

@ -18,6 +18,7 @@
"kibanaUtils",
"savedObjects",
"unifiedSearch",
"fieldFormats",
"dataViews",
"dataViewEditor",
"alerting",

View file

@ -23,6 +23,7 @@ import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/publi
import { PluginStartContract as AlertingStart } from '@kbn/alerting-plugin/public';
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
@ -73,6 +74,7 @@ export interface TriggersAndActionsUiServices extends CoreStart {
licensing: LicensingPluginStart;
expressions: ExpressionsStart;
isServerless: boolean;
fieldFormats: FieldFormatsStart;
}
export const renderApp = (deps: TriggersAndActionsUiServices) => {

View file

@ -0,0 +1,48 @@
/*
* 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 { get } from 'lodash';
import React from 'react';
import { type EuiDataGridColumn, EuiDescriptionList, EuiPanel, EuiTitle } from '@elastic/eui';
import { ALERT_RULE_NAME } from '@kbn/rule-data-utils';
import { AlertsTableFlyoutBaseProps, AlertTableFlyoutComponent } from '../../../..';
import { RegisterFormatter } from '../cells/render_cell_value';
const FlyoutHeader: AlertTableFlyoutComponent = ({ alert }: AlertsTableFlyoutBaseProps) => {
const name = alert[ALERT_RULE_NAME];
return (
<EuiTitle size="s">
<h3>{name}</h3>
</EuiTitle>
);
};
export const getDefaultAlertFlyout =
(columns: EuiDataGridColumn[], formatter: RegisterFormatter) => () => {
const FlyoutBody: AlertTableFlyoutComponent = ({ alert }: AlertsTableFlyoutBaseProps) => (
<EuiPanel>
<EuiDescriptionList
listItems={columns.map((column) => {
const value = get(alert, column.id)?.[0];
return {
title: column.displayAsText as string,
description: value != null ? formatter(column.id, value) : '—',
};
})}
type="column"
columnWidths={[1, 3]}
/>
</EuiPanel>
);
return {
body: FlyoutBody,
header: FlyoutHeader,
footer: null,
};
};

View file

@ -0,0 +1,116 @@
/*
* 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 { isEmpty } from 'lodash';
import React, { type ReactNode } from 'react';
import { ALERT_DURATION, TIMESTAMP } from '@kbn/rule-data-utils';
import {
FIELD_FORMAT_IDS,
FieldFormatParams,
FieldFormatsRegistry,
} from '@kbn/field-formats-plugin/common';
import { GetRenderCellValue } from '../../../../types';
import { useKibana } from '../../../../common/lib/kibana';
interface Props {
columnId: string;
data: any;
}
export const getMappedNonEcsValue = ({
data,
fieldName,
}: {
data: any[];
fieldName: string;
}): string[] | undefined => {
const item = data.find((d) => d.field === fieldName);
if (item != null && item.value != null) {
return item.value;
}
return undefined;
};
const getRenderValue = (mappedNonEcsValue: any) => {
const value = Array.isArray(mappedNonEcsValue) ? mappedNonEcsValue.join() : mappedNonEcsValue;
if (!isEmpty(value)) {
if (typeof value === 'object') {
return JSON.stringify(value);
}
return value;
}
return '—';
};
export const getRenderCellValue = (fieldFormats: FieldFormatsRegistry): GetRenderCellValue => {
const alertValueFormatter = getAlertFormatters(fieldFormats);
return () =>
(props): ReactNode => {
const { columnId, data } = props as Props;
if (data == null) return null;
const mappedNonEcsValue = getMappedNonEcsValue({
data,
fieldName: columnId,
});
const value = getRenderValue(mappedNonEcsValue);
return alertValueFormatter(columnId, value);
};
};
const defaultParam: Record<string, FieldFormatParams> = {
[FIELD_FORMAT_IDS.DURATION]: {
inputFormat: 'milliseconds',
outputFormat: 'humanizePrecise',
},
[FIELD_FORMAT_IDS.NUMBER]: {
pattern: '00.00',
},
};
export const getFieldFormatterProvider =
(fieldFormats: FieldFormatsRegistry) =>
(fieldType: FIELD_FORMAT_IDS, params?: FieldFormatParams) => {
const fieldFormatter = fieldFormats.deserialize({
id: fieldType,
params: params ?? defaultParam[fieldType],
});
return fieldFormatter.convert.bind(fieldFormatter);
};
export function useFieldFormatter(fieldType: FIELD_FORMAT_IDS) {
const { fieldFormats } = useKibana().services;
return getFieldFormatterProvider(fieldFormats as FieldFormatsRegistry)(fieldType);
}
export function getAlertFormatters(fieldFormats: FieldFormatsRegistry) {
const getFormatter = getFieldFormatterProvider(fieldFormats);
return (columnId: string, value: any): React.ReactElement => {
switch (columnId) {
case TIMESTAMP:
return <>{getFormatter(FIELD_FORMAT_IDS.DATE)(value)}</>;
case ALERT_DURATION:
return (
<>
{getFormatter(FIELD_FORMAT_IDS.DURATION, {
inputFormat: 'microseconds',
outputFormat: 'humanizePrecise',
})(value) || '--'}
</>
);
default:
return <>{value}</>;
}
};
}
export type RegisterFormatter = ReturnType<typeof getAlertFormatters>;

View file

@ -0,0 +1,97 @@
/*
* 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 React from 'react';
import {
ALERT_DURATION,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_REASON,
ALERT_STATUS,
TIMESTAMP,
} from '@kbn/rule-data-utils';
import { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { FieldFormatsRegistry } from '@kbn/field-formats-plugin/common';
import { i18n } from '@kbn/i18n';
import { getDefaultAlertFlyout } from './alerts_flyout/default_alerts_flyout';
import { AlertActionsCell } from './row_actions/alert_actions_cell';
import { AlertsTableConfigurationRegistry, RenderCustomActionsRowArgs } from '../../../types';
import { getAlertFormatters, getRenderCellValue } from './cells/render_cell_value';
import { ALERT_TABLE_GENERIC_CONFIG_ID } from '../../../../common';
const columns = [
{
columnHeaderType: 'not-filtered',
displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.statusColumnDescription', {
defaultMessage: 'Alert Status',
}),
id: ALERT_STATUS,
initialWidth: 110,
},
{
columnHeaderType: 'not-filtered',
displayAsText: i18n.translate(
'xpack.triggersActionsUI.alertsTable.lastUpdatedColumnDescription',
{
defaultMessage: 'Last updated',
}
),
id: TIMESTAMP,
initialWidth: 230,
schema: 'datetime',
},
{
columnHeaderType: 'not-filtered',
displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.durationColumnDescription', {
defaultMessage: 'Duration',
}),
id: ALERT_DURATION,
initialWidth: 116,
},
{
columnHeaderType: 'not-filtered',
displayAsText: i18n.translate('xpack.triggersActionsUI.alertsTable.reasonColumnDescription', {
defaultMessage: 'Reason',
}),
id: ALERT_REASON,
linkField: '*',
},
{
columnHeaderType: 'not-filtered',
displayAsText: i18n.translate(
'xpack.triggersActionsUI.alertsTable.maintenanceWindowsColumnDescription',
{
defaultMessage: 'Maintenance windows',
}
),
id: ALERT_MAINTENANCE_WINDOW_IDS,
schema: 'string',
initialWidth: 180,
},
];
export const getAlertsTableConfiguration = (
fieldFormats: FieldFormatsRegistry
): AlertsTableConfigurationRegistry => {
return {
id: ALERT_TABLE_GENERIC_CONFIG_ID,
columns,
getRenderCellValue: getRenderCellValue(fieldFormats),
useInternalFlyout: getDefaultAlertFlyout(columns, getAlertFormatters(fieldFormats)),
sort: [
{
[TIMESTAMP]: {
order: 'desc' as SortOrder,
},
},
],
useActionsColumn: () => ({
renderCustomActionsRow: (props: RenderCustomActionsRowArgs) => {
return <AlertActionsCell {...props} />;
},
}),
};
};

View file

@ -10,6 +10,7 @@ import { useFetchBrowserFieldCapabilities } from './use_fetch_browser_fields_cap
import { useKibana } from '../../../../common/lib/kibana';
import { BrowserFields } from '@kbn/rule-registry-plugin/common';
import { AlertsField } from '../../../../types';
import { AlertConsumers } from '@kbn/rule-data-utils';
jest.mock('../../../../common/lib/kibana');
@ -48,7 +49,7 @@ describe('useFetchBrowserFieldCapabilities', () => {
});
afterEach(() => {
httpMock.mockReset();
httpMock.mockClear();
});
it('should not fetch for siem', () => {
@ -98,4 +99,41 @@ describe('useFetchBrowserFieldCapabilities', () => {
expect(httpMock).toHaveBeenCalledTimes(0);
expect(result.current).toEqual([undefined, browserFields, []]);
});
it('should not fetch if the only featureId is not valid', async () => {
const { result } = renderHook(() =>
useFetchBrowserFieldCapabilities({
featureIds: ['alerts'] as unknown as AlertConsumers[],
})
);
expect(httpMock).toHaveBeenCalledTimes(0);
expect(result.current).toEqual([undefined, {}, []]);
});
it('should not fetch if all featureId are not valid', async () => {
const { result } = renderHook(() =>
useFetchBrowserFieldCapabilities({
featureIds: ['alerts', 'tomato'] as unknown as AlertConsumers[],
})
);
expect(httpMock).toHaveBeenCalledTimes(0);
expect(result.current).toEqual([undefined, {}, []]);
});
it('should filter out the non valid feature id', async () => {
const { waitForNextUpdate } = renderHook(() =>
useFetchBrowserFieldCapabilities({
featureIds: ['alerts', 'apm', 'logs'] as unknown as AlertConsumers[],
})
);
await waitForNextUpdate();
expect(httpMock).toHaveBeenCalledTimes(1);
expect(httpMock).toHaveBeenCalledWith('/internal/rac/alerts/browser_fields', {
query: { featureIds: ['apm', 'logs'] },
});
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { ValidFeatureId } from '@kbn/rule-data-utils';
import { isValidFeatureId, ValidFeatureId } from '@kbn/rule-data-utils';
import { BASE_RAC_ALERTS_API_PATH, BrowserFields } from '@kbn/rule-registry-plugin/common';
import { useCallback, useEffect, useState } from 'react';
import type { FieldDescriptor } from '@kbn/data-views-plugin/server';
@ -41,24 +41,29 @@ export const useFetchBrowserFieldCapabilities = ({
);
const [fields, setFields] = useState<FieldDescriptor[]>([]);
const getBrowserFieldInfo = useCallback(async (): Promise<{
browserFields: BrowserFields;
fields: FieldDescriptor[];
}> => {
if (!http) return Promise.resolve({ browserFields: {}, fields: [] });
const getBrowserFieldInfo = useCallback(
async (
validFeatureId: ValidFeatureId[]
): Promise<{
browserFields: BrowserFields;
fields: FieldDescriptor[];
}> => {
if (!http) return Promise.resolve({ browserFields: {}, fields: [] });
try {
return await http.get<{ browserFields: BrowserFields; fields: FieldDescriptor[] }>(
`${BASE_RAC_ALERTS_API_PATH}/browser_fields`,
{
query: { featureIds },
}
);
} catch (e) {
toasts.addDanger(ERROR_FETCH_BROWSER_FIELDS);
return Promise.resolve({ browserFields: {}, fields: [] });
}
}, [featureIds, http, toasts]);
try {
return await http.get<{ browserFields: BrowserFields; fields: FieldDescriptor[] }>(
`${BASE_RAC_ALERTS_API_PATH}/browser_fields`,
{
query: { featureIds: validFeatureId },
}
);
} catch (e) {
toasts.addDanger(ERROR_FETCH_BROWSER_FIELDS);
return Promise.resolve({ browserFields: {}, fields: [] });
}
},
[http, toasts]
);
useEffect(() => {
if (initialBrowserFields) {
@ -67,21 +72,26 @@ export const useFetchBrowserFieldCapabilities = ({
setBrowserFields(initialBrowserFields);
return;
}
if (isLoading !== undefined || featureIds.includes(INVALID_FEATURE_ID)) {
const validFeatureIdTmp = featureIds.filter((fid) => isValidFeatureId(fid));
if (
isLoading !== undefined ||
featureIds.includes(INVALID_FEATURE_ID) ||
validFeatureIdTmp.length === 0
) {
return;
}
setIsLoading(true);
const callApi = async () => {
const { browserFields: browserFieldsInfo, fields: newFields } = await getBrowserFieldInfo();
const callApi = async (validFeatureId: ValidFeatureId[]) => {
const { browserFields: browserFieldsInfo, fields: newFields } = await getBrowserFieldInfo(
validFeatureId
);
setFields(newFields);
setBrowserFields(browserFieldsInfo);
setIsLoading(false);
};
callApi();
callApi(validFeatureIdTmp);
}, [getBrowserFieldInfo, isLoading, featureIds, initialBrowserFields]);
return [isLoading, browserFields, fields];

View file

@ -0,0 +1,84 @@
/*
* 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 {
EuiButtonIcon,
EuiFlexItem,
EuiContextMenuPanel,
EuiPopover,
EuiToolTip,
} from '@elastic/eui';
import React, { useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { getAlertsTableDefaultAlertActionsLazy } from '../../../../common/get_alerts_table_default_row_actions';
import type { AlertActionsProps } from '../../../../types';
const actionsToolTip = i18n.translate('xpack.triggersActionsUI.alertsTable.moreActionsTextLabel', {
defaultMessage: 'More actions',
});
/**
* The cell containing contextual actions for a single alert row in the table
*/
export function AlertActionsCell(alertActionsProps: AlertActionsProps) {
const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false);
const closeActionsPopover = () => {
setIsPopoverOpen(false);
};
const toggleActionsPopover = () => {
setIsPopoverOpen(!isPopoverOpen);
};
const DefaultRowActions = useMemo(
() =>
getAlertsTableDefaultAlertActionsLazy({
key: 'defaultRowActions',
onActionExecuted: closeActionsPopover,
isAlertDetailsEnabled: false,
...alertActionsProps,
} as AlertActionsProps),
[alertActionsProps]
);
// TODO re-enable view in app when it works
const actionsMenuItems = [DefaultRowActions];
return (
<>
<EuiFlexItem>
<EuiPopover
anchorPosition="downLeft"
button={
<EuiToolTip content={actionsToolTip}>
<EuiButtonIcon
aria-label={actionsToolTip}
color="text"
data-test-subj="alertsTableRowActionMore"
display="empty"
iconType="boxesHorizontal"
onClick={toggleActionsPopover}
size="s"
/>
</EuiToolTip>
}
closePopover={closeActionsPopover}
isOpen={isPopoverOpen}
panelPaddingSize="none"
>
<EuiContextMenuPanel
size="s"
items={actionsMenuItems}
data-test-subj="alertsTableActionsMenu"
/>
</EuiPopover>
</EuiFlexItem>
</>
);
}

View file

@ -5,10 +5,13 @@
* 2.0.
*/
import React, { lazy } from 'react';
import React, { lazy, useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiTabbedContent } from '@elastic/eui';
import { AlertStatusValues } from '@kbn/alerting-plugin/common';
import { AlertStatusValues, ALERTS_FEATURE_ID } from '@kbn/alerting-plugin/common';
import { ALERT_RULE_UUID, AlertConsumers } from '@kbn/rule-data-utils';
import { ALERT_TABLE_GENERIC_CONFIG_ID } from '../../../../../common';
import { AlertTableConfigRegistry } from '../../../alert_table_config_registry';
import { useKibana } from '../../../../common/lib/kibana';
import { Rule, RuleSummary, AlertStatus, RuleType } from '../../../../types';
import {
@ -34,6 +37,7 @@ import {
const RuleEventLogList = lazy(() => import('./rule_event_log_list'));
const RuleAlertList = lazy(() => import('./rule_alert_list'));
const RuleDefinition = lazy(() => import('./rule_definition'));
const AlertsTable = lazy(() => import('../../alerts_table/alerts_table_state'));
export type RuleComponentProps = {
rule: Rule;
@ -65,18 +69,22 @@ export function RuleComponent({
durationEpoch = Date.now(),
isLoadingChart,
}: RuleComponentProps) {
const { ruleTypeRegistry, actionTypeRegistry } = useKibana().services;
const { ruleTypeRegistry, actionTypeRegistry, alertsTableConfigurationRegistry } =
useKibana().services;
const alerts = Object.entries(ruleSummary.alerts)
.map(([alertId, alert]) => alertToListItem(durationEpoch, alertId, alert))
.sort((leftAlert, rightAlert) => leftAlert.sortPriority - rightAlert.sortPriority);
const onMuteAction = async (alert: AlertListItem) => {
await (alert.isMuted
? unmuteAlertInstance(rule, alert.alert)
: muteAlertInstance(rule, alert.alert));
requestRefresh();
};
const onMuteAction = useCallback(
async (alert: AlertListItem) => {
await (alert.isMuted
? unmuteAlertInstance(rule, alert.alert)
: muteAlertInstance(rule, alert.alert));
requestRefresh();
},
[muteAlertInstance, requestRefresh, rule, unmuteAlertInstance]
);
const healthColor = getRuleHealthColor(rule);
const statusMessage = getRuleStatusMessage({
@ -86,7 +94,25 @@ export function RuleComponent({
executionStatusTranslations: rulesStatusesTranslationsMapping,
});
const renderRuleAlertList = () => {
const renderRuleAlertList = useCallback(() => {
if (ruleType.hasAlertsMappings || ruleType.hasFieldsForAAD) {
return (
<AlertsTable
id="rule-detail-alerts-table"
configurationId={ALERT_TABLE_GENERIC_CONFIG_ID}
alertsTableConfigurationRegistry={
alertsTableConfigurationRegistry as AlertTableConfigRegistry
}
featureIds={
(rule.consumer === ALERTS_FEATURE_ID
? [ruleType.producer]
: [rule.consumer]) as AlertConsumers[]
}
query={{ bool: { filter: { term: { [ALERT_RULE_UUID]: rule.id } } } }}
showAlertStatusWithFlapping
/>
);
}
return suspendedComponentWithProps(
RuleAlertList,
'xl'
@ -95,7 +121,17 @@ export function RuleComponent({
readOnly,
onMuteAction,
});
};
}, [
alerts,
alertsTableConfigurationRegistry,
onMuteAction,
readOnly,
rule.consumer,
rule.id,
ruleType.hasAlertsMappings,
ruleType.hasFieldsForAAD,
ruleType.producer,
]);
const tabs = [
{

View file

@ -11,6 +11,7 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
import { dashboardPluginMock } from '@kbn/dashboard-plugin/public/mocks';
import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks';
import { coreMock, scopedHistoryMock, themeServiceMock } from '@kbn/core/public/mocks';
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
@ -75,6 +76,7 @@ export const createStartServicesMock = (): TriggersAndActionsUiServices => {
licensing: licensingPluginMock,
expressions: expressionsPluginMock.createStartContract(),
isServerless: false,
fieldFormats: fieldFormatsServiceMock.createStartContract(),
} as TriggersAndActionsUiServices;
};

View file

@ -28,6 +28,7 @@ import { DashboardStart } from '@kbn/dashboard-plugin/public';
import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import { ExpressionsStart } from '@kbn/expressions-plugin/public';
import { ServerlessPluginStart } from '@kbn/serverless/public';
import { FieldFormatsRegistry } from '@kbn/field-formats-plugin/common';
import { getAlertsTableDefaultAlertActionsLazy } from './common/get_alerts_table_default_row_actions';
import type { AlertActionsProps } from './types';
import type { AlertsSearchBarProps } from './application/sections/alerts_search_bar';
@ -172,6 +173,7 @@ interface PluginsStart {
unifiedSearch: UnifiedSearchPublicPluginStart;
licensing: LicensingPluginStart;
serverless?: ServerlessPluginStart;
fieldFormats: FieldFormatsRegistry;
}
export class Plugin
@ -298,6 +300,7 @@ export class Plugin
licensing: pluginsStart.licensing,
expressions: pluginsStart.expressions,
isServerless: !!pluginsStart.serverless,
fieldFormats: pluginsStart.fieldFormats,
});
},
});
@ -363,7 +366,15 @@ export class Plugin
};
}
public start(): TriggersAndActionsUIPublicPluginStart {
public start(_: CoreStart, plugins: PluginsStart): TriggersAndActionsUIPublicPluginStart {
import('./application/sections/alerts_table/configuration').then(
({ getAlertsTableConfiguration }) => {
this.alertsTableConfigurationRegistry.register(
getAlertsTableConfiguration(plugins.fieldFormats)
);
}
);
return {
actionTypeRegistry: this.actionTypeRegistry,
ruleTypeRegistry: this.ruleTypeRegistry,

View file

@ -57,6 +57,7 @@
"@kbn/expressions-plugin",
"@kbn/core-saved-objects-api-server",
"@kbn/serverless",
"@kbn/field-formats-plugin",
"@kbn/triggers-actions-ui-types"
],
"exclude": ["target/**/*"]