[v11.3.x] Alerting: Update texts for gm rr in the form (#94886)

Alerting: Update texts for gm rr in the form (#94844)

* Update texts for gm rr in the form

* fix translations

* Fix test

* address review comments

* address review comments - part2

* translations

* update docs for new term: output

(cherry picked from commit 1860737117)

Co-authored-by: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>
pull/94903/head
grafana-delivery-bot[bot] 8 months ago committed by GitHub
parent ab368bfb06
commit 4590698e10
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 13
      .betterer.results
  2. 6
      docs/sources/alerting/alerting-rules/create-mimir-loki-managed-recording-rule.md
  3. 19
      public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.test.tsx
  4. 13
      public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx
  5. 32
      public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx
  6. 27
      public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx
  7. 4
      public/app/features/alerting/unified/components/rule-editor/NotificationsStep.tsx
  8. 24
      public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.tsx
  9. 15
      public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx
  10. 43
      public/locales/en-US/grafana.json
  11. 43
      public/locales/pseudo-LOCALE/grafana.json

@ -1697,9 +1697,6 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"] [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"]
], ],
"public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPointMenu.tsx:5381": [ "public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPointMenu.tsx:5381": [
[0, 0, 0, "Do not re-export imported variable (\`app/features/explore/extensions/ToolbarExtensionPointMenu\`)", "0"] [0, 0, 0, "Do not re-export imported variable (\`app/features/explore/extensions/ToolbarExtensionPointMenu\`)", "0"]
], ],
@ -1935,8 +1932,7 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "13"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "13"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "14"]
], ],
"public/app/features/alerting/unified/components/rule-editor/NeedHelpInfo.tsx:5381": [ "public/app/features/alerting/unified/components/rule-editor/NeedHelpInfo.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"] [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
@ -2035,16 +2031,13 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"]
], ],
"public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx:5381": [ "public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"]
], ],
"public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx:5381": [ "public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"], [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],

@ -114,7 +114,7 @@ For more information, refer to [Metrics and labels](https://prometheus.io/docs/c
#### Define recording rule #### Define recording rule
Define a query to get the data you want to measure and set the condition. Define a query to get the data you want to measure and set the recording rule output.
1. Select a data source. 1. Select a data source.
1. From the **Options** dropdown, specify a time range. 1. From the **Options** dropdown, specify a time range.
@ -141,9 +141,9 @@ It does not support absolute time ranges: `2021-12-02 00:00:00 to 2021-12-05 23:
3. To add a recovery threshold, turn the **Custom recovery threshold** toggle on and fill in a value for when your recording rule should stop meeting the condition. 3. To add a recovery threshold, turn the **Custom recovery threshold** toggle on and fill in a value for when your recording rule should stop meeting the condition.
You can only add one recovery threshold in a query and it must be the recording rule condition. You can only add one recovery threshold in a query and it must be the recording rule output.
4. Click **Set as recording rule condition** on the query or expression you want to set as your rule condition. 4. Click **Set as recording rule output** on the query or expression you want to set as your rule output.
#### Set evaluation behavior #### Set evaluation behavior

@ -1,16 +1,29 @@
import { screen, render } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { FormProvider, useForm } from 'react-hook-form';
import { RuleFormValues } from '../../types/rule-form';
import { getDefaultFormValues } from '../../utils/rule-form';
import { ExpressionStatusIndicator } from './ExpressionStatusIndicator'; import { ExpressionStatusIndicator } from './ExpressionStatusIndicator';
function FormWrapper({ isCondition }: { isCondition: boolean }) {
const formApi = useForm<RuleFormValues>({ defaultValues: { ...getDefaultFormValues() } });
return (
<FormProvider {...formApi}>
<ExpressionStatusIndicator isCondition={isCondition} />
</FormProvider>
);
}
describe('ExpressionStatusIndicator', () => { describe('ExpressionStatusIndicator', () => {
it('should render one element if condition', () => { it('should render one element if condition', () => {
render(<ExpressionStatusIndicator isCondition />); render(<FormWrapper isCondition />);
expect(screen.getByText('Alert condition')).toBeInTheDocument(); expect(screen.getByText('Alert condition')).toBeInTheDocument();
}); });
it('should render one element if not condition', () => { it('should render one element if not condition', () => {
render(<ExpressionStatusIndicator isCondition={false} />); render(<FormWrapper isCondition={false} />);
expect(screen.queryByRole('button', { name: 'Alert condition' })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Alert condition' })).not.toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Set as alert condition' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Set as alert condition' })).toBeInTheDocument();

@ -1,8 +1,12 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { Badge, clearButtonStyles, useStyles2 } from '@grafana/ui'; import { Badge, clearButtonStyles, useStyles2 } from '@grafana/ui';
import { RuleFormValues } from '../../types/rule-form';
import { isGrafanaRecordingRuleByType } from '../../utils/rules';
interface AlertConditionProps { interface AlertConditionProps {
isCondition?: boolean; isCondition?: boolean;
onSetCondition?: () => void; onSetCondition?: () => void;
@ -10,9 +14,14 @@ interface AlertConditionProps {
export const ExpressionStatusIndicator = ({ isCondition, onSetCondition }: AlertConditionProps) => { export const ExpressionStatusIndicator = ({ isCondition, onSetCondition }: AlertConditionProps) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const { watch } = useFormContext<RuleFormValues>();
const type = watch('type');
const isGrafanaRecordingRule = type ? isGrafanaRecordingRuleByType(type) : false;
const conditionText = isGrafanaRecordingRule ? 'Recording rule output' : 'Alert condition';
const makeConditionText = isGrafanaRecordingRule ? 'Set as recording rule output' : 'Set as alert condition';
if (isCondition) { if (isCondition) {
return <Badge key="condition" color="green" icon="check" text="Alert condition" />; return <Badge key="condition" color="green" icon="check" text={conditionText} />;
} else { } else {
return ( return (
<button <button
@ -21,7 +30,7 @@ export const ExpressionStatusIndicator = ({ isCondition, onSetCondition }: Alert
className={styles.actionLink} className={styles.actionLink}
onClick={() => onSetCondition && onSetCondition()} onClick={() => onSetCondition && onSetCondition()}
> >
Set as alert condition {makeConditionText}
</button> </button>
); );
} }

@ -1,13 +1,14 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { debounce, take, uniqueId } from 'lodash'; import { debounce, take, uniqueId } from 'lodash';
import { useCallback, useMemo, useState } from 'react';
import * as React from 'react'; import * as React from 'react';
import { FormProvider, useForm, useFormContext, Controller } from 'react-hook-form'; import { useCallback, useMemo, useState } from 'react';
import { Controller, FormProvider, useForm, useFormContext } from 'react-hook-form';
import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data'; import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { AsyncSelect, Box, Button, Field, Input, Label, Modal, Stack, Text, useStyles2 } from '@grafana/ui'; import { AsyncSelect, Box, Button, Field, Input, Label, Modal, Stack, Text, useStyles2 } from '@grafana/ui';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
import { t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import { createFolder } from 'app/features/manage-dashboards/state/actions'; import { createFolder } from 'app/features/manage-dashboards/state/actions';
import { AccessControlAction } from 'app/types'; import { AccessControlAction } from 'app/types';
@ -17,7 +18,7 @@ import { alertRuleApi } from '../../api/alertRuleApi';
import { GRAFANA_RULER_CONFIG } from '../../api/featureDiscoveryApi'; import { GRAFANA_RULER_CONFIG } from '../../api/featureDiscoveryApi';
import { RuleFormValues } from '../../types/rule-form'; import { RuleFormValues } from '../../types/rule-form';
import { DEFAULT_GROUP_EVALUATION_INTERVAL } from '../../utils/rule-form'; import { DEFAULT_GROUP_EVALUATION_INTERVAL } from '../../utils/rule-form';
import { isGrafanaRulerRule } from '../../utils/rules'; import { isGrafanaRecordingRuleByType, isGrafanaRulerRule } from '../../utils/rules';
import { ProvisioningBadge } from '../Provisioning'; import { ProvisioningBadge } from '../Provisioning';
import { evaluateEveryValidationOptions } from '../rules/EditRuleGroupModal'; import { evaluateEveryValidationOptions } from '../rules/EditRuleGroupModal';
@ -98,8 +99,8 @@ export function FolderAndGroup({
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const folder = watch('folder'); const [folder, group, type] = watch(['folder', 'group', 'type']);
const group = watch('group'); const isGrafanaRecordingRule = type ? isGrafanaRecordingRuleByType(type) : false;
const { groupOptions, loading } = useFolderGroupOptions(folder?.uid ?? '', enableProvisionedGroups); const { groupOptions, loading } = useFolderGroupOptions(folder?.uid ?? '', enableProvisionedGroups);
@ -139,6 +140,10 @@ export function FolderAndGroup({
const defaultGroupValue = group ? { value: group, label: group } : undefined; const defaultGroupValue = group ? { value: group, label: group } : undefined;
const evaluationDesc = isGrafanaRecordingRule
? t('alerting.folderAndGroup.evaluation.text.recording', 'Define how often the recording rule is evaluated.')
: t('alerting.folderAndGroup.evaluation.text.alerting', 'Define how often the alert rule is evaluated.');
return ( return (
<div className={styles.container}> <div className={styles.container}>
<Stack alignItems="center"> <Stack alignItems="center">
@ -207,7 +212,7 @@ export function FolderAndGroup({
<Field <Field
label="Evaluation group and interval" label="Evaluation group and interval"
data-testid="group-picker" data-testid="group-picker"
description="Define how often the alert rule is evaluated." description={evaluationDesc}
className={styles.formInput} className={styles.formInput}
error={errors.group?.message} error={errors.group?.message}
invalid={!!errors.group?.message} invalid={!!errors.group?.message}
@ -358,7 +363,8 @@ function EvaluationGroupCreationModal({
const evaluateEveryId = 'eval-every-input'; const evaluateEveryId = 'eval-every-input';
const evaluationGroupNameId = 'new-eval-group-name'; const evaluationGroupNameId = 'new-eval-group-name';
const [groupName, folderName] = watch(['group', 'folder.title']); const [groupName, folderName, type] = watch(['group', 'folder.title', 'type']);
const isGrafanaRecordingRule = type ? isGrafanaRecordingRuleByType(type) : false;
const groupRules = const groupRules =
(groupfoldersForGrafana && groupfoldersForGrafana[folderName]?.find((g) => g.name === groupName)?.rules) ?? []; (groupfoldersForGrafana && groupfoldersForGrafana[folderName]?.find((g) => g.name === groupName)?.rules) ?? [];
@ -380,6 +386,16 @@ function EvaluationGroupCreationModal({
setValue('evaluateEvery', interval, { shouldValidate: true }); setValue('evaluateEvery', interval, { shouldValidate: true });
}; };
const modalTitle = isGrafanaRecordingRule
? t(
'alerting.folderAndGroup.evaluation.modal.text.recording',
'Create a new evaluation group to use for this recording rule.'
)
: t(
'alerting.folderAndGroup.evaluation.modal.text.alerting',
'Create a new evaluation group to use for this alert rule.'
);
return ( return (
<Modal <Modal
className={styles.modal} className={styles.modal}
@ -388,7 +404,7 @@ function EvaluationGroupCreationModal({
onDismiss={onCancel} onDismiss={onCancel}
onClickBackdrop={onCancel} onClickBackdrop={onCancel}
> >
<div className={styles.modalTitle}>Create a new evaluation group to use for this alert rule.</div> <div className={styles.modalTitle}>{modalTitle}</div>
<FormProvider {...formAPI}> <FormProvider {...formAPI}>
<form onSubmit={handleSubmit(() => onSubmit())}> <form onSubmit={handleSubmit(() => onSubmit())}>

@ -5,7 +5,7 @@ import { Controller, RegisterOptions, useFormContext } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Field, Icon, IconButton, Input, Label, Stack, Switch, Text, Tooltip, useStyles2 } from '@grafana/ui'; import { Field, Icon, IconButton, Input, Label, Stack, Switch, Text, Tooltip, useStyles2 } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization'; import { Trans, t } from 'app/core/internationalization';
import { isGrafanaAlertingRuleByType } from 'app/features/alerting/unified/utils/rules'; import { isGrafanaAlertingRuleByType, isGrafanaRecordingRuleByType } from 'app/features/alerting/unified/utils/rules';
import { CombinedRuleGroup, CombinedRuleNamespace } from '../../../../../types/unified-alerting'; import { CombinedRuleGroup, CombinedRuleNamespace } from '../../../../../types/unified-alerting';
import { LogMessages, logInfo } from '../../Analytics'; import { LogMessages, logInfo } from '../../Analytics';
@ -231,15 +231,21 @@ function NeedHelpInfoForConfigureNoDataError() {
); );
} }
function getDescription() { function getDescription(isGrafanaRecordingRule: boolean) {
const docsLink = 'https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/rule-evaluation/'; const docsLink = 'https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/rule-evaluation/';
return ( return (
<Stack direction="row" gap={0.5} alignItems="center"> <Stack direction="row" gap={0.5} alignItems="center">
<Text variant="bodySmall" color="secondary"> <Text variant="bodySmall" color="secondary">
<Trans i18nKey="alert-rule-form.evaluation-behaviour.description.text"> {isGrafanaRecordingRule ? (
Define how the alert rule is evaluated. <Trans i18nKey="alerting.alert-recording-rule-form.evaluation-behaviour.description.text">
</Trans> Define how the recording rule is evaluated.
</Trans>
) : (
<Trans i18nKey="alerting.alert-rule-form.evaluation-behaviour.description.text">
Define how the alert rule is evaluated.
</Trans>
)}
</Text> </Text>
<NeedHelpInfo <NeedHelpInfo
contentText={ contentText={
@ -291,10 +297,15 @@ export function GrafanaEvaluationBehavior({
const type = watch('type'); const type = watch('type');
const isGrafanaAlertingRule = isGrafanaAlertingRuleByType(type); const isGrafanaAlertingRule = isGrafanaAlertingRuleByType(type);
const isGrafanaRecordingRule = type ? isGrafanaRecordingRuleByType(type) : false;
const pauseContentText = isGrafanaRecordingRule
? t('alert-rule-form.pause.recording', 'Turn on to pause evaluation for this recording rule.')
: t('alert-rule-form.pause.alerting', 'Turn on to pause evaluation for this alert rule.');
return ( return (
// TODO remove "and alert condition" for recording rules // TODO remove "and alert condition" for recording rules
<RuleEditorSection stepNo={3} title="Set evaluation behavior" description={getDescription()}> <RuleEditorSection stepNo={3} title="Set evaluation behavior" description={getDescription(isGrafanaRecordingRule)}>
<Stack direction="column" justify-content="flex-start" align-items="flex-start"> <Stack direction="column" justify-content="flex-start" align-items="flex-start">
<FolderGroupAndEvaluationInterval <FolderGroupAndEvaluationInterval
setEvaluateEvery={setEvaluateEvery} setEvaluateEvery={setEvaluateEvery}
@ -317,8 +328,8 @@ export function GrafanaEvaluationBehavior({
value={Boolean(isPaused)} value={Boolean(isPaused)}
/> />
<label htmlFor="pause-alert" className={styles.switchLabel}> <label htmlFor="pause-alert" className={styles.switchLabel}>
<Trans i18nKey="alert-rule-form.pause">Pause evaluation</Trans> <Trans i18nKey="alert-rule-form.pause.label">Pause evaluation</Trans>
<Tooltip placement="top" content="Turn on to pause evaluation for this alert rule." theme={'info'}> <Tooltip placement="top" content={pauseContentText} theme={'info'}>
<Icon tabIndex={0} name="info-circle" size="sm" className={styles.infoIcon} /> <Icon tabIndex={0} name="info-circle" size="sm" className={styles.infoIcon} />
</Tooltip> </Tooltip>
</label> </label>

@ -73,9 +73,9 @@ export const NotificationsStep = ({ alertUid }: NotificationsStepProps) => {
title={isRecordingRuleByType(type) ? 'Add labels' : 'Configure labels and notifications'} title={isRecordingRuleByType(type) ? 'Add labels' : 'Configure labels and notifications'}
description={ description={
<Stack direction="row" gap={0.5} alignItems="center"> <Stack direction="row" gap={0.5} alignItems="center">
{type === RuleFormType.cloudRecording ? ( {isRecordingRuleByType(type) ? (
<Text variant="bodySmall" color="secondary"> <Text variant="bodySmall" color="secondary">
Add labels to help you better manage your recording rules Add labels to help you better manage your recording rules.
</Text> </Text>
) : ( ) : (
shouldAllowSimplifiedRouting && ( shouldAllowSimplifiedRouting && (

@ -4,12 +4,14 @@ import { Controller, FormProvider, useFieldArray, useForm, useFormContext } from
import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Button, Field, InlineLabel, Input, LoadingPlaceholder, Space, Stack, Text, useStyles2 } from '@grafana/ui'; import { Button, Field, InlineLabel, Input, LoadingPlaceholder, Space, Stack, Text, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { labelsApi } from '../../../api/labelsApi'; import { labelsApi } from '../../../api/labelsApi';
import { usePluginBridge } from '../../../hooks/usePluginBridge'; import { usePluginBridge } from '../../../hooks/usePluginBridge';
import { SupportedPlugin } from '../../../types/pluginBridges'; import { SupportedPlugin } from '../../../types/pluginBridges';
import { RuleFormValues } from '../../../types/rule-form'; import { RuleFormType, RuleFormValues } from '../../../types/rule-form';
import { isPrivateLabelKey } from '../../../utils/labels'; import { isPrivateLabelKey } from '../../../utils/labels';
import { isRecordingRuleByType } from '../../../utils/rules';
import AlertLabelDropdown from '../../AlertLabelDropdown'; import AlertLabelDropdown from '../../AlertLabelDropdown';
import { AlertLabels } from '../../AlertLabels'; import { AlertLabels } from '../../AlertLabels';
import { NeedHelpInfo } from '../NeedHelpInfo'; import { NeedHelpInfo } from '../NeedHelpInfo';
@ -64,6 +66,8 @@ export interface LabelsSubFormProps {
export function LabelsSubForm({ dataSourceName, onClose, initialLabels }: LabelsSubFormProps) { export function LabelsSubForm({ dataSourceName, onClose, initialLabels }: LabelsSubFormProps) {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const { watch } = useFormContext<RuleFormValues>();
const type = watch('type') ?? RuleFormType.grafana;
const onSave = (labels: LabelsSubformValues) => { const onSave = (labels: LabelsSubformValues) => {
onClose(labels.labelsInSubform); onClose(labels.labelsInSubform);
@ -81,7 +85,7 @@ export function LabelsSubForm({ dataSourceName, onClose, initialLabels }: Labels
<FormProvider {...formAPI}> <FormProvider {...formAPI}>
<form onSubmit={formAPI.handleSubmit(onSave)}> <form onSubmit={formAPI.handleSubmit(onSave)}>
<Stack direction="column" gap={4}> <Stack direction="column" gap={4}>
<Text>Add labels to your rule for searching, silencing, or routing to a notification policy.</Text> <Text>{getLabelText(type)}</Text>
<Stack direction="column" gap={1}> <Stack direction="column" gap={1}>
<LabelsWithSuggestions dataSourceName={dataSourceName} /> <LabelsWithSuggestions dataSourceName={dataSourceName} />
<Space v={2} /> <Space v={2} />
@ -393,13 +397,16 @@ export const LabelsWithoutSuggestions: FC = () => {
}; };
function LabelsField() { function LabelsField() {
const { watch } = useFormContext<RuleFormValues>();
const type = watch('type') ?? RuleFormType.grafana;
return ( return (
<div> <div>
<Stack direction="column" gap={1}> <Stack direction="column" gap={1}>
<Text element="h5">Labels</Text> <Text element="h5">Labels</Text>
<Stack direction={'row'} gap={1}> <Stack direction={'row'} gap={1}>
<Text variant="bodySmall" color="secondary"> <Text variant="bodySmall" color="secondary">
Add labels to your rule for searching, silencing, or routing to a notification policy. {getLabelText(type)}
</Text> </Text>
<NeedHelpInfo <NeedHelpInfo
contentText="The dropdown only displays labels that you have previously used for alerts. contentText="The dropdown only displays labels that you have previously used for alerts.
@ -413,6 +420,17 @@ function LabelsField() {
); );
} }
function getLabelText(type: RuleFormType) {
const isRecordingRule = type ? isRecordingRuleByType(type) : false;
const text = isRecordingRule
? t('alerting.alertform.labels.recording', 'Add labels to your rule.')
: t(
'alerting.alertform.labels.alerting',
'Add labels to your rule for searching, silencing, or routing to a notification policy.'
);
return text;
}
const getStyles = (theme: GrafanaTheme2) => { const getStyles = (theme: GrafanaTheme2) => {
return { return {
flexColumn: css({ flexColumn: css({

@ -1,8 +1,10 @@
import { useFormContext } from 'react-hook-form'; import { useFormContext } from 'react-hook-form';
import { Button, Stack, Text } from '@grafana/ui'; import { Button, Stack, Text } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { RuleFormValues } from '../../../types/rule-form'; import { RuleFormValues } from '../../../types/rule-form';
import { isRecordingRuleByType } from '../../../utils/rules';
import { NeedHelpInfo } from '../NeedHelpInfo'; import { NeedHelpInfo } from '../NeedHelpInfo';
import { LabelsInRule } from './LabelsField'; import { LabelsInRule } from './LabelsField';
@ -13,6 +15,17 @@ interface LabelsFieldInFormProps {
export function LabelsFieldInForm({ onEditClick }: LabelsFieldInFormProps) { export function LabelsFieldInForm({ onEditClick }: LabelsFieldInFormProps) {
const { watch } = useFormContext<RuleFormValues>(); const { watch } = useFormContext<RuleFormValues>();
const labels = watch('labels'); const labels = watch('labels');
const type = watch('type');
const isRecordingRule = type ? isRecordingRuleByType(type) : false;
const text = isRecordingRule
? t('alerting.alertform.labels.recording', 'Add labels to your rule.')
: t(
'alerting.alertform.labels.alerting',
'Add labels to your rule for searching, silencing, or routing to a notification policy.'
);
const hasLabels = Object.keys(labels).length > 0 && labels.some((label) => label.key || label.value); const hasLabels = Object.keys(labels).length > 0 && labels.some((label) => label.key || label.value);
return ( return (
@ -21,7 +34,7 @@ export function LabelsFieldInForm({ onEditClick }: LabelsFieldInFormProps) {
<Text element="h5">Labels</Text> <Text element="h5">Labels</Text>
<Stack direction={'row'} gap={1}> <Stack direction={'row'} gap={1}>
<Text variant="bodySmall" color="secondary"> <Text variant="bodySmall" color="secondary">
Add labels to your rule for searching, silencing, or routing to a notification policy. {text}
</Text> </Text>
<NeedHelpInfo <NeedHelpInfo
contentText="The dropdown only displays labels that you have previously used for alerts. contentText="The dropdown only displays labels that you have previously used for alerts.

@ -35,9 +35,6 @@
}, },
"alert-rule-form": { "alert-rule-form": {
"evaluation-behaviour": { "evaluation-behaviour": {
"description": {
"text": "Define how the alert rule is evaluated."
},
"info-help": { "info-help": {
"text": "Define the alert behavior when the evaluation fails or the query returns no data." "text": "Define the alert behavior when the evaluation fails or the query returns no data."
}, },
@ -53,9 +50,33 @@
"evaluation-behaviour-group": { "evaluation-behaviour-group": {
"text": "All rules in the selected group are evaluated every {{evaluateEvery}}." "text": "All rules in the selected group are evaluated every {{evaluateEvery}}."
}, },
"pause": "Pause evaluation" "pause": {
"alerting": "Turn on to pause evaluation for this alert rule.",
"label": "Pause evaluation",
"recording": "Turn on to pause evaluation for this recording rule."
}
}, },
"alerting": { "alerting": {
"alert-recording-rule-form": {
"evaluation-behaviour": {
"description": {
"text": "Define how the recording rule is evaluated."
}
}
},
"alert-rule-form": {
"evaluation-behaviour": {
"description": {
"text": "Define how the alert rule is evaluated."
}
}
},
"alertform": {
"labels": {
"alerting": "Add labels to your rule for searching, silencing, or routing to a notification policy.",
"recording": "Add labels to your rule."
}
},
"annotations": { "annotations": {
"description": "Add more context to your alert notifications.", "description": "Add more context to your alert notifications.",
"title": "Configure notification message" "title": "Configure notification message"
@ -141,6 +162,20 @@
"contactPointFilter": { "contactPointFilter": {
"label": "Contact point" "label": "Contact point"
}, },
"folderAndGroup": {
"evaluation": {
"modal": {
"text": {
"alerting": "Create a new evaluation group to use for this alert rule.",
"recording": "Create a new evaluation group to use for this recording rule."
}
},
"text": {
"alerting": "Define how often the alert rule is evaluated.",
"recording": "Define how often the recording rule is evaluated."
}
}
},
"list-view": { "list-view": {
"empty": { "empty": {
"new-alert-rule": "New alert rule", "new-alert-rule": "New alert rule",

@ -35,9 +35,6 @@
}, },
"alert-rule-form": { "alert-rule-form": {
"evaluation-behaviour": { "evaluation-behaviour": {
"description": {
"text": "Đęƒįʼnę ĥőŵ ŧĥę äľęřŧ řūľę įş ęväľūäŧęđ."
},
"info-help": { "info-help": {
"text": "Đęƒįʼnę ŧĥę äľęřŧ þęĥävįőř ŵĥęʼn ŧĥę ęväľūäŧįőʼn ƒäįľş őř ŧĥę qūęřy řęŧūřʼnş ʼnő đäŧä." "text": "Đęƒįʼnę ŧĥę äľęřŧ þęĥävįőř ŵĥęʼn ŧĥę ęväľūäŧįőʼn ƒäįľş őř ŧĥę qūęřy řęŧūřʼnş ʼnő đäŧä."
}, },
@ -53,9 +50,33 @@
"evaluation-behaviour-group": { "evaluation-behaviour-group": {
"text": "Åľľ řūľęş įʼn ŧĥę şęľęčŧęđ ģřőūp äřę ęväľūäŧęđ ęvęřy {{evaluateEvery}}." "text": "Åľľ řūľęş įʼn ŧĥę şęľęčŧęđ ģřőūp äřę ęväľūäŧęđ ęvęřy {{evaluateEvery}}."
}, },
"pause": "Päūşę ęväľūäŧįőʼn" "pause": {
"alerting": "Ŧūřʼn őʼn ŧő päūşę ęväľūäŧįőʼn ƒőř ŧĥįş äľęřŧ řūľę.",
"label": "Päūşę ęväľūäŧįőʼn",
"recording": "Ŧūřʼn őʼn ŧő päūşę ęväľūäŧįőʼn ƒőř ŧĥįş řęčőřđįʼnģ řūľę."
}
}, },
"alerting": { "alerting": {
"alert-recording-rule-form": {
"evaluation-behaviour": {
"description": {
"text": "Đęƒįʼnę ĥőŵ ŧĥę řęčőřđįʼnģ řūľę įş ęväľūäŧęđ."
}
}
},
"alert-rule-form": {
"evaluation-behaviour": {
"description": {
"text": "Đęƒįʼnę ĥőŵ ŧĥę äľęřŧ řūľę įş ęväľūäŧęđ."
}
}
},
"alertform": {
"labels": {
"alerting": "Åđđ ľäþęľş ŧő yőūř řūľę ƒőř şęäřčĥįʼnģ, şįľęʼnčįʼnģ, őř řőūŧįʼnģ ŧő ä ʼnőŧįƒįčäŧįőʼn pőľįčy.",
"recording": "Åđđ ľäþęľş ŧő yőūř řūľę."
}
},
"annotations": { "annotations": {
"description": "Åđđ mőřę čőʼnŧęχŧ ŧő yőūř äľęřŧ ʼnőŧįƒįčäŧįőʼnş.", "description": "Åđđ mőřę čőʼnŧęχŧ ŧő yőūř äľęřŧ ʼnőŧįƒįčäŧįőʼnş.",
"title": "Cőʼnƒįģūřę ʼnőŧįƒįčäŧįőʼn męşşäģę" "title": "Cőʼnƒįģūřę ʼnőŧįƒįčäŧįőʼn męşşäģę"
@ -141,6 +162,20 @@
"contactPointFilter": { "contactPointFilter": {
"label": "Cőʼnŧäčŧ pőįʼnŧ" "label": "Cőʼnŧäčŧ pőįʼnŧ"
}, },
"folderAndGroup": {
"evaluation": {
"modal": {
"text": {
"alerting": "Cřęäŧę ä ʼnęŵ ęväľūäŧįőʼn ģřőūp ŧő ūşę ƒőř ŧĥįş äľęřŧ řūľę.",
"recording": "Cřęäŧę ä ʼnęŵ ęväľūäŧįőʼn ģřőūp ŧő ūşę ƒőř ŧĥįş řęčőřđįʼnģ řūľę."
}
},
"text": {
"alerting": "Đęƒįʼnę ĥőŵ őƒŧęʼn ŧĥę äľęřŧ řūľę įş ęväľūäŧęđ.",
"recording": "Đęƒįʼnę ĥőŵ őƒŧęʼn ŧĥę řęčőřđįʼnģ řūľę įş ęväľūäŧęđ."
}
}
},
"list-view": { "list-view": {
"empty": { "empty": {
"new-alert-rule": "Ńęŵ äľęřŧ řūľę", "new-alert-rule": "Ńęŵ äľęřŧ řūľę",

Loading…
Cancel
Save