mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Fix alertmanager query param when returning to silences list (#80021)
* Add alertmanager query param when returning to silences list. Sync query and storage alertmanager param * Remove unused imports
This commit is contained in:
parent
9cdd519e53
commit
6fd0ae0474
@ -15,6 +15,8 @@ import { SilenceState } from '../../../plugins/datasource/alertmanager/types';
|
|||||||
import Silences from './Silences';
|
import Silences from './Silences';
|
||||||
import { createOrUpdateSilence, fetchAlerts, fetchSilences } from './api/alertmanager';
|
import { createOrUpdateSilence, fetchAlerts, fetchSilences } from './api/alertmanager';
|
||||||
import { grantUserPermissions, mockAlertmanagerAlert, mockDataSource, MockDataSourceSrv, mockSilence } from './mocks';
|
import { grantUserPermissions, mockAlertmanagerAlert, mockDataSource, MockDataSourceSrv, mockSilence } from './mocks';
|
||||||
|
import { AlertmanagerProvider } from './state/AlertmanagerContext';
|
||||||
|
import { setupDataSources } from './testSetup/datasources';
|
||||||
import { parseMatchers } from './utils/alertmanager';
|
import { parseMatchers } from './utils/alertmanager';
|
||||||
import { DataSourceType } from './utils/datasource';
|
import { DataSourceType } from './utils/datasource';
|
||||||
|
|
||||||
@ -37,7 +39,9 @@ const renderSilences = (location = '/alerting/silences/') => {
|
|||||||
|
|
||||||
return render(
|
return render(
|
||||||
<TestProvider>
|
<TestProvider>
|
||||||
|
<AlertmanagerProvider accessType="instance">
|
||||||
<Silences />
|
<Silences />
|
||||||
|
</AlertmanagerProvider>
|
||||||
</TestProvider>
|
</TestProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -218,7 +222,7 @@ describe('Silence edit', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
setUserLogged(true);
|
setUserLogged(true);
|
||||||
setDataSourceSrv(new MockDataSourceSrv(dataSources));
|
setupDataSources(dataSources.am);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should not render createdBy if user is logged in and has a name', async () => {
|
it('Should not render createdBy if user is logged in and has a name', async () => {
|
||||||
@ -325,4 +329,32 @@ describe('Silence edit', () => {
|
|||||||
},
|
},
|
||||||
TEST_TIMEOUT
|
TEST_TIMEOUT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
'silences page should contain alertmanager parameter after creating a silence',
|
||||||
|
async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
renderSilences(`${baseUrlPath}?alertmanager=Alertmanager`);
|
||||||
|
await waitFor(() => expect(ui.editor.durationField.query()).not.toBeNull());
|
||||||
|
|
||||||
|
await user.type(ui.editor.matcherName.getAll()[0], 'foo');
|
||||||
|
await user.type(ui.editor.matcherOperatorSelect.getAll()[0], '=');
|
||||||
|
await user.type(ui.editor.matcherValue.getAll()[0], 'bar');
|
||||||
|
|
||||||
|
await user.click(ui.editor.submit.get());
|
||||||
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(mocks.api.createOrUpdateSilence).toHaveBeenCalledWith(
|
||||||
|
'Alertmanager',
|
||||||
|
expect.objectContaining({
|
||||||
|
matchers: [{ isEqual: true, isRegex: false, name: 'foo', value: 'bar' }],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(locationService.getSearch().get('alertmanager')).toBe('Alertmanager');
|
||||||
|
},
|
||||||
|
TEST_TIMEOUT
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
|
||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
import { AlertManagerDataSourceJsonData, AlertManagerImplementation } from 'app/plugins/datasource/alertmanager/types';
|
import { AlertManagerDataSourceJsonData, AlertManagerImplementation } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { useAlertManagersByPermission } from '../hooks/useAlertManagerSources';
|
import { useAlertManagersByPermission } from '../hooks/useAlertManagerSources';
|
||||||
|
import { useURLSearchParams } from '../hooks/useURLSearchParams';
|
||||||
import { ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, ALERTMANAGER_NAME_QUERY_KEY } from '../utils/constants';
|
import { ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, ALERTMANAGER_NAME_QUERY_KEY } from '../utils/constants';
|
||||||
import {
|
import {
|
||||||
AlertManagerDataSource,
|
AlertManagerDataSource,
|
||||||
@ -30,7 +30,7 @@ interface Props extends React.PropsWithChildren {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AlertmanagerProvider = ({ children, accessType, alertmanagerSourceName }: Props) => {
|
const AlertmanagerProvider = ({ children, accessType, alertmanagerSourceName }: Props) => {
|
||||||
const [queryParams, updateQueryParams] = useQueryParams();
|
const [queryParams, updateQueryParams] = useURLSearchParams();
|
||||||
const allAvailableAlertManagers = useAlertManagersByPermission(accessType);
|
const allAvailableAlertManagers = useAlertManagersByPermission(accessType);
|
||||||
const availableAlertManagers = allAvailableAlertManagers.availableInternalDataSources.concat(
|
const availableAlertManagers = allAvailableAlertManagers.availableInternalDataSources.concat(
|
||||||
allAvailableAlertManagers.availableExternalDataSources
|
allAvailableAlertManagers.availableExternalDataSources
|
||||||
@ -44,7 +44,7 @@ const AlertmanagerProvider = ({ children, accessType, alertmanagerSourceName }:
|
|||||||
|
|
||||||
if (selectedAlertManager === GRAFANA_RULES_SOURCE_NAME) {
|
if (selectedAlertManager === GRAFANA_RULES_SOURCE_NAME) {
|
||||||
store.delete(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY);
|
store.delete(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY);
|
||||||
updateQueryParams({ [ALERTMANAGER_NAME_QUERY_KEY]: null });
|
updateQueryParams({ [ALERTMANAGER_NAME_QUERY_KEY]: undefined });
|
||||||
} else {
|
} else {
|
||||||
store.set(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, selectedAlertManager);
|
store.set(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, selectedAlertManager);
|
||||||
updateQueryParams({ [ALERTMANAGER_NAME_QUERY_KEY]: selectedAlertManager });
|
updateQueryParams({ [ALERTMANAGER_NAME_QUERY_KEY]: selectedAlertManager });
|
||||||
@ -53,10 +53,19 @@ const AlertmanagerProvider = ({ children, accessType, alertmanagerSourceName }:
|
|||||||
[availableAlertManagers, updateQueryParams]
|
[availableAlertManagers, updateQueryParams]
|
||||||
);
|
);
|
||||||
|
|
||||||
const sourceFromQuery = queryParams[ALERTMANAGER_NAME_QUERY_KEY];
|
const sourceFromQuery = queryParams.get(ALERTMANAGER_NAME_QUERY_KEY);
|
||||||
const sourceFromStore = store.get(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY);
|
const sourceFromStore = store.get(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY);
|
||||||
const defaultSource = GRAFANA_RULES_SOURCE_NAME;
|
const defaultSource = GRAFANA_RULES_SOURCE_NAME;
|
||||||
|
|
||||||
|
// This overrides AM in the store to be in sync with the one in the URL
|
||||||
|
// When the user uses multiple tabs with different AMs, the store will be changing all the time
|
||||||
|
// It's safest to always use URLs with alertmanager query param
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (sourceFromQuery && sourceFromQuery !== sourceFromStore) {
|
||||||
|
store.set(ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, sourceFromQuery);
|
||||||
|
}
|
||||||
|
}, [sourceFromQuery, sourceFromStore]);
|
||||||
|
|
||||||
// queryParam > localStorage > default
|
// queryParam > localStorage > default
|
||||||
const desiredAlertmanager = alertmanagerSourceName ?? sourceFromQuery ?? sourceFromStore ?? defaultSource;
|
const desiredAlertmanager = alertmanagerSourceName ?? sourceFromQuery ?? sourceFromStore ?? defaultSource;
|
||||||
const selectedAlertmanager = isAlertManagerAvailable(availableAlertManagers, desiredAlertmanager)
|
const selectedAlertmanager = isAlertManagerAvailable(availableAlertManagers, desiredAlertmanager)
|
||||||
|
@ -575,7 +575,7 @@ export const createOrUpdateSilenceAction = createAsyncThunk<void, UpdateSilenceA
|
|||||||
(async () => {
|
(async () => {
|
||||||
await createOrUpdateSilence(alertManagerSourceName, payload);
|
await createOrUpdateSilence(alertManagerSourceName, payload);
|
||||||
if (exitOnSave) {
|
if (exitOnSave) {
|
||||||
locationService.push('/alerting/silences');
|
locationService.push(makeAMLink('/alerting/silences', alertManagerSourceName));
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
),
|
),
|
||||||
|
@ -105,7 +105,7 @@ export function makeAMLink(path: string, alertManagerName?: string, options?: UR
|
|||||||
const search = new URLSearchParams(options);
|
const search = new URLSearchParams(options);
|
||||||
|
|
||||||
if (alertManagerName) {
|
if (alertManagerName) {
|
||||||
search.append(ALERTMANAGER_NAME_QUERY_KEY, alertManagerName);
|
search.set(ALERTMANAGER_NAME_QUERY_KEY, alertManagerName);
|
||||||
}
|
}
|
||||||
return `${path}?${search.toString()}`;
|
return `${path}?${search.toString()}`;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user