+ Grafana is configured to send alerts to external Alertmanagers only. Changing Grafana Alertmanager configuration
+ will not affect delivery of your alerts!
+
+ You can change the configuration on the Alerting Admin page. If you do not have access, contact your
+ Administrator
+
+
+ );
+}
+
+const getStyles = (theme: GrafanaTheme2) => ({
+ adminHint: css`
+ font-size: ${theme.typography.bodySmall.fontSize};
+ font-weight: ${theme.typography.bodySmall.fontWeight};
+ `,
+});
diff --git a/public/app/features/alerting/unified/components/admin/ExternalAlertmanagers.tsx b/public/app/features/alerting/unified/components/admin/ExternalAlertmanagers.tsx
index 9c5002eadc6..d076aed7375 100644
--- a/public/app/features/alerting/unified/components/admin/ExternalAlertmanagers.tsx
+++ b/public/app/features/alerting/unified/components/admin/ExternalAlertmanagers.tsx
@@ -17,15 +17,10 @@ import {
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { loadDataSources } from 'app/features/datasources/state/actions';
import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
-import { useDispatch, useSelector } from 'app/types';
-import { StoreState } from 'app/types/store';
+import { useDispatch } from 'app/types';
+import { alertmanagerApi } from '../../api/alertmanagerApi';
import { useExternalAmSelector, useExternalDataSourceAlertmanagers } from '../../hooks/useExternalAmSelector';
-import {
- addExternalAlertmanagersAction,
- fetchExternalAlertmanagersAction,
- fetchExternalAlertmanagersConfigAction,
-} from '../../state/actions';
import { AddAlertManagerModal } from './AddAlertManagerModal';
import { ExternalAlertmanagerDataSources } from './ExternalAlertmanagerDataSources';
@@ -45,20 +40,23 @@ export const ExternalAlertmanagers = () => {
const externalAlertManagers = useExternalAmSelector();
const externalDsAlertManagers = useExternalDataSourceAlertmanagers();
- const alertmanagersChoice = useSelector(
- (state: StoreState) => state.unifiedAlerting.externalAlertmanagers.alertmanagerConfig.result?.alertmanagersChoice
- );
+ const {
+ useSaveExternalAlertmanagersConfigMutation,
+ useGetExternalAlertmanagerConfigQuery,
+ useGetExternalAlertmanagersQuery,
+ } = alertmanagerApi;
+
+ const [saveExternalAlertManagers] = useSaveExternalAlertmanagersConfigMutation();
+ const { currentData: externalAlertmanagerConfig } = useGetExternalAlertmanagerConfigQuery();
+
+ // Just to refresh the status periodically
+ useGetExternalAlertmanagersQuery(undefined, { pollingInterval: 5000 });
+
+ const alertmanagersChoice = externalAlertmanagerConfig?.alertmanagersChoice;
const theme = useTheme2();
useEffect(() => {
- dispatch(fetchExternalAlertmanagersAction());
- dispatch(fetchExternalAlertmanagersConfigAction());
dispatch(loadDataSources());
- const interval = setInterval(() => dispatch(fetchExternalAlertmanagersAction()), 5000);
-
- return () => {
- clearInterval(interval);
- };
}, [dispatch]);
const onDelete = useCallback(
@@ -69,15 +67,15 @@ export const ExternalAlertmanagers = () => {
.map((am) => {
return am.url;
});
- dispatch(
- addExternalAlertmanagersAction({
- alertmanagers: newList,
- alertmanagersChoice: alertmanagersChoice ?? AlertmanagerChoice.All,
- })
- );
+
+ saveExternalAlertManagers({
+ alertmanagers: newList,
+ alertmanagersChoice: alertmanagersChoice ?? AlertmanagerChoice.All,
+ });
+
setDeleteModalState({ open: false, index: 0 });
},
- [externalAlertManagers, dispatch, alertmanagersChoice]
+ [externalAlertManagers, saveExternalAlertManagers, alertmanagersChoice]
);
const onEdit = useCallback(() => {
@@ -108,18 +106,14 @@ export const ExternalAlertmanagers = () => {
}, [setModalState]);
const onChangeAlertmanagerChoice = (alertmanagersChoice: AlertmanagerChoice) => {
- dispatch(
- addExternalAlertmanagersAction({ alertmanagers: externalAlertManagers.map((am) => am.url), alertmanagersChoice })
- );
+ saveExternalAlertManagers({ alertmanagers: externalAlertManagers.map((am) => am.url), alertmanagersChoice });
};
const onChangeAlertmanagers = (alertmanagers: string[]) => {
- dispatch(
- addExternalAlertmanagersAction({
- alertmanagers,
- alertmanagersChoice: alertmanagersChoice ?? AlertmanagerChoice.All,
- })
- );
+ saveExternalAlertManagers({
+ alertmanagers,
+ alertmanagersChoice: alertmanagersChoice ?? AlertmanagerChoice.All,
+ });
};
const getStatusColor = (status: string) => {
diff --git a/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx b/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx
index f829676380a..3bdbdd5ac05 100644
--- a/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx
@@ -1,21 +1,58 @@
import { renderHook } from '@testing-library/react-hooks';
+import { setupServer } from 'msw/node';
import React from 'react';
import { Provider } from 'react-redux';
+import 'whatwg-fetch';
+
import { DataSourceJsonData, DataSourceSettings } from '@grafana/data';
import { config } from '@grafana/runtime';
+import { backendSrv } from 'app/core/services/backend_srv';
import { AlertmanagerChoice, AlertManagerDataSourceJsonData } from 'app/plugins/datasource/alertmanager/types';
import { mockDataSource, mockDataSourcesStore, mockStore } from '../mocks';
+import { mockAlertmanagerConfigResponse, mockAlertmanagersResponse } from '../mocks/alertmanagerApi';
import { useExternalAmSelector, useExternalDataSourceAlertmanagers } from './useExternalAmSelector';
+const server = setupServer();
+
+jest.mock('@grafana/runtime', () => ({
+ ...(jest.requireActual('@grafana/runtime') as unknown as object),
+ getBackendSrv: () => backendSrv,
+}));
+
+beforeAll(() => {
+ server.listen({ onUnhandledRequest: 'error' });
+});
+
+beforeEach(() => {
+ server.resetHandlers();
+});
+
+afterAll(() => {
+ server.close();
+});
+
describe('useExternalAmSelector', () => {
- it('should have one in pending', () => {
- const store = createMockStoreState([], [], ['some/url/to/am']);
+ it('should have one in pending', async () => {
+ mockAlertmanagersResponse(server, {
+ data: {
+ activeAlertManagers: [],
+ droppedAlertManagers: [],
+ },
+ });
+ mockAlertmanagerConfigResponse(server, {
+ alertmanagers: ['some/url/to/am'],
+ alertmanagersChoice: AlertmanagerChoice.All,
+ });
+ const store = mockStore(() => null);
+
const wrapper = ({ children }: React.PropsWithChildren<{}>) =>