mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[AO] Add charts to Alert Summary Widget (#148143)
Resolves #147752
## 📝 Summary
Add charts to Alert Summary Widget
|Dark theme|Light Theme|Storybook|
|---|---|---|
||
## 🧪 How to test
1. Create a rule that generates alerts, check the Alert Summary Widget
component on the rule details page
2. Or just check the
[storybook](https://ci-artifacts.kibana.dev/storybooks/pr-148143/4cbef9ea90dac5b6858e64979f1a4b96e8523a7a/triggers_actions_ui/index.html?path=/story/app-alertssummarywidgetui--overview)
This commit is contained in:
parent
f115807ce0
commit
7875f0c348
13 changed files with 290 additions and 155 deletions
|
@ -372,7 +372,7 @@ export function RuleDetailsPage() {
|
|||
: [],
|
||||
}}
|
||||
>
|
||||
<EuiFlexGroup wrap={true} gutterSize="m">
|
||||
<EuiFlexGroup wrap gutterSize="m">
|
||||
<EuiFlexItem style={{ minWidth: 350 }}>
|
||||
{getRuleStatusPanel({
|
||||
rule,
|
||||
|
@ -382,17 +382,15 @@ export function RuleDetailsPage() {
|
|||
statusMessage,
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexItem style={{ minWidth: 350 }}>
|
||||
<AlertSummaryWidget
|
||||
featureIds={featureIds}
|
||||
onClick={(status) => onAlertSummaryWidgetClick(status)}
|
||||
onClick={onAlertSummaryWidgetClick}
|
||||
timeRange={defaultAlertTimeRange}
|
||||
filter={alertSummaryWidgetFilter.current}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiSpacer size="m" />
|
||||
{getRuleDefinition({ rule, onEditRule: () => reloadRule() } as RuleDefinitionProps)}
|
||||
{getRuleDefinition({ rule, onEditRule: reloadRule } as RuleDefinitionProps)}
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="l" />
|
||||
|
|
|
@ -35271,7 +35271,6 @@
|
|||
"xpack.triggersActionsUI.sections.ruleDetails.alertsList.columns.status": "Statut",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsList.ruleTypeExcessDurationMessage": "La durée dépasse le temps d'exécution attendu de la règle.",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.activeLabel": "Actuellement actives",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.allAlertsLabel": "Tous",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.errorLoadingBody": "Une erreur s'est produite lors du chargement du récapitulatif des alertes. Contactez votre administrateur pour obtenir de l'aide.",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.errorLoadingTitle": "Impossible de charger le récapitulatif des alertes",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.title": "Alertes",
|
||||
|
|
|
@ -35240,7 +35240,6 @@
|
|||
"xpack.triggersActionsUI.sections.ruleDetails.alertsList.columns.status": "ステータス",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsList.ruleTypeExcessDurationMessage": "期間がルールの想定実行時間を超えています。",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.activeLabel": "現在アクティブ",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.allAlertsLabel": "すべて",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.errorLoadingBody": "アラート概要の読み込みエラーが発生しました。ヘルプについては、管理者にお問い合わせください。",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.errorLoadingTitle": "アラート概要を読み込めません",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.title": "アラート",
|
||||
|
|
|
@ -35276,7 +35276,6 @@
|
|||
"xpack.triggersActionsUI.sections.ruleDetails.alertsList.columns.status": "状态",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsList.ruleTypeExcessDurationMessage": "持续时间超出了规则的预期运行时间。",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.activeLabel": "当前处于活动状态",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.allAlertsLabel": "全部",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.errorLoadingBody": "加载告警摘要时出现错误。请联系您的管理员寻求帮助。",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.errorLoadingTitle": "无法加载告警摘要",
|
||||
"xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.title": "告警",
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('useLoadAlertSummary', () => {
|
|||
|
||||
it('should return the mocked data from API', async () => {
|
||||
mockedPostAPI.mockResolvedValue({
|
||||
...mockAlertSummaryResponse(),
|
||||
...mockAlertSummaryResponse,
|
||||
});
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
|
@ -39,15 +39,19 @@ describe('useLoadAlertSummary', () => {
|
|||
);
|
||||
expect(result.current).toEqual({
|
||||
isLoading: true,
|
||||
alertSummary: { active: 0, recovered: 0 },
|
||||
alertSummary: {
|
||||
activeAlertCount: 0,
|
||||
activeAlerts: [],
|
||||
recoveredAlertCount: 0,
|
||||
recoveredAlerts: [],
|
||||
},
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
const { alertSummary, error } = result.current;
|
||||
expect(alertSummary).toEqual({
|
||||
active: 1,
|
||||
recovered: 1,
|
||||
...mockAlertSummaryResponse,
|
||||
});
|
||||
expect(error).toBeFalsy();
|
||||
});
|
||||
|
@ -61,7 +65,7 @@ describe('useLoadAlertSummary', () => {
|
|||
},
|
||||
};
|
||||
mockedPostAPI.mockResolvedValue({
|
||||
...mockAlertSummaryResponse(),
|
||||
...mockAlertSummaryResponse,
|
||||
});
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() =>
|
||||
|
|
|
@ -21,6 +21,11 @@ export interface AlertSummaryTimeRange {
|
|||
title: JSX.Element | string;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
key: number;
|
||||
doc_count: number;
|
||||
}
|
||||
|
||||
interface UseLoadAlertSummaryProps {
|
||||
featureIds?: ValidFeatureId[];
|
||||
timeRange: AlertSummaryTimeRange;
|
||||
|
@ -29,18 +34,14 @@ interface UseLoadAlertSummaryProps {
|
|||
|
||||
interface AlertSummary {
|
||||
activeAlertCount: number;
|
||||
activeAlerts?: object[];
|
||||
activeAlerts: Alert[];
|
||||
recoveredAlertCount: number;
|
||||
recoveredAlerts?: object[];
|
||||
error?: string;
|
||||
recoveredAlerts: Alert[];
|
||||
}
|
||||
|
||||
interface LoadAlertSummaryResponse {
|
||||
isLoading: boolean;
|
||||
alertSummary: {
|
||||
active: number;
|
||||
recovered: number;
|
||||
};
|
||||
alertSummary: AlertSummary;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
|
@ -48,7 +49,12 @@ export function useLoadAlertSummary({ featureIds, timeRange, filter }: UseLoadAl
|
|||
const { http } = useKibana().services;
|
||||
const [alertSummary, setAlertSummary] = useState<LoadAlertSummaryResponse>({
|
||||
isLoading: true,
|
||||
alertSummary: { active: 0, recovered: 0 },
|
||||
alertSummary: {
|
||||
activeAlertCount: 0,
|
||||
activeAlerts: [],
|
||||
recoveredAlertCount: 0,
|
||||
recoveredAlerts: [],
|
||||
},
|
||||
});
|
||||
const isCancelledRef = useRef(false);
|
||||
const abortCtrlRef = useRef(new AbortController());
|
||||
|
@ -59,20 +65,23 @@ export function useLoadAlertSummary({ featureIds, timeRange, filter }: UseLoadAl
|
|||
abortCtrlRef.current = new AbortController();
|
||||
|
||||
try {
|
||||
const { activeAlertCount, recoveredAlertCount, error } = await fetchAlertSummary({
|
||||
featureIds,
|
||||
filter,
|
||||
http,
|
||||
signal: abortCtrlRef.current.signal,
|
||||
timeRange,
|
||||
});
|
||||
if (error) throw error;
|
||||
const { activeAlertCount, activeAlerts, recoveredAlertCount, recoveredAlerts } =
|
||||
await fetchAlertSummary({
|
||||
featureIds,
|
||||
filter,
|
||||
http,
|
||||
signal: abortCtrlRef.current.signal,
|
||||
timeRange,
|
||||
});
|
||||
|
||||
if (!isCancelledRef.current) {
|
||||
setAlertSummary((oldState) => ({
|
||||
...oldState,
|
||||
alertSummary: {
|
||||
active: activeAlertCount,
|
||||
recovered: recoveredAlertCount,
|
||||
activeAlertCount,
|
||||
activeAlerts,
|
||||
recoveredAlertCount,
|
||||
recoveredAlerts,
|
||||
},
|
||||
isLoading: false,
|
||||
}));
|
||||
|
@ -110,30 +119,26 @@ async function fetchAlertSummary({
|
|||
timeRange: AlertSummaryTimeRange;
|
||||
filter?: estypes.QueryDslQueryContainer;
|
||||
}): Promise<AlertSummary> {
|
||||
try {
|
||||
const res = await http.post<AsApiContract<any>>(`${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, {
|
||||
signal,
|
||||
body: JSON.stringify({
|
||||
fixed_interval: fixedInterval,
|
||||
gte: utcFrom,
|
||||
lte: utcTo,
|
||||
featureIds,
|
||||
filter: [filter],
|
||||
}),
|
||||
});
|
||||
const res = await http.post<AsApiContract<any>>(`${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, {
|
||||
signal,
|
||||
body: JSON.stringify({
|
||||
fixed_interval: fixedInterval,
|
||||
gte: utcFrom,
|
||||
lte: utcTo,
|
||||
featureIds,
|
||||
filter: [filter],
|
||||
}),
|
||||
});
|
||||
|
||||
const activeAlertCount = res?.activeAlertCount ?? 0;
|
||||
const recoveredAlertCount = res?.recoveredAlertCount ?? 0;
|
||||
const activeAlertCount = res?.activeAlertCount ?? 0;
|
||||
const activeAlerts = res?.activeAlerts ?? [];
|
||||
const recoveredAlertCount = res?.recoveredAlertCount ?? 0;
|
||||
const recoveredAlerts = res?.recoveredAlerts ?? [];
|
||||
|
||||
return {
|
||||
activeAlertCount,
|
||||
recoveredAlertCount,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error,
|
||||
activeAlertCount: 0,
|
||||
recoveredAlertCount: 0,
|
||||
};
|
||||
}
|
||||
return {
|
||||
activeAlertCount,
|
||||
activeAlerts,
|
||||
recoveredAlertCount,
|
||||
recoveredAlerts,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -69,19 +69,17 @@ export const mockRule = (): Rule => {
|
|||
};
|
||||
};
|
||||
|
||||
export const mockAlertSummaryResponse = () => {
|
||||
return {
|
||||
activeAlertCount: 1,
|
||||
recoveredAlertCount: 1,
|
||||
activeAlerts: [
|
||||
{ key_as_string: '1671321600000', key: 1671321600000, doc_count: 0 },
|
||||
{ key_as_string: '1671408000000', key: 1671408000000, doc_count: 2 },
|
||||
],
|
||||
recoveredAlerts: [
|
||||
{ key_as_string: '2022-12-18T00:00:00.000Z', key: 1671321600000, doc_count: 0 },
|
||||
{ key_as_string: '2022-12-19T00:00:00.000Z', key: 1671408000000, doc_count: 1 },
|
||||
],
|
||||
};
|
||||
export const mockAlertSummaryResponse = {
|
||||
activeAlertCount: 1,
|
||||
recoveredAlertCount: 1,
|
||||
activeAlerts: [
|
||||
{ key: 1671321600000, doc_count: 0 },
|
||||
{ key: 1671408000000, doc_count: 2 },
|
||||
],
|
||||
recoveredAlerts: [
|
||||
{ key: 1671321600000, doc_count: 0 },
|
||||
{ key: 1671408000000, doc_count: 1 },
|
||||
],
|
||||
};
|
||||
|
||||
export const mockAlertSummaryTimeRange: AlertSummaryTimeRange = {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { nextTick } from '@kbn/test-jest-helpers';
|
||||
|
@ -18,11 +19,22 @@ jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({
|
|||
|
||||
jest.mock('../../../../hooks/use_load_alert_summary', () => ({
|
||||
useLoadAlertSummary: jest.fn().mockReturnValue({
|
||||
alertSummary: { active: 1, recovered: 7 },
|
||||
alertSummary: {
|
||||
activeAlertCount: 1,
|
||||
recoveredAlertCount: 7,
|
||||
activeAlerts: [
|
||||
{ key: 1671321600000, doc_count: 0 },
|
||||
{ key: 1671408000000, doc_count: 1 },
|
||||
],
|
||||
recoveredAlerts: [
|
||||
{ key: 1671321600000, doc_count: 2 },
|
||||
{ key: 1671408000000, doc_count: 5 },
|
||||
],
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('Rule Alert Summary', () => {
|
||||
describe('Alert Summary Widget', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
const mockedTimeRange = {
|
||||
...mockAlertSummaryTimeRange,
|
||||
|
@ -52,7 +64,7 @@ describe('Rule Alert Summary', () => {
|
|||
it('should show zeros for all alerts counters', async () => {
|
||||
expect(wrapper.find('[data-test-subj="activeAlertsCount"]').text()).toEqual('1');
|
||||
expect(wrapper.find('[data-test-subj="recoveredAlertsCount"]').text()).toBe('7');
|
||||
expect(wrapper.find('[data-test-subj="totalAlertsCount"]').text()).toBe('8');
|
||||
expect(wrapper.find('[data-test-subj="totalAlertsCount"]').at(1).text()).toBe('Alerts (8)');
|
||||
expect(wrapper.find('[data-test-subj="mockedTimeRangeTitle"]').text()).toBe(
|
||||
'mockedTimeRangeTitle'
|
||||
);
|
||||
|
|
|
@ -18,7 +18,7 @@ export const AlertSummaryWidget = ({
|
|||
timeRange,
|
||||
}: AlertSummaryWidgetProps) => {
|
||||
const {
|
||||
alertSummary: { active, recovered },
|
||||
alertSummary: { activeAlertCount, activeAlerts, recoveredAlertCount, recoveredAlerts },
|
||||
isLoading,
|
||||
error,
|
||||
} = useLoadAlertSummary({
|
||||
|
@ -32,9 +32,11 @@ export const AlertSummaryWidget = ({
|
|||
|
||||
return (
|
||||
<AlertsSummaryWidgetUI
|
||||
active={active}
|
||||
activeAlertCount={activeAlertCount}
|
||||
activeAlerts={activeAlerts}
|
||||
onClick={onClick}
|
||||
recovered={recovered}
|
||||
recoveredAlertCount={recoveredAlertCount}
|
||||
recoveredAlerts={recoveredAlerts}
|
||||
timeRangeTitle={timeRange.title}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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 { Chart, CurveType, LineSeries, ScaleType, Settings } from '@elastic/charts';
|
||||
import { Color } from '@elastic/charts/dist/common/colors';
|
||||
import { ColorVariant } from '@elastic/charts/dist/utils/common';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiListGroupItemProps, EuiText } from '@elastic/eui';
|
||||
import {
|
||||
EUI_CHARTS_THEME_DARK,
|
||||
EUI_CHARTS_THEME_LIGHT,
|
||||
EUI_SPARKLINE_THEME_PARTIAL,
|
||||
} from '@elastic/eui/dist/eui_charts_theme';
|
||||
import { useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||
import { euiLightVars, euiDarkVars } from '@kbn/ui-theme';
|
||||
import React from 'react';
|
||||
import { Alert } from '../../../../../hooks/use_load_alert_summary';
|
||||
|
||||
interface AlertChartProps {
|
||||
count: number;
|
||||
data: Alert[];
|
||||
dataTestSubj: string;
|
||||
id: string;
|
||||
stroke: Color | ColorVariant;
|
||||
title: EuiListGroupItemProps['label'];
|
||||
}
|
||||
|
||||
export const AlertStateInfo = ({
|
||||
count,
|
||||
data,
|
||||
dataTestSubj,
|
||||
id,
|
||||
stroke,
|
||||
title,
|
||||
}: AlertChartProps) => {
|
||||
const isDarkMode = useUiSetting<boolean>('theme:darkMode');
|
||||
const textColor = isDarkMode ? euiDarkVars.euiTextColor : euiLightVars.euiTextColor;
|
||||
const theme = [
|
||||
EUI_SPARKLINE_THEME_PARTIAL,
|
||||
{
|
||||
...(isDarkMode ? EUI_CHARTS_THEME_DARK.theme : EUI_CHARTS_THEME_LIGHT.theme),
|
||||
chartMargins: {
|
||||
left: 10,
|
||||
right: 10,
|
||||
top: 10,
|
||||
bottom: 10,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}>
|
||||
<EuiFlexItem grow={1} style={{ minWidth: '70px' }}>
|
||||
<EuiText color={textColor}>
|
||||
<h3 data-test-subj={dataTestSubj}>{count}</h3>
|
||||
</EuiText>
|
||||
<EuiText size="s" color="subdued">
|
||||
{title}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={3}>
|
||||
<Chart size={{ height: 50 }}>
|
||||
<Settings theme={theme} tooltip={{ type: 'none' }} />
|
||||
<LineSeries
|
||||
id={id}
|
||||
xScaleType={ScaleType.Time}
|
||||
yScaleType={ScaleType.Linear}
|
||||
xAccessor="key"
|
||||
yAccessors={['doc_count']}
|
||||
data={data}
|
||||
lineSeriesStyle={{
|
||||
line: {
|
||||
strokeWidth: 2,
|
||||
stroke,
|
||||
},
|
||||
}}
|
||||
curve={CurveType.CURVE_MONOTONE_X}
|
||||
/>
|
||||
</Chart>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -15,8 +15,44 @@ export default {
|
|||
|
||||
export const Overview = {
|
||||
args: {
|
||||
active: 15,
|
||||
recovered: 53,
|
||||
activeAlertCount: 94,
|
||||
activeAlerts: [
|
||||
{ key: 1671108000000, doc_count: 0 },
|
||||
{ key: 1671208000000, doc_count: 0 },
|
||||
{ key: 1671308000000, doc_count: 0 },
|
||||
{ key: 1671408000000, doc_count: 2 },
|
||||
{ key: 1671508000000, doc_count: 4 },
|
||||
{ key: 1671608000000, doc_count: 5 },
|
||||
{ key: 1671708000000, doc_count: 3 },
|
||||
{ key: 1671808000000, doc_count: 6 },
|
||||
{ key: 1671908000000, doc_count: 14 },
|
||||
{ key: 1672008000000, doc_count: 15 },
|
||||
{ key: 1672108000000, doc_count: 15 },
|
||||
{ key: 1672208000000, doc_count: 10 },
|
||||
{ key: 1672308000000, doc_count: 9 },
|
||||
{ key: 1672408000000, doc_count: 7 },
|
||||
{ key: 1672508000000, doc_count: 2 },
|
||||
{ key: 1672608000000, doc_count: 2 },
|
||||
],
|
||||
recoveredAlertCount: 15,
|
||||
recoveredAlerts: [
|
||||
{ key: 1671108000000, doc_count: 0 },
|
||||
{ key: 1671208000000, doc_count: 0 },
|
||||
{ key: 1671308000000, doc_count: 0 },
|
||||
{ key: 1671408000000, doc_count: 0 },
|
||||
{ key: 1671508000000, doc_count: 0 },
|
||||
{ key: 1671608000000, doc_count: 0 },
|
||||
{ key: 1671708000000, doc_count: 2 },
|
||||
{ key: 1671808000000, doc_count: 0 },
|
||||
{ key: 1671908000000, doc_count: 0 },
|
||||
{ key: 1672008000000, doc_count: 0 },
|
||||
{ key: 1672108000000, doc_count: 0 },
|
||||
{ key: 1672208000000, doc_count: 5 },
|
||||
{ key: 1672308000000, doc_count: 1 },
|
||||
{ key: 1672408000000, doc_count: 2 },
|
||||
{ key: 1672508000000, doc_count: 5 },
|
||||
{ key: 1672608000000, doc_count: 0 },
|
||||
],
|
||||
timeRangeTitle: 'Last 30 days',
|
||||
onClick: action('clicked'),
|
||||
},
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, AlertStatus } from '@kbn/rule-data-utils';
|
||||
import { euiLightVars } from '@kbn/ui-theme';
|
||||
import React, { MouseEvent } from 'react';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -16,13 +15,16 @@ import {
|
|||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import React, { MouseEvent } from 'react';
|
||||
import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, AlertStatus } from '@kbn/rule-data-utils';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { AlertStateInfo } from './alert_state_chart';
|
||||
import { AlertsSummaryWidgetUIProps } from './types';
|
||||
|
||||
export const AlertsSummaryWidgetUI = ({
|
||||
active,
|
||||
recovered,
|
||||
activeAlertCount,
|
||||
activeAlerts,
|
||||
recoveredAlertCount,
|
||||
recoveredAlerts,
|
||||
timeRangeTitle,
|
||||
onClick,
|
||||
}: AlertsSummaryWidgetUIProps) => {
|
||||
|
@ -45,79 +47,71 @@ export const AlertsSummaryWidgetUI = ({
|
|||
onClick={handleClick}
|
||||
>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xxs">
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.title"
|
||||
defaultMessage="Alerts"
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
{!!timeRangeTitle && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s" color="subdued" data-test-subj="timeRangeTitle">
|
||||
{timeRangeTitle}
|
||||
</EuiText>
|
||||
</>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<h5 data-test-subj="totalAlertsCount">
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.title"
|
||||
defaultMessage="Alerts"
|
||||
/>
|
||||
({activeAlertCount + recoveredAlertCount})
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
{!!timeRangeTitle && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s" color="subdued" data-test-subj="timeRangeTitle">
|
||||
{timeRangeTitle}
|
||||
</EuiText>
|
||||
</>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup gutterSize="s" alignItems="flexStart" responsive={false}>
|
||||
<EuiFlexItem>
|
||||
<EuiLink onClick={handleClick}>
|
||||
<EuiText color={euiLightVars.euiTextColor}>
|
||||
<h3 data-test-subj="totalAlertsCount">{active + recovered}</h3>
|
||||
</EuiText>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.allAlertsLabel"
|
||||
defaultMessage="All"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiLink
|
||||
onClick={(event: React.MouseEvent<HTMLAnchorElement>) =>
|
||||
handleClick(event, ALERT_STATUS_ACTIVE)
|
||||
}
|
||||
>
|
||||
<EuiText color={euiLightVars.euiColorDangerText}>
|
||||
<h3 data-test-subj="activeAlertsCount">{active}</h3>
|
||||
</EuiText>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.activeLabel"
|
||||
defaultMessage="Currently active"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiLink
|
||||
onClick={(event: React.MouseEvent<HTMLAnchorElement>) =>
|
||||
handleClick(event, ALERT_STATUS_RECOVERED)
|
||||
}
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<EuiText color={euiLightVars.euiColorSuccessText}>
|
||||
<h3 data-test-subj="recoveredAlertsCount">{recovered}</h3>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.rule.ruleSummary.recoveredLabel"
|
||||
defaultMessage="Recovered"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup wrap>
|
||||
{/* Active */}
|
||||
<EuiFlexItem style={{ minWidth: '200px' }}>
|
||||
<EuiLink
|
||||
onClick={(event: React.MouseEvent<HTMLAnchorElement>) =>
|
||||
handleClick(event, ALERT_STATUS_ACTIVE)
|
||||
}
|
||||
>
|
||||
<AlertStateInfo
|
||||
count={activeAlertCount}
|
||||
data={activeAlerts}
|
||||
dataTestSubj="activeAlertsCount"
|
||||
id="active"
|
||||
stroke="#E7664C"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.alertsSummary.activeLabel"
|
||||
defaultMessage="Active"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
{/* Recovered */}
|
||||
<EuiFlexItem style={{ minWidth: '200px' }}>
|
||||
<EuiLink
|
||||
onClick={(event: React.MouseEvent<HTMLAnchorElement>) =>
|
||||
handleClick(event, ALERT_STATUS_RECOVERED)
|
||||
}
|
||||
>
|
||||
<AlertStateInfo
|
||||
count={recoveredAlertCount}
|
||||
data={recoveredAlerts}
|
||||
dataTestSubj="recoveredAlertsCount"
|
||||
id="recovered"
|
||||
stroke="#54B399"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.triggersActionsUI.sections.ruleDetails.rule.ruleSummary.recoveredLabel"
|
||||
defaultMessage="Recovered"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
*/
|
||||
|
||||
import { AlertStatus } from '@kbn/rule-data-utils';
|
||||
import { Alert } from '../../../../../hooks/use_load_alert_summary';
|
||||
|
||||
export interface AlertsSummaryWidgetUIProps {
|
||||
active: number;
|
||||
recovered: number;
|
||||
activeAlertCount: number;
|
||||
activeAlerts: Alert[];
|
||||
recoveredAlertCount: number;
|
||||
recoveredAlerts: Alert[];
|
||||
timeRangeTitle: JSX.Element | string;
|
||||
onClick: (status?: AlertStatus) => void;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue