diff --git a/public/app/features/alerting/unified/AmRoutes.test.tsx b/public/app/features/alerting/unified/AmRoutes.test.tsx index 247fe95ab64..819823f6756 100644 --- a/public/app/features/alerting/unified/AmRoutes.test.tsx +++ b/public/app/features/alerting/unified/AmRoutes.test.tsx @@ -95,6 +95,9 @@ const ui = { groupWaitContainer: byTestId('am-group-wait'), groupIntervalContainer: byTestId('am-group-interval'), groupRepeatContainer: byTestId('am-repeat-interval'), + + confirmDeleteModal: byRole('dialog'), + confirmDeleteButton: byLabelText('Confirm Modal Danger Button'), }; describe('AmRoutes', () => { @@ -154,6 +157,8 @@ describe('AmRoutes', () => { }, ]; + const emptyRoute: Route = {}; + const simpleRoute: Route = { receiver: 'simple-receiver', matchers: ['hello=world', 'foo!=bar'], @@ -465,6 +470,61 @@ describe('AmRoutes', () => { }); }); + it('Should be able to delete an empty route', async () => { + const routeConfig = { + continue: false, + receiver: 'default', + group_by: ['alertname'], + routes: [emptyRoute], + group_interval: '4m', + group_wait: '1m', + repeat_interval: '5h', + mute_time_intervals: [], + }; + + const defaultConfig: AlertManagerCortexConfig = { + alertmanager_config: { + receivers: [{ name: 'default' }, { name: 'critical' }], + route: routeConfig, + templates: [], + }, + template_files: {}, + }; + + mocks.api.fetchAlertManagerConfig.mockImplementation(() => { + return Promise.resolve(defaultConfig); + }); + + mocks.api.updateAlertManagerConfig.mockResolvedValue(Promise.resolve()); + + await renderAmRoutes(GRAFANA_RULES_SOURCE_NAME); + expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled(); + + const deleteButtons = await ui.deleteRouteButton.findAll(); + expect(deleteButtons).toHaveLength(1); + + await userEvent.click(deleteButtons[0]); + + const confirmDeleteButton = ui.confirmDeleteButton.get(ui.confirmDeleteModal.get()); + expect(confirmDeleteButton).toBeInTheDocument(); + + await userEvent.click(confirmDeleteButton); + + expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith<[string, AlertManagerCortexConfig]>( + GRAFANA_RULES_SOURCE_NAME, + { + ...defaultConfig, + alertmanager_config: { + ...defaultConfig.alertmanager_config, + route: { + ...routeConfig, + routes: [], + }, + }, + } + ); + }); + it('Keeps matchers for non-grafana alertmanager sources', async () => { const defaultConfig: AlertManagerCortexConfig = { alertmanager_config: { diff --git a/public/app/features/alerting/unified/utils/amroutes.ts b/public/app/features/alerting/unified/utils/amroutes.ts index 7d5a2bb8e6e..18f804aae39 100644 --- a/public/app/features/alerting/unified/utils/amroutes.ts +++ b/public/app/features/alerting/unified/utils/amroutes.ts @@ -77,20 +77,22 @@ export const emptyRoute: FormAmRoute = { muteTimeIntervals: [], }; -//returns route, and a record mapping id to existing route route +//returns route, and a record mapping id to existing route export const amRouteToFormAmRoute = (route: Route | undefined): [FormAmRoute, Record] => { - if (!route || Object.keys(route).length === 0) { + if (!route) { return [emptyRoute, {}]; } - const [groupWaitValue, groupWaitValueType] = intervalToValueAndType(route.group_wait, ['', 's']); - const [groupIntervalValue, groupIntervalValueType] = intervalToValueAndType(route.group_interval, ['', 'm']); - const [repeatIntervalValue, repeatIntervalValueType] = intervalToValueAndType(route.repeat_interval, ['', 'h']); - const id = String(Math.random()); const id2route = { [id]: route, }; + + if (Object.keys(route).length === 0) { + const formAmRoute = { ...emptyRoute, id }; + return [formAmRoute, id2route]; + } + const formRoutes: FormAmRoute[] = []; route.routes?.forEach((subRoute) => { const [subFormRoute, subId2Route] = amRouteToFormAmRoute(subRoute); @@ -105,6 +107,10 @@ export const amRouteToFormAmRoute = (route: Route | undefined): [FormAmRoute, Re (matcher) => ({ name: matcher[0], operator: matcher[1], value: matcher[2] } as MatcherFieldValue) ) ?? []; + const [groupWaitValue, groupWaitValueType] = intervalToValueAndType(route.group_wait, ['', 's']); + const [groupIntervalValue, groupIntervalValueType] = intervalToValueAndType(route.group_interval, ['', 'm']); + const [repeatIntervalValue, repeatIntervalValueType] = intervalToValueAndType(route.repeat_interval, ['', 'h']); + return [ { id,