diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index f5152ffe2e..54eac880ec 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -101,7 +101,7 @@ import * as plugins from './plugins';
import { techDocsPage } from './components/techdocs/TechDocsPage';
import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow';
-import { PermissionedRoute } from '@backstage/plugin-permission-react';
+import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
const app = createApp({
@@ -157,10 +157,13 @@ const routes = (
>
{entityPage}
- }
+ element={
+
+
+
+ }
/>
;
-// @public
+// @public @deprecated
export const PermissionedRoute: (
- props: ComponentProps & {
+ _props: ComponentProps & {
errorComponent?: ReactElement | null;
} & (
| {
@@ -62,7 +63,27 @@ export const PermissionedRoute: (
resourceRef: string | undefined;
}
),
-) => JSX.Element;
+) => never;
+
+// @public
+export function RequirePermission(
+ props: RequirePermissionProps,
+): JSX.Element | null;
+
+// @public
+export type RequirePermissionProps = (
+ | {
+ permission: Exclude;
+ resourceRef?: never;
+ }
+ | {
+ permission: ResourcePermission;
+ resourceRef: string | undefined;
+ }
+) & {
+ errorPage?: ReactNode;
+ children: ReactNode;
+};
// @public
export function usePermission(
diff --git a/plugins/permission-react/src/components/PermissionedRoute.tsx b/plugins/permission-react/src/components/PermissionedRoute.tsx
index dd39c5bb4f..4a0046c61a 100644
--- a/plugins/permission-react/src/components/PermissionedRoute.tsx
+++ b/plugins/permission-react/src/components/PermissionedRoute.tsx
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-import React, { ComponentProps, ReactElement } from 'react';
+import { ComponentProps, ReactElement } from 'react';
import { Route } from 'react-router';
-import { useApp } from '@backstage/core-plugin-api';
-import { usePermission } from '../hooks';
import {
- isResourcePermission,
Permission,
ResourcePermission,
} from '@backstage/plugin-permission-common';
@@ -29,9 +26,10 @@ import {
* NotFoundErrorPage (see {@link @backstage/core-app-api#AppComponents}).
*
* @public
+ * @deprecated This component no longer works with the most recent version of `@backstage/core-app-api` and react-router v6, use {@link RequirePermission} instead.
*/
export const PermissionedRoute = (
- props: ComponentProps & {
+ _props: ComponentProps & {
errorComponent?: ReactElement | null;
} & (
| {
@@ -44,24 +42,7 @@ export const PermissionedRoute = (
}
),
) => {
- const { permission, resourceRef, errorComponent, ...otherProps } = props;
-
- const permissionResult = usePermission(
- isResourcePermission(permission)
- ? { permission, resourceRef }
- : { permission },
+ throw new Error(
+ 'PermissionedRoute is no longer supported, switch to using instead: ...}/>',
);
- const app = useApp();
- const { NotFoundErrorPage } = app.getComponents();
-
- let shownElement: ReactElement | null | undefined =
- errorComponent === undefined ? : errorComponent;
-
- if (permissionResult.loading) {
- shownElement = null;
- } else if (permissionResult.allowed) {
- shownElement = props.element;
- }
-
- return ;
};
diff --git a/plugins/permission-react/src/components/PermissionedRoute.test.tsx b/plugins/permission-react/src/components/RequirePermission.test.tsx
similarity index 85%
rename from plugins/permission-react/src/components/PermissionedRoute.test.tsx
rename to plugins/permission-react/src/components/RequirePermission.test.tsx
index 9159227925..262a602ead 100644
--- a/plugins/permission-react/src/components/PermissionedRoute.test.tsx
+++ b/plugins/permission-react/src/components/RequirePermission.test.tsx
@@ -15,7 +15,7 @@
*/
import React from 'react';
-import { PermissionedRoute } from '.';
+import { RequirePermission } from './RequirePermission';
import { usePermission } from '../hooks';
import { renderInTestApp } from '@backstage/test-utils';
import { createPermission } from '@backstage/plugin-permission-common';
@@ -32,14 +32,14 @@ const permission = createPermission({
attributes: { action: 'read' },
});
-describe('PermissionedRoute', () => {
+describe('RequirePermission', () => {
it('Does not render when loading', async () => {
mockUsePermission.mockReturnValue({ loading: true, allowed: false });
const { queryByText } = await renderInTestApp(
- content}
+ children={content
}
/>,
);
@@ -50,9 +50,9 @@ describe('PermissionedRoute', () => {
mockUsePermission.mockReturnValue({ loading: false, allowed: true });
const { getByText } = await renderInTestApp(
- content}
+ children={content
}
/>,
);
@@ -64,9 +64,9 @@ describe('PermissionedRoute', () => {
await expect(
renderInTestApp(
- content}
+ children={content
}
/>,
),
).rejects.toThrowError('Reached NotFound Page');
@@ -76,10 +76,10 @@ describe('PermissionedRoute', () => {
mockUsePermission.mockReturnValue({ loading: false, allowed: false });
const { getByText } = await renderInTestApp(
- content}
- errorComponent={Custom Error
}
+ children={content
}
+ errorPage={Custom Error
}
/>,
);
diff --git a/plugins/permission-react/src/components/RequirePermission.tsx b/plugins/permission-react/src/components/RequirePermission.tsx
new file mode 100644
index 0000000000..801eb0fe24
--- /dev/null
+++ b/plugins/permission-react/src/components/RequirePermission.tsx
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { ReactNode } from 'react';
+import { useApp } from '@backstage/core-plugin-api';
+import { usePermission } from '../hooks';
+import {
+ isResourcePermission,
+ Permission,
+ ResourcePermission,
+} from '@backstage/plugin-permission-common';
+
+/**
+ * Properties for {@link RequirePermission}
+ *
+ * @public
+ */
+export type RequirePermissionProps = (
+ | {
+ permission: Exclude;
+ resourceRef?: never;
+ }
+ | {
+ permission: ResourcePermission;
+ resourceRef: string | undefined;
+ }
+) & {
+ /**
+ * The error page to be displayed if the user is not allowed access.
+ *
+ * Defaults to the `NotFoundErrorPage` app component.
+ */
+ errorPage?: ReactNode;
+ children: ReactNode;
+};
+
+/**
+ * A boundary that only renders its child elements if the user has the specified permission.
+ *
+ * While loading, nothing will be rendered. If the user does not have
+ * permission, the `errorPage` element will be rendered, falling back
+ * to the `NotFoundErrorPage` app component if no `errorPage` is provider.
+ *
+ * @public
+ */
+export function RequirePermission(
+ props: RequirePermissionProps,
+): JSX.Element | null {
+ const { permission, resourceRef } = props;
+ const permissionResult = usePermission(
+ isResourcePermission(permission)
+ ? { permission, resourceRef }
+ : { permission },
+ );
+ const app = useApp();
+
+ if (permissionResult.loading) {
+ return null;
+ } else if (permissionResult.allowed) {
+ return <>{props.children}>;
+ }
+
+ if (props.errorPage) {
+ return <>{props.errorPage}>;
+ }
+ // If no explicit error element is provided, the not found page is used as fallback.
+ const { NotFoundErrorPage } = app.getComponents();
+ return ;
+}
diff --git a/plugins/permission-react/src/components/index.ts b/plugins/permission-react/src/components/index.ts
index 05f13bca81..e443ad0b5e 100644
--- a/plugins/permission-react/src/components/index.ts
+++ b/plugins/permission-react/src/components/index.ts
@@ -15,3 +15,5 @@
*/
export { PermissionedRoute } from './PermissionedRoute';
+export { RequirePermission } from './RequirePermission';
+export type { RequirePermissionProps } from './RequirePermission';