diff --git a/public/app/features/alerting/unified/Templates.test.tsx b/public/app/features/alerting/unified/Templates.test.tsx index 6d695af5826..99cd7a39d7f 100644 --- a/public/app/features/alerting/unified/Templates.test.tsx +++ b/public/app/features/alerting/unified/Templates.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Props } from 'react-virtualized-auto-sizer'; -import { render, screen, within } from 'test/test-utils'; -import { byRole } from 'testing-library-selector'; +import { render, screen, waitFor, within } from 'test/test-utils'; +import { byLabelText, byRole } from 'testing-library-selector'; import { CodeEditorProps } from '@grafana/ui/src/components/Monaco/types'; import { AppNotificationList } from 'app/core/components/AppNotifications/AppNotificationList'; @@ -40,6 +40,10 @@ jest.mock('@grafana/ui', () => ({ const ui = { templateForm: byRole('form', { name: 'Template form' }), + form: { + title: byLabelText(/Template name/), + saveButton: byRole('button', { name: 'Save' }), + }, }; const navUrl = { @@ -77,6 +81,40 @@ describe('Templates routes', () => { expect(form).toBeInTheDocument(); expect(within(form).getByRole('textbox', { name: /Template name/ })).toHaveValue(''); }); + + it('should pass name validation when editing existing template', async () => { + const { user } = render( + <> + + + , + { historyOptions: { initialEntries: [navUrl.edit('custom-email')] } } + ); + + const titleElement = await ui.form.title.find(); + await waitFor(() => { + expect(titleElement).toHaveValue('custom-email'); + }); + + await user.click(ui.form.saveButton.get()); + + // No error message should be displayed for a unique name + expect(screen.queryByText('Another template with this name already exists')).not.toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText('Template saved')).toBeInTheDocument(); + }); + }); + + it('should display error message when creating new template with duplicate name', async () => { + const { user } = render(, { historyOptions: { initialEntries: [navUrl.new] } }); + + const titleElement = await ui.form.title.find(); + await user.type(titleElement, 'custom-email'); + + await user.click(ui.form.saveButton.get()); + + expect(screen.getByText('Another template with this name already exists')).toBeInTheDocument(); + }); }); describe('Templates K8s API', () => { diff --git a/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts b/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts index e98aca41847..c20e2dc1650 100644 --- a/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts +++ b/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts @@ -281,7 +281,15 @@ export function useDeleteNotificationTemplate({ alertmanager }: BaseAlertmanager return k8sApiSupported ? deleteUsingK8sApi : deleteUsingConfigFileApi; } -export function useValidateNotificationTemplate({ alertmanager }: BaseAlertmanagerArgs) { +interface ValidateNotificationTemplateParams { + alertmanager: string; + originalTemplate?: NotificationTemplate; +} + +export function useValidateNotificationTemplate({ + alertmanager, + originalTemplate, +}: ValidateNotificationTemplateParams) { const { useLazyGetAlertmanagerConfigurationQuery } = alertmanagerApi; const [fetchAmConfig] = useLazyGetAlertmanagerConfigurationQuery(); @@ -294,6 +302,11 @@ export function useValidateNotificationTemplate({ alertmanager }: BaseAlertmanag return true; } + if (originalTemplate?.title === name) { + // If original template is defined we update existing template so name will not be unique but it's ok + return true; + } + const amConfig = await fetchAmConfig(alertmanager).unwrap(); const templates = amConfigToTemplates(amConfig); const templateOfThisNameExists = templates.some((t) => t.title === name); diff --git a/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx b/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx index c306701172b..8dadda756e1 100644 --- a/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx +++ b/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx @@ -93,7 +93,7 @@ export const TemplateForm = ({ originalTemplate, prefill, alertmanager }: Props) const createNewTemplate = useCreateNotificationTemplate({ alertmanager }); const updateTemplate = useUpdateNotificationTemplate({ alertmanager }); - const { titleIsUnique } = useValidateNotificationTemplate({ alertmanager }); + const { titleIsUnique } = useValidateNotificationTemplate({ alertmanager, originalTemplate }); useCleanup((state) => (state.unifiedAlerting.saveAMConfig = initialAsyncRequestState)); const formRef = useRef(null);