diff --git a/public/app/features/alerting/routes.tsx b/public/app/features/alerting/routes.tsx
index 8430a85d0b0..ee8fe2bbb17 100644
--- a/public/app/features/alerting/routes.tsx
+++ b/public/app/features/alerting/routes.tsx
@@ -3,10 +3,7 @@ import { config } from 'app/core/config';
import { GrafanaRouteComponent, RouteDescriptor } from 'app/core/navigation/types';
import { AccessControlAction } from 'app/types';
-import {
- PERMISSIONS_CONTACT_POINTS,
- PERMISSIONS_CONTACT_POINTS_MODIFY,
-} from './unified/components/contact-points/permissions';
+import { PERMISSIONS_CONTACT_POINTS } from './unified/components/contact-points/permissions';
import { evaluateAccess } from './unified/utils/access-control';
export function getAlertingRoutes(cfg = config): RouteDescriptor[] {
@@ -104,7 +101,43 @@ export function getAlertingRoutes(cfg = config): RouteDescriptor[] {
...PERMISSIONS_CONTACT_POINTS,
]),
component: importAlertingComponent(
- () => import(/* webpackChunkName: "NotificationsListPage" */ 'app/features/alerting/unified/Receivers')
+ () =>
+ import(
+ /* webpackChunkName: "ContactPoints" */ 'app/features/alerting/unified/components/contact-points/ContactPoints'
+ )
+ ),
+ },
+ {
+ path: '/alerting/notifications/receivers/new',
+ roles: evaluateAccess([
+ AccessControlAction.AlertingNotificationsRead,
+ AccessControlAction.AlertingNotificationsExternalRead,
+ ...PERMISSIONS_CONTACT_POINTS,
+ ]),
+ component: importAlertingComponent(
+ () =>
+ import(
+ /* webpackChunkName: "NewReceiverView" */ 'app/features/alerting/unified/components/receivers/NewReceiverView'
+ )
+ ),
+ },
+ {
+ path: '/alerting/notifications/receivers/:name/edit',
+ roles: evaluateAccess([
+ AccessControlAction.AlertingNotificationsWrite,
+ AccessControlAction.AlertingNotificationsExternalWrite,
+ AccessControlAction.AlertingNotificationsRead,
+ AccessControlAction.AlertingNotificationsExternalRead,
+ // We check any contact point permission here because a user without edit permissions
+ // still has to be able to visit the "edit" page, because we don't have a separate view for edit vs view
+ // (we just disable the form instead)
+ ...PERMISSIONS_CONTACT_POINTS,
+ ]),
+ component: importAlertingComponent(
+ () =>
+ import(
+ /* webpackChunkName: "EditContactPoint" */ 'app/features/alerting/unified/components/contact-points/EditContactPoint'
+ )
),
},
{
@@ -118,60 +151,16 @@ export function getAlertingRoutes(cfg = config): RouteDescriptor[] {
),
},
{
- path: '/alerting/notifications/:type/new',
- roles: evaluateAccess([
- AccessControlAction.AlertingNotificationsWrite,
- AccessControlAction.AlertingNotificationsExternalWrite,
- ...PERMISSIONS_CONTACT_POINTS_MODIFY,
- ]),
- component: importAlertingComponent(
- () => import(/* webpackChunkName: "NotificationsListPage" */ 'app/features/alerting/unified/Receivers')
- ),
- },
- {
- path: '/alerting/notifications/receivers/:id/edit',
- roles: evaluateAccess([
- AccessControlAction.AlertingNotificationsWrite,
- AccessControlAction.AlertingNotificationsExternalWrite,
- AccessControlAction.AlertingNotificationsRead,
- AccessControlAction.AlertingNotificationsExternalRead,
- // We check any contact point permission here because a user without edit permissions
- // still has to be able to visit the "edit" page, because we don't have a separate view for edit vs view
- // (we just disable the form instead)
- ...PERMISSIONS_CONTACT_POINTS,
- ]),
- component: importAlertingComponent(
- () => import(/* webpackChunkName: "NotificationsListPage" */ 'app/features/alerting/unified/Receivers')
- ),
- },
- {
- path: '/alerting/notifications/:type/:id/edit',
+ path: '/alerting/notifications/global-config',
roles: evaluateAccess([
AccessControlAction.AlertingNotificationsWrite,
AccessControlAction.AlertingNotificationsExternalWrite,
]),
component: importAlertingComponent(
- () => import(/* webpackChunkName: "NotificationsListPage" */ 'app/features/alerting/unified/Receivers')
- ),
- },
- {
- path: '/alerting/notifications/:type/:id/duplicate',
- roles: evaluateAccess([
- AccessControlAction.AlertingNotificationsWrite,
- AccessControlAction.AlertingNotificationsExternalWrite,
- ]),
- component: importAlertingComponent(
- () => import(/* webpackChunkName: "NotificationsListPage" */ 'app/features/alerting/unified/Receivers')
- ),
- },
- {
- path: '/alerting/notifications/:type',
- roles: evaluateAccess([
- AccessControlAction.AlertingNotificationsWrite,
- AccessControlAction.AlertingNotificationsExternalWrite,
- ]),
- component: importAlertingComponent(
- () => import(/* webpackChunkName: "NotificationsListPage" */ 'app/features/alerting/unified/Receivers')
+ () =>
+ import(
+ /* webpackChunkName: "GlobalConfig" */ 'app/features/alerting/unified/components/contact-points/components/GlobalConfig'
+ )
),
},
{
diff --git a/public/app/features/alerting/unified/Receivers.test.tsx b/public/app/features/alerting/unified/Receivers.test.tsx
index c7619e39f18..6a4d4227e6f 100644
--- a/public/app/features/alerting/unified/Receivers.test.tsx
+++ b/public/app/features/alerting/unified/Receivers.test.tsx
@@ -1,3 +1,4 @@
+import { Route, Routes } from 'react-router-dom-v5-compat';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { render, screen, waitFor, userEvent } from 'test/test-utils';
@@ -11,9 +12,10 @@ import { grantUserPermissions } from 'app/features/alerting/unified/mocks';
import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources';
import { AccessControlAction } from 'app/types';
-import ContactPoints from './Receivers';
-
import 'core-js/stable/structured-clone';
+import ContactPoints from './components/contact-points/ContactPoints';
+import EditContactPoint from './components/contact-points/EditContactPoint';
+import NewReceiverView from './components/receivers/NewReceiverView';
const server = setupMswServer();
@@ -28,6 +30,21 @@ const saveContactPoint = async () => {
return user.click(await screen.findByRole('button', { name: /save contact point/i }));
};
+const setup = (location: string) => {
+ return render(
+
+ } />
+ } />
+ } />
+ ,
+ {
+ historyOptions: {
+ initialEntries: [location],
+ },
+ }
+ );
+};
+
beforeEach(() => {
grantUserPermissions([
AccessControlAction.AlertingNotificationsRead,
@@ -41,18 +58,7 @@ beforeEach(() => {
});
it('can save a contact point with a select dropdown', async () => {
- const user = userEvent.setup();
-
- render(, {
- historyOptions: {
- initialEntries: [
- {
- pathname: `/alerting/notifications/receivers/new`,
- search: `?alertmanager=${PROVISIONED_MIMIR_ALERTMANAGER_UID}`,
- },
- ],
- },
- });
+ const { user } = setup(`/alerting/notifications/receivers/new?alertmanager=${PROVISIONED_MIMIR_ALERTMANAGER_UID}`);
// Fill out contact point name
const contactPointName = await screen.findByPlaceholderText(/name/i);
@@ -75,16 +81,7 @@ it('can save a contact point with a select dropdown', async () => {
});
it('can save existing Telegram contact point', async () => {
- render(, {
- historyOptions: {
- initialEntries: [
- {
- pathname: `/alerting/notifications/receivers/Telegram/edit`,
- search: `?alertmanager=${PROVISIONED_MIMIR_ALERTMANAGER_UID}`,
- },
- ],
- },
- });
+ setup(`/alerting/notifications/receivers/Telegram/edit?alertmanager=${PROVISIONED_MIMIR_ALERTMANAGER_UID}`);
// Here, we're implicitly testing that our parsing of an existing Telegram integration works correctly
// Our mock server will reject a request if we've sent the Chat ID as `0`,
diff --git a/public/app/features/alerting/unified/Receivers.tsx b/public/app/features/alerting/unified/Receivers.tsx
deleted file mode 100644
index 7b6e3b87052..00000000000
--- a/public/app/features/alerting/unified/Receivers.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Route, Switch } from 'react-router-dom';
-
-import { withErrorBoundary } from '@grafana/ui';
-import { SafeDynamicImport } from 'app/core/components/DynamicImports/SafeDynamicImport';
-
-import { AlertmanagerPageWrapper } from './components/AlertingPageWrapper';
-
-const ContactPointsV2 = SafeDynamicImport(() => import('./components/contact-points/ContactPoints'));
-const EditContactPoint = SafeDynamicImport(() => import('./components/contact-points/EditContactPoint'));
-const NewReceiverView = SafeDynamicImport(() => import('./components/receivers/NewReceiverView'));
-const GlobalConfig = SafeDynamicImport(() => import('./components/contact-points/components/GlobalConfig'));
-
-const ContactPoints = (): JSX.Element => (
-
-
-
-
-
-
-
-
-);
-
-export default withErrorBoundary(ContactPoints, { style: 'page' });
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
index cf5417fc4ac..76d8b271183 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
@@ -19,7 +19,7 @@ import { setupDataSources } from '../../testSetup/datasources';
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
import { ContactPoint } from './ContactPoint';
-import ContactPointsPageContents from './ContactPoints';
+import { ContactPointsPageContents } from './ContactPoints';
import setupMimirFlavoredServer, { MIMIR_DATASOURCE_UID } from './__mocks__/mimirFlavoredServer';
import setupVanillaAlertmanagerFlavoredServer, {
VANILLA_ALERTMANAGER_DATASOURCE_UID,
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
index 17c4f58cd9b..7f89081d217 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
@@ -12,6 +12,7 @@ import {
TabContent,
TabsBar,
Text,
+ withErrorBoundary,
} from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { t, Trans } from 'app/core/internationalization';
@@ -24,6 +25,7 @@ import { usePagination } from '../../hooks/usePagination';
import { useURLSearchParams } from '../../hooks/useURLSearchParams';
import { useAlertmanager } from '../../state/AlertmanagerContext';
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
+import { AlertmanagerPageWrapper } from '../AlertingPageWrapper';
import { GrafanaAlertmanagerDeliveryWarning } from '../GrafanaAlertmanagerDeliveryWarning';
import { ContactPoint } from './ContactPoint';
@@ -179,7 +181,7 @@ const useTabQueryParam = () => {
return [param, setParam] as const;
};
-const ContactPointsPageContents = () => {
+export const ContactPointsPageContents = () => {
const { selectedAlertmanager } = useAlertmanager();
const [activeTab, setActiveTab] = useTabQueryParam();
@@ -242,4 +244,12 @@ const ContactPointsList = ({ contactPoints, search, pageSize = DEFAULT_PAGE_SIZE
);
};
-export default ContactPointsPageContents;
+function ContactPointsPage() {
+ return (
+
+
+
+ );
+}
+
+export default withErrorBoundary(ContactPointsPage, { style: 'page' });
diff --git a/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx b/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx
index f85c3eeeef0..96a00fc1d33 100644
--- a/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx
@@ -1,18 +1,18 @@
-import { RouteChildrenProps } from 'react-router-dom';
+import { useParams } from 'react-router-dom-v5-compat';
-import { Alert, LoadingPlaceholder } from '@grafana/ui';
+import { Alert, LoadingPlaceholder, withErrorBoundary } from '@grafana/ui';
import { useGetContactPoint } from 'app/features/alerting/unified/components/contact-points/useContactPoints';
import { stringifyErrorLike } from 'app/features/alerting/unified/utils/misc';
import { useAlertmanager } from '../../state/AlertmanagerContext';
+import { AlertmanagerPageWrapper } from '../AlertingPageWrapper';
import { EditReceiverView } from '../receivers/EditReceiverView';
-type Props = RouteChildrenProps<{ name: string }>;
-
-const EditContactPoint = ({ match }: Props) => {
+const EditContactPoint = () => {
const { selectedAlertmanager } = useAlertmanager();
+ const { name = '' } = useParams();
- const contactPointName = decodeURIComponent(match?.params.name!);
+ const contactPointName = decodeURIComponent(name);
const {
isLoading,
error,
@@ -42,4 +42,12 @@ const EditContactPoint = ({ match }: Props) => {
return ;
};
-export default EditContactPoint;
+function EditContactPointPage() {
+ return (
+
+
+
+ );
+}
+
+export default withErrorBoundary(EditContactPointPage, { style: 'page' });
diff --git a/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx b/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx
index da56a3f5148..e5514b01d66 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx
@@ -1,7 +1,8 @@
-import { Alert } from '@grafana/ui';
+import { Alert, withErrorBoundary } from '@grafana/ui';
import { useAlertmanagerConfig } from '../../../hooks/useAlertmanagerConfig';
import { useAlertmanager } from '../../../state/AlertmanagerContext';
+import { AlertmanagerPageWrapper } from '../../AlertingPageWrapper';
import { GlobalConfigForm } from '../../receivers/GlobalConfigForm';
const NewMessageTemplate = () => {
@@ -27,4 +28,12 @@ const NewMessageTemplate = () => {
return ;
};
-export default NewMessageTemplate;
+function NewMessageTemplatePage() {
+ return (
+
+
+
+ );
+}
+
+export default withErrorBoundary(NewMessageTemplatePage, { style: 'page' });
diff --git a/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx b/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx
index c84a9492d26..4f2a3322da4 100644
--- a/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx
+++ b/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx
@@ -1,6 +1,8 @@
+import { withErrorBoundary } from '@grafana/ui';
import { useAlertmanager } from 'app/features/alerting/unified/state/AlertmanagerContext';
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
+import { AlertmanagerPageWrapper } from '../AlertingPageWrapper';
import { CloudReceiverForm } from './form/CloudReceiverForm';
import { GrafanaReceiverForm } from './form/GrafanaReceiverForm';
@@ -14,4 +16,12 @@ const NewReceiverView = () => {
}
};
-export default NewReceiverView;
+function NewReceiverViewPage() {
+ return (
+
+
+
+ );
+}
+
+export default withErrorBoundary(NewReceiverViewPage, { style: 'page' });