mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Tidy up contact points/misc other tests' mock server behaviour (#90469)
This commit is contained in:
parent
c5775b3778
commit
a61cd94a70
@ -12,8 +12,8 @@ import { searchFolders } from '../../manage-dashboards/state/actions';
|
||||
|
||||
import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler';
|
||||
import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor';
|
||||
import { mockApi, mockFeatureDiscoveryApi, setupMswServer } from './mockApi';
|
||||
import { grantUserPermissions, labelsPluginMetaMock, mockDataSource } from './mocks';
|
||||
import { mockFeatureDiscoveryApi, setupMswServer } from './mockApi';
|
||||
import { grantUserPermissions, mockDataSource } from './mocks';
|
||||
import { emptyExternalAlertmanagersResponse, mockAlertmanagersResponse } from './mocks/alertmanagerApi';
|
||||
import { fetchRulerRulesIfNotFetchedYet } from './state/actions';
|
||||
import { setupDataSources } from './testSetup/datasources';
|
||||
@ -51,7 +51,6 @@ const server = setupMswServer();
|
||||
|
||||
mockFeatureDiscoveryApi(server).discoverDsFeatures(dataSources.default, buildInfoResponse.mimir);
|
||||
mockAlertmanagersResponse(server, emptyExternalAlertmanagersResponse);
|
||||
mockApi(server).plugins.getPluginSettings({ ...labelsPluginMetaMock, enabled: false });
|
||||
|
||||
// these tests are rather slow because we have to wait for various API calls and mocks to be called
|
||||
// and wait for the UI to be in particular states, drone seems to time out quite often so
|
||||
|
@ -276,6 +276,7 @@ export const alertmanagerApi = alertingApi.injectEndpoints({
|
||||
},
|
||||
}),
|
||||
// Grafana Managed Alertmanager only
|
||||
// TODO: Remove as part of migration to k8s API for receivers
|
||||
getContactPointsList: build.query<GrafanaManagedContactPoint[], void>({
|
||||
query: () => ({ url: '/api/v1/notifications/receivers' }),
|
||||
}),
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { MemoryHistoryBuildOptions } from 'history';
|
||||
import { noop } from 'lodash';
|
||||
import { ComponentProps, PropsWithChildren } from 'react';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
import { ComponentProps, ReactNode } from 'react';
|
||||
import { render, screen, waitFor, waitForElementToBeRemoved } from 'test/test-utils';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { AlertManagerDataSourceJsonData, AlertManagerImplementation } from 'app/plugins/datasource/alertmanager/types';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
|
||||
@ -16,7 +15,6 @@ import { setupDataSources } from '../../testSetup/datasources';
|
||||
import { DataSourceType } from '../../utils/datasource';
|
||||
|
||||
import ContactPoints, { ContactPoint } from './ContactPoints';
|
||||
import setupGrafanaManagedServer from './__mocks__/grafanaManagedServer';
|
||||
import setupMimirFlavoredServer, { MIMIR_DATASOURCE_UID } from './__mocks__/mimirFlavoredServer';
|
||||
import setupVanillaAlertmanagerFlavoredServer, {
|
||||
VANILLA_ALERTMANAGER_DATASOURCE_UID,
|
||||
@ -42,66 +40,54 @@ import { RouteReference } from './utils';
|
||||
const server = setupMswServer();
|
||||
|
||||
const renderWithProvider = (
|
||||
providerProps?: Partial<ComponentProps<typeof AlertmanagerProvider>>,
|
||||
contactPointProps?: Partial<ComponentProps<typeof ContactPoints>>
|
||||
children: ReactNode,
|
||||
historyOptions?: MemoryHistoryBuildOptions,
|
||||
providerProps?: Partial<ComponentProps<typeof AlertmanagerProvider>>
|
||||
) =>
|
||||
render(
|
||||
<TestProvider>
|
||||
<AlertmanagerProvider accessType={'notification'} {...providerProps}>
|
||||
<ContactPoints {...contactPointProps} />
|
||||
</AlertmanagerProvider>
|
||||
</TestProvider>
|
||||
<AlertmanagerProvider accessType="notification" {...providerProps}>
|
||||
{children}
|
||||
</AlertmanagerProvider>,
|
||||
{ historyOptions }
|
||||
);
|
||||
|
||||
describe('contact points', () => {
|
||||
beforeEach(() => {
|
||||
// The location service is stateful between tests - `TestProvider` uses the same instance between each test
|
||||
// and this results in the query params being persisted between tests
|
||||
// To get round this for now, we can push "/" onto the history so there are no query params
|
||||
locationService.push('/');
|
||||
});
|
||||
|
||||
describe('Contact points with Grafana managed alertmanager', () => {
|
||||
beforeEach(() => {
|
||||
grantUserPermissions([
|
||||
AccessControlAction.AlertingNotificationsRead,
|
||||
AccessControlAction.AlertingNotificationsWrite,
|
||||
]);
|
||||
|
||||
setupGrafanaManagedServer(server);
|
||||
});
|
||||
|
||||
describe('tabs behaviour', () => {
|
||||
test('loads contact points tab', async () => {
|
||||
locationService.push('/?tab=contact_points');
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />, { initialEntries: ['/?tab=contact_points'] });
|
||||
|
||||
expect(await screen.findByText(/add contact point/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('loads templates tab', async () => {
|
||||
locationService.push('/?tab=templates');
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />, { initialEntries: ['/?tab=templates'] });
|
||||
|
||||
expect(await screen.findByText(/add notification template/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('defaults to contact points tab with invalid query param', async () => {
|
||||
locationService.push('/?tab=foo_bar');
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />, { initialEntries: ['/?tab=foo_bar'] });
|
||||
|
||||
expect(await screen.findByText(/add contact point/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('defaults to contact points tab with no query param', async () => {
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />);
|
||||
|
||||
expect(await screen.findByText(/add contact point/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show / hide loading states, have all actions enabled', async () => {
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />);
|
||||
|
||||
await waitFor(async () => {
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
@ -140,7 +126,7 @@ describe('contact points', () => {
|
||||
it('should disable certain actions if the user has no write permissions', async () => {
|
||||
grantUserPermissions([AccessControlAction.AlertingNotificationsRead]);
|
||||
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />);
|
||||
|
||||
// wait for loading to be done
|
||||
await waitFor(async () => {
|
||||
@ -178,10 +164,7 @@ describe('contact points', () => {
|
||||
|
||||
it('should call delete when clicked and not disabled', async () => {
|
||||
const onDelete = jest.fn();
|
||||
|
||||
render(<ContactPoint name={'my-contact-point'} receivers={[]} onDelete={onDelete} />, {
|
||||
wrapper,
|
||||
});
|
||||
renderWithProvider(<ContactPoint name={'my-contact-point'} receivers={[]} onDelete={onDelete} />);
|
||||
|
||||
const moreActions = screen.getByRole('button', { name: /More/ });
|
||||
await userEvent.click(moreActions);
|
||||
@ -193,9 +176,7 @@ describe('contact points', () => {
|
||||
});
|
||||
|
||||
it('should disable edit button', async () => {
|
||||
render(<ContactPoint name={'my-contact-point'} disabled={true} receivers={[]} onDelete={noop} />, {
|
||||
wrapper,
|
||||
});
|
||||
renderWithProvider(<ContactPoint name={'my-contact-point'} disabled={true} receivers={[]} onDelete={noop} />);
|
||||
|
||||
const moreActions = screen.getByRole('button', { name: /More/ });
|
||||
expect(moreActions).not.toBeDisabled();
|
||||
@ -205,9 +186,7 @@ describe('contact points', () => {
|
||||
});
|
||||
|
||||
it('should disable buttons when provisioned', async () => {
|
||||
render(<ContactPoint name={'my-contact-point'} provisioned={true} receivers={[]} onDelete={noop} />, {
|
||||
wrapper,
|
||||
});
|
||||
renderWithProvider(<ContactPoint name={'my-contact-point'} provisioned={true} receivers={[]} onDelete={noop} />);
|
||||
|
||||
expect(screen.getByText(/provisioned/i)).toBeInTheDocument();
|
||||
|
||||
@ -235,9 +214,7 @@ describe('contact points', () => {
|
||||
},
|
||||
];
|
||||
|
||||
render(<ContactPoint name={'my-contact-point'} receivers={[]} policies={policies} onDelete={noop} />, {
|
||||
wrapper,
|
||||
});
|
||||
renderWithProvider(<ContactPoint name={'my-contact-point'} receivers={[]} policies={policies} onDelete={noop} />);
|
||||
|
||||
expect(screen.getByRole('link', { name: /1 notification policy/ })).toBeInTheDocument();
|
||||
|
||||
@ -258,9 +235,7 @@ describe('contact points', () => {
|
||||
},
|
||||
];
|
||||
|
||||
render(<ContactPoint name={'my-contact-point'} receivers={[]} policies={policies} onDelete={noop} />, {
|
||||
wrapper,
|
||||
});
|
||||
renderWithProvider(<ContactPoint name={'my-contact-point'} receivers={[]} policies={policies} onDelete={noop} />);
|
||||
|
||||
const moreActions = screen.getByRole('button', { name: /More/ });
|
||||
await userEvent.click(moreActions);
|
||||
@ -270,7 +245,7 @@ describe('contact points', () => {
|
||||
});
|
||||
|
||||
it('should be able to search', async () => {
|
||||
renderWithProvider();
|
||||
renderWithProvider(<ContactPoints />);
|
||||
|
||||
const searchInput = screen.getByRole('textbox', { name: 'search contact points' });
|
||||
await userEvent.type(searchInput, 'slack');
|
||||
@ -308,7 +283,7 @@ describe('contact points', () => {
|
||||
});
|
||||
|
||||
it('should show / hide loading states, have the right actions enabled', async () => {
|
||||
renderWithProvider({ alertmanagerSourceName: MIMIR_DATASOURCE_UID });
|
||||
renderWithProvider(<ContactPoints />, undefined, { alertmanagerSourceName: MIMIR_DATASOURCE_UID });
|
||||
|
||||
await waitFor(async () => {
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
@ -364,16 +339,7 @@ describe('contact points', () => {
|
||||
});
|
||||
|
||||
it("should not allow any editing because it's not supported", async () => {
|
||||
render(
|
||||
<TestProvider>
|
||||
<AlertmanagerProvider
|
||||
accessType={'notification'}
|
||||
alertmanagerSourceName={VANILLA_ALERTMANAGER_DATASOURCE_UID}
|
||||
>
|
||||
<ContactPoints />
|
||||
</AlertmanagerProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
renderWithProvider(<ContactPoints />, undefined, { alertmanagerSourceName: VANILLA_ALERTMANAGER_DATASOURCE_UID });
|
||||
|
||||
await waitFor(async () => {
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
@ -394,9 +360,3 @@ describe('contact points', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const wrapper = ({ children }: PropsWithChildren) => (
|
||||
<TestProvider>
|
||||
<AlertmanagerProvider accessType={'notification'}>{children}</AlertmanagerProvider>
|
||||
</TestProvider>
|
||||
);
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
import { render, screen, waitFor, userEvent } from 'test/test-utils';
|
||||
import { byLabelText, byPlaceholderText, byRole, byTestId } from 'testing-library-selector';
|
||||
|
||||
import { AccessControlAction } from 'app/types';
|
||||
@ -10,10 +8,7 @@ import { grantUserPermissions } from '../../mocks';
|
||||
import { AlertmanagerProvider } from '../../state/AlertmanagerContext';
|
||||
|
||||
import NewContactPoint from './NewContactPoint';
|
||||
import setupGrafanaManagedServer, {
|
||||
setupSaveEndpointMock,
|
||||
setupTestEndpointMock,
|
||||
} from './__mocks__/grafanaManagedServer';
|
||||
import { setupSaveEndpointMock, setupTestEndpointMock } from './__mocks__/grafanaManagedServer';
|
||||
|
||||
import 'core-js/stable/structured-clone';
|
||||
|
||||
@ -22,7 +17,6 @@ const user = userEvent.setup();
|
||||
|
||||
beforeEach(() => {
|
||||
grantUserPermissions([AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsWrite]);
|
||||
setupGrafanaManagedServer(server);
|
||||
});
|
||||
|
||||
it('should be able to test and save a receiver', async () => {
|
||||
@ -32,15 +26,12 @@ it('should be able to test and save a receiver', async () => {
|
||||
render(
|
||||
<AlertmanagerProvider accessType={'notification'} alertmanagerSourceName="grafana">
|
||||
<NewContactPoint />
|
||||
</AlertmanagerProvider>,
|
||||
{ wrapper: TestProvider }
|
||||
</AlertmanagerProvider>
|
||||
);
|
||||
|
||||
// wait for loading to be done
|
||||
// type in a name for the new receiver
|
||||
await waitFor(() => {
|
||||
user.type(ui.inputs.name.get(), 'my new receiver');
|
||||
});
|
||||
await user.type(await ui.inputs.name.find(), 'my new receiver');
|
||||
|
||||
// enter some email
|
||||
const email = ui.inputs.email.addresses.get();
|
||||
@ -50,12 +41,8 @@ it('should be able to test and save a receiver', async () => {
|
||||
// try to test the contact point
|
||||
await user.click(await ui.testContactPointButton.find());
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(ui.testContactPointModal.get()).toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 1000 }
|
||||
);
|
||||
expect(await ui.testContactPointModal.find()).toBeInTheDocument();
|
||||
|
||||
await user.click(ui.customContactPointOption.get());
|
||||
|
||||
// enter custom annotations and labels
|
||||
@ -70,14 +57,14 @@ it('should be able to test and save a receiver', async () => {
|
||||
// it can't seem to assert on the success toast
|
||||
await waitFor(() => {
|
||||
expect(testMock).toHaveBeenCalled();
|
||||
expect(testMock.mock.lastCall).toMatchSnapshot();
|
||||
});
|
||||
expect(testMock.mock.lastCall).toMatchSnapshot();
|
||||
|
||||
await user.click(ui.saveContactButton.get());
|
||||
await waitFor(() => {
|
||||
expect(saveMock).toHaveBeenCalled();
|
||||
expect(saveMock.mock.lastCall).toMatchSnapshot();
|
||||
});
|
||||
expect(saveMock.mock.lastCall).toMatchSnapshot();
|
||||
});
|
||||
|
||||
const ui = {
|
||||
|
@ -1,48 +1,7 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { SetupServer } from 'msw/node';
|
||||
|
||||
import { AlertmanagerChoice, AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
||||
import { ReceiversStateDTO } from 'app/types';
|
||||
|
||||
import { mockApi } from '../../../mockApi';
|
||||
import { mockAlertmanagerChoiceResponse } from '../../../mocks/alertmanagerApi';
|
||||
import { grafanaNotifiersMock } from '../../../mocks/grafana-notifiers';
|
||||
|
||||
import alertmanagerMock from './alertmanager.config.mock.json';
|
||||
import receiversMock from './receivers.mock.json';
|
||||
|
||||
export default (server: SetupServer) => {
|
||||
server.use(
|
||||
// this endpoint is a grafana built-in alertmanager
|
||||
http.get('/api/alertmanager/grafana/config/api/v1/alerts', () =>
|
||||
HttpResponse.json<AlertManagerCortexConfig>(alertmanagerMock)
|
||||
),
|
||||
// this endpoint is only available for the built-in alertmanager
|
||||
http.get('/api/alertmanager/grafana/config/api/v1/receivers', () =>
|
||||
HttpResponse.json<ReceiversStateDTO[]>(receiversMock)
|
||||
),
|
||||
// this endpoint will respond if the OnCall plugin is installed
|
||||
http.get('/api/plugins/grafana-oncall-app/settings', () => HttpResponse.json({}, { status: 404 })),
|
||||
|
||||
// this endpoint looks up alerts when copying notification template
|
||||
http.get('/api/alertmanager/grafana/api/v2/alerts', () => HttpResponse.json([])),
|
||||
|
||||
// this endpoint returns preview of a template we're editing
|
||||
http.post('/api/alertmanager/grafana/config/api/v1/templates/test', () => HttpResponse.json({}, { status: 200 }))
|
||||
);
|
||||
|
||||
// this endpoint is for rendering the "additional AMs to configure" warning
|
||||
mockAlertmanagerChoiceResponse(server, {
|
||||
alertmanagersChoice: AlertmanagerChoice.Internal,
|
||||
numExternalAlertmanagers: 1,
|
||||
});
|
||||
|
||||
// mock the endpoint for contact point metadata
|
||||
mockApi(server).grafanaNotifiers(grafanaNotifiersMock);
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
/** @deprecated */
|
||||
export const setupTestEndpointMock = (server: SetupServer) => {
|
||||
const mock = jest.fn();
|
||||
|
||||
@ -64,6 +23,7 @@ export const setupTestEndpointMock = (server: SetupServer) => {
|
||||
return mock;
|
||||
};
|
||||
|
||||
/** @deprecated */
|
||||
export const setupSaveEndpointMock = (server: SetupServer) => {
|
||||
const mock = jest.fn();
|
||||
|
||||
|
@ -21,9 +21,7 @@ export default (server: SetupServer) => {
|
||||
},
|
||||
{ status: 404 }
|
||||
)
|
||||
),
|
||||
// this endpoint will respond if the OnCall plugin is installed
|
||||
http.get('/api/plugins/grafana-oncall-app/settings', () => HttpResponse.json({}, { status: 404 }))
|
||||
)
|
||||
);
|
||||
|
||||
return server;
|
||||
|
@ -12,9 +12,7 @@ export default (server: SetupServer) => {
|
||||
server.use(
|
||||
http.get(`/api/alertmanager/${VANILLA_ALERTMANAGER_DATASOURCE_UID}/api/v2/status`, () =>
|
||||
HttpResponse.json<AlertmanagerStatus>(vanillaAlertManagerConfig)
|
||||
),
|
||||
// this endpoint will respond if the OnCall plugin is installed
|
||||
http.get('/api/plugins/grafana-oncall-app/settings', () => HttpResponse.json({}, { status: 404 }))
|
||||
)
|
||||
);
|
||||
|
||||
return server;
|
||||
|
@ -19,7 +19,7 @@ exports[`should be able to test and save a receiver 1`] = `
|
||||
"name": "test",
|
||||
"secureSettings": {},
|
||||
"settings": {
|
||||
"addresses": "nteews treerc@egirvaefrana.com",
|
||||
"addresses": "tester@grafana.com",
|
||||
"singleEmail": false,
|
||||
},
|
||||
"type": "email",
|
||||
@ -132,16 +132,16 @@ exports[`should be able to test and save a receiver 2`] = `
|
||||
"grafana_managed_receiver_configs": [
|
||||
{
|
||||
"disableResolveMessage": false,
|
||||
"name": "my ",
|
||||
"name": "my new receiver",
|
||||
"secureSettings": {},
|
||||
"settings": {
|
||||
"addresses": "nteews treerc@egirvaefrana.com",
|
||||
"addresses": "tester@grafana.com",
|
||||
"singleEmail": false,
|
||||
},
|
||||
"type": "email",
|
||||
},
|
||||
],
|
||||
"name": "my ",
|
||||
"name": "my new receiver",
|
||||
},
|
||||
],
|
||||
"route": {
|
||||
|
@ -78,8 +78,8 @@ exports[`useContactPoints should return contact points with status 1`] = `
|
||||
"type": "oncall",
|
||||
Symbol(receiver_status): undefined,
|
||||
Symbol(receiver_metadata): {
|
||||
"description": undefined,
|
||||
"name": "Oncall",
|
||||
"description": "Sends notifications to Grafana OnCall",
|
||||
"name": "Grafana OnCall",
|
||||
},
|
||||
Symbol(receiver_plugin_metadata): {
|
||||
"description": "grafana-integration",
|
||||
@ -259,8 +259,8 @@ exports[`useContactPoints when having oncall plugin installed and no alert manag
|
||||
"type": "oncall",
|
||||
Symbol(receiver_status): undefined,
|
||||
Symbol(receiver_metadata): {
|
||||
"description": undefined,
|
||||
"name": "Oncall",
|
||||
"description": "Sends notifications to Grafana OnCall",
|
||||
"name": "Grafana OnCall",
|
||||
},
|
||||
Symbol(receiver_plugin_metadata): {
|
||||
"icon": "public/img/alerting/oncall_logo.svg",
|
||||
|
@ -2,31 +2,24 @@ import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import alertmanagerMock from 'app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json';
|
||||
import { setOnCallIntegrations } from 'app/features/alerting/unified/mocks/server/handlers/plugins/configure-plugins';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
|
||||
import { ONCALL_INTEGRATION_V2_FEATURE } from '../../api/onCallApi';
|
||||
import { mockApi, setupMswServer } from '../../mockApi';
|
||||
import { grantUserPermissions, onCallPluginMetaMock } from '../../mocks';
|
||||
import { grantUserPermissions } from '../../mocks';
|
||||
import { AlertmanagerProvider } from '../../state/AlertmanagerContext';
|
||||
|
||||
import setupGrafanaManagedServer from './__mocks__/grafanaManagedServer';
|
||||
import { useContactPointsWithStatus } from './useContactPoints';
|
||||
|
||||
const server = setupMswServer();
|
||||
|
||||
describe('useContactPoints', () => {
|
||||
beforeEach(() => {
|
||||
setupGrafanaManagedServer(server);
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
grantUserPermissions([AccessControlAction.AlertingNotificationsRead]);
|
||||
});
|
||||
|
||||
it('should return contact points with status', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([
|
||||
setOnCallIntegrations([
|
||||
{
|
||||
display_name: 'grafana-integration',
|
||||
value: 'ABC123',
|
||||
@ -34,6 +27,7 @@ describe('useContactPoints', () => {
|
||||
},
|
||||
]);
|
||||
mockApi(server).getContactPointsList(receivers);
|
||||
|
||||
const { result } = renderHook(() => useContactPointsWithStatus(), {
|
||||
wrapper: ({ children }) => (
|
||||
<TestProvider>
|
||||
@ -43,16 +37,16 @@ describe('useContactPoints', () => {
|
||||
</TestProvider>
|
||||
),
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current).toMatchSnapshot();
|
||||
});
|
||||
expect(result.current).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('when having oncall plugin installed and no alert manager config data', () => {
|
||||
it('should return contact points with oncall metadata', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([
|
||||
setOnCallIntegrations([
|
||||
{
|
||||
display_name: 'grafana-integration',
|
||||
value: 'ABC123',
|
||||
@ -60,6 +54,7 @@ describe('useContactPoints', () => {
|
||||
},
|
||||
]);
|
||||
mockApi(server).getContactPointsList(receivers);
|
||||
|
||||
const { result } = renderHook(
|
||||
() => useContactPointsWithStatus({ includePoliciesCount: false, receiverStatusPollingInterval: 0 }),
|
||||
{
|
||||
@ -75,8 +70,8 @@ describe('useContactPoints', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current).toMatchSnapshot();
|
||||
});
|
||||
expect(result.current).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,23 +1,24 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
import { clickSelectOption } from 'test/helpers/selectOptionInTest';
|
||||
import { render, waitFor, userEvent } from 'test/test-utils';
|
||||
import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector';
|
||||
|
||||
import { disablePlugin } from 'app/features/alerting/unified/mocks/server/configure';
|
||||
import {
|
||||
setOnCallFeatures,
|
||||
setOnCallIntegrations,
|
||||
} from 'app/features/alerting/unified/mocks/server/handlers/plugins/configure-plugins';
|
||||
import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';
|
||||
import { clearPluginSettingsCache } from 'app/features/plugins/pluginSettings';
|
||||
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
|
||||
|
||||
import { ONCALL_INTEGRATION_V2_FEATURE } from '../../../api/onCallApi';
|
||||
import { AlertmanagerConfigBuilder, mockApi, setupMswServer } from '../../../mockApi';
|
||||
import { grafanaAlertNotifiersMock } from '../../../mockGrafanaNotifiers';
|
||||
import { onCallPluginMetaMock } from '../../../mocks';
|
||||
import { AlertmanagerConfigBuilder, setupMswServer } from '../../../mockApi';
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
|
||||
|
||||
import { GrafanaReceiverForm } from './GrafanaReceiverForm';
|
||||
|
||||
import 'core-js/stable/structured-clone';
|
||||
|
||||
const server = setupMswServer();
|
||||
setupMswServer();
|
||||
|
||||
const ui = {
|
||||
loadingIndicator: byText('Loading notifiers...'),
|
||||
@ -40,14 +41,11 @@ describe('GrafanaReceiverForm', () => {
|
||||
|
||||
describe('OnCall contact point', () => {
|
||||
it('OnCall contact point should be disabled if OnCall integration is not enabled', async () => {
|
||||
mockApi(server).grafanaNotifiers(grafanaAlertNotifiersMock);
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: false });
|
||||
disablePlugin(SupportedPlugin.OnCall);
|
||||
|
||||
const amConfig = getAmCortexConfig((_) => {});
|
||||
|
||||
render(<GrafanaReceiverForm alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME} config={amConfig} />, {
|
||||
wrapper: TestProvider,
|
||||
});
|
||||
render(<GrafanaReceiverForm alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME} config={amConfig} />);
|
||||
|
||||
await waitFor(() => expect(ui.loadingIndicator.query()).not.toBeInTheDocument());
|
||||
|
||||
@ -60,10 +58,7 @@ describe('GrafanaReceiverForm', () => {
|
||||
});
|
||||
|
||||
it('OnCall contact point should support new and existing integration options if OnCall integration V2 is enabled', async () => {
|
||||
mockApi(server).grafanaNotifiers(grafanaAlertNotifiersMock);
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([
|
||||
setOnCallIntegrations([
|
||||
{ display_name: 'nasa-oncall', value: 'nasa-oncall', integration_url: 'https://nasa.oncall.example.com' },
|
||||
{ display_name: 'apac-oncall', value: 'apac-oncall', integration_url: 'https://apac.oncall.example.com' },
|
||||
]);
|
||||
@ -72,9 +67,7 @@ describe('GrafanaReceiverForm', () => {
|
||||
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<GrafanaReceiverForm alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME} config={amConfig} />, {
|
||||
wrapper: TestProvider,
|
||||
});
|
||||
render(<GrafanaReceiverForm alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME} config={amConfig} />);
|
||||
|
||||
await waitFor(() => expect(ui.loadingIndicator.query()).not.toBeInTheDocument());
|
||||
|
||||
@ -112,10 +105,8 @@ describe('GrafanaReceiverForm', () => {
|
||||
});
|
||||
|
||||
it('Should render URL text input field for OnCall concact point if OnCall plugin uses legacy integration', async () => {
|
||||
mockApi(server).grafanaNotifiers(grafanaAlertNotifiersMock);
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([]);
|
||||
setOnCallFeatures([]);
|
||||
setOnCallIntegrations([]);
|
||||
|
||||
const amConfig = getAmCortexConfig((config) =>
|
||||
config.addReceivers((receiver) =>
|
||||
@ -130,10 +121,7 @@ describe('GrafanaReceiverForm', () => {
|
||||
alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME}
|
||||
config={amConfig}
|
||||
existing={amConfig.alertmanager_config.receivers![0]}
|
||||
/>,
|
||||
{
|
||||
wrapper: TestProvider,
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
await waitFor(() => expect(ui.loadingIndicator.query()).not.toBeInTheDocument());
|
||||
|
@ -1,29 +1,37 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { mockApi, setupMswServer } from 'app/features/alerting/unified/mockApi';
|
||||
import { onCallPluginMetaMock } from 'app/features/alerting/unified/mocks';
|
||||
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
|
||||
import { disablePlugin } from 'app/features/alerting/unified/mocks/server/configure';
|
||||
import {
|
||||
setOnCallFeatures,
|
||||
setOnCallIntegrations,
|
||||
} from 'app/features/alerting/unified/mocks/server/handlers/plugins/configure-plugins';
|
||||
import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';
|
||||
import { option } from 'app/features/alerting/unified/utils/notifier-types';
|
||||
import { clearPluginSettingsCache } from 'app/features/plugins/pluginSettings';
|
||||
|
||||
import { ONCALL_INTEGRATION_V2_FEATURE } from '../../../../api/onCallApi';
|
||||
|
||||
import { ReceiverTypes } from './onCall';
|
||||
import { OnCallIntegrationSetting, OnCallIntegrationType, useOnCallIntegration } from './useOnCallIntegration';
|
||||
|
||||
const server = setupMswServer();
|
||||
setupMswServer();
|
||||
|
||||
describe('useOnCallIntegration', () => {
|
||||
beforeEach(() => {
|
||||
setOnCallIntegrations([
|
||||
{
|
||||
display_name: 'grafana-integration',
|
||||
value: 'ABC123',
|
||||
integration_url: 'https://oncall.com/grafana-integration',
|
||||
},
|
||||
]);
|
||||
});
|
||||
afterEach(() => {
|
||||
clearPluginSettingsCache();
|
||||
});
|
||||
|
||||
describe('When OnCall Alerting V2 integration enabled', () => {
|
||||
it('extendOnCalReceivers should add new settings to the oncall receiver', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([]);
|
||||
|
||||
it('extendOnCallReceivers should add new settings to the oncall receiver', async () => {
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
@ -31,7 +39,7 @@ describe('useOnCallIntegration', () => {
|
||||
const { extendOnCallReceivers } = result.current;
|
||||
|
||||
const receiver = extendOnCallReceivers({
|
||||
name: 'OnCall Conctact point',
|
||||
name: 'OnCall Contact point',
|
||||
grafana_managed_receiver_configs: [
|
||||
{
|
||||
name: 'Oncall-integration',
|
||||
@ -54,17 +62,6 @@ describe('useOnCallIntegration', () => {
|
||||
});
|
||||
|
||||
it('createOnCallIntegrations should provide integration name and url validators', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([
|
||||
{
|
||||
display_name: 'grafana-integration',
|
||||
value: 'ABC123',
|
||||
integration_url: 'https://oncall.com/grafana-integration',
|
||||
},
|
||||
]);
|
||||
mockApi(server).oncall.validateIntegrationName(['grafana-integration', 'alertmanager-integration']);
|
||||
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
@ -86,16 +83,6 @@ describe('useOnCallIntegration', () => {
|
||||
});
|
||||
|
||||
it('extendOnCallNotifierFeatures should add integration type and name options and swap url to a select option', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([ONCALL_INTEGRATION_V2_FEATURE]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([
|
||||
{
|
||||
display_name: 'grafana-integration',
|
||||
value: 'ABC123',
|
||||
integration_url: 'https://oncall.com/grafana-integration',
|
||||
},
|
||||
]);
|
||||
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
@ -127,11 +114,12 @@ describe('useOnCallIntegration', () => {
|
||||
});
|
||||
|
||||
describe('When OnCall Alerting V2 integration disabled', () => {
|
||||
it('extendOnCalReceivers should not add new settings to the oncall receiver', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([]);
|
||||
beforeEach(() => {
|
||||
setOnCallFeatures([]);
|
||||
setOnCallIntegrations([]);
|
||||
});
|
||||
|
||||
it('extendOnCalReceivers should not add new settings to the oncall receiver', async () => {
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
@ -159,10 +147,6 @@ describe('useOnCallIntegration', () => {
|
||||
});
|
||||
|
||||
it('extendConCallNotifierFeatures should not extend notifier', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: true });
|
||||
mockApi(server).oncall.features([]);
|
||||
mockApi(server).oncall.getOnCallIntegrations([]);
|
||||
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
@ -183,9 +167,11 @@ describe('useOnCallIntegration', () => {
|
||||
});
|
||||
|
||||
describe('When OnCall plugin disabled', () => {
|
||||
it('extendOnCalReceivers should not add new settings to the oncall receiver', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: false });
|
||||
beforeEach(() => {
|
||||
disablePlugin(SupportedPlugin.OnCall);
|
||||
});
|
||||
|
||||
it('extendOnCalReceivers should not add new settings to the oncall receiver', async () => {
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
@ -213,8 +199,6 @@ describe('useOnCallIntegration', () => {
|
||||
});
|
||||
|
||||
it('extendConCallNotifierFeatures should not extend notifier', async () => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...onCallPluginMetaMock, enabled: false });
|
||||
|
||||
const { result } = renderHook(() => useOnCallIntegration(), { wrapper: TestProvider });
|
||||
|
||||
await waitFor(() => expect(result.current.isLoadingOnCallIntegration).toBe(false));
|
||||
|
@ -6,8 +6,8 @@ import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { clearPluginSettingsCache } from 'app/features/plugins/pluginSettings';
|
||||
|
||||
import { mockAlertRuleApi, mockApi, setupMswServer } from '../../../mockApi';
|
||||
import { getGrafanaRule, labelsPluginMetaMock } from '../../../mocks';
|
||||
import { mockAlertRuleApi, setupMswServer } from '../../../mockApi';
|
||||
import { getGrafanaRule } from '../../../mocks';
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
|
||||
|
||||
import LabelsField, { LabelsWithSuggestions } from './LabelsField';
|
||||
@ -70,7 +70,6 @@ describe('LabelsField with suggestions', () => {
|
||||
clearPluginSettingsCache();
|
||||
});
|
||||
beforeEach(() => {
|
||||
mockApi(server).plugins.getPluginSettings({ ...labelsPluginMetaMock, enabled: false });
|
||||
mockAlertRuleApi(server).rulerRules(GRAFANA_RULES_SOURCE_NAME, {
|
||||
[grafanaRule.namespace.name]: [{ name: grafanaRule.group.name, interval: '1m', rules: [grafanaRule.rulerRule!] }],
|
||||
});
|
||||
|
@ -2,10 +2,10 @@ import { render, userEvent, screen } from 'test/test-utils';
|
||||
import { byRole } from 'testing-library-selector';
|
||||
|
||||
import { setPluginExtensionsHook } from '@grafana/runtime';
|
||||
import { mockApi, setupMswServer } from 'app/features/alerting/unified/mockApi';
|
||||
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
|
||||
|
||||
import { AlertRuleAction, useAlertRuleAbility } from '../../hooks/useAbilities';
|
||||
import { getCloudRule, getGrafanaRule, getMockPluginMeta } from '../../mocks';
|
||||
import { getCloudRule, getGrafanaRule } from '../../mocks';
|
||||
|
||||
import { RulesTable } from './RulesTable';
|
||||
|
||||
@ -32,15 +32,9 @@ const ui = {
|
||||
};
|
||||
|
||||
const user = userEvent.setup();
|
||||
const server = setupMswServer();
|
||||
setupMswServer();
|
||||
|
||||
describe('RulesTable RBAC', () => {
|
||||
beforeEach(() => {
|
||||
mockApi(server).plugins.getPluginSettings({
|
||||
...getMockPluginMeta('grafana-incident-app', 'Grafana Incident'),
|
||||
});
|
||||
});
|
||||
|
||||
describe('Grafana rules action buttons', () => {
|
||||
const grafanaRule = getGrafanaRule({ name: 'Grafana' });
|
||||
|
||||
|
@ -14,7 +14,6 @@ import AlertmanagerConfig from './AlertmanagerConfig';
|
||||
import {
|
||||
EXTERNAL_VANILLA_ALERTMANAGER_UID,
|
||||
PROVISIONED_MIMIR_ALERTMANAGER_UID,
|
||||
setupGrafanaManagedServer,
|
||||
setupVanillaAlertmanagerServer,
|
||||
} from './__mocks__/server';
|
||||
|
||||
@ -43,10 +42,9 @@ const ui = {
|
||||
};
|
||||
|
||||
describe('Alerting Settings', () => {
|
||||
const server = setupMswServer();
|
||||
setupMswServer();
|
||||
|
||||
beforeEach(() => {
|
||||
setupGrafanaManagedServer(server);
|
||||
grantUserPermissions([AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingInstanceRead]);
|
||||
});
|
||||
|
||||
@ -54,7 +52,7 @@ describe('Alerting Settings', () => {
|
||||
const onReset = jest.fn();
|
||||
renderConfiguration('grafana', { onReset });
|
||||
|
||||
await userEvent.click(await ui.resetButton.get());
|
||||
await userEvent.click(await ui.resetButton.find());
|
||||
|
||||
await waitFor(() => {
|
||||
expect(ui.resetConfirmButton.query()).toBeInTheDocument();
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { setupServer, SetupServer } from 'msw/node';
|
||||
|
||||
import { DataSourceInstanceSettings, PluginMeta } from '@grafana/data';
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { setBackendSrv } from '@grafana/runtime';
|
||||
import { AlertGroupUpdated } from 'app/features/alerting/unified/api/alertRuleApi';
|
||||
import allHandlers from 'app/features/alerting/unified/mocks/server/all-handlers';
|
||||
import { DashboardDTO, FolderDTO, NotifierDTO, OrgUser } from 'app/types';
|
||||
import { DashboardDTO, FolderDTO, OrgUser } from 'app/types';
|
||||
import {
|
||||
PromBuildInfoResponse,
|
||||
PromRulesResponse,
|
||||
@ -27,8 +27,6 @@ import {
|
||||
} from '../../../plugins/datasource/alertmanager/types';
|
||||
import { DashboardSearchItem } from '../../search/types';
|
||||
|
||||
import { OnCallIntegrationDTO } from './api/onCallApi';
|
||||
|
||||
type Configurator<T> = (builder: T) => T;
|
||||
|
||||
export class AlertmanagerConfigBuilder {
|
||||
@ -173,47 +171,9 @@ export function mockApi(server: SetupServer) {
|
||||
);
|
||||
},
|
||||
|
||||
grafanaNotifiers: (response: NotifierDTO[]) => {
|
||||
server.use(http.get(`api/alert-notifiers`, () => HttpResponse.json(response)));
|
||||
},
|
||||
|
||||
plugins: {
|
||||
getPluginSettings: (response: PluginMeta) => {
|
||||
server.use(http.get(`api/plugins/${response.id}/settings`, () => HttpResponse.json(response)));
|
||||
},
|
||||
},
|
||||
getContactPointsList: (response: GrafanaManagedContactPoint[]) => {
|
||||
server.use(http.get(`/api/v1/notifications/receivers`, () => HttpResponse.json(response)));
|
||||
},
|
||||
|
||||
oncall: {
|
||||
getOnCallIntegrations: (response: OnCallIntegrationDTO[]) => {
|
||||
server.use(
|
||||
http.get(`api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels`, () =>
|
||||
HttpResponse.json<OnCallIntegrationDTO[]>(response)
|
||||
)
|
||||
);
|
||||
},
|
||||
features: (response: string[]) => {
|
||||
server.use(
|
||||
http.get(`api/plugin-proxy/grafana-oncall-app/api/internal/v1/features`, () => HttpResponse.json(response))
|
||||
);
|
||||
},
|
||||
validateIntegrationName: (invalidNames: string[]) => {
|
||||
server.use(
|
||||
http.get(
|
||||
`api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels/validate_name`,
|
||||
({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const isValid = !invalidNames.includes(url.searchParams.get('verbal_name') ?? '');
|
||||
return HttpResponse.json(isValid, {
|
||||
status: isValid ? 200 : 409,
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,6 @@ import {
|
||||
DataSourceRef,
|
||||
PluginExtensionLink,
|
||||
PluginExtensionTypes,
|
||||
PluginMeta,
|
||||
PluginType,
|
||||
ScopedVars,
|
||||
TestDataSourceResponse,
|
||||
} from '@grafana/data';
|
||||
@ -796,28 +794,3 @@ export function mockDashboardDto(
|
||||
meta: { ...meta },
|
||||
};
|
||||
}
|
||||
|
||||
export const getMockPluginMeta: (id: string, name: string) => PluginMeta = (id, name) => {
|
||||
return {
|
||||
name,
|
||||
id,
|
||||
type: PluginType.app,
|
||||
module: `plugins/${id}/module`,
|
||||
baseUrl: `public/plugins/${id}`,
|
||||
info: {
|
||||
author: { name: 'Grafana Labs' },
|
||||
description: name,
|
||||
updated: '',
|
||||
version: '',
|
||||
links: [],
|
||||
logos: {
|
||||
small: '',
|
||||
large: '',
|
||||
},
|
||||
screenshots: [],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const labelsPluginMetaMock = getMockPluginMeta('grafana-labels-app', 'Grafana IRM Labels');
|
||||
export const onCallPluginMetaMock = getMockPluginMeta('grafana-oncall-app', 'Grafana OnCall');
|
||||
|
@ -1,378 +0,0 @@
|
||||
import { NotifierDTO } from 'app/types';
|
||||
|
||||
export const grafanaNotifiersMock: NotifierDTO[] = [
|
||||
{
|
||||
type: 'teams',
|
||||
name: 'Microsoft Teams',
|
||||
heading: 'Teams settings',
|
||||
description: 'Sends notifications using Incoming Webhook connector to Microsoft Teams',
|
||||
info: '',
|
||||
options: [
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'URL',
|
||||
description: '',
|
||||
placeholder: 'Teams incoming webhook url',
|
||||
propertyName: 'url',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'hipchat',
|
||||
name: 'HipChat',
|
||||
heading: 'HipChat settings',
|
||||
description: 'Sends notifications uto a HipChat Room',
|
||||
info: '',
|
||||
options: [
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Hip Chat Url',
|
||||
description: '',
|
||||
placeholder: 'HipChat URL (ex https://grafana.hipchat.com)',
|
||||
propertyName: 'url',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'API Key',
|
||||
description: '',
|
||||
placeholder: 'HipChat API Key',
|
||||
propertyName: 'apiKey',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Room ID',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'roomid',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'webhook',
|
||||
name: 'webhook',
|
||||
heading: 'Webhook settings',
|
||||
description: 'Sends HTTP POST request to a URL',
|
||||
info: '',
|
||||
options: [
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Url',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'url',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'select',
|
||||
inputType: '',
|
||||
label: 'Http Method',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'httpMethod',
|
||||
selectOptions: [
|
||||
{ value: 'POST', label: 'POST' },
|
||||
{ value: 'PUT', label: 'PUT' },
|
||||
],
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Username',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'username',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'password',
|
||||
label: 'Password',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'password',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: true,
|
||||
dependsOn: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'prometheus-alertmanager',
|
||||
name: 'Prometheus Alertmanager',
|
||||
heading: 'Alertmanager settings',
|
||||
description: 'Sends alert to Prometheus Alertmanager',
|
||||
info: '',
|
||||
options: [
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Url',
|
||||
description:
|
||||
'As specified in Alertmanager documentation, do not specify a load balancer here. Enter all your Alertmanager URLs comma-separated.',
|
||||
placeholder: 'http://localhost:9093',
|
||||
propertyName: 'url',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Basic Auth User',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'basicAuthUser',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'password',
|
||||
label: 'Basic Auth Password',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
propertyName: 'basicAuthPassword',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: true,
|
||||
dependsOn: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'email',
|
||||
name: 'Email',
|
||||
heading: 'Email settings',
|
||||
description: 'Sends notifications using Grafana server configured SMTP settings',
|
||||
info: '',
|
||||
options: [
|
||||
{
|
||||
element: 'checkbox',
|
||||
inputType: '',
|
||||
label: 'Single email',
|
||||
description: 'Send a single email to all recipients',
|
||||
placeholder: '',
|
||||
propertyName: 'singleEmail',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'textarea',
|
||||
inputType: '',
|
||||
label: 'Addresses',
|
||||
description: 'You can enter multiple email addresses using a ";" separator',
|
||||
placeholder: '',
|
||||
propertyName: 'addresses',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'slack',
|
||||
name: 'Slack',
|
||||
heading: 'Slack settings',
|
||||
description: 'Sends notifications to Slack',
|
||||
info: '',
|
||||
options: [
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Recipient',
|
||||
description:
|
||||
'Specify channel or user, use #channel-name, @username (has to be all lowercase, no whitespace), or user/channel Slack ID - required unless you provide a webhook',
|
||||
placeholder: '',
|
||||
propertyName: 'recipient',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: 'secureSettings.url',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Token',
|
||||
description: 'Provide a Slack API token (starts with "xoxb") - required unless you provide a webhook',
|
||||
placeholder: '',
|
||||
propertyName: 'token',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: true,
|
||||
dependsOn: 'secureSettings.url',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Username',
|
||||
description: "Set the username for the bot's message",
|
||||
placeholder: '',
|
||||
propertyName: 'username',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Icon emoji',
|
||||
description: "Provide an emoji to use as the icon for the bot's message. Overrides the icon URL.",
|
||||
placeholder: '',
|
||||
propertyName: 'iconEmoji',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Icon URL',
|
||||
description: "Provide a URL to an image to use as the icon for the bot's message",
|
||||
placeholder: '',
|
||||
propertyName: 'iconUrl',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Mention Users',
|
||||
description:
|
||||
"Mention one or more users (comma separated) when notifying in a channel, by ID (you can copy this from the user's Slack profile)",
|
||||
placeholder: '',
|
||||
propertyName: 'mentionUsers',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Mention Groups',
|
||||
description:
|
||||
"Mention one or more groups (comma separated) when notifying in a channel (you can copy this from the group's Slack profile URL)",
|
||||
placeholder: '',
|
||||
propertyName: 'mentionGroups',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'select',
|
||||
inputType: '',
|
||||
label: 'Mention Channel',
|
||||
description: 'Mention whole channel or just active members when notifying',
|
||||
placeholder: '',
|
||||
propertyName: 'mentionChannel',
|
||||
selectOptions: [
|
||||
{ value: '', label: 'Disabled' },
|
||||
{ value: 'here', label: 'Every active channel member' },
|
||||
{ value: 'channel', label: 'Every channel member' },
|
||||
],
|
||||
showWhen: { field: '', is: '' },
|
||||
required: false,
|
||||
validationRule: '',
|
||||
secure: false,
|
||||
dependsOn: '',
|
||||
},
|
||||
{
|
||||
element: 'input',
|
||||
inputType: 'text',
|
||||
label: 'Webhook URL',
|
||||
description:
|
||||
"Optionally provide a Slack incoming webhook URL for sending messages, in this case the token isn't necessary",
|
||||
placeholder: 'Slack incoming webhook URL',
|
||||
propertyName: 'url',
|
||||
selectOptions: null,
|
||||
showWhen: { field: '', is: '' },
|
||||
required: true,
|
||||
validationRule: '',
|
||||
secure: true,
|
||||
dependsOn: 'token',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
@ -2,6 +2,7 @@
|
||||
* Contains all handlers that are required for test rendering of components within Alerting
|
||||
*/
|
||||
|
||||
import alertNotifierHandlers from 'app/features/alerting/unified/mocks/server/handlers/alertNotifiers';
|
||||
import alertmanagerHandlers from 'app/features/alerting/unified/mocks/server/handlers/alertmanagers';
|
||||
import datasourcesHandlers from 'app/features/alerting/unified/mocks/server/handlers/datasources';
|
||||
import evalHandlers from 'app/features/alerting/unified/mocks/server/handlers/eval';
|
||||
@ -9,12 +10,13 @@ import folderHandlers from 'app/features/alerting/unified/mocks/server/handlers/
|
||||
import grafanaRulerHandlers from 'app/features/alerting/unified/mocks/server/handlers/grafanaRuler';
|
||||
import mimirRulerHandlers from 'app/features/alerting/unified/mocks/server/handlers/mimirRuler';
|
||||
import pluginsHandlers from 'app/features/alerting/unified/mocks/server/handlers/plugins';
|
||||
import allPluginHandlers from 'app/features/alerting/unified/mocks/server/handlers/plugins/all-plugin-handlers';
|
||||
import silenceHandlers from 'app/features/alerting/unified/mocks/server/handlers/silences';
|
||||
|
||||
/**
|
||||
* Array of all mock handlers that are required across Alerting tests
|
||||
*/
|
||||
const allHandlers = [
|
||||
...alertNotifierHandlers,
|
||||
...grafanaRulerHandlers,
|
||||
...mimirRulerHandlers,
|
||||
...alertmanagerHandlers,
|
||||
@ -23,6 +25,8 @@ const allHandlers = [
|
||||
...folderHandlers,
|
||||
...pluginsHandlers,
|
||||
...silenceHandlers,
|
||||
|
||||
...allPluginHandlers,
|
||||
];
|
||||
|
||||
export default allHandlers;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { HttpResponse } from 'msw';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import server, { mockFeatureDiscoveryApi } from 'app/features/alerting/unified/mockApi';
|
||||
import { mockDataSource, mockFolder } from 'app/features/alerting/unified/mocks';
|
||||
import {
|
||||
@ -7,6 +8,11 @@ import {
|
||||
grafanaAlertingConfigurationStatusHandler,
|
||||
} from 'app/features/alerting/unified/mocks/server/handlers/alertmanagers';
|
||||
import { getFolderHandler } from 'app/features/alerting/unified/mocks/server/handlers/folders';
|
||||
import {
|
||||
getDisabledPluginHandler,
|
||||
getPluginMissingHandler,
|
||||
} from 'app/features/alerting/unified/mocks/server/handlers/plugins';
|
||||
import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';
|
||||
import { AlertManagerCortexConfig, AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
|
||||
import { FolderDTO } from 'app/types';
|
||||
|
||||
@ -87,3 +93,14 @@ export function mimirDataSource() {
|
||||
|
||||
return { dataSource };
|
||||
}
|
||||
|
||||
/** Make a given plugin ID respond with a 404, as if it isn't installed at all */
|
||||
export const removePlugin = (pluginId: string) => {
|
||||
delete config.apps[pluginId];
|
||||
server.use(getPluginMissingHandler(pluginId));
|
||||
};
|
||||
|
||||
/** Make a plugin respond with `enabled: false`, as if its installed but disabled */
|
||||
export const disablePlugin = (pluginId: SupportedPlugin) => {
|
||||
server.use(getDisabledPluginHandler(pluginId));
|
||||
};
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { HttpResponse, http } from 'msw';
|
||||
|
||||
import { grafanaAlertNotifiersMock } from 'app/features/alerting/unified/mockGrafanaNotifiers';
|
||||
|
||||
const getAlertNotifiers = () =>
|
||||
http.get('/api/alert-notifiers', () => {
|
||||
return HttpResponse.json(grafanaAlertNotifiersMock);
|
||||
});
|
||||
|
||||
const handlers = [getAlertNotifiers()];
|
||||
export default handlers;
|
@ -1,6 +1,7 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import alertmanagerConfigMock from 'app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json';
|
||||
import receiversMock from 'app/features/alerting/unified/components/contact-points/__mocks__/receivers.mock.json';
|
||||
import { MOCK_SILENCE_ID_EXISTING, mockAlertmanagerAlert } from 'app/features/alerting/unified/mocks';
|
||||
import { defaultGrafanaAlertingConfigurationStatusResponse } from 'app/features/alerting/unified/mocks/alertmanagerApi';
|
||||
import { MOCK_DATASOURCE_UID_BROKEN_ALERTMANAGER } from 'app/features/alerting/unified/mocks/server/handlers/datasources';
|
||||
@ -41,11 +42,15 @@ const getGrafanaAlertmanagerTemplatePreview = () =>
|
||||
HttpResponse.json({})
|
||||
);
|
||||
|
||||
const getGrafanaReceiversHandler = () =>
|
||||
http.get('/api/alertmanager/grafana/config/api/v1/receivers', () => HttpResponse.json(receiversMock));
|
||||
|
||||
const handlers = [
|
||||
alertmanagerAlertsListHandler(),
|
||||
grafanaAlertingConfigurationStatusHandler(),
|
||||
getGrafanaAlertmanagerConfigHandler(),
|
||||
updateGrafanaAlertmanagerConfigHandler(),
|
||||
getGrafanaAlertmanagerTemplatePreview(),
|
||||
getGrafanaReceiversHandler(),
|
||||
];
|
||||
export default handlers;
|
||||
|
@ -4,6 +4,8 @@ import { PluginMeta } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { plugins } from 'app/features/alerting/unified/testSetup/plugins';
|
||||
|
||||
const PLUGIN_NOT_FOUND_RESPONSE = { message: 'Plugin not found, no installed plugin with that id' };
|
||||
|
||||
/**
|
||||
* Returns a handler that maps from plugin ID to PluginMeta, and additionally sets up necessary
|
||||
* config side effects that are expected to come along with this API behaviour
|
||||
@ -23,9 +25,23 @@ export const getPluginsHandler = (pluginsArray: PluginMeta[] = plugins) => {
|
||||
const matchingPlugin = pluginsArray.find((plugin) => plugin.id === pluginId);
|
||||
return matchingPlugin
|
||||
? HttpResponse.json<PluginMeta>(matchingPlugin)
|
||||
: HttpResponse.json({ message: 'Plugin not found, no installed plugin with that id' }, { status: 404 });
|
||||
: HttpResponse.json(PLUGIN_NOT_FOUND_RESPONSE, { status: 404 });
|
||||
});
|
||||
};
|
||||
|
||||
export const getDisabledPluginHandler = (pluginIdToDisable: string) => {
|
||||
return http.get<{ pluginId: string }>(`/api/plugins/${pluginIdToDisable}/settings`, ({ params: { pluginId } }) => {
|
||||
const matchingPlugin = plugins.find((plugin) => plugin.id === pluginId);
|
||||
return matchingPlugin
|
||||
? HttpResponse.json<PluginMeta>({ ...matchingPlugin, enabled: false })
|
||||
: HttpResponse.json(PLUGIN_NOT_FOUND_RESPONSE, { status: 404 });
|
||||
});
|
||||
};
|
||||
|
||||
export const getPluginMissingHandler = (pluginIdToRemove: string) =>
|
||||
http.get(`/api/plugins/${pluginIdToRemove}/settings`, () =>
|
||||
HttpResponse.json(PLUGIN_NOT_FOUND_RESPONSE, { status: 404 })
|
||||
);
|
||||
|
||||
const handlers = [getPluginsHandler()];
|
||||
export default handlers;
|
||||
|
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Re-exports all plugin proxy handlers
|
||||
*/
|
||||
import onCallHandlers from './grafana-oncall';
|
||||
|
||||
/**
|
||||
* Array of all plugin handlers that are required across Alerting tests
|
||||
*/
|
||||
const allPluginProxyHandlers = [...onCallHandlers];
|
||||
|
||||
export default allPluginProxyHandlers;
|
@ -0,0 +1,14 @@
|
||||
import { OnCallIntegrationDTO } from 'app/features/alerting/unified/api/onCallApi';
|
||||
import server from 'app/features/alerting/unified/mockApi';
|
||||
import {
|
||||
getOnCallIntegrationsHandler,
|
||||
getFeaturesHandler,
|
||||
} from 'app/features/alerting/unified/mocks/server/handlers/plugins/grafana-oncall';
|
||||
|
||||
export const setOnCallFeatures = (features: string[]) => {
|
||||
server.use(getFeaturesHandler(features));
|
||||
};
|
||||
|
||||
export const setOnCallIntegrations = (integrations: OnCallIntegrationDTO[]) => {
|
||||
server.use(getOnCallIntegrationsHandler(integrations));
|
||||
};
|
@ -0,0 +1,30 @@
|
||||
import { HttpResponse, http } from 'msw';
|
||||
|
||||
import { ONCALL_INTEGRATION_V2_FEATURE, OnCallIntegrationDTO } from 'app/features/alerting/unified/api/onCallApi';
|
||||
|
||||
const BASE_URL = `/api/plugin-proxy/grafana-oncall-app`;
|
||||
|
||||
export const getOnCallIntegrationsHandler = (receiveChannels: OnCallIntegrationDTO[] = []) =>
|
||||
http.get(`${BASE_URL}/api/internal/v1/alert_receive_channels`, () => {
|
||||
return HttpResponse.json(receiveChannels);
|
||||
});
|
||||
|
||||
export const getFeaturesHandler = (features = [ONCALL_INTEGRATION_V2_FEATURE]) =>
|
||||
http.get(`${BASE_URL}/api/internal/v1/features`, () => {
|
||||
return HttpResponse.json(features);
|
||||
});
|
||||
|
||||
const validateIntegrationNameHandler = (
|
||||
invalidNames: string[] = ['grafana-integration', 'alertmanager-integration']
|
||||
) => {
|
||||
return http.get(`${BASE_URL}/api/internal/v1/alert_receive_channels/validate_name`, ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const isValid = !invalidNames.includes(url.searchParams.get('verbal_name') ?? '');
|
||||
return HttpResponse.json(isValid, {
|
||||
status: isValid ? 200 : 409,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handlers = [getOnCallIntegrationsHandler(), getFeaturesHandler(), validateIntegrationNameHandler()];
|
||||
export default handlers;
|
@ -1,5 +1,6 @@
|
||||
import { PluginMeta, PluginType } from '@grafana/data';
|
||||
import { setPluginExtensionsHook } from '@grafana/runtime';
|
||||
import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';
|
||||
|
||||
import { mockPluginLinkExtension } from '../mocks';
|
||||
|
||||
@ -18,7 +19,7 @@ export function setupPluginsExtensionsHook() {
|
||||
|
||||
export const plugins: PluginMeta[] = [
|
||||
{
|
||||
id: 'grafana-slo-app',
|
||||
id: SupportedPlugin.Slo,
|
||||
name: 'SLO dashboard',
|
||||
type: PluginType.app,
|
||||
enabled: true,
|
||||
@ -41,7 +42,7 @@ export const plugins: PluginMeta[] = [
|
||||
baseUrl: 'public/plugins/grafana-slo-app',
|
||||
},
|
||||
{
|
||||
id: 'grafana-incident-app',
|
||||
id: SupportedPlugin.Incident,
|
||||
name: 'Incident management',
|
||||
type: PluginType.app,
|
||||
enabled: true,
|
||||
@ -87,7 +88,7 @@ export const plugins: PluginMeta[] = [
|
||||
baseUrl: 'public/plugins/grafana-asserts-app',
|
||||
},
|
||||
{
|
||||
id: 'grafana-oncall-app',
|
||||
id: SupportedPlugin.OnCall,
|
||||
name: 'OnCall',
|
||||
type: PluginType.app,
|
||||
enabled: true,
|
||||
|
Loading…
Reference in New Issue
Block a user