diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx index d676664f2f1..900ca46a35c 100644 --- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx @@ -1,8 +1,8 @@ import { css } from '@emotion/css'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { Field, FieldValidationMessage, @@ -14,6 +14,7 @@ import { Text, useStyles2, } from '@grafana/ui'; +import { MultiValueRemove, MultiValueRemoveProps } from '@grafana/ui/src/components/Select/MultiValue'; import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form'; import { commonGroupByOptions, @@ -27,6 +28,15 @@ import { TIMING_OPTIONS_DEFAULTS } from '../../../../notification-policies/timin import { RouteTimings } from './RouteTimings'; +const REQUIRED_FIELDS_IN_GROUPBY = ['grafana_folder', 'alertname']; + +const DEFAULTS_TIMINGS = { + groupWaitValue: TIMING_OPTIONS_DEFAULTS.group_wait, + groupIntervalValue: TIMING_OPTIONS_DEFAULTS.group_interval, + repeatIntervalValue: TIMING_OPTIONS_DEFAULTS.repeat_interval, +}; +const DISABLE_GROUPING = '...'; + export interface RoutingSettingsProps { alertManager: string; } @@ -40,12 +50,18 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => { formState: { errors }, } = useFormContext(); const [groupByOptions, setGroupByOptions] = useState(stringsToSelectableValues([])); - const { groupIntervalValue, groupWaitValue, repeatIntervalValue } = getDefaultsForRoutingSettings(); + const { groupIntervalValue, groupWaitValue, repeatIntervalValue } = DEFAULTS_TIMINGS; const overrideGrouping = watch(`contactPoints.${alertManager}.overrideGrouping`); const overrideTimings = watch(`contactPoints.${alertManager}.overrideTimings`); - const requiredFieldsInGroupBy = ['grafana_folder', 'alertname']; - const disableGrouping = '...'; + const groupByCount = watch(`contactPoints.${alertManager}.groupBy`)?.length ?? 0; + const styles = useStyles2(getStyles); + useEffect(() => { + if (overrideGrouping && groupByCount === 0) { + setValue(`contactPoints.${alertManager}.groupBy`, REQUIRED_FIELDS_IN_GROUPBY); + } + }, [overrideGrouping, setValue, alertManager, groupByCount]); + return ( @@ -54,7 +70,7 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => { {!overrideGrouping && ( - Grouping: {requiredFieldsInGroupBy.join(', ')} + Grouping: {REQUIRED_FIELDS_IN_GROUPBY.join(', ')} )} @@ -72,14 +88,13 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => { if (!value || value.length === 0) { return 'At least one group by option is required.'; } - // if value includes only the allowedSingleFieldInGroupBy, it is valid - if (value.length === 1 && value[0] === disableGrouping) { + if (value.length === 1 && value[0] === DISABLE_GROUPING) { return true; } // we need to make sure that the required fields are included - const requiredFieldsIncluded = requiredFieldsInGroupBy.every((field) => value.includes(field)); + const requiredFieldsIncluded = REQUIRED_FIELDS_IN_GROUPBY.every((field) => value.includes(field)); if (!requiredFieldsIncluded) { - return `Group by must include ${requiredFieldsInGroupBy.join(', ')}`; + return `Group by must include ${REQUIRED_FIELDS_IN_GROUPBY.join(', ')}`; } return true; }, @@ -97,8 +112,30 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => { // @ts-ignore-check: react-hook-form made me do this setValue(`contactPoints.${alertManager}.groupBy`, [...field.value, opt]); }} - onChange={(value) => onChange(mapMultiSelectValueToStrings(value))} + onChange={(value) => { + return onChange(mapMultiSelectValueToStrings(value)); + }} options={[...commonGroupByOptions, ...groupByOptions]} + components={{ + MultiValueRemove( + props: React.PropsWithChildren< + MultiValueRemoveProps & + Array> & { + data: { + label: string; + value: string; + isFixed: boolean; + }; + } + > + ) { + const { data } = props; + if (data.isFixed) { + return null; + } + return MultiValueRemove(props); + }, + }} /> {error && {error.message}} @@ -129,13 +166,6 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => { ); }; -function getDefaultsForRoutingSettings() { - return { - groupWaitValue: TIMING_OPTIONS_DEFAULTS.group_wait, - groupIntervalValue: TIMING_OPTIONS_DEFAULTS.group_interval, - repeatIntervalValue: TIMING_OPTIONS_DEFAULTS.repeat_interval, - }; -} const getStyles = (theme: GrafanaTheme2) => ({ switchElement: css({ flexFlow: 'row-reverse', @@ -144,5 +174,6 @@ const getStyles = (theme: GrafanaTheme2) => ({ }), optionalContent: css({ marginLeft: '49px', + marginBottom: theme.spacing(1), }), }); diff --git a/public/app/features/alerting/unified/utils/amroutes.ts b/public/app/features/alerting/unified/utils/amroutes.ts index f3724401587..dbfbd58ad3b 100644 --- a/public/app/features/alerting/unified/utils/amroutes.ts +++ b/public/app/features/alerting/unified/utils/amroutes.ts @@ -44,8 +44,8 @@ export const defaultGroupBy = ['grafana_folder', 'alertname']; // Common route group_by options for multiselect drop-down export const commonGroupByOptions = [ - { label: 'grafana_folder', value: 'grafana_folder' }, - { label: 'alertname', value: 'alertname' }, + { label: 'grafana_folder', value: 'grafana_folder', isFixed: true }, + { label: 'alertname', value: 'alertname', isFixed: true }, { label: 'Disable (...)', value: '...' }, ];