From b71ae13b63f5743d163dbbb97c67d84874172c1a Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 12 Dec 2022 13:53:18 +0100 Subject: [PATCH] Alerting: Adds evaluation interval to group view (#59974) --- .../alerting/unified/RuleList.test.tsx | 7 +- .../features/alerting/unified/RuleList.tsx | 2 +- .../unified/components/rules/RuleStats.tsx | 115 +++++++++--------- .../unified/components/rules/RulesGroup.tsx | 20 ++- 4 files changed, 79 insertions(+), 65 deletions(-) diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx index 2f5c36da86e..81ea10fcbf9 100644 --- a/public/app/features/alerting/unified/RuleList.test.tsx +++ b/public/app/features/alerting/unified/RuleList.test.tsx @@ -322,8 +322,11 @@ describe('RuleList', () => { const groups = await ui.ruleGroup.findAll(); expect(groups).toHaveLength(2); - expect(groups[0]).toHaveTextContent('1 rule'); - expect(groups[1]).toHaveTextContent('4 rules: 1 firing, 1 pending'); + expect(groups[0]).toHaveTextContent('1 firing'); + expect(groups[1]).toHaveTextContent('1 firing'); + expect(groups[1]).toHaveTextContent('1 pending'); + expect(groups[1]).toHaveTextContent('1 recording'); + expect(groups[1]).toHaveTextContent('1 normal'); // expand second group to see rules table expect(ui.rulesTable.query()).not.toBeInTheDocument(); diff --git a/public/app/features/alerting/unified/RuleList.tsx b/public/app/features/alerting/unified/RuleList.tsx index a4de01df680..a46ddfc9523 100644 --- a/public/app/features/alerting/unified/RuleList.tsx +++ b/public/app/features/alerting/unified/RuleList.tsx @@ -105,7 +105,7 @@ const RuleList = withErrorBoundary( {expandAll ? 'Collapse all' : 'Expand all'} )} - + {(canCreateGrafanaRules || canCreateCloudRules) && ( = ({ showInactive, showRecording, group, namespaces }) => { +export const RuleStats: FC = ({ group, namespaces, includeTotal }) => { + const evaluationInterval = group?.interval; + const calculated = useMemo(() => { const stats = { ...emptyStats }; + const calcRule = (rule: CombinedRule) => { if (rule.promRule && isAlertingRule(rule.promRule)) { stats[rule.promRule.state] += 1; } - if (rule.promRule?.health === 'err' || rule.promRule?.health === 'error') { + if (ruleHasError(rule)) { stats.error += 1; } if ( @@ -41,75 +44,73 @@ export const RuleStats: FC = ({ showInactive, showRecording, group, names } stats.total += 1; }; + if (group) { group.rules.forEach(calcRule); } + if (namespaces) { namespaces.forEach((namespace) => namespace.groups.forEach((group) => group.rules.forEach(calcRule))); } + return stats; }, [group, namespaces]); const statsComponents: React.ReactNode[] = []; - if (calculated[PromAlertingRuleState.Firing]) { + + if (includeTotal) { statsComponents.push( - - {calculated[PromAlertingRuleState.Firing]} firing - - ); - } - if (calculated.error) { - statsComponents.push( - - {calculated.error} errors - - ); - } - if (calculated[PromAlertingRuleState.Pending]) { - statsComponents.push( - - {calculated[PromAlertingRuleState.Pending]} pending - - ); - } - if (showInactive && calculated[PromAlertingRuleState.Inactive]) { - statsComponents.push( - - {calculated[PromAlertingRuleState.Inactive]} normal - - ); - } - if (showRecording && calculated.recording) { - statsComponents.push( - - {calculated.recording} recording - + + {calculated.total} {pluralize('rule', calculated.total)} + ); } + if (calculated[PromAlertingRuleState.Firing]) { + statsComponents.push( + + ); + } + + if (calculated.error) { + statsComponents.push(); + } + + if (calculated[PromAlertingRuleState.Pending]) { + statsComponents.push( + + ); + } + + if (calculated[PromAlertingRuleState.Inactive]) { + statsComponents.push( + + ); + } + + if (calculated.recording) { + statsComponents.push(); + } + + const hasStats = Boolean(statsComponents.length); + return ( -
- - {calculated.total} {pluralize('rule', calculated.total)} - - {!!statsComponents.length && ( + + {hasStats && ( +
+ {statsComponents} +
+ )} + {evaluationInterval && ( <> - : - {statsComponents.reduce( - (prev, curr, idx) => - prev.length - ? [ - prev, - - , - , - curr, - ] - : [curr], - [] - )} +
|
+ )} -
+ ); }; + +function ruleHasError(rule: CombinedRule) { + return rule.promRule?.health === 'err' || rule.promRule?.health === 'error'; +} diff --git a/public/app/features/alerting/unified/components/rules/RulesGroup.tsx b/public/app/features/alerting/unified/components/rules/RulesGroup.tsx index 2d75fdcf86b..9924f6fbe73 100644 --- a/public/app/features/alerting/unified/components/rules/RulesGroup.tsx +++ b/public/app/features/alerting/unified/components/rules/RulesGroup.tsx @@ -3,6 +3,7 @@ import pluralize from 'pluralize'; import React, { FC, useEffect, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; +import { Stack } from '@grafana/experimental'; import { logInfo } from '@grafana/runtime'; import { Badge, ConfirmModal, HorizontalGroup, Icon, Spinner, Tooltip, useStyles2 } from '@grafana/ui'; import { useDispatch } from 'app/types'; @@ -213,12 +214,22 @@ export const RulesGroup: FC = React.memo(({ group, namespace, expandAll,
- +
+ {isProvisioned && ( + <> +
|
+
+ +
+ + )} {!!actionIcons.length && ( <>
|
-
{actionIcons}
+
+ {actionIcons} +
)}
@@ -313,9 +324,8 @@ export const getStyles = (theme: GrafanaTheme2) => ({ margin: 0 ${theme.spacing(2)}; `, actionIcons: css` - & > * + * { - margin-left: ${theme.spacing(0.5)}; - } + width: 80px; + align-items: center; `, rulesTable: css` margin-top: ${theme.spacing(3)};