mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Rule detail table with bulk actions (#136601)
* first commit * remove not needed variable * row action in o11y * fix view in app for inventory rule when using the new alert table * mistake * review I Co-authored-by: Xavier Mouligneau <xavier.mouligneau@elastic.co> Co-authored-by: Maryam Saeidi <maryam.saeidi@elastic.co>
This commit is contained in:
parent
6e3f5850ff
commit
12259ce281
8 changed files with 288 additions and 70 deletions
|
@ -7,9 +7,70 @@
|
|||
|
||||
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common/parse_technical_fields';
|
||||
import { ALERT_RULE_PARAMETERS, TIMESTAMP } from '@kbn/rule-data-utils';
|
||||
import { getInventoryViewInAppUrl } from './alert_link';
|
||||
import { getInventoryViewInAppUrl, flatAlertRuleParams } from './alert_link';
|
||||
|
||||
describe('Inventory Threshold Rule', () => {
|
||||
describe('flatAlertRuleParams', () => {
|
||||
it('flat ALERT_RULE_PARAMETERS', () => {
|
||||
expect(
|
||||
flatAlertRuleParams(
|
||||
{
|
||||
sourceId: 'default',
|
||||
criteria: [
|
||||
{
|
||||
comparator: '>',
|
||||
timeSize: 1,
|
||||
metric: 'cpu',
|
||||
threshold: [5],
|
||||
customMetric: {
|
||||
field: '',
|
||||
aggregation: 'avg',
|
||||
id: 'alert-custom-metric',
|
||||
type: 'custom',
|
||||
},
|
||||
timeUnit: 'm',
|
||||
},
|
||||
],
|
||||
nodeType: 'host',
|
||||
},
|
||||
ALERT_RULE_PARAMETERS
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"kibana.alert.rule.parameters.criteria.comparator": Array [
|
||||
">",
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.customMetric.aggregation": Array [
|
||||
"avg",
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.customMetric.field": Array [
|
||||
"",
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.customMetric.id": Array [
|
||||
"alert-custom-metric",
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.customMetric.type": Array [
|
||||
"custom",
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.metric": Array [
|
||||
"cpu",
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.timeSize": Array [
|
||||
1,
|
||||
],
|
||||
"kibana.alert.rule.parameters.criteria.timeUnit": Array [
|
||||
"m",
|
||||
],
|
||||
"kibana.alert.rule.parameters.nodeType": Array [
|
||||
"host",
|
||||
],
|
||||
"kibana.alert.rule.parameters.sourceId": Array [
|
||||
"default",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
describe('getInventoryViewInAppUrl', () => {
|
||||
it('should work with custom metrics', () => {
|
||||
const fields = {
|
||||
|
@ -36,5 +97,61 @@ describe('Inventory Threshold Rule', () => {
|
|||
'/app/metrics/link-to/inventory?customMetric=&metric=%28type%3Acpu%29&nodeType=h×tamp=1640995200000'
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with custom metrics when ALERT_RULE_PARAMETERS is an object', () => {
|
||||
const fields = {
|
||||
'@timestamp': '2022-01-01T00:00:00.000Z',
|
||||
'kibana.alert.rule.parameters': {
|
||||
sourceId: 'default',
|
||||
criteria: [
|
||||
{
|
||||
comparator: '>',
|
||||
timeSize: 1,
|
||||
metric: 'custom',
|
||||
threshold: [5],
|
||||
customMetric: {
|
||||
field: 'system.cpu.user.pct',
|
||||
aggregation: 'avg',
|
||||
id: 'alert-custom-metric',
|
||||
type: 'custom',
|
||||
},
|
||||
timeUnit: 'm',
|
||||
},
|
||||
],
|
||||
nodeType: 'host',
|
||||
},
|
||||
_id: 'eaa439aa-a4bb-4e7c-b7f8-fbe532ca7366',
|
||||
_index: '.internal.alerts-observability.metrics.alerts-default-000001',
|
||||
} as unknown as ParsedTechnicalFields & Record<string, any>;
|
||||
const url = getInventoryViewInAppUrl(fields);
|
||||
expect(url).toEqual(
|
||||
'/app/metrics/link-to/inventory?customMetric=%28aggregation%3Aavg%2Cfield%3Asystem.cpu.user.pct%2Cid%3Aalert-custom-metric%2Ctype%3Acustom%29&metric=%28aggregation%3Aavg%2Cfield%3Asystem.cpu.user.pct%2Cid%3Aalert-custom-metric%2Ctype%3Acustom%29&nodeType=host×tamp=1640995200000'
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with non-custom metrics when ALERT_RULE_PARAMETERS is an object', () => {
|
||||
const fields = {
|
||||
'@timestamp': '2022-01-01T00:00:00.000Z',
|
||||
'kibana.alert.rule.parameters': {
|
||||
sourceId: 'default',
|
||||
criteria: [
|
||||
{
|
||||
comparator: '>',
|
||||
timeSize: 1,
|
||||
metric: 'cpu',
|
||||
threshold: [5],
|
||||
timeUnit: 'm',
|
||||
},
|
||||
],
|
||||
nodeType: 'host',
|
||||
},
|
||||
_id: 'eaa439aa-a4bb-4e7c-b7f8-fbe532ca7366',
|
||||
_index: '.internal.alerts-observability.metrics.alerts-default-000001',
|
||||
} as unknown as ParsedTechnicalFields & Record<string, any>;
|
||||
const url = getInventoryViewInAppUrl(fields);
|
||||
expect(url).toEqual(
|
||||
'/app/metrics/link-to/inventory?customMetric=&metric=%28type%3Acpu%29&nodeType=host×tamp=1640995200000'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,26 +10,68 @@ import { encode } from 'rison-node';
|
|||
import { stringify } from 'query-string';
|
||||
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common/parse_technical_fields';
|
||||
|
||||
export const flatAlertRuleParams = (params: {}, pKey = ''): Record<string, unknown[]> => {
|
||||
return Object.entries(params).reduce((acc, [key, field]) => {
|
||||
const objectKey = pKey.length ? `${pKey}.${key}` : key;
|
||||
if (typeof field === 'object' && field != null) {
|
||||
if (Array.isArray(field) && field.length > 0) {
|
||||
return {
|
||||
...acc,
|
||||
...flatAlertRuleParams(field[0] as {}, objectKey),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...acc,
|
||||
...flatAlertRuleParams(field as {}, objectKey),
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
...acc,
|
||||
[objectKey]: Array.isArray(field) ? field : [field],
|
||||
};
|
||||
}, {});
|
||||
};
|
||||
|
||||
export const getInventoryViewInAppUrl = (
|
||||
fields: ParsedTechnicalFields & Record<string, any>
|
||||
): string => {
|
||||
let inventoryFields = fields;
|
||||
|
||||
/* Temporary Solution -> https://github.com/elastic/kibana/issues/137033
|
||||
* In the alert table from timelines plugin (old table), we are using an API who is flattening all the response
|
||||
* from elasticsearch to Record<string, string[]>, The new alert table API from TriggersActionUI is not doing that
|
||||
* anymore, it is trusting and returning the way it has been done from the field API from elasticsearch. I think
|
||||
* it is better to trust elasticsearch and the mapping of the doc. When o11y will only use the new alert table from
|
||||
* triggersActionUI then we will stop using this flattening way and we will update the code to work with fields API,
|
||||
* it will be less magic.
|
||||
*/
|
||||
if (fields[ALERT_RULE_PARAMETERS]) {
|
||||
inventoryFields = {
|
||||
...fields,
|
||||
...flatAlertRuleParams(fields[ALERT_RULE_PARAMETERS] as {}, ALERT_RULE_PARAMETERS),
|
||||
};
|
||||
}
|
||||
|
||||
const nodeTypeField = `${ALERT_RULE_PARAMETERS}.nodeType`;
|
||||
const nodeType = fields[nodeTypeField];
|
||||
const nodeType = inventoryFields[nodeTypeField];
|
||||
let inventoryViewInAppUrl = '/app/metrics/link-to/inventory?';
|
||||
|
||||
if (nodeType) {
|
||||
const linkToParams: Record<string, any> = {
|
||||
nodeType: fields[nodeTypeField][0],
|
||||
timestamp: Date.parse(fields[TIMESTAMP]),
|
||||
nodeType: inventoryFields[nodeTypeField][0],
|
||||
timestamp: Date.parse(inventoryFields[TIMESTAMP]),
|
||||
customMetric: '',
|
||||
};
|
||||
// We always pick the first criteria metric for the URL
|
||||
const criteriaMetric = fields[`${ALERT_RULE_PARAMETERS}.criteria.metric`][0];
|
||||
const criteriaMetric = inventoryFields[`${ALERT_RULE_PARAMETERS}.criteria.metric`][0];
|
||||
if (criteriaMetric === 'custom') {
|
||||
const criteriaCustomMetricId = fields[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.id`][0];
|
||||
const criteriaCustomMetricId =
|
||||
inventoryFields[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.id`][0];
|
||||
const criteriaCustomMetricAggregation =
|
||||
fields[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.aggregation`][0];
|
||||
inventoryFields[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.aggregation`][0];
|
||||
const criteriaCustomMetricField =
|
||||
fields[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.field`][0];
|
||||
inventoryFields[`${ALERT_RULE_PARAMETERS}.criteria.customMetric.field`][0];
|
||||
|
||||
const customMetric = encode({
|
||||
id: criteriaCustomMetricId,
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
import type { GetRenderCellValue } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { observabilityFeatureId } from '../../common';
|
||||
import { useBulkAddToCaseActions } from '../hooks/use_alert_bulk_case_actions';
|
||||
import { TopAlert, useToGetInternalFlyout } from '../pages/alerts';
|
||||
import { getRenderCellValue } from '../pages/alerts/components/render_cell_value';
|
||||
import { addDisplayNames } from '../pages/alerts/containers/alerts_table_t_grid/add_display_names';
|
||||
import { columns as alertO11yColumns } from '../pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid';
|
||||
import { getRowActions } from '../pages/alerts/containers/alerts_table_t_grid/get_row_actions';
|
||||
import type { ObservabilityRuleTypeRegistry } from '../rules/create_observability_rule_type_registry';
|
||||
|
||||
const getO11yAlertsTableConfiguration = (
|
||||
|
@ -22,9 +24,11 @@ const getO11yAlertsTableConfiguration = (
|
|||
const { header, body, footer } = useToGetInternalFlyout(observabilityRuleTypeRegistry);
|
||||
return { header, body, footer };
|
||||
},
|
||||
useActionsColumn: getRowActions(observabilityRuleTypeRegistry),
|
||||
getRenderCellValue: (({ setFlyoutAlert }: { setFlyoutAlert: (data: TopAlert) => void }) => {
|
||||
return getRenderCellValue({ observabilityRuleTypeRegistry, setFlyoutAlert });
|
||||
}) as unknown as GetRenderCellValue,
|
||||
useBulkActions: useBulkAddToCaseActions,
|
||||
});
|
||||
|
||||
export { getO11yAlertsTableConfiguration };
|
||||
|
|
|
@ -63,7 +63,7 @@ import { getRenderCellValue } from '../../components/render_cell_value';
|
|||
import { observabilityAppId, observabilityFeatureId } from '../../../../../common';
|
||||
import { useGetUserCasesPermissions } from '../../../../hooks/use_get_user_cases_permissions';
|
||||
import { usePluginContext } from '../../../../hooks/use_plugin_context';
|
||||
import { LazyAlertsFlyout } from '../../../..';
|
||||
import { LazyAlertsFlyout, ObservabilityRuleTypeRegistry } from '../../../..';
|
||||
import { parseAlert } from '../../components/parse_alert';
|
||||
import { translations, paths } from '../../../../config';
|
||||
import { addDisplayNames } from './add_display_names';
|
||||
|
@ -82,9 +82,13 @@ interface AlertsTableTGridProps {
|
|||
itemsPerPage?: number;
|
||||
}
|
||||
|
||||
interface ObservabilityActionsProps extends ActionProps {
|
||||
export type ObservabilityActionsProps = Pick<
|
||||
ActionProps,
|
||||
'data' | 'eventId' | 'ecsData' | 'setEventsDeleted'
|
||||
> & {
|
||||
setFlyoutAlert: React.Dispatch<React.SetStateAction<TopAlert | undefined>>;
|
||||
}
|
||||
observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry;
|
||||
};
|
||||
|
||||
const EventsThContent = styled.div.attrs(({ className = '' }) => ({
|
||||
className: `siemEventsTable__thContent ${className}`,
|
||||
|
@ -142,13 +146,13 @@ const NO_ROW_RENDER: RowRenderer[] = [];
|
|||
|
||||
const trailingControlColumns: never[] = [];
|
||||
|
||||
function ObservabilityActions({
|
||||
export function ObservabilityActions({
|
||||
data,
|
||||
eventId,
|
||||
ecsData,
|
||||
observabilityRuleTypeRegistry,
|
||||
setFlyoutAlert,
|
||||
}: ObservabilityActionsProps) {
|
||||
const { observabilityRuleTypeRegistry } = usePluginContext();
|
||||
const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {});
|
||||
const [openActionsPopoverId, setActionsPopover] = useState(null);
|
||||
const { cases, http } = useKibana<ObservabilityAppServices>().services;
|
||||
|
@ -263,42 +267,40 @@ function ObservabilityActions({
|
|||
|
||||
return (
|
||||
<>
|
||||
<EuiFlexGroup gutterSize="none" responsive={false}>
|
||||
<EuiFlexItem>
|
||||
<EuiToolTip content={translations.alertsTable.viewInAppTextLabel}>
|
||||
<EuiButtonIcon
|
||||
size="s"
|
||||
href={http.basePath.prepend(alert.link ?? '')}
|
||||
iconType="eye"
|
||||
color="text"
|
||||
aria-label={translations.alertsTable.viewInAppTextLabel}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiPopover
|
||||
button={
|
||||
<EuiToolTip content={actionsToolTip}>
|
||||
<EuiButtonIcon
|
||||
display="empty"
|
||||
size="s"
|
||||
color="text"
|
||||
iconType="boxesHorizontal"
|
||||
aria-label={actionsToolTip}
|
||||
onClick={() => toggleActionsPopover(eventId)}
|
||||
data-test-subj="alertsTableRowActionMore"
|
||||
/>
|
||||
</EuiToolTip>
|
||||
}
|
||||
isOpen={openActionsPopoverId === eventId}
|
||||
closePopover={closeActionsPopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
>
|
||||
<EuiContextMenuPanel size="s" items={actionsMenuItems} />
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiToolTip content={translations.alertsTable.viewInAppTextLabel}>
|
||||
<EuiButtonIcon
|
||||
size="s"
|
||||
href={http.basePath.prepend(alert.link ?? '')}
|
||||
iconType="eye"
|
||||
color="text"
|
||||
aria-label={translations.alertsTable.viewInAppTextLabel}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiPopover
|
||||
button={
|
||||
<EuiToolTip content={actionsToolTip}>
|
||||
<EuiButtonIcon
|
||||
display="empty"
|
||||
size="s"
|
||||
color="text"
|
||||
iconType="boxesHorizontal"
|
||||
aria-label={actionsToolTip}
|
||||
onClick={() => toggleActionsPopover(eventId)}
|
||||
data-test-subj="alertsTableRowActionMore"
|
||||
/>
|
||||
</EuiToolTip>
|
||||
}
|
||||
isOpen={openActionsPopoverId === eventId}
|
||||
closePopover={closeActionsPopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downLeft"
|
||||
>
|
||||
<EuiContextMenuPanel size="s" items={actionsMenuItems} />
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -377,16 +379,19 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
|
|||
},
|
||||
rowCellRender: (actionProps: ActionProps) => {
|
||||
return (
|
||||
<ObservabilityActions
|
||||
{...actionProps}
|
||||
setEventsDeleted={setEventsDeleted}
|
||||
setFlyoutAlert={setFlyoutAlert}
|
||||
/>
|
||||
<EuiFlexGroup gutterSize="none" responsive={false}>
|
||||
<ObservabilityActions
|
||||
{...actionProps}
|
||||
setEventsDeleted={setEventsDeleted}
|
||||
setFlyoutAlert={setFlyoutAlert}
|
||||
observabilityRuleTypeRegistry={observabilityRuleTypeRegistry}
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
}, [setEventsDeleted]);
|
||||
}, [setEventsDeleted, observabilityRuleTypeRegistry]);
|
||||
|
||||
const onStateChange = useCallback(
|
||||
(state: TGridState) => {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy';
|
||||
import { ObservabilityRuleTypeRegistry } from '../../../../rules/create_observability_rule_type_registry';
|
||||
import { ObservabilityActions } from './alerts_table_t_grid';
|
||||
import type { ObservabilityActionsProps } from './alerts_table_t_grid';
|
||||
|
||||
const buildData = (alerts: EcsFieldsResponse): ObservabilityActionsProps['data'] => {
|
||||
return Object.entries(alerts).reduce<ObservabilityActionsProps['data']>(
|
||||
(acc, [field, value]) => [...acc, { field, value }],
|
||||
[]
|
||||
);
|
||||
};
|
||||
const fakeSetEventsDeleted = () => [];
|
||||
export const getRowActions = (observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry) => {
|
||||
return () => ({
|
||||
renderCustomActionsRow: (alert: EcsFieldsResponse, setFlyoutAlert: (data: unknown) => void) => {
|
||||
return (
|
||||
<ObservabilityActions
|
||||
data={buildData(alert)}
|
||||
eventId={alert._id}
|
||||
ecsData={{ _id: alert._id, _index: alert._index }}
|
||||
observabilityRuleTypeRegistry={observabilityRuleTypeRegistry}
|
||||
setEventsDeleted={fakeSetEventsDeleted}
|
||||
setFlyoutAlert={setFlyoutAlert}
|
||||
/>
|
||||
);
|
||||
},
|
||||
width: 120,
|
||||
});
|
||||
};
|
|
@ -34,6 +34,7 @@ import {
|
|||
import { ALERTS_FEATURE_ID, RuleExecutionStatusErrorReasons } from '@kbn/alerting-plugin/common';
|
||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import { RuleDefinitionProps } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { DeleteModalConfirmation } from './components/delete_modal_confirmation';
|
||||
import { CenterJustifiedSpinner } from './components/center_justified_spinner';
|
||||
import { RuleDetailsPathParams, EVENT_LOG_LIST_TAB, ALERT_LIST_TAB } from './types';
|
||||
|
@ -42,15 +43,17 @@ import { usePluginContext } from '../../hooks/use_plugin_context';
|
|||
import { useFetchRule } from '../../hooks/use_fetch_rule';
|
||||
import { RULES_BREADCRUMB_TEXT } from '../rules/translations';
|
||||
import { PageTitle } from './components';
|
||||
import { useKibana } from '../../utils/kibana_react';
|
||||
import { getHealthColor } from './config';
|
||||
import { hasExecuteActionsCapability, hasAllPrivilege } from './config';
|
||||
import { paths } from '../../config/paths';
|
||||
import { observabilityFeatureId } from '../../../common';
|
||||
import { ALERT_STATUS_LICENSE_ERROR, rulesStatusesTranslationsMapping } from './translations';
|
||||
import { ObservabilityAppServices } from '../../application/types';
|
||||
import { useGetUserCasesPermissions } from '../../hooks/use_get_user_cases_permissions';
|
||||
|
||||
export function RuleDetailsPage() {
|
||||
const {
|
||||
cases,
|
||||
http,
|
||||
triggersActionsUi: {
|
||||
alertsTableConfigurationRegistry,
|
||||
|
@ -63,7 +66,7 @@ export function RuleDetailsPage() {
|
|||
},
|
||||
application: { capabilities, navigateToUrl },
|
||||
notifications: { toasts },
|
||||
} = useKibana().services;
|
||||
} = useKibana<ObservabilityAppServices>().services;
|
||||
|
||||
const { ruleId } = useParams<RuleDetailsPathParams>();
|
||||
const { ObservabilityPageTemplate, observabilityRuleTypeRegistry } = usePluginContext();
|
||||
|
@ -150,7 +153,13 @@ export function RuleDetailsPage() {
|
|||
? !ruleTypeRegistry.get(rule.ruleTypeId).requiresAppContext
|
||||
: false);
|
||||
|
||||
const userPermissions = useGetUserCasesPermissions();
|
||||
|
||||
const alertStateProps = {
|
||||
cases: {
|
||||
ui: cases.ui,
|
||||
permissions: userPermissions,
|
||||
},
|
||||
alertsTableConfigurationRegistry,
|
||||
configurationId: observabilityFeatureId,
|
||||
id: `case-details-alerts-o11y`,
|
||||
|
|
|
@ -92,6 +92,17 @@ const AlertsTable: React.FunctionComponent<AlertsTableProps> = (props: AlertsTab
|
|||
|
||||
const [visibleColumns, setVisibleColumns] = useState(props.visibleColumns);
|
||||
|
||||
// TODO when every solution is using this table, we will be able to simplify it by just passing the alert index
|
||||
const handleFlyoutAlert = useCallback(
|
||||
(alert) => {
|
||||
const idx = alerts.findIndex((a) =>
|
||||
(a as any)[ALERT_UUID].includes(alert.fields[ALERT_UUID])
|
||||
);
|
||||
setFlyoutAlertIndex(idx);
|
||||
},
|
||||
[alerts, setFlyoutAlertIndex]
|
||||
);
|
||||
|
||||
const onChangeVisibleColumns = useCallback(
|
||||
(newColumns: string[]) => {
|
||||
setVisibleColumns(newColumns);
|
||||
|
@ -144,7 +155,8 @@ const AlertsTable: React.FunctionComponent<AlertsTableProps> = (props: AlertsTab
|
|||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
{renderCustomActionsRow && renderCustomActionsRow(alerts[visibleRowIndex])}
|
||||
{renderCustomActionsRow &&
|
||||
renderCustomActionsRow(alerts[visibleRowIndex], handleFlyoutAlert)}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
},
|
||||
|
@ -161,6 +173,7 @@ const AlertsTable: React.FunctionComponent<AlertsTableProps> = (props: AlertsTab
|
|||
}, [
|
||||
actionsColumnWidth,
|
||||
alerts,
|
||||
handleFlyoutAlert,
|
||||
getBulkActionsLeadingControlColumn,
|
||||
isBulkActionsColumnActive,
|
||||
props.leadingControlColumns,
|
||||
|
@ -179,17 +192,6 @@ const AlertsTable: React.FunctionComponent<AlertsTableProps> = (props: AlertsTab
|
|||
|
||||
const handleFlyoutClose = useCallback(() => setFlyoutAlertIndex(-1), [setFlyoutAlertIndex]);
|
||||
|
||||
// TODO when every solution is using this table, we will be able to simplify it by just passing the alert index
|
||||
const handleFlyoutAlert = useCallback(
|
||||
(alert) => {
|
||||
const idx = alerts.findIndex((a) =>
|
||||
(a as any)[ALERT_UUID].includes(alert.fields[ALERT_UUID])
|
||||
);
|
||||
setFlyoutAlertIndex(idx);
|
||||
},
|
||||
[alerts, setFlyoutAlertIndex]
|
||||
);
|
||||
|
||||
const basicRenderCellValue = ({
|
||||
data,
|
||||
columnId,
|
||||
|
|
|
@ -460,7 +460,10 @@ export interface AlertsTableConfigurationRegistry {
|
|||
sort?: SortCombinations[];
|
||||
getRenderCellValue?: GetRenderCellValue;
|
||||
useActionsColumn?: () => {
|
||||
renderCustomActionsRow: (alert?: EcsFieldsResponse) => JSX.Element;
|
||||
renderCustomActionsRow: (
|
||||
alert: EcsFieldsResponse,
|
||||
setFlyoutAlert: (data: unknown) => void
|
||||
) => JSX.Element;
|
||||
width?: number;
|
||||
};
|
||||
useBulkActions?: UseBulkActionsRegistry;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue