diff --git a/public/app/features/alerting/unified/RuleEditor.test.tsx b/public/app/features/alerting/unified/RuleEditor.test.tsx index a0915090de5..98faaacc647 100644 --- a/public/app/features/alerting/unified/RuleEditor.test.tsx +++ b/public/app/features/alerting/unified/RuleEditor.test.tsx @@ -281,6 +281,19 @@ describe('RuleEditor', () => { await userEvent.type(ui.inputs.labelKey(1).get(), 'team'); await userEvent.type(ui.inputs.labelValue(1).get(), 'the a-team'); + // try to save, find out that recording rule name is invalid + userEvent.click(ui.buttons.save.get()); + expect( + await byText( + 'Recording rule name must be valid metric name. It may only contain letters, numbers, and colons. It may not contain whitespace.' + ).find() + ).toBeInTheDocument(); + expect(mocks.api.setRulerRuleGroup).not.toBeCalled(); + + // fix name and re-submit + await userEvent.type(await ui.inputs.name.find(), '{selectall}{del}my:great:new:recording:rule'); + userEvent.click(ui.buttons.save.get()); + // save and check what was sent to backend userEvent.click(ui.buttons.save.get()); await waitFor(() => expect(mocks.api.setRulerRuleGroup).toHaveBeenCalled()); @@ -288,7 +301,7 @@ describe('RuleEditor', () => { name: 'group2', rules: [ { - record: 'my great new recording rule', + record: 'my:great:new:recording:rule', labels: { team: 'the a-team' }, expr: 'up == 1', }, diff --git a/public/app/features/alerting/unified/components/rule-editor/AlertTypeStep.tsx b/public/app/features/alerting/unified/components/rule-editor/AlertTypeStep.tsx index 6640c852d1f..e158b714bd5 100644 --- a/public/app/features/alerting/unified/components/rule-editor/AlertTypeStep.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/AlertTypeStep.tsx @@ -14,6 +14,12 @@ interface Props { editingExistingRule: boolean; } +const recordingRuleNameValidationPattern = { + message: + 'Recording rule name must be valid metric name. It may only contain letters, numbers, and colons. It may not contain whitespace.', + value: /^[a-zA-Z_:][a-zA-Z0-9_:]*$/, +}; + export const AlertTypeStep: FC = ({ editingExistingRule }) => { const styles = useStyles2(getStyles); @@ -63,7 +69,10 @@ export const AlertTypeStep: FC = ({ editingExistingRule }) => { >