diff --git a/public/app/features/alerting/unified/Settings.test.tsx b/public/app/features/alerting/unified/Settings.test.tsx index 5fb3835d3e5..9d2ca68f3b2 100644 --- a/public/app/features/alerting/unified/Settings.test.tsx +++ b/public/app/features/alerting/unified/Settings.test.tsx @@ -24,8 +24,8 @@ const ui = { builtInAlertmanagerSection: byText('Built-in Alertmanager'), otherAlertmanagerSection: byText('Other Alertmanagers'), + alertmanagerCard: (name: string) => byTestId(`alertmanager-card-${name}`), builtInAlertmanagerCard: byTestId('alertmanager-card-Grafana built-in'), - otherAlertmanagerCard: (name: string) => byTestId(`alertmanager-card-${name}`), statusReceiving: byText(/receiving grafana-managed alerts/i), statusNotReceiving: byText(/not receiving/i), @@ -34,7 +34,11 @@ const ui = { editConfigurationButton: byRole('button', { name: /edit configuration/i }), saveConfigurationButton: byRole('button', { name: /save/i }), + enableButton: byRole('button', { name: 'Enable' }), + disableButton: byRole('button', { name: 'Disable' }), + versionsTab: byRole('tab', { name: /versions/i }), + provisionedBadge: byText(/^Provisioned$/), }; describe('Alerting settings', () => { @@ -59,7 +63,7 @@ describe('Alerting settings', () => { // check external altermanagers DataSourcesResponse.forEach((ds) => { // get the card for datasource - const card = ui.otherAlertmanagerCard(ds.name).get(); + const card = ui.alertmanagerCard(ds.name).get(); // expect link to data source, provisioned badge, type, and status expect(within(card).getByRole('link', { name: ds.name })).toBeInTheDocument(); @@ -120,4 +124,26 @@ describe('Alerting settings', () => { expect(screen.getByText(/last applied/i)).toBeInTheDocument(); }); }); + + it('should correctly render provisioned data sources', async () => { + render(); + + // wait for loading to be done + await waitFor(() => expect(ui.builtInAlertmanagerSection.get()).toBeInTheDocument()); + + // provisioned alertmanager card + const provisionedCard = ui.alertmanagerCard('Provisioned Mimir-based Alertmanager').get(); + expect(ui.provisionedBadge.get(provisionedCard)).toBeInTheDocument(); + + // should still be editable + const editConfigButton = ui.editConfigurationButton.get(provisionedCard); + expect(editConfigButton).toBeInTheDocument(); + + // enable / disable should not be avaiable when provisioned + const enableButton = ui.enableButton.query(provisionedCard); + const disableButton = ui.disableButton.query(provisionedCard); + + expect(enableButton).not.toBeInTheDocument(); + expect(disableButton).not.toBeInTheDocument(); + }); }); diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx index c692ce38839..76ef9d9606a 100644 --- a/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx +++ b/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx @@ -76,6 +76,7 @@ export function AlertmanagerCard({ {/* we'll use the "tags" area to append buttons and actions */} + {/* ⚠️ provisioned Data sources cannot have their "enable" / "disable" actions but we should still allow editing of the configuration */} diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx index 26d3ce9a165..dd1af8d3380 100644 --- a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx +++ b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx @@ -14,7 +14,7 @@ import { AlertmanagerProvider } from '../../state/AlertmanagerContext'; import AlertmanagerConfig from './AlertmanagerConfig'; import { EXTERNAL_VANILLA_ALERTMANAGER_UID, - PROVISIONED_VANILLA_ALERTMANAGER_UID, + PROVISIONED_MIMIR_ALERTMANAGER_UID, setupGrafanaManagedServer, setupVanillaAlertmanagerServer, } from './__mocks__/server'; @@ -96,11 +96,11 @@ describe('vanilla Alertmanager', () => { expect(ui.resetButton.query()).not.toBeInTheDocument(); }); - it('should be read-only when provisioned Alertmanager', async () => { - renderConfiguration(PROVISIONED_VANILLA_ALERTMANAGER_UID, {}); + it('should not be read-only when Mimir Alertmanager', async () => { + renderConfiguration(PROVISIONED_MIMIR_ALERTMANAGER_UID, {}); expect(ui.cancelButton.get()).toBeInTheDocument(); - expect(ui.saveButton.query()).not.toBeInTheDocument(); - expect(ui.resetButton.query()).not.toBeInTheDocument(); + expect(ui.saveButton.get()).toBeInTheDocument(); + expect(ui.resetButton.get()).toBeInTheDocument(); }); }); diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx index 9177aff1c9e..109116f96b9 100644 --- a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx +++ b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx @@ -9,11 +9,7 @@ import { Alert, Button, CodeEditor, ConfirmModal, Stack, useStyles2 } from '@gra import { reportFormErrors } from '../../Analytics'; import { useAlertmanagerConfig } from '../../hooks/useAlertmanagerConfig'; import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector'; -import { - GRAFANA_RULES_SOURCE_NAME, - isProvisionedDataSource, - isVanillaPrometheusAlertManagerDataSource, -} from '../../utils/datasource'; +import { GRAFANA_RULES_SOURCE_NAME, isVanillaPrometheusAlertManagerDataSource } from '../../utils/datasource'; import { Spacer } from '../Spacer'; export interface FormValues { @@ -32,9 +28,9 @@ export default function AlertmanagerConfig({ alertmanagerName, onDismiss, onSave const { loading: isSaving, error: savingError } = useUnifiedAlertingSelector((state) => state.saveAMConfig); const [showResetConfirmation, setShowResetConfirmation] = useState(false); + // ⚠️ provisioned data sources should not prevent the configuration from being edited const immutableDataSource = alertmanagerName ? isVanillaPrometheusAlertManagerDataSource(alertmanagerName) : false; - const provisionedDataSource = isProvisionedDataSource(alertmanagerName); - const readOnly = immutableDataSource || provisionedDataSource; + const readOnly = immutableDataSource; const isGrafanaManagedAlertmanager = alertmanagerName === GRAFANA_RULES_SOURCE_NAME; const styles = useStyles2(getStyles); diff --git a/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx b/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx index 414cf4d1d95..f9f0541ca43 100644 --- a/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx +++ b/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx @@ -7,6 +7,7 @@ import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types'; import { ExternalAlertmanagerDataSourceWithStatus } from '../../hooks/useExternalAmSelector'; import { isAlertmanagerDataSourceInterestedInAlerts, + isProvisionedDataSource, isVanillaPrometheusAlertManagerDataSource, } from '../../utils/datasource'; import { createUrl } from '../../utils/url'; @@ -44,9 +45,9 @@ export const ExternalAlertmanagers = ({ onEditConfiguration }: Props) => { const { status } = alertmanager; const isReceiving = isReceivingGrafanaAlerts(alertmanager); - const isProvisioned = alertmanager.dataSourceSettings.readOnly === true; - const isReadOnly = - isProvisioned || isVanillaPrometheusAlertManagerDataSource(alertmanager.dataSourceSettings.name); + const isProvisioned = isProvisionedDataSource(alertmanager.dataSourceSettings); + const isReadOnly = isVanillaPrometheusAlertManagerDataSource(alertmanager.dataSourceSettings.name); + const detailHref = createUrl(DATASOURCES_ROUTES.Edit.replace(/:uid/gi, uid)); const handleEditConfiguration = () => onEditConfiguration(name); diff --git a/public/app/features/alerting/unified/components/settings/__mocks__/api/datasources.json b/public/app/features/alerting/unified/components/settings/__mocks__/api/datasources.json index a31e1fdc10e..e7ca54b8f86 100644 --- a/public/app/features/alerting/unified/components/settings/__mocks__/api/datasources.json +++ b/public/app/features/alerting/unified/components/settings/__mocks__/api/datasources.json @@ -19,6 +19,26 @@ }, "readOnly": false }, + { + "id": 183, + "uid": "xPVD2XISx", + "orgId": 1, + "name": "Provisioned Mimir-based Alertmanager", + "type": "alertmanager", + "typeName": "Alertmanager", + "typeLogoUrl": "public/app/plugins/datasource/prometheus/img/prometheus_logo.svg", + "access": "proxy", + "url": "http://foo.bar:9090/", + "user": "", + "database": "", + "basicAuth": false, + "isDefault": false, + "jsonData": { + "httpMethod": "POST", + "implementation": "mimir" + }, + "readOnly": true + }, { "id": 160, "uid": "iETbvsT4z", diff --git a/public/app/features/alerting/unified/components/settings/__mocks__/server.ts b/public/app/features/alerting/unified/components/settings/__mocks__/server.ts index 0a64f290eac..428b6f54de6 100644 --- a/public/app/features/alerting/unified/components/settings/__mocks__/server.ts +++ b/public/app/features/alerting/unified/components/settings/__mocks__/server.ts @@ -23,7 +23,7 @@ export { vanillaAlertmanagerConfig as VanillaAlertmanagerConfiguration }; export { history as alertmanagerConfigurationHistory }; export const EXTERNAL_VANILLA_ALERTMANAGER_UID = 'vanilla-alertmanager'; -export const PROVISIONED_VANILLA_ALERTMANAGER_UID = 'provisioned-alertmanager'; +export const PROVISIONED_MIMIR_ALERTMANAGER_UID = 'provisioned-alertmanager'; jest.spyOn(config, 'getAllDataSources'); @@ -40,9 +40,9 @@ const mockDataSources = { implementation: AlertManagerImplementation.prometheus, }, }), - [PROVISIONED_VANILLA_ALERTMANAGER_UID]: mockDataSource({ - uid: PROVISIONED_VANILLA_ALERTMANAGER_UID, - name: PROVISIONED_VANILLA_ALERTMANAGER_UID, + [PROVISIONED_MIMIR_ALERTMANAGER_UID]: mockDataSource({ + uid: PROVISIONED_MIMIR_ALERTMANAGER_UID, + name: PROVISIONED_MIMIR_ALERTMANAGER_UID, type: DataSourceType.Alertmanager, jsonData: { // this is a mutable data source type but we're making it readOnly @@ -70,7 +70,7 @@ export function setupVanillaAlertmanagerServer(server: SetupServerApi) { server.use( createVanillaAlertmanagerConfigurationHandler(EXTERNAL_VANILLA_ALERTMANAGER_UID), - ...createAlertmanagerConfigurationHandlers(PROVISIONED_VANILLA_ALERTMANAGER_UID) + ...createAlertmanagerConfigurationHandlers(PROVISIONED_MIMIR_ALERTMANAGER_UID) ); return server; diff --git a/public/app/features/alerting/unified/utils/datasource.ts b/public/app/features/alerting/unified/utils/datasource.ts index bb5fb463c8d..4a74e122e2e 100644 --- a/public/app/features/alerting/unified/utils/datasource.ts +++ b/public/app/features/alerting/unified/utils/datasource.ts @@ -210,8 +210,8 @@ export function isVanillaPrometheusAlertManagerDataSource(name: string): boolean ); } -export function isProvisionedDataSource(name: string): boolean { - return getAlertmanagerDataSourceByName(name)?.readOnly === true; +export function isProvisionedDataSource(dataSource: DataSourceSettings): boolean { + return dataSource.readOnly === true; } export function isGrafanaRulesSource(