[RAM] Refactor alert 011y fly-out to just use hook (#135161)

* refactor alert flyout to just use hook

* fix unit test

* thanks to test, we find out discrepency between reconcilliation of components

* open rule details from o11y
This commit is contained in:
Xavier Mouligneau 2022-06-28 02:28:32 -04:00 committed by GitHub
parent 1916efbb1c
commit c4350f1f2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 239 additions and 439 deletions

View file

@ -51,7 +51,7 @@ describe('Case View Page activity tab', () => {
values: ['alert-id-1'], values: ['alert-id-1'],
}, },
}, },
flyoutState: 'internal', flyoutSize: 'm',
showExpandToDetails: true, showExpandToDetails: true,
}); });
}); });
@ -73,7 +73,7 @@ describe('Case View Page activity tab', () => {
values: ['alert-id-1'], values: ['alert-id-1'],
}, },
}, },
flyoutState: 'external', flyoutSize: 's',
showExpandToDetails: false, showExpandToDetails: false,
}); });
}); });

View file

@ -7,8 +7,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { AlertsTableFlyoutState } from '@kbn/triggers-actions-ui-plugin/public'; import { EuiFlexItem, EuiFlexGroup, EuiProgress, EuiFlyoutSize } from '@elastic/eui';
import { EuiFlexItem, EuiFlexGroup, EuiProgress } from '@elastic/eui';
import { Case } from '../../../../common'; import { Case } from '../../../../common';
import { useKibana } from '../../../common/lib/kibana'; import { useKibana } from '../../../common/lib/kibana';
import { getManualAlertIds, getRegistrationContextFromAlerts } from './helpers'; import { getManualAlertIds, getRegistrationContextFromAlerts } from './helpers';
@ -41,9 +40,7 @@ export const CaseViewAlerts = ({ caseData }: CaseViewAlertsProps) => {
alertsTableConfigurationRegistry: triggersActionsUi.alertsTableConfigurationRegistry, alertsTableConfigurationRegistry: triggersActionsUi.alertsTableConfigurationRegistry,
configurationId: caseData.owner, configurationId: caseData.owner,
id: `case-details-alerts-${caseData.owner}`, id: `case-details-alerts-${caseData.owner}`,
flyoutState: alertFeatureIds.includes('siem') flyoutSize: (alertFeatureIds.includes('siem') ? 'm' : 's') as EuiFlyoutSize,
? AlertsTableFlyoutState.internal
: AlertsTableFlyoutState.external,
featureIds: alertFeatureIds, featureIds: alertFeatureIds,
query: alertIdsQuery, query: alertIdsQuery,
showExpandToDetails: alertFeatureIds.includes('siem'), showExpandToDetails: alertFeatureIds.includes('siem'),

View file

@ -5,36 +5,26 @@
* 2.0. * 2.0.
*/ */
import type { import type { GetRenderCellValue } from '@kbn/triggers-actions-ui-plugin/public';
AlertTableFlyoutComponent,
GetRenderCellValue,
} from '@kbn/triggers-actions-ui-plugin/public';
import { lazy } from 'react';
import { observabilityFeatureId } from '../../common'; import { observabilityFeatureId } from '../../common';
import { TopAlert, useToGetInternalFlyout } from '../pages/alerts';
import { getRenderCellValue } from '../pages/alerts/components/render_cell_value'; import { getRenderCellValue } from '../pages/alerts/components/render_cell_value';
import { addDisplayNames } from '../pages/alerts/containers/alerts_table_t_grid/add_display_names'; 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 { columns as alertO11yColumns } from '../pages/alerts/containers/alerts_table_t_grid/alerts_table_t_grid';
import type { ObservabilityRuleTypeRegistry } from '../rules/create_observability_rule_type_registry';
const AlertsPageFlyoutHeaderLazy = lazy( const getO11yAlertsTableConfiguration = (
() => import('../pages/alerts/components/alerts_flyout/alerts_flyout_header') observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry
); ) => ({
const AlertsPageFlyoutBodyLazy = lazy(
() => import('../pages/alerts/components/alerts_flyout/alerts_flyout_body')
);
const AlertsFlyoutFooterLazy = lazy(
() => import('../pages/alerts/components/alerts_flyout/alerts_flyout_footer')
);
const getO11yAlertsTableConfiguration = () => ({
id: observabilityFeatureId, id: observabilityFeatureId,
columns: alertO11yColumns.map(addDisplayNames), columns: alertO11yColumns.map(addDisplayNames),
externalFlyout: { useInternalFlyout: () => {
header: AlertsPageFlyoutHeaderLazy as AlertTableFlyoutComponent, const { header, body, footer } = useToGetInternalFlyout(observabilityRuleTypeRegistry);
body: AlertsPageFlyoutBodyLazy as AlertTableFlyoutComponent, return { header, body, footer };
footer: AlertsFlyoutFooterLazy as AlertTableFlyoutComponent,
}, },
getRenderCellValue: getRenderCellValue as GetRenderCellValue, getRenderCellValue: (({ setFlyoutAlert }: { setFlyoutAlert: (data: TopAlert) => void }) => {
return getRenderCellValue({ observabilityRuleTypeRegistry, setFlyoutAlert });
}) as unknown as GetRenderCellValue,
}); });
export { getO11yAlertsTableConfiguration }; export { getO11yAlertsTableConfiguration };

View file

@ -5,41 +5,15 @@
* 2.0. * 2.0.
*/ */
import { import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutProps } from '@elastic/eui';
EuiButton, import { ALERT_UUID } from '@kbn/rule-data-utils';
EuiDescriptionList,
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiFlyoutProps,
EuiLink,
EuiSpacer,
EuiText,
EuiTitle,
EuiHorizontalRule,
} from '@elastic/eui';
import {
ALERT_DURATION,
ALERT_EVALUATION_THRESHOLD,
ALERT_EVALUATION_VALUE,
ALERT_UUID,
ALERT_RULE_CATEGORY,
ALERT_RULE_NAME,
ALERT_STATUS_ACTIVE,
ALERT_STATUS_RECOVERED,
} from '@kbn/rule-data-utils';
import moment from 'moment-timezone';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useKibana, useUiSetting } from '@kbn/kibana-react-plugin/public';
import type { TopAlert } from '../../containers'; import type { TopAlert } from '../../containers';
import { asDuration } from '../../../../../common/utils/formatters';
import type { ObservabilityRuleTypeRegistry } from '../../../../rules/create_observability_rule_type_registry'; import type { ObservabilityRuleTypeRegistry } from '../../../../rules/create_observability_rule_type_registry';
import { parseAlert } from '../parse_alert'; import { parseAlert } from '../parse_alert';
import { AlertStatusIndicator } from '../../../../components/shared/alert_status_indicator'; import AlertsFlyoutHeader from './alerts_flyout_header';
import { translations, paths } from '../../../../config'; import AlertsFlyoutBody from './alerts_flyout_body';
import AlertsFlyoutFooter from './alerts_flyout_footer';
type AlertsFlyoutProps = { type AlertsFlyoutProps = {
alert?: TopAlert; alert?: TopAlert;
@ -57,11 +31,6 @@ export function AlertsFlyout({
onClose, onClose,
selectedAlertId, selectedAlertId,
}: AlertsFlyoutProps) { }: AlertsFlyoutProps) {
const dateFormat = useUiSetting<string>('dateFormat');
const { services } = useKibana();
const { http } = services;
const prepend = http?.basePath.prepend;
const decoratedAlerts = useMemo(() => { const decoratedAlerts = useMemo(() => {
const parseObservabilityAlert = parseAlert(observabilityRuleTypeRegistry); const parseObservabilityAlert = parseAlert(observabilityRuleTypeRegistry);
return (alerts ?? []).map(parseObservabilityAlert); return (alerts ?? []).map(parseObservabilityAlert);
@ -69,107 +38,19 @@ export function AlertsFlyout({
let alertData = alert; let alertData = alert;
if (!alertData) { if (!alertData) {
alertData = decoratedAlerts?.find((a) => a.fields[ALERT_UUID] === selectedAlertId); alertData = decoratedAlerts?.find((a) => a.fields[ALERT_UUID] === selectedAlertId) as TopAlert;
} }
if (!alertData) { if (!alertData) {
return null; return null;
} }
const ruleId = alertData.fields['kibana.alert.rule.uuid'] ?? null;
const linkToRule = ruleId && prepend ? prepend(paths.observability.ruleDetails(ruleId)) : null;
const overviewListItems = [
{
title: translations.alertsFlyout.statusLabel,
description: (
<AlertStatusIndicator
alertStatus={alertData.active ? ALERT_STATUS_ACTIVE : ALERT_STATUS_RECOVERED}
/>
),
},
{
title: translations.alertsFlyout.startedAtLabel,
description: (
<span title={alertData.start.toString()}>{moment(alertData.start).format(dateFormat)}</span>
),
},
{
title: translations.alertsFlyout.lastUpdatedLabel,
description: (
<span title={alertData.lastUpdated.toString()}>
{moment(alertData.lastUpdated).format(dateFormat)}
</span>
),
},
{
title: translations.alertsFlyout.durationLabel,
description: asDuration(alertData.fields[ALERT_DURATION], { extended: true }),
},
{
title: translations.alertsFlyout.expectedValueLabel,
description: alertData.fields[ALERT_EVALUATION_THRESHOLD] ?? '-',
},
{
title: translations.alertsFlyout.actualValueLabel,
description: alertData.fields[ALERT_EVALUATION_VALUE] ?? '-',
},
{
title: translations.alertsFlyout.ruleTypeLabel,
description: alertData.fields[ALERT_RULE_CATEGORY] ?? '-',
},
];
return ( return (
<EuiFlyout onClose={onClose} size="s" data-test-subj="alertsFlyout"> <EuiFlyout onClose={onClose} size="s" data-test-subj="alertsFlyout">
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<EuiSpacer size="s" /> <AlertsFlyoutHeader alert={alertData} />
<EuiTitle size="m" data-test-subj="alertsFlyoutTitle">
<h2>{alertData.fields[ALERT_RULE_NAME]}</h2>
</EuiTitle>
</EuiFlyoutHeader> </EuiFlyoutHeader>
<EuiFlyoutBody> <AlertsFlyoutBody alert={alertData} />
<EuiTitle size="xs"> <AlertsFlyoutFooter alert={alertData} isInApp={isInApp} />
<h4>{translations.alertsFlyout.reasonTitle}</h4>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText size="s">{alertData.reason}</EuiText>
<EuiSpacer size="s" />
{!!linkToRule && (
<EuiLink href={linkToRule} data-test-subj="viewRuleDetailsFlyout">
{translations.alertsFlyout.viewRulesDetailsLinkText}
</EuiLink>
)}
<EuiHorizontalRule size="full" />
<EuiTitle size="xs">
<h4>{translations.alertsFlyout.documentSummaryTitle}</h4>
</EuiTitle>
<EuiSpacer size="m" />
<EuiDescriptionList
compressed={true}
type="responsiveColumn"
listItems={overviewListItems}
titleProps={{
'data-test-subj': 'alertsFlyoutDescriptionListTitle',
}}
descriptionProps={{
'data-test-subj': 'alertsFlyoutDescriptionListDescription',
}}
/>
</EuiFlyoutBody>
{alertData.link && !isInApp && (
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton
href={prepend && prepend(alertData.link)}
data-test-subj="alertsFlyoutViewInAppButton"
fill
>
{translations.alertsFlyout.viewInAppButtonText}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
)}
</EuiFlyout> </EuiFlyout>
); );
} }

View file

@ -13,12 +13,14 @@ import {
EuiLink, EuiLink,
EuiHorizontalRule, EuiHorizontalRule,
EuiDescriptionList, EuiDescriptionList,
EuiFlyoutBody,
} from '@elastic/eui'; } from '@elastic/eui';
import { import {
ALERT_DURATION, ALERT_DURATION,
ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_THRESHOLD,
ALERT_EVALUATION_VALUE, ALERT_EVALUATION_VALUE,
ALERT_RULE_CATEGORY, ALERT_RULE_CATEGORY,
ALERT_RULE_UUID,
ALERT_STATUS_ACTIVE, ALERT_STATUS_ACTIVE,
ALERT_STATUS_RECOVERED, ALERT_STATUS_RECOVERED,
} from '@kbn/rule-data-utils'; } from '@kbn/rule-data-utils';
@ -27,22 +29,17 @@ import { useKibana, useUiSetting } from '@kbn/kibana-react-plugin/public';
import { asDuration } from '../../../../../common/utils/formatters'; import { asDuration } from '../../../../../common/utils/formatters';
import { translations, paths } from '../../../../config'; import { translations, paths } from '../../../../config';
import { AlertStatusIndicator } from '../../../../components/shared/alert_status_indicator'; import { AlertStatusIndicator } from '../../../../components/shared/alert_status_indicator';
import { usePluginContext } from '../../../../hooks/use_plugin_context';
import { parseAlert } from '../parse_alert';
import { FlyoutProps } from './types'; import { FlyoutProps } from './types';
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default function AlertsFlyoutBody(props: FlyoutProps) { export default function AlertsFlyoutBody(props: FlyoutProps) {
const { observabilityRuleTypeRegistry } = usePluginContext(); const alert = props.alert;
const alert = props.alert.start
? props.alert
: parseAlert(observabilityRuleTypeRegistry)(props.alert as unknown as Record<string, unknown>);
const { services } = useKibana(); const { services } = useKibana();
const { http } = services; const { http } = services;
const dateFormat = useUiSetting<string>('dateFormat'); const dateFormat = useUiSetting<string>('dateFormat');
const prepend = http?.basePath.prepend; const prepend = http?.basePath.prepend;
const ruleId = get(props.alert, 'kibana.alert.rule.uuid') ?? null; const ruleId = get(props.alert.fields, ALERT_RULE_UUID) ?? null;
const linkToRule = ruleId && prepend ? prepend(paths.management.ruleDetails(ruleId)) : null; const linkToRule = ruleId && prepend ? prepend(paths.observability.ruleDetails(ruleId)) : null;
const overviewListItems = [ const overviewListItems = [
{ {
title: translations.alertsFlyout.statusLabel, title: translations.alertsFlyout.statusLabel,
@ -53,11 +50,19 @@ export default function AlertsFlyoutBody(props: FlyoutProps) {
), ),
}, },
{ {
title: translations.alertsFlyout.lastUpdatedLabel, title: translations.alertsFlyout.startedAtLabel,
description: ( description: (
<span title={alert.start.toString()}>{moment(alert.start).format(dateFormat)}</span> <span title={alert.start.toString()}>{moment(alert.start).format(dateFormat)}</span>
), ),
}, },
{
title: translations.alertsFlyout.lastUpdatedLabel,
description: (
<span title={alert.lastUpdated.toString()}>
{moment(alert.lastUpdated).format(dateFormat)}
</span>
),
},
{ {
title: translations.alertsFlyout.durationLabel, title: translations.alertsFlyout.durationLabel,
description: asDuration(alert.fields[ALERT_DURATION], { extended: true }), description: asDuration(alert.fields[ALERT_DURATION], { extended: true }),
@ -77,7 +82,7 @@ export default function AlertsFlyoutBody(props: FlyoutProps) {
]; ];
return ( return (
<> <EuiFlyoutBody>
<EuiTitle size="xs"> <EuiTitle size="xs">
<h4>{translations.alertsFlyout.reasonTitle}</h4> <h4>{translations.alertsFlyout.reasonTitle}</h4>
</EuiTitle> </EuiTitle>
@ -105,6 +110,6 @@ export default function AlertsFlyoutBody(props: FlyoutProps) {
'data-test-subj': 'alertsFlyoutDescriptionListDescription', 'data-test-subj': 'alertsFlyoutDescriptionListDescription',
}} }}
/> />
</> </EuiFlyoutBody>
); );
} }

View file

@ -5,7 +5,7 @@
* 2.0. * 2.0.
*/ */
import React from 'react'; import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; import { EuiFlyoutFooter, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui';
import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public';
import { FlyoutProps } from './types'; import { FlyoutProps } from './types';
import { translations } from '../../../../config'; import { translations } from '../../../../config';
@ -18,16 +18,18 @@ export default function AlertsFlyoutFooter({ alert, isInApp }: FlyoutProps & { i
if (!alert.link || isInApp) return <></>; if (!alert.link || isInApp) return <></>;
return ( return (
<EuiFlexGroup justifyContent="flexEnd"> <EuiFlyoutFooter>
<EuiFlexItem grow={false}> <EuiFlexGroup justifyContent="flexEnd">
<EuiButton <EuiFlexItem grow={false}>
href={prepend && prepend(alert.link)} <EuiButton
data-test-subj="alertsFlyoutViewInAppButton" href={prepend && prepend(alert.link)}
fill data-test-subj="alertsFlyoutViewInAppButton"
> fill
{translations.alertsFlyout.viewInAppButtonText} >
</EuiButton> {translations.alertsFlyout.viewInAppButtonText}
</EuiFlexItem> </EuiButton>
</EuiFlexGroup> </EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
); );
} }

View file

@ -6,7 +6,6 @@
*/ */
import React from 'react'; import React from 'react';
import { ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { ALERT_RULE_NAME } from '@kbn/rule-data-utils';
import { get } from 'lodash';
import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { EuiSpacer, EuiTitle } from '@elastic/eui';
import { FlyoutProps } from './types'; import { FlyoutProps } from './types';
@ -16,7 +15,7 @@ export default function AlertsFlyoutHeader({ alert }: FlyoutProps) {
<> <>
<EuiSpacer size="s" /> <EuiSpacer size="s" />
<EuiTitle size="m" data-test-subj="alertsFlyoutTitle"> <EuiTitle size="m" data-test-subj="alertsFlyoutTitle">
<h2>{get(alert, ALERT_RULE_NAME)}</h2> <h2>{alert.fields[ALERT_RULE_NAME]}</h2>
</EuiTitle> </EuiTitle>
</> </>
); );

View file

@ -1,8 +0,0 @@
/*
* 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.
*/
export { AlertsFlyout } from './alerts_flyout';

View file

@ -0,0 +1,60 @@
/*
* 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, { useCallback, useMemo } from 'react';
import { AlertsTableFlyoutBaseProps } from '@kbn/triggers-actions-ui-plugin/public';
import { ObservabilityRuleTypeRegistry } from '../../../../rules/create_observability_rule_type_registry';
import { parseAlert } from '../parse_alert';
import AlertsFlyoutHeader from './alerts_flyout_header';
import AlertsFlyoutBody from './alerts_flyout_body';
import AlertsFlyoutFooter from './alerts_flyout_footer';
export { AlertsFlyout } from './alerts_flyout';
export const useToGetInternalFlyout = (
observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry
) => {
const body = useCallback(
(props: AlertsTableFlyoutBaseProps) => {
const alert = parseAlert(observabilityRuleTypeRegistry)(
props.alert as unknown as Record<string, unknown>
);
return <AlertsFlyoutBody alert={alert} />;
},
[observabilityRuleTypeRegistry]
);
const header = useCallback(
(props: AlertsTableFlyoutBaseProps) => {
const alert = parseAlert(observabilityRuleTypeRegistry)(
props.alert as unknown as Record<string, unknown>
);
return <AlertsFlyoutHeader alert={alert} />;
},
[observabilityRuleTypeRegistry]
);
const footer = useCallback(
(props: AlertsTableFlyoutBaseProps) => {
const alert = parseAlert(observabilityRuleTypeRegistry)(
props.alert as unknown as Record<string, unknown>
);
return <AlertsFlyoutFooter isInApp={false} alert={alert} />;
},
[observabilityRuleTypeRegistry]
);
return useMemo(
() => ({
body,
header,
footer,
}),
[body, header, footer]
);
};

View file

@ -4,17 +4,9 @@
* 2.0; you may not use this file except in compliance with the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License
* 2.0. * 2.0.
*/ */
import { AlertsTableFlyoutBaseProps } from '@kbn/triggers-actions-ui-plugin/public';
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common/parse_technical_fields';
import { ParsedExperimentalFields } from '@kbn/rule-registry-plugin/common/parse_experimental_fields';
import { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy';
export type FlyoutProps = AlertsTableFlyoutBaseProps & { import { TopAlert } from '../../containers';
alert: EcsFieldsResponse & {
fields: ParsedTechnicalFields & ParsedExperimentalFields; export interface FlyoutProps {
start: number; alert: TopAlert;
reason: string; }
link?: string;
active: boolean;
};
};

View file

@ -8,7 +8,6 @@
import { ALERT_STATUS, ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; import { ALERT_STATUS, ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils';
import type { CellValueElementProps } from '@kbn/timelines-plugin/common'; import type { CellValueElementProps } from '@kbn/timelines-plugin/common';
import { createObservabilityRuleTypeRegistryMock } from '../../../../rules/observability_rule_type_registry_mock'; import { createObservabilityRuleTypeRegistryMock } from '../../../../rules/observability_rule_type_registry_mock';
import * as PluginHook from '../../../../hooks/use_plugin_context';
import { render } from '../../../../utils/test_helper'; import { render } from '../../../../utils/test_helper';
import { getRenderCellValue } from './render_cell_value'; import { getRenderCellValue } from './render_cell_value';
@ -18,15 +17,10 @@ interface AlertsTableRow {
describe('getRenderCellValue', () => { describe('getRenderCellValue', () => {
const observabilityRuleTypeRegistryMock = createObservabilityRuleTypeRegistryMock(); const observabilityRuleTypeRegistryMock = createObservabilityRuleTypeRegistryMock();
jest.spyOn(PluginHook, 'usePluginContext').mockImplementation(
() =>
({
observabilityRuleTypeRegistry: observabilityRuleTypeRegistryMock,
} as any)
);
const renderCellValue = getRenderCellValue({ const renderCellValue = getRenderCellValue({
setFlyoutAlert: jest.fn(), setFlyoutAlert: jest.fn(),
observabilityRuleTypeRegistry: observabilityRuleTypeRegistryMock,
}); });
describe('when column is alert status', () => { describe('when column is alert status', () => {

View file

@ -22,7 +22,7 @@ import { asDuration } from '../../../../../common/utils/formatters';
import { SeverityBadge } from '../severity_badge'; import { SeverityBadge } from '../severity_badge';
import { TopAlert } from '../..'; import { TopAlert } from '../..';
import { parseAlert } from '../parse_alert'; import { parseAlert } from '../parse_alert';
import { usePluginContext } from '../../../../hooks/use_plugin_context'; import { ObservabilityRuleTypeRegistry } from '../../../../rules/create_observability_rule_type_registry';
export const getMappedNonEcsValue = ({ export const getMappedNonEcsValue = ({
data, data,
@ -46,12 +46,13 @@ export const getMappedNonEcsValue = ({
export const getRenderCellValue = ({ export const getRenderCellValue = ({
setFlyoutAlert, setFlyoutAlert,
observabilityRuleTypeRegistry,
}: { }: {
setFlyoutAlert: (data: TopAlert) => void; setFlyoutAlert: (data: TopAlert) => void;
observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry;
}) => { }) => {
return ({ columnId, data }: CellValueElementProps) => { return ({ columnId, data }: CellValueElementProps) => {
if (!data) return null; if (!data) return null;
const { observabilityRuleTypeRegistry } = usePluginContext();
const value = getMappedNonEcsValue({ const value = getMappedNonEcsValue({
data, data,
fieldName: columnId, fieldName: columnId,

View file

@ -325,6 +325,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
timelines, timelines,
application: { capabilities }, application: { capabilities },
} = useKibana<ObservabilityAppServices>().services; } = useKibana<ObservabilityAppServices>().services;
const { observabilityRuleTypeRegistry } = usePluginContext();
const [flyoutAlert, setFlyoutAlert] = useState<TopAlert | undefined>(undefined); const [flyoutAlert, setFlyoutAlert] = useState<TopAlert | undefined>(undefined);
const [tGridState, setTGridState] = useState<Partial<TGridModel> | null>( const [tGridState, setTGridState] = useState<Partial<TGridModel> | null>(
@ -432,7 +433,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
query: kuery ?? '', query: kuery ?? '',
language: 'kuery', language: 'kuery',
}, },
renderCellValue: getRenderCellValue({ setFlyoutAlert }), renderCellValue: getRenderCellValue({ setFlyoutAlert, observabilityRuleTypeRegistry }),
rowRenderers: NO_ROW_RENDER, rowRenderers: NO_ROW_RENDER,
// TODO: implement Kibana data view runtime fields in observability // TODO: implement Kibana data view runtime fields in observability
runtimeMappings: {}, runtimeMappings: {},
@ -471,6 +472,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
hasAlertsCrudPermissions, hasAlertsCrudPermissions,
indexNames, indexNames,
itemsPerPage, itemsPerPage,
observabilityRuleTypeRegistry,
onStateChange, onStateChange,
kuery, kuery,
rangeFrom, rangeFrom,
@ -480,7 +482,6 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) {
]); ]);
const handleFlyoutClose = () => setFlyoutAlert(undefined); const handleFlyoutClose = () => setFlyoutAlert(undefined);
const { observabilityRuleTypeRegistry } = usePluginContext();
return ( return (
<> <>

View file

@ -15,6 +15,7 @@ import {
EuiButtonEmpty, EuiButtonEmpty,
EuiFlexGroup, EuiFlexGroup,
EuiFlexItem, EuiFlexItem,
EuiFlyoutSize,
EuiButtonIcon, EuiButtonIcon,
EuiPanel, EuiPanel,
EuiTitle, EuiTitle,
@ -36,7 +37,6 @@ import {
RuleType, RuleType,
getNotifyWhenOptions, getNotifyWhenOptions,
RuleEventLogListProps, RuleEventLogListProps,
AlertsTableFlyoutState,
} from '@kbn/triggers-actions-ui-plugin/public'; } from '@kbn/triggers-actions-ui-plugin/public';
// TODO: use a Delete modal from triggersActionUI when it's sharable // TODO: use a Delete modal from triggersActionUI when it's sharable
import { ALERTS_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { ALERTS_FEATURE_ID } from '@kbn/alerting-plugin/common';
@ -177,7 +177,7 @@ export function RuleDetailsPage() {
alertsTableConfigurationRegistry, alertsTableConfigurationRegistry,
configurationId: observabilityFeatureId, configurationId: observabilityFeatureId,
id: `case-details-alerts-o11y`, id: `case-details-alerts-o11y`,
flyoutState: AlertsTableFlyoutState.external, flyoutSize: 's' as EuiFlyoutSize,
featureIds: [features] as AlertConsumers[], featureIds: [features] as AlertConsumers[],
query: { query: {
bool: { bool: {

View file

@ -37,7 +37,10 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
import { observabilityAppId, observabilityFeatureId, casesPath } from '../common'; import { observabilityAppId, observabilityFeatureId, casesPath } from '../common';
import { createLazyObservabilityPageTemplate } from './components/shared'; import { createLazyObservabilityPageTemplate } from './components/shared';
import { registerDataHandler } from './data_handler'; import { registerDataHandler } from './data_handler';
import { createObservabilityRuleTypeRegistry } from './rules/create_observability_rule_type_registry'; import {
createObservabilityRuleTypeRegistry,
ObservabilityRuleTypeRegistry,
} from './rules/create_observability_rule_type_registry';
import { createCallObservabilityApi } from './services/call_observability_api'; import { createCallObservabilityApi } from './services/call_observability_api';
import { createNavigationRegistry, NavigationEntry } from './services/navigation_registry'; import { createNavigationRegistry, NavigationEntry } from './services/navigation_registry';
import { updateGlobalNavigation } from './update_global_navigation'; import { updateGlobalNavigation } from './update_global_navigation';
@ -83,6 +86,8 @@ export class Plugin
{ {
private readonly appUpdater$ = new BehaviorSubject<AppUpdater>(() => ({})); private readonly appUpdater$ = new BehaviorSubject<AppUpdater>(() => ({}));
private readonly navigationRegistry = createNavigationRegistry(); private readonly navigationRegistry = createNavigationRegistry();
private observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry =
{} as ObservabilityRuleTypeRegistry;
// Define deep links as constant and hidden. Whether they are shown or hidden // Define deep links as constant and hidden. Whether they are shown or hidden
// in the global navigation will happen in `updateGlobalNavigation`. // in the global navigation will happen in `updateGlobalNavigation`.
@ -134,7 +139,7 @@ export class Plugin
createCallObservabilityApi(coreSetup.http); createCallObservabilityApi(coreSetup.http);
const observabilityRuleTypeRegistry = createObservabilityRuleTypeRegistry( this.observabilityRuleTypeRegistry = createObservabilityRuleTypeRegistry(
pluginsSetup.triggersActionsUi.ruleTypeRegistry pluginsSetup.triggersActionsUi.ruleTypeRegistry
); );
@ -158,7 +163,7 @@ export class Plugin
core: coreStart, core: coreStart,
plugins: pluginsStart, plugins: pluginsStart,
appMountParameters: params, appMountParameters: params,
observabilityRuleTypeRegistry, observabilityRuleTypeRegistry: this.observabilityRuleTypeRegistry,
ObservabilityPageTemplate: navigation.PageTemplate, ObservabilityPageTemplate: navigation.PageTemplate,
kibanaFeatures, kibanaFeatures,
usageCollection: pluginsSetup.usageCollection, usageCollection: pluginsSetup.usageCollection,
@ -257,7 +262,7 @@ export class Plugin
return { return {
dashboard: { register: registerDataHandler }, dashboard: { register: registerDataHandler },
observabilityRuleTypeRegistry, observabilityRuleTypeRegistry: this.observabilityRuleTypeRegistry,
navigation: { navigation: {
registerSections: this.navigationRegistry.registerSections, registerSections: this.navigationRegistry.registerSections,
}, },
@ -286,7 +291,7 @@ export class Plugin
const { getO11yAlertsTableConfiguration } = await import( const { getO11yAlertsTableConfiguration } = await import(
'./config/register_alerts_table_configuration' './config/register_alerts_table_configuration'
); );
return getO11yAlertsTableConfiguration(); return getO11yAlertsTableConfiguration(this.observabilityRuleTypeRegistry);
}; };
const { alertsTableConfigurationRegistry } = pluginsStart.triggersActionsUi; const { alertsTableConfigurationRegistry } = pluginsStart.triggersActionsUi;

View file

@ -8,7 +8,7 @@ import React from 'react';
import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import { AlertsFlyout } from './alerts_flyout'; import { AlertsFlyout } from './alerts_flyout';
import { AlertsField, AlertsTableFlyoutState } from '../../../../types'; import { AlertsField } from '../../../../types';
const onClose = jest.fn(); const onClose = jest.fn();
const onPaginate = jest.fn(); const onPaginate = jest.fn();
@ -33,9 +33,6 @@ const props = {
initialWidth: 250, initialWidth: 250,
}, },
], ],
externalFlyout: {
body: () => <h3>External flyout body</h3>,
},
useInternalFlyout: () => ({ useInternalFlyout: () => ({
body: () => <h3>Internal flyout body</h3>, body: () => <h3>Internal flyout body</h3>,
header: null, header: null,
@ -49,7 +46,6 @@ const props = {
flyoutIndex: 0, flyoutIndex: 0,
alertsCount: 4, alertsCount: 4,
isLoading: false, isLoading: false,
state: AlertsTableFlyoutState.internal,
onClose, onClose,
onPaginate, onPaginate,
}; };
@ -66,123 +62,70 @@ describe('AlertsFlyout', () => {
wrapper.update(); wrapper.update();
}); });
expect(wrapper.find('h3').first().text()).toBe('Internal flyout body'); expect(wrapper.find('h3').first().text()).toBe('Internal flyout body');
const externalWrapper = mountWithIntl(
<AlertsFlyout
{...{
...props,
state: AlertsTableFlyoutState.external,
}}
/>
);
await act(async () => {
await nextTick();
externalWrapper.update();
});
expect(externalWrapper.find('h3').first().text()).toBe('External flyout body');
}); });
const configurations = [AlertsTableFlyoutState.external, AlertsTableFlyoutState.internal]; const base = {
for (const configuration of configurations) { body: () => null,
const base = { header: () => null,
body: () => <h5>Body</h5>, footer: () => null,
footer: () => null, };
it(`should use header from useInternalFlyout configuration`, async () => {
const customProps = {
...props,
alertsTableConfiguration: {
...props.alertsTableConfiguration,
useInternalFlyout: () => ({
...base,
header: () => <h4>Header</h4>,
footer: () => null,
}),
},
}; };
const wrapper = mountWithIntl(<AlertsFlyout {...customProps} />);
it(`should use ${configuration} header configuration`, async () => { await act(async () => {
const customProps = { await nextTick();
...props, wrapper.update();
alertsTableConfiguration: {
...props.alertsTableConfiguration,
...(configuration === AlertsTableFlyoutState.external
? {
[`${configuration}Flyout`]: {
...base,
header: () => <h4>Header</h4>,
footer: () => null,
},
}
: {
useInternalFlyout: () => ({
...base,
header: () => <h4>Header</h4>,
footer: () => null,
}),
}),
},
state: configuration,
};
const wrapper = mountWithIntl(<AlertsFlyout {...customProps} />);
await act(async () => {
await nextTick();
wrapper.update();
});
expect(wrapper.find('h4').first().text()).toBe('Header');
expect(wrapper.find('h5').first().text()).toBe('Body');
}); });
expect(wrapper.find('h4').first().text()).toBe('Header');
});
it(`should use ${configuration} body configuration`, async () => { it(`should use body from useInternalFlyout configuration`, async () => {
const customProps = { const customProps = {
...props, ...props,
alertsTableConfiguration: { alertsTableConfiguration: {
...props.alertsTableConfiguration, ...props.alertsTableConfiguration,
...(configuration === AlertsTableFlyoutState.external useInternalFlyout: () => ({
? { ...base,
[`${configuration}Flyout`]: { body: () => <h5>Body</h5>,
...base, }),
}, },
} };
: { const wrapper = mountWithIntl(<AlertsFlyout {...customProps} />);
useInternalFlyout: () => ({ await act(async () => {
...base, await nextTick();
}), wrapper.update();
}),
[`${configuration}Flyout`]: {
...base,
},
},
state: configuration,
};
const wrapper = mountWithIntl(<AlertsFlyout {...customProps} />);
await act(async () => {
await nextTick();
wrapper.update();
});
expect(wrapper.find('h2').first().text()).toBe('one');
expect(wrapper.find('h5').first().text()).toBe('Body');
}); });
expect(wrapper.find('h5').first().text()).toBe('Body');
});
it(`should use ${configuration} body configuration`, async () => { it(`should use footer from useInternalFlyout configuration`, async () => {
const customProps = { const customProps = {
...props, ...props,
alertsTableConfiguration: { alertsTableConfiguration: {
...props.alertsTableConfiguration, ...props.alertsTableConfiguration,
...(configuration === AlertsTableFlyoutState.external useInternalFlyout: () => ({
? { ...base,
[`${configuration}Flyout`]: { footer: () => <h6>Footer</h6>,
...base, }),
footer: () => <h6>Footer</h6>, },
}, };
} const wrapper = mountWithIntl(<AlertsFlyout {...customProps} />);
: { await act(async () => {
useInternalFlyout: () => ({ await nextTick();
...base, wrapper.update();
footer: () => <h6>Footer</h6>,
}),
}),
},
state: configuration,
};
const wrapper = mountWithIntl(<AlertsFlyout {...customProps} />);
await act(async () => {
await nextTick();
wrapper.update();
});
expect(wrapper.find('h2').first().text()).toBe('one');
expect(wrapper.find('h5').first().text()).toBe('Body');
expect(wrapper.find('h6').first().text()).toBe('Footer');
}); });
} expect(wrapper.find('h6').first().text()).toBe('Footer');
});
it('should allow pagination with next', async () => { it('should allow pagination with next', async () => {
const wrapper = mountWithIntl(<AlertsFlyout {...props} />); const wrapper = mountWithIntl(<AlertsFlyout {...props} />);

View file

@ -8,21 +8,16 @@ import React, { Suspense, lazy, useCallback, useMemo } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { import {
EuiFlyout, EuiFlyout,
EuiFlyoutBody,
EuiFlyoutHeader, EuiFlyoutHeader,
EuiSpacer, EuiSpacer,
EuiFlexGroup, EuiFlexGroup,
EuiFlexItem, EuiFlexItem,
EuiPagination, EuiPagination,
EuiProgress, EuiProgress,
EuiFlyoutFooter, EuiFlyoutSize,
} from '@elastic/eui'; } from '@elastic/eui';
import type { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy'; import type { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy';
import { import { AlertsTableConfigurationRegistry } from '../../../../types';
AlertsTableConfigurationRegistry,
AlertsTableFlyoutState,
AlertTableFlyoutComponent,
} from '../../../../types';
const AlertsFlyoutHeader = lazy(() => import('./alerts_flyout_header')); const AlertsFlyoutHeader = lazy(() => import('./alerts_flyout_header'));
const PAGINATION_LABEL = i18n.translate( const PAGINATION_LABEL = i18n.translate(
@ -36,9 +31,9 @@ interface AlertsFlyoutProps {
alert: EcsFieldsResponse; alert: EcsFieldsResponse;
alertsTableConfiguration: AlertsTableConfigurationRegistry; alertsTableConfiguration: AlertsTableConfigurationRegistry;
flyoutIndex: number; flyoutIndex: number;
flyoutSize?: EuiFlyoutSize;
alertsCount: number; alertsCount: number;
isLoading: boolean; isLoading: boolean;
state: AlertsTableFlyoutState;
onClose: () => void; onClose: () => void;
onPaginate: (pageIndex: number) => void; onPaginate: (pageIndex: number) => void;
} }
@ -46,39 +41,22 @@ export const AlertsFlyout: React.FunctionComponent<AlertsFlyoutProps> = ({
alert, alert,
alertsTableConfiguration, alertsTableConfiguration,
flyoutIndex, flyoutIndex,
flyoutSize = 'm',
alertsCount, alertsCount,
isLoading, isLoading,
state,
onClose, onClose,
onPaginate, onPaginate,
}: AlertsFlyoutProps) => { }: AlertsFlyoutProps) => {
let Header: AlertTableFlyoutComponent;
let Body: AlertTableFlyoutComponent;
let Footer: AlertTableFlyoutComponent;
const { const {
header: internalHeader, header: Header,
body: internalBody, body: Body,
footer: internalFooter, footer: Footer,
} = alertsTableConfiguration?.useInternalFlyout?.() ?? { } = alertsTableConfiguration?.useInternalFlyout?.() ?? {
header: null, header: AlertsFlyoutHeader,
body: null, body: null,
footer: null, footer: null,
}; };
switch (state) {
case AlertsTableFlyoutState.external:
Header = alertsTableConfiguration?.externalFlyout?.header ?? AlertsFlyoutHeader;
Body = alertsTableConfiguration?.externalFlyout?.body ?? null;
Footer = alertsTableConfiguration?.externalFlyout?.footer ?? null;
break;
case AlertsTableFlyoutState.internal:
Header = internalHeader ?? AlertsFlyoutHeader;
Body = internalBody ?? null;
Footer = internalFooter ?? null;
break;
}
const passedProps = useMemo( const passedProps = useMemo(
() => ({ () => ({
alert, alert,
@ -107,42 +85,22 @@ export const AlertsFlyout: React.FunctionComponent<AlertsFlyoutProps> = ({
[Footer, passedProps] [Footer, passedProps]
); );
const FlyoutBodyMemo = useMemo(() => { const FlyoutHeader = useCallback(
if (FlyoutBody) { () =>
if (state === AlertsTableFlyoutState.external) { Header ? (
return ( <Suspense fallback={null}>
<EuiFlyoutBody> <Header {...passedProps} />
<FlyoutBody /> </Suspense>
</EuiFlyoutBody> ) : null,
); [Header, passedProps]
} );
return <FlyoutBody />;
}
}, [FlyoutBody, state]);
const FlyoutFooterMemo = useMemo(() => {
if (FlyoutFooter) {
if (state === AlertsTableFlyoutState.external) {
return (
<EuiFlyoutFooter>
<FlyoutFooter />
</EuiFlyoutFooter>
);
}
return <FlyoutFooter />;
}
}, [FlyoutFooter, state]);
return ( return (
<EuiFlyout <EuiFlyout onClose={onClose} size={flyoutSize} data-test-subj="alertsFlyout">
onClose={onClose}
size={state === AlertsTableFlyoutState.external ? 's' : 'm'}
data-test-subj="alertsFlyout"
>
{isLoading && <EuiProgress size="xs" color="accent" data-test-subj="alertsFlyoutLoading" />} {isLoading && <EuiProgress size="xs" color="accent" data-test-subj="alertsFlyoutLoading" />}
<EuiFlyoutHeader hasBorder> <EuiFlyoutHeader hasBorder>
<Suspense fallback={null}> <Suspense fallback={null}>
<Header {...passedProps} /> <FlyoutHeader />
</Suspense> </Suspense>
<EuiSpacer size="m" /> <EuiSpacer size="m" />
<EuiFlexGroup gutterSize="none" justifyContent="flexEnd"> <EuiFlexGroup gutterSize="none" justifyContent="flexEnd">
@ -158,8 +116,8 @@ export const AlertsFlyout: React.FunctionComponent<AlertsFlyoutProps> = ({
</EuiFlexItem> </EuiFlexItem>
</EuiFlexGroup> </EuiFlexGroup>
</EuiFlyoutHeader> </EuiFlyoutHeader>
{FlyoutBodyMemo} <FlyoutBody />
{FlyoutFooterMemo} <FlyoutFooter />
</EuiFlyout> </EuiFlyout>
); );
}; };

View file

@ -10,7 +10,7 @@ import { AlertConsumers } from '@kbn/rule-data-utils';
import { getAlertsTableStateLazy } from '../../../../common/get_alerts_table_state'; import { getAlertsTableStateLazy } from '../../../../common/get_alerts_table_state';
import { PLUGIN_ID } from '../../../../common/constants'; import { PLUGIN_ID } from '../../../../common/constants';
import { useKibana } from '../../../../common/lib/kibana'; import { useKibana } from '../../../../common/lib/kibana';
import { AlertsTableConfigurationRegistry, AlertsTableFlyoutState } from '../../../../types'; import { AlertsTableConfigurationRegistry } from '../../../../types';
import { TypeRegistry } from '../../../type_registry'; import { TypeRegistry } from '../../../type_registry';
const consumers = [ const consumers = [
@ -28,7 +28,6 @@ const AlertsPage: React.FunctionComponent = () => {
alertsTableConfigurationRegistry as TypeRegistry<AlertsTableConfigurationRegistry>, alertsTableConfigurationRegistry as TypeRegistry<AlertsTableConfigurationRegistry>,
configurationId: PLUGIN_ID, configurationId: PLUGIN_ID,
id: `internal-alerts-page`, id: `internal-alerts-page`,
flyoutState: AlertsTableFlyoutState.internal,
featureIds: consumers, featureIds: consumers,
query: { bool: { must: [] } }, query: { bool: { must: [] } },
showExpandToDetails: true, showExpandToDetails: true,

View file

@ -48,10 +48,6 @@ export function registerAlertsTableConfiguration({
}, },
], ],
useInternalFlyout, useInternalFlyout,
externalFlyout: {
header: AlertsPageFlyoutHeader,
body: AlertsPageFlyoutBody,
},
getRenderCellValue: () => (props) => { getRenderCellValue: () => (props) => {
const myProps = props as any; const myProps = props as any;
const value = myProps.data.find((d: any) => d.field === myProps.columnId)?.value ?? []; const value = myProps.data.find((d: any) => d.field === myProps.columnId)?.value ?? [];

View file

@ -11,7 +11,7 @@ import userEvent from '@testing-library/user-event';
import { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy'; import { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy';
import { AlertsTable } from './alerts_table'; import { AlertsTable } from './alerts_table';
import { AlertsField, AlertsTableFlyoutState } from '../../../types'; import { AlertsField } from '../../../types';
jest.mock('@kbn/data-plugin/public'); jest.mock('@kbn/data-plugin/public');
@ -60,16 +60,11 @@ describe('AlertsTable', () => {
id: '', id: '',
columns, columns,
sort: [], sort: [],
externalFlyout: { useInternalFlyout: jest.fn().mockImplementation(() => ({
header: jest.fn(), header: jest.fn(),
body: jest.fn(), body: jest.fn(),
footer: jest.fn(), footer: jest.fn(),
}, })),
internalFlyout: {
header: jest.fn(),
body: jest.fn(),
footer: jest.fn(),
},
getRenderCellValue: () => getRenderCellValue: () =>
jest.fn().mockImplementation((props) => { jest.fn().mockImplementation((props) => {
return `${props.colIndex}:${props.rowIndex}`; return `${props.colIndex}:${props.rowIndex}`;
@ -89,7 +84,6 @@ describe('AlertsTable', () => {
showExpandToDetails: true, showExpandToDetails: true,
trailingControlColumns: [], trailingControlColumns: [],
alerts, alerts,
flyoutState: AlertsTableFlyoutState.internal,
useFetchAlertsData, useFetchAlertsData,
visibleColumns: columns.map((c) => c.id), visibleColumns: columns.map((c) => c.id),
'data-test-subj': 'testTable', 'data-test-subj': 'testTable',

View file

@ -181,7 +181,6 @@ const AlertsTable: React.FunctionComponent<AlertsTableProps> = (props: AlertsTab
<AlertsFlyout <AlertsFlyout
alert={alerts[flyoutAlertIndex]} alert={alerts[flyoutAlertIndex]}
alertsCount={alertsCount} alertsCount={alertsCount}
state={props.flyoutState}
onClose={handleFlyoutClose} onClose={handleFlyoutClose}
alertsTableConfiguration={props.alertsTableConfiguration} alertsTableConfiguration={props.alertsTableConfiguration}
flyoutIndex={flyoutAlertIndex + pagination.pageIndex * pagination.pageSize} flyoutIndex={flyoutAlertIndex + pagination.pageIndex * pagination.pageSize}

View file

@ -16,7 +16,6 @@ import {
AlertsField, AlertsField,
AlertsTableConfigurationRegistry, AlertsTableConfigurationRegistry,
AlertsTableFlyoutBaseProps, AlertsTableFlyoutBaseProps,
AlertsTableFlyoutState,
} from '../../../types'; } from '../../../types';
import { PLUGIN_ID } from '../../../common/constants'; import { PLUGIN_ID } from '../../../common/constants';
import { TypeRegistry } from '../../type_registry'; import { TypeRegistry } from '../../type_registry';
@ -110,7 +109,6 @@ describe('AlertsTableState', () => {
configurationId: PLUGIN_ID, configurationId: PLUGIN_ID,
id: `test-alerts`, id: `test-alerts`,
featureIds: [AlertConsumers.LOGS], featureIds: [AlertConsumers.LOGS],
flyoutState: AlertsTableFlyoutState.internal,
query: {}, query: {},
showExpandToDetails: true, showExpandToDetails: true,
}; };

View file

@ -6,7 +6,13 @@
*/ */
import React, { useState, useCallback, useRef, useMemo } from 'react'; import React, { useState, useCallback, useRef, useMemo } from 'react';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { EuiDataGridColumn, EuiProgress, EuiDataGridSorting, EuiEmptyPrompt } from '@elastic/eui'; import {
EuiDataGridColumn,
EuiProgress,
EuiDataGridSorting,
EuiEmptyPrompt,
EuiFlyoutSize,
} from '@elastic/eui';
import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { ValidFeatureId } from '@kbn/rule-data-utils';
import type { RuleRegistrySearchRequestPagination } from '@kbn/rule-registry-plugin/common'; import type { RuleRegistrySearchRequestPagination } from '@kbn/rule-registry-plugin/common';
import { Storage } from '@kbn/kibana-utils-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public';
@ -16,7 +22,7 @@ import type {
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { useFetchAlerts } from './hooks/use_fetch_alerts'; import { useFetchAlerts } from './hooks/use_fetch_alerts';
import { AlertsTable } from './alerts_table'; import { AlertsTable } from './alerts_table';
import { AlertsTableConfigurationRegistry, AlertsTableFlyoutState } from '../../../types'; import { AlertsTableConfigurationRegistry } from '../../../types';
import { ALERTS_TABLE_CONF_ERROR_MESSAGE, ALERTS_TABLE_CONF_ERROR_TITLE } from './translations'; import { ALERTS_TABLE_CONF_ERROR_MESSAGE, ALERTS_TABLE_CONF_ERROR_TITLE } from './translations';
import { TypeRegistry } from '../../type_registry'; import { TypeRegistry } from '../../type_registry';
@ -30,7 +36,7 @@ export interface AlertsTableStateProps {
configurationId: string; configurationId: string;
id: string; id: string;
featureIds: ValidFeatureId[]; featureIds: ValidFeatureId[];
flyoutState: AlertsTableFlyoutState; flyoutSize?: EuiFlyoutSize;
query: Pick<QueryDslQueryContainer, 'bool' | 'ids'>; query: Pick<QueryDslQueryContainer, 'bool' | 'ids'>;
pageSize?: number; pageSize?: number;
showExpandToDetails: boolean; showExpandToDetails: boolean;
@ -64,7 +70,7 @@ const AlertsTableState = ({
configurationId, configurationId,
id, id,
featureIds, featureIds,
flyoutState, flyoutSize,
query, query,
pageSize, pageSize,
showExpandToDetails, showExpandToDetails,
@ -191,7 +197,7 @@ const AlertsTableState = ({
bulkActions: [], bulkActions: [],
deletedEventIds: [], deletedEventIds: [],
disabledCellActions: [], disabledCellActions: [],
flyoutState, flyoutSize,
pageSize: pagination.pageSize, pageSize: pagination.pageSize,
pageSizeOptions: [10, 20, 50, 100], pageSizeOptions: [10, 20, 50, 100],
leadingControlColumns: [], leadingControlColumns: [],
@ -205,7 +211,7 @@ const AlertsTableState = ({
[ [
alertsTableConfiguration, alertsTableConfiguration,
columns, columns,
flyoutState, flyoutSize,
pagination.pageSize, pagination.pageSize,
showCheckboxes, showCheckboxes,
showExpandToDetails, showExpandToDetails,

View file

@ -41,8 +41,6 @@ export type {
GetRenderCellValue, GetRenderCellValue,
} from './types'; } from './types';
export { AlertsTableFlyoutState } from './types';
export { export {
ActionForm, ActionForm,
CreateConnectorFlyout, CreateConnectorFlyout,

View file

@ -13,7 +13,7 @@ import type { ChartsPluginSetup } from '@kbn/charts-plugin/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { IconType } from '@elastic/eui'; import type { IconType, EuiFlyoutSize } from '@elastic/eui';
import { EuiDataGridColumn, EuiDataGridControlColumn, EuiDataGridSorting } from '@elastic/eui'; import { EuiDataGridColumn, EuiDataGridControlColumn, EuiDataGridSorting } from '@elastic/eui';
import { import {
ActionType, ActionType,
@ -390,7 +390,7 @@ export interface AlertsTableProps {
// defaultCellActions: TGridCellAction[]; // defaultCellActions: TGridCellAction[];
deletedEventIds: string[]; deletedEventIds: string[];
disabledCellActions: string[]; disabledCellActions: string[];
flyoutState: AlertsTableFlyoutState; flyoutSize?: EuiFlyoutSize;
pageSize: number; pageSize: number;
pageSizeOptions: number[]; pageSizeOptions: number[];
leadingControlColumns: EuiDataGridControlColumn[]; leadingControlColumns: EuiDataGridControlColumn[];
@ -416,15 +416,10 @@ export type AlertTableFlyoutComponent =
export interface AlertsTableConfigurationRegistry { export interface AlertsTableConfigurationRegistry {
id: string; id: string;
columns: EuiDataGridColumn[]; columns: EuiDataGridColumn[];
externalFlyout?: {
header?: AlertTableFlyoutComponent;
body?: AlertTableFlyoutComponent;
footer?: AlertTableFlyoutComponent;
};
useInternalFlyout?: () => { useInternalFlyout?: () => {
header?: AlertTableFlyoutComponent; header: AlertTableFlyoutComponent;
body?: AlertTableFlyoutComponent; body: AlertTableFlyoutComponent;
footer?: AlertTableFlyoutComponent; footer: AlertTableFlyoutComponent;
}; };
sort?: SortCombinations[]; sort?: SortCombinations[];
getRenderCellValue?: GetRenderCellValue; getRenderCellValue?: GetRenderCellValue;
@ -435,11 +430,6 @@ export interface AlertsTableFlyoutBaseProps {
isLoading: boolean; isLoading: boolean;
} }
export enum AlertsTableFlyoutState {
internal = 'internal',
external = 'external',
}
export type RuleStatus = 'enabled' | 'disabled' | 'snoozed'; export type RuleStatus = 'enabled' | 'disabled' | 'snoozed';
export enum RRuleFrequency { export enum RRuleFrequency {