Alerting: Don't redirect after failed contact point creation (#92761)

non-working-nested-field-overrides
Tom Ratcliffe 9 months ago committed by GitHub
parent 91cbaa4afe
commit 9f5dca96f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 10
      public/app/features/alerting/unified/components/contact-points/useContactPoints.tsx
  2. 15
      public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx
  3. 14
      public/app/features/alerting/unified/components/receivers/form/CloudReceiverForm.tsx
  4. 24
      public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.tsx
  5. 7
      public/app/features/alerting/unified/mocks/server/configure.ts
  6. 19
      public/app/features/alerting/unified/mocks/server/handlers/alertmanagers.ts

@ -410,10 +410,12 @@ export const useCreateContactPoint = ({ alertmanager }: BaseAlertmanagerArgs) =>
oldConfig: config,
alertManagerSourceName: alertmanager,
})
).then(() => {
dispatch(alertingApi.util.invalidateTags(['AlertmanagerConfiguration', 'ContactPoint', 'ContactPointsStatus']));
dispatch(generatedReceiversApi.util.invalidateTags(['Receiver']));
});
)
.unwrap()
.then(() => {
dispatch(alertingApi.util.invalidateTags(['AlertmanagerConfiguration', 'ContactPoint', 'ContactPointsStatus']));
dispatch(generatedReceiversApi.util.invalidateTags(['Receiver']));
});
};
};

@ -4,6 +4,7 @@ import { render, screen } from 'test/test-utils';
import { byLabelText, byPlaceholderText, byRole, byTestId } from 'testing-library-selector';
import { config } from '@grafana/runtime';
import { makeGrafanaAlertmanagerConfigUpdateFail } from 'app/features/alerting/unified/mocks/server/configure';
import { captureRequests } from 'app/features/alerting/unified/mocks/server/events';
import { AccessControlAction } from 'app/types';
@ -106,6 +107,20 @@ describe('alerting API server disabled', () => {
expect([testBody]).toMatchSnapshot();
expect([saveBody]).toMatchSnapshot();
});
it('does not redirect when creating contact point and API errors', async () => {
makeGrafanaAlertmanagerConfigUpdateFail();
const { user } = renderForm();
await user.type(await ui.inputs.name.find(), 'receiver that should fail');
const email = ui.inputs.email.addresses.get();
await user.clear(email);
await user.type(email, 'tester@grafana.com');
await user.click(ui.saveContactButton.get());
expect(screen.queryByText(/redirected/i)).not.toBeInTheDocument();
});
});
const ui = {

@ -54,12 +54,16 @@ export const CloudReceiverForm = ({ contactPoint, alertManagerSourceName, readOn
const onSubmit = async (values: ReceiverFormValues<CloudChannelValues>) => {
const newReceiver = formValuesToCloudReceiver(values, defaultChannelValues);
if (editMode) {
await updateContactPoint({ contactPoint: newReceiver, originalName: contactPoint!.name });
} else {
await createContactPoint({ contactPoint: newReceiver });
try {
if (editMode) {
await updateContactPoint({ contactPoint: newReceiver, originalName: contactPoint!.name });
} else {
await createContactPoint({ contactPoint: newReceiver });
}
locationService.push('/alerting/notifications');
} catch (error) {
// React form validation will handle this for us
}
locationService.push('/alerting/notifications');
};
// this basically checks if we can manage the selected alert manager data source, either because it's a Grafana Managed one

@ -81,17 +81,21 @@ export const GrafanaReceiverForm = ({ contactPoint, readOnly = false, editMode }
const onSubmit = async (values: ReceiverFormValues<GrafanaChannelValues>) => {
const newReceiver = formValuesToGrafanaReceiver(values, id2original, defaultChannelValues, grafanaNotifiers);
if (editMode) {
await updateContactPoint({
contactPoint: newReceiver,
id: contactPoint!.id,
resourceVersion: contactPoint?.metadata?.resourceVersion,
originalName: contactPoint?.name,
});
} else {
await createContactPoint({ contactPoint: newReceiver });
try {
if (editMode) {
await updateContactPoint({
contactPoint: newReceiver,
id: contactPoint!.id,
resourceVersion: contactPoint?.metadata?.resourceVersion,
originalName: contactPoint?.name,
});
} else {
await createContactPoint({ contactPoint: newReceiver });
}
locationService.push('/alerting/notifications');
} catch (error) {
// React form validation will handle this for us
}
locationService.push('/alerting/notifications');
};
const onTestChannel = (values: GrafanaChannelValues) => {

@ -4,9 +4,11 @@ import { config } from '@grafana/runtime';
import server, { mockFeatureDiscoveryApi } from 'app/features/alerting/unified/mockApi';
import { mockDataSource, mockFolder } from 'app/features/alerting/unified/mocks';
import {
ALERTMANAGER_UPDATE_ERROR_RESPONSE,
getAlertmanagerConfigHandler,
getGrafanaAlertmanagerConfigHandler,
grafanaAlertingConfigurationStatusHandler,
updateGrafanaAlertmanagerConfigHandler,
} from 'app/features/alerting/unified/mocks/server/handlers/alertmanagers';
import { getFolderHandler } from 'app/features/alerting/unified/mocks/server/handlers/folders';
import { listNamespacedTimeIntervalHandler } from 'app/features/alerting/unified/mocks/server/handlers/k8s/timeIntervals.k8s';
@ -126,3 +128,8 @@ export const removePlugin = (pluginId: string) => {
export const disablePlugin = (pluginId: SupportedPlugin) => {
server.use(getDisabledPluginHandler(pluginId));
};
/** Make alertmanager config update fail */
export const makeGrafanaAlertmanagerConfigUpdateFail = () => {
server.use(updateGrafanaAlertmanagerConfigHandler(ALERTMANAGER_UPDATE_ERROR_RESPONSE));
};

@ -35,7 +35,7 @@ export const getGrafanaAlertmanagerConfigHandler = (config: AlertManagerCortexCo
export const getAlertmanagerConfigHandler = (config: AlertManagerCortexConfig = alertmanagerConfigMock) =>
http.get('/api/alertmanager/:name/config/api/v1/alerts', () => HttpResponse.json(config));
const alertmanagerUpdateError = HttpResponse.json({ message: 'bad request' }, { status: 400 });
export const ALERTMANAGER_UPDATE_ERROR_RESPONSE = HttpResponse.json({ message: 'bad request' }, { status: 400 });
/** Perform some basic validation on the config that we expect the backend to also do */
const validateGrafanaAlertmanagerConfig = (config: AlertManagerCortexConfig) => {
@ -46,27 +46,28 @@ const validateGrafanaAlertmanagerConfig = (config: AlertManagerCortexConfig) =>
const intervalsByName = new Set(intervals.map((interval) => interval.name));
const duplicatedIntervals = intervalsByName.size !== intervals.length;
let routesReferencingMissingMuteTimings = false;
if (route) {
const routesReferencingMissingMuteTimings = Boolean(
routesReferencingMissingMuteTimings = Boolean(
route.routes?.find((route) => {
return route.mute_time_intervals?.some((name) => !intervalsByName.has(name));
})
);
if (routesReferencingMissingMuteTimings) {
return alertmanagerUpdateError;
}
}
if (duplicatedIntervals) {
return alertmanagerUpdateError;
if (routesReferencingMissingMuteTimings || duplicatedIntervals) {
return ALERTMANAGER_UPDATE_ERROR_RESPONSE;
}
return null;
};
const updateGrafanaAlertmanagerConfigHandler = () =>
export const updateGrafanaAlertmanagerConfigHandler = (responseOverride?: typeof ALERTMANAGER_UPDATE_ERROR_RESPONSE) =>
http.post('/api/alertmanager/grafana/config/api/v1/alerts', async ({ request }) => {
if (responseOverride) {
return responseOverride;
}
const body: AlertManagerCortexConfig = await request.clone().json();
const potentialError = validateGrafanaAlertmanagerConfig(body);
return potentialError ? potentialError : HttpResponse.json({ message: 'configuration created' });

Loading…
Cancel
Save