diff --git a/public/app/features/alerting/unified/Templates.test.tsx b/public/app/features/alerting/unified/Templates.test.tsx
index d782eea1ea7..61e859042cf 100644
--- a/public/app/features/alerting/unified/Templates.test.tsx
+++ b/public/app/features/alerting/unified/Templates.test.tsx
@@ -1,18 +1,22 @@
import React from 'react';
-import { render, screen } from 'test/test-utils';
+import { render, screen, userEvent } from 'test/test-utils';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
+import { setGrafanaAlertmanagerConfig } from 'app/features/alerting/unified/mocks/server/configure';
+import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types';
import Templates from './Templates';
-import setupGrafanaManagedServer from './components/contact-points/__mocks__/grafanaManagedServer';
import { grantUserPermissions } from './mocks';
-const server = setupMswServer();
+jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({
+ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) =>
{actions}
,
+}));
+
+setupMswServer();
beforeEach(() => {
grantUserPermissions([AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsWrite]);
- setupGrafanaManagedServer(server);
});
describe('Templates routes', () => {
@@ -25,4 +29,29 @@ describe('Templates routes', () => {
expect(await screen.findByText('Edit payload')).toBeInTheDocument();
});
+
+ it('shows an error when remote AM config has been updated ', async () => {
+ const originalConfig: AlertManagerCortexConfig = {
+ template_files: {},
+ alertmanager_config: {},
+ };
+ setGrafanaAlertmanagerConfig(originalConfig);
+
+ const user = userEvent.setup();
+ render(, {
+ historyOptions: {
+ initialEntries: ['/alerting/notifications/templates/new'],
+ },
+ });
+
+ await user.type(await screen.findByLabelText(/template name/i), 'a');
+
+ // Once the user has loaded the page and started creating their template,
+ // update the API behaviour as if another user has also edited the config and added something in
+ setGrafanaAlertmanagerConfig({ ...originalConfig, template_files: { a: 'b' } });
+
+ await user.click(screen.getByRole('button', { name: /save/i }));
+
+ expect(await screen.findByText(/a newer alertmanager configuration is available/i)).toBeInTheDocument();
+ });
});
diff --git a/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx b/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx
index 275c69cecdd..abbc2dd34f9 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx
@@ -220,6 +220,7 @@ export const TemplateForm = ({ existing, alertManagerSourceName, config, provena
placeholder="Give your template a name"
width={42}
autoFocus={true}
+ id="new-template-name"
/>
diff --git a/public/app/features/alerting/unified/mocks/server/configure.ts b/public/app/features/alerting/unified/mocks/server/configure.ts
index 2566a218e1e..7bfdacaee50 100644
--- a/public/app/features/alerting/unified/mocks/server/configure.ts
+++ b/public/app/features/alerting/unified/mocks/server/configure.ts
@@ -1,8 +1,11 @@
import server from 'app/features/alerting/unified/mockApi';
import { mockFolder } from 'app/features/alerting/unified/mocks';
-import { grafanaAlertingConfigurationStatusHandler } from 'app/features/alerting/unified/mocks/server/handlers/alertmanagers';
+import {
+ getGrafanaAlertmanagerConfigHandler,
+ grafanaAlertingConfigurationStatusHandler,
+} from 'app/features/alerting/unified/mocks/server/handlers/alertmanagers';
import { getFolderHandler } from 'app/features/alerting/unified/mocks/server/handlers/folders';
-import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
+import { AlertManagerCortexConfig, AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
import { FolderDTO } from 'app/types';
/**
@@ -23,3 +26,10 @@ export const setAlertmanagerChoices = (alertmanagersChoice: AlertmanagerChoice,
export const setFolderAccessControl = (accessControl: FolderDTO['accessControl']) => {
server.use(getFolderHandler(mockFolder({ hasAcl: true, accessControl })));
};
+
+/**
+ * Makes the mock server respond with different Grafana Alertmanager config
+ */
+export const setGrafanaAlertmanagerConfig = (config: AlertManagerCortexConfig) => {
+ server.use(getGrafanaAlertmanagerConfigHandler(config));
+};
diff --git a/public/app/features/alerting/unified/mocks/server/handlers/alertmanagers.ts b/public/app/features/alerting/unified/mocks/server/handlers/alertmanagers.ts
index 06fdf657ebd..e789139f65b 100644
--- a/public/app/features/alerting/unified/mocks/server/handlers/alertmanagers.ts
+++ b/public/app/features/alerting/unified/mocks/server/handlers/alertmanagers.ts
@@ -1,9 +1,10 @@
import { http, HttpResponse } from 'msw';
+import alertmanagerConfigMock from 'app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json';
import { MOCK_SILENCE_ID_EXISTING, mockAlertmanagerAlert } from 'app/features/alerting/unified/mocks';
import { defaultGrafanaAlertingConfigurationStatusResponse } from 'app/features/alerting/unified/mocks/alertmanagerApi';
import { MOCK_DATASOURCE_UID_BROKEN_ALERTMANAGER } from 'app/features/alerting/unified/mocks/server/handlers/datasources';
-import { AlertState } from 'app/plugins/datasource/alertmanager/types';
+import { AlertManagerCortexConfig, AlertState } from 'app/plugins/datasource/alertmanager/types';
export const grafanaAlertingConfigurationStatusHandler = (
response = defaultGrafanaAlertingConfigurationStatusResponse
@@ -26,5 +27,25 @@ export const alertmanagerAlertsListHandler = () =>
]);
});
-const handlers = [alertmanagerAlertsListHandler(), grafanaAlertingConfigurationStatusHandler()];
+export const getGrafanaAlertmanagerConfigHandler = (config: AlertManagerCortexConfig = alertmanagerConfigMock) =>
+ http.get('/api/alertmanager/grafana/config/api/v1/alerts', () => HttpResponse.json(config));
+
+const updateGrafanaAlertmanagerConfigHandler = () =>
+ http.post('/api/alertmanager/grafana/config/api/v1/alerts', () =>
+ HttpResponse.json({ message: 'configuration created' })
+ );
+
+const getGrafanaAlertmanagerTemplatePreview = () =>
+ http.post('/api/alertmanager/grafana/config/api/v1/templates/test', () =>
+ // TODO: Scaffold out template preview response as needed by tests
+ HttpResponse.json({})
+ );
+
+const handlers = [
+ alertmanagerAlertsListHandler(),
+ grafanaAlertingConfigurationStatusHandler(),
+ getGrafanaAlertmanagerConfigHandler(),
+ updateGrafanaAlertmanagerConfigHandler(),
+ getGrafanaAlertmanagerTemplatePreview(),
+];
export default handlers;
diff --git a/public/app/features/alerting/unified/state/actions.ts b/public/app/features/alerting/unified/state/actions.ts
index 5724e3e1341..d72184b4443 100644
--- a/public/app/features/alerting/unified/state/actions.ts
+++ b/public/app/features/alerting/unified/state/actions.ts
@@ -491,7 +491,11 @@ export const updateAlertManagerConfigAction = createAsyncThunk {
const latestConfig = await thunkAPI
- .dispatch(alertmanagerApi.endpoints.getAlertmanagerConfiguration.initiate(alertManagerSourceName))
+ .dispatch(
+ alertmanagerApi.endpoints.getAlertmanagerConfiguration.initiate(alertManagerSourceName, {
+ forceRefetch: true,
+ })
+ )
.unwrap();
const isLatestConfigEmpty = isEmpty(latestConfig.alertmanager_config) && isEmpty(latestConfig.template_files);