From 1430698a8b711f206895f999acd4f6b46127a30c Mon Sep 17 00:00:00 2001 From: laurenashleigh Date: Fri, 24 Oct 2025 16:27:11 +0100 Subject: [PATCH] replace evaluation inputs with group dropdown --- .../components/RuleConditionSection.tsx | 91 +-------- .../rule-editor/EvaluationGroupFieldRow.tsx | 191 ++++++++++++++++++ .../rule-editor/GrafanaEvaluationBehavior.tsx | 2 +- public/locales/en-US/grafana.json | 12 +- 4 files changed, 198 insertions(+), 98 deletions(-) create mode 100644 public/app/features/alerting/unified/components/rule-editor/EvaluationGroupFieldRow.tsx diff --git a/public/app/features/alerting/unified/components/RuleConditionSection.tsx b/public/app/features/alerting/unified/components/RuleConditionSection.tsx index 1dc9a0eb0cc..51df3c8c131 100644 --- a/public/app/features/alerting/unified/components/RuleConditionSection.tsx +++ b/public/app/features/alerting/unified/components/RuleConditionSection.tsx @@ -7,12 +7,10 @@ import { Trans, t } from '@grafana/i18n'; import { Combobox, ComboboxOption, - Field, Icon, InlineField, InlineFieldRow, Input, - Select, Stack, Text, useStyles2, @@ -24,29 +22,15 @@ import { reducerTypes, thresholdFunctions } from 'app/features/expressions/types import { isRangeEvaluator } from 'app/features/expressions/utils/expressionTypes'; import { RuleFormType, RuleFormValues } from '../types/rule-form'; -import { safeParsePrometheusDuration } from '../utils/time'; -import { getPendingPeriodQuickOptions } from './rule-editor/DurationQuickPick'; +// no custom pending/eval parsing here; use defaults from form +import { EvaluationGroupFieldRow } from './rule-editor/EvaluationGroupFieldRow'; export function RuleConditionSection({ type }: { type: RuleFormType }) { const base = useStyles2(getStyles); - const { register, watch, setValue } = useFormContext(); - const evaluateEvery = watch('evaluateEvery') || '5m'; + const { watch } = useFormContext(); const evaluateFor = watch('evaluateFor') || '0s'; - const pendingOptions = getPendingPeriodQuickOptions(evaluateEvery); - const [customMode, setCustomMode] = useState(false); - const isCustomSelected = customMode; - const customDelay = isCustomSelected ? evaluateFor : ''; - const evalMs = safeParsePrometheusDuration(evaluateEvery); - const customMs = safeParsePrometheusDuration(customDelay || '0s'); - const isCustomInvalid = isCustomSelected && (evalMs <= 0 || customMs <= 0 || customMs % evalMs !== 0); - - let fireSelectLabel: string = evaluateFor; - if (isCustomSelected) { - fireSelectLabel = customDelay || pendingOptions[1] || '1m'; - } else if (evaluateFor === '0s') { - fireSelectLabel = t('alerting.duration.immediately', 'immediately'); - } + watch('folder'); type LocalSimpleCondition = { whenField?: string; evaluator: { params: number[]; type: EvalFunction } }; const [simpleCondition, setSimpleCondition] = useState({ @@ -145,72 +129,7 @@ export function RuleConditionSection({ type }: { type: RuleFormType }) { -
- - Evaluate the rule every - - - . - - Wait - - setValue('evaluateFor', e.currentTarget.value)} /> - {isCustomSelected && ( - - setValue('evaluateFor', e.currentTarget.value)} /> - - )} - - - after the condition is breached before firing. - - - - Fire the alert rule - - { + field.onChange(group.label ?? ''); + }} + isLoading={loadingGroups} + invalid={Boolean(folder?.uid) && !group && Boolean(fieldState.error)} + cacheOptions + loadingMessage={t( + 'alerting.grafana-evaluation-behavior-step.loadingMessage-loading-groups', + 'Loading groups...' + )} + defaultValue={defaultGroupValue} + options={groupOptions} + getOptionLabel={(option: GroupOption) => ( +
+ {option.label} + {option.isProvisioned && ( + <> + {' '} + + + )} +
+ )} + placeholder={t( + 'alerting.grafana-evaluation-behavior-step.placeholder-select-an-evaluation-group', + 'Select an evaluation group...' + )} + /> + )} + name="group" + control={control} + rules={{ + required: { + value: true, + message: t( + 'alerting.grafana-evaluation-behavior-step.message.must-enter-a-group-name', + 'Must enter a group name' + ), + }, + }} + /> + +
+ + + or + + + + {isCreatingEvaluationGroup && ( + setIsCreatingEvaluationGroup(false)} + groupfoldersForGrafana={rulerNamespace} + /> + )} + {getValues('group') && getValues('evaluateEvery') && ( +
+ +
+ + + All rules in the selected group are evaluated every {{ evaluateEvery: getValues('evaluateEvery') }}. + + +
+
+
+ )} + + ); +} + +function getStyles(theme: GrafanaTheme2) { + return { + formInput: css({ + flexGrow: 1, + }), + evaluationContainer: css({ + color: theme.colors.text.secondary, + maxWidth: `${theme.breakpoints.values.sm}px`, + fontSize: theme.typography.size.sm, + }), + marginTop: css({ + marginTop: theme.spacing(1), + }), + }; +} diff --git a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx index 50163827bdb..8d0cbc90314 100644 --- a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx @@ -439,7 +439,7 @@ export function GrafanaEvaluationBehaviorStep({ ); } -function EvaluationGroupCreationModal({ +export function EvaluationGroupCreationModal({ onClose, onCreate, groupfoldersForGrafana, diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 32a5dea74c4..9bd3d847c2f 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1079,9 +1079,6 @@ "text-loading-notification-template": "Loading notification template", "title-error-loading-notification-template": "Error loading notification template" }, - "duration": { - "immediately": "immediately" - }, "duration-quick-pick": { "none": "None" }, @@ -2824,14 +2821,7 @@ "continue-in-alerting": "Continue in Alerting", "create": "Create", "evaluation": { - "after-breached": "after the condition is initially breached.", - "custom-delay": "with custom delay of", - "custom-delay-invalid": "The delay must be a multiple of the evaluation frequency.", - "every": "Evaluate the rule every", - "fire": "Fire the alert rule", - "immediate-warning": "Immediate firing might lead to unnecessary alerts being sent for temporary issues", - "wait-prefix": "Wait", - "wait-suffix": "after the condition is breached before firing." + "immediate-warning": "Immediate firing might lead to unnecessary alerts being sent for temporary issues" }, "notification": { "contact-point": {