@backstage/plugin-permission-react 0.0.0-nightly-202111922557

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # @backstage/plugin-permission-react
2
+
3
+ ## 0.0.0-nightly-202111922557
4
+
5
+ ### Patch Changes
6
+
7
+ - cd450844f6: Moved React dependencies to `peerDependencies` and allow both React v16 and v17 to be used.
8
+ - dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly
9
+ - Updated dependencies
10
+ - @backstage/core-plugin-api@0.0.0-nightly-202111922557
11
+
12
+ ## 0.1.0
13
+
14
+ ### Minor Changes
15
+
16
+ - 6ed24445a9: Add @backstage/plugin-permission-react
17
+
18
+ @backstage/plugin-permission-react is a library containing utils for implementing permissions in your frontend Backstage plugins. See [the authorization PRFC](https://github.com/backstage/backstage/pull/7761) for more details.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+ - @backstage/core-plugin-api@0.2.2
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # permission
2
+
3
+ **NOTE: THIS PACKAGE IS EXPERIMENTAL!**
4
+
5
+ Components and hooks to help implement permissions in Backstage frontend plugins. For more information, see the [authorization PRFC](https://github.com/backstage/backstage/pull/7761).
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var reactRouter = require('react-router');
7
+ var corePluginApi = require('@backstage/core-plugin-api');
8
+ var reactUse = require('react-use');
9
+ var pluginPermissionCommon = require('@backstage/plugin-permission-common');
10
+
11
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
+
13
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
14
+
15
+ const permissionApiRef = corePluginApi.createApiRef({
16
+ id: "plugin.permission.api"
17
+ });
18
+
19
+ class IdentityPermissionApi {
20
+ constructor(permissionClient, identityApi) {
21
+ this.permissionClient = permissionClient;
22
+ this.identityApi = identityApi;
23
+ }
24
+ static create(options) {
25
+ const { configApi, discoveryApi, identityApi } = options;
26
+ const permissionClient = new pluginPermissionCommon.PermissionClient({ discoveryApi, configApi });
27
+ return new IdentityPermissionApi(permissionClient, identityApi);
28
+ }
29
+ async authorize(request) {
30
+ const response = await this.permissionClient.authorize([request], {
31
+ token: await this.identityApi.getIdToken()
32
+ });
33
+ return response[0];
34
+ }
35
+ }
36
+
37
+ const usePermission = (permission, resourceRef) => {
38
+ const permissionApi = corePluginApi.useApi(permissionApiRef);
39
+ const { loading, error, value } = reactUse.useAsync(async () => {
40
+ const { result } = await permissionApi.authorize({
41
+ permission,
42
+ resourceRef
43
+ });
44
+ return result;
45
+ }, [permissionApi, permission, resourceRef]);
46
+ if (loading) {
47
+ return { loading: true, allowed: false };
48
+ }
49
+ if (error) {
50
+ return { error, loading: false, allowed: false };
51
+ }
52
+ return { loading: false, allowed: value === pluginPermissionCommon.AuthorizeResult.ALLOW };
53
+ };
54
+
55
+ const PermissionedRoute = (props) => {
56
+ const { permission, resourceRef, errorComponent, ...otherProps } = props;
57
+ const permissionResult = usePermission(permission, resourceRef);
58
+ const app = corePluginApi.useApp();
59
+ const { NotFoundErrorPage } = app.getComponents();
60
+ let shownElement = errorComponent === void 0 ? /* @__PURE__ */ React__default["default"].createElement(NotFoundErrorPage, null) : errorComponent;
61
+ if (permissionResult.loading) {
62
+ shownElement = null;
63
+ } else if (permissionResult.allowed) {
64
+ shownElement = props.element;
65
+ }
66
+ return /* @__PURE__ */ React__default["default"].createElement(reactRouter.Route, {
67
+ ...otherProps,
68
+ element: shownElement
69
+ });
70
+ };
71
+
72
+ exports.IdentityPermissionApi = IdentityPermissionApi;
73
+ exports.PermissionedRoute = PermissionedRoute;
74
+ exports.permissionApiRef = permissionApiRef;
75
+ exports.usePermission = usePermission;
76
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/apis/PermissionApi.ts","../src/apis/IdentityPermissionApi.ts","../src/hooks/usePermission.ts","../src/components/PermissionedRoute.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthorizeRequest,\n AuthorizeResponse,\n} from '@backstage/plugin-permission-common';\nimport { ApiRef, createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * This API is used by various frontend utilities that allow developers to implement authorization wihtin their frontend\n * plugins. A plugin developer will likely not have to interact with this API or its implementations directly, but\n * rather with the aforementioned utility components/hooks.\n * @public\n */\nexport type PermissionApi = {\n authorize(request: AuthorizeRequest): Promise<AuthorizeResponse>;\n};\n\n/**\n * A Backstage ApiRef for the Permission API. See https://backstage.io/docs/api/utility-apis for more information on\n * Backstage ApiRefs.\n * @public\n */\nexport const permissionApiRef: ApiRef<PermissionApi> = createApiRef({\n id: 'plugin.permission.api',\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';\nimport { PermissionApi } from './PermissionApi';\nimport {\n AuthorizeRequest,\n AuthorizeResponse,\n PermissionClient,\n} from '@backstage/plugin-permission-common';\nimport { Config } from '@backstage/config';\n\n/**\n * The default implementation of the PermissionApi, which simply calls the authorize method of the given\n * {@link @backstage/plugin-permission-common#PermissionClient}.\n * @public\n */\nexport class IdentityPermissionApi implements PermissionApi {\n private constructor(\n private readonly permissionClient: PermissionClient,\n private readonly identityApi: IdentityApi,\n ) {}\n\n static create(options: {\n configApi: Config;\n discoveryApi: DiscoveryApi;\n identityApi: IdentityApi;\n }) {\n const { configApi, discoveryApi, identityApi } = options;\n const permissionClient = new PermissionClient({ discoveryApi, configApi });\n return new IdentityPermissionApi(permissionClient, identityApi);\n }\n\n async authorize(request: AuthorizeRequest): Promise<AuthorizeResponse> {\n const response = await this.permissionClient.authorize([request], {\n token: await this.identityApi.getIdToken(),\n });\n return response[0];\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useAsync } from 'react-use';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { permissionApiRef } from '../apis';\nimport {\n AuthorizeResult,\n Permission,\n} from '@backstage/plugin-permission-common';\n\n/** @public */\nexport type AsyncPermissionResult = {\n loading: boolean;\n allowed: boolean;\n error?: Error;\n};\n\n/**\n * React hook utlity for authorization. Given a {@link @backstage/plugin-permission-common#Permission} and an optional\n * resourceRef, it will return whether or not access is allowed (for the given resource, if resourceRef is provided). See\n * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for more details.\n * @public\n */\nexport const usePermission = (\n permission: Permission,\n resourceRef?: string,\n): AsyncPermissionResult => {\n const permissionApi = useApi(permissionApiRef);\n\n const { loading, error, value } = useAsync(async () => {\n const { result } = await permissionApi.authorize({\n permission,\n resourceRef,\n });\n\n return result;\n }, [permissionApi, permission, resourceRef]);\n\n if (loading) {\n return { loading: true, allowed: false };\n }\n if (error) {\n return { error, loading: false, allowed: false };\n }\n return { loading: false, allowed: value === AuthorizeResult.ALLOW };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { ComponentProps, ReactElement } from 'react';\nimport { Route } from 'react-router';\nimport { useApp } from '@backstage/core-plugin-api';\nimport { usePermission } from '../hooks';\nimport { Permission } from '@backstage/plugin-permission-common';\n\n/**\n * Returns a React Router Route which only renders the element when authorized. If unauthorized, the Route will render a\n * NotFoundErrorPage (see {@link @backstage/core-app-api#AppComponents}).\n *\n * @public\n */\nexport const PermissionedRoute = (\n props: ComponentProps<typeof Route> & {\n permission: Permission;\n resourceRef?: string;\n errorComponent?: ReactElement | null;\n },\n) => {\n const { permission, resourceRef, errorComponent, ...otherProps } = props;\n const permissionResult = usePermission(permission, resourceRef);\n const app = useApp();\n const { NotFoundErrorPage } = app.getComponents();\n\n let shownElement: ReactElement | null | undefined =\n errorComponent === undefined ? <NotFoundErrorPage /> : errorComponent;\n\n if (permissionResult.loading) {\n shownElement = null;\n } else if (permissionResult.allowed) {\n shownElement = props.element;\n }\n\n return <Route {...otherProps} element={shownElement} />;\n};\n"],"names":["createApiRef","PermissionClient","useApi","useAsync","AuthorizeResult","useApp","Route"],"mappings":";;;;;;;;;;;;;;MAqCa,mBAA0CA,2BAAa;AAAA,EAClE,IAAI;AAAA;;4BCRsD;AAAA,EAClD,YACW,kBACA,aACjB;AAFiB;AACA;AAAA;AAAA,SAGZ,OAAO,SAIX;AACD,UAAM,EAAE,WAAW,cAAc,gBAAgB;AACjD,UAAM,mBAAmB,IAAIC,wCAAiB,EAAE,cAAc;AAC9D,WAAO,IAAI,sBAAsB,kBAAkB;AAAA;AAAA,QAG/C,UAAU,SAAuD;AACrE,UAAM,WAAW,MAAM,KAAK,iBAAiB,UAAU,CAAC,UAAU;AAAA,MAChE,OAAO,MAAM,KAAK,YAAY;AAAA;AAEhC,WAAO,SAAS;AAAA;AAAA;;MCbP,gBAAgB,CAC3B,YACA,gBAC0B;AAC1B,QAAM,gBAAgBC,qBAAO;AAE7B,QAAM,EAAE,SAAS,OAAO,UAAUC,kBAAS,YAAY;AACrD,UAAM,EAAE,WAAW,MAAM,cAAc,UAAU;AAAA,MAC/C;AAAA,MACA;AAAA;AAGF,WAAO;AAAA,KACN,CAAC,eAAe,YAAY;AAE/B,MAAI,SAAS;AACX,WAAO,EAAE,SAAS,MAAM,SAAS;AAAA;AAEnC,MAAI,OAAO;AACT,WAAO,EAAE,OAAO,SAAS,OAAO,SAAS;AAAA;AAE3C,SAAO,EAAE,SAAS,OAAO,SAAS,UAAUC,uCAAgB;AAAA;;MC9BjD,oBAAoB,CAC/B,UAKG;AACH,QAAM,EAAE,YAAY,aAAa,mBAAmB,eAAe;AACnE,QAAM,mBAAmB,cAAc,YAAY;AACnD,QAAM,MAAMC;AACZ,QAAM,EAAE,sBAAsB,IAAI;AAElC,MAAI,eACF,mBAAmB,iEAAa,mBAAD,QAAwB;AAEzD,MAAI,iBAAiB,SAAS;AAC5B,mBAAe;AAAA,aACN,iBAAiB,SAAS;AACnC,mBAAe,MAAM;AAAA;AAGvB,iEAAQC,mBAAD;AAAA,OAAW;AAAA,IAAY,SAAS;AAAA;AAAA;;;;;;;"}
@@ -0,0 +1,66 @@
1
+ import { ComponentProps, ReactElement } from 'react';
2
+ import { Route } from 'react-router';
3
+ import { Permission, AuthorizeRequest, AuthorizeResponse } from '@backstage/plugin-permission-common';
4
+ import { ApiRef, DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
5
+ import { Config } from '@backstage/config';
6
+
7
+ /**
8
+ * Returns a React Router Route which only renders the element when authorized. If unauthorized, the Route will render a
9
+ * NotFoundErrorPage (see {@link @backstage/core-app-api#AppComponents}).
10
+ *
11
+ * @public
12
+ */
13
+ declare const PermissionedRoute: (props: ComponentProps<typeof Route> & {
14
+ permission: Permission;
15
+ resourceRef?: string;
16
+ errorComponent?: ReactElement | null;
17
+ }) => JSX.Element;
18
+
19
+ /** @public */
20
+ declare type AsyncPermissionResult = {
21
+ loading: boolean;
22
+ allowed: boolean;
23
+ error?: Error;
24
+ };
25
+ /**
26
+ * React hook utlity for authorization. Given a {@link @backstage/plugin-permission-common#Permission} and an optional
27
+ * resourceRef, it will return whether or not access is allowed (for the given resource, if resourceRef is provided). See
28
+ * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for more details.
29
+ * @public
30
+ */
31
+ declare const usePermission: (permission: Permission, resourceRef?: string | undefined) => AsyncPermissionResult;
32
+
33
+ /**
34
+ * This API is used by various frontend utilities that allow developers to implement authorization wihtin their frontend
35
+ * plugins. A plugin developer will likely not have to interact with this API or its implementations directly, but
36
+ * rather with the aforementioned utility components/hooks.
37
+ * @public
38
+ */
39
+ declare type PermissionApi = {
40
+ authorize(request: AuthorizeRequest): Promise<AuthorizeResponse>;
41
+ };
42
+ /**
43
+ * A Backstage ApiRef for the Permission API. See https://backstage.io/docs/api/utility-apis for more information on
44
+ * Backstage ApiRefs.
45
+ * @public
46
+ */
47
+ declare const permissionApiRef: ApiRef<PermissionApi>;
48
+
49
+ /**
50
+ * The default implementation of the PermissionApi, which simply calls the authorize method of the given
51
+ * {@link @backstage/plugin-permission-common#PermissionClient}.
52
+ * @public
53
+ */
54
+ declare class IdentityPermissionApi implements PermissionApi {
55
+ private readonly permissionClient;
56
+ private readonly identityApi;
57
+ private constructor();
58
+ static create(options: {
59
+ configApi: Config;
60
+ discoveryApi: DiscoveryApi;
61
+ identityApi: IdentityApi;
62
+ }): IdentityPermissionApi;
63
+ authorize(request: AuthorizeRequest): Promise<AuthorizeResponse>;
64
+ }
65
+
66
+ export { AsyncPermissionResult, IdentityPermissionApi, PermissionApi, PermissionedRoute, permissionApiRef, usePermission };
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+ import { Route } from 'react-router';
3
+ import { createApiRef, useApi, useApp } from '@backstage/core-plugin-api';
4
+ import { useAsync } from 'react-use';
5
+ import { PermissionClient, AuthorizeResult } from '@backstage/plugin-permission-common';
6
+
7
+ const permissionApiRef = createApiRef({
8
+ id: "plugin.permission.api"
9
+ });
10
+
11
+ class IdentityPermissionApi {
12
+ constructor(permissionClient, identityApi) {
13
+ this.permissionClient = permissionClient;
14
+ this.identityApi = identityApi;
15
+ }
16
+ static create(options) {
17
+ const { configApi, discoveryApi, identityApi } = options;
18
+ const permissionClient = new PermissionClient({ discoveryApi, configApi });
19
+ return new IdentityPermissionApi(permissionClient, identityApi);
20
+ }
21
+ async authorize(request) {
22
+ const response = await this.permissionClient.authorize([request], {
23
+ token: await this.identityApi.getIdToken()
24
+ });
25
+ return response[0];
26
+ }
27
+ }
28
+
29
+ const usePermission = (permission, resourceRef) => {
30
+ const permissionApi = useApi(permissionApiRef);
31
+ const { loading, error, value } = useAsync(async () => {
32
+ const { result } = await permissionApi.authorize({
33
+ permission,
34
+ resourceRef
35
+ });
36
+ return result;
37
+ }, [permissionApi, permission, resourceRef]);
38
+ if (loading) {
39
+ return { loading: true, allowed: false };
40
+ }
41
+ if (error) {
42
+ return { error, loading: false, allowed: false };
43
+ }
44
+ return { loading: false, allowed: value === AuthorizeResult.ALLOW };
45
+ };
46
+
47
+ const PermissionedRoute = (props) => {
48
+ const { permission, resourceRef, errorComponent, ...otherProps } = props;
49
+ const permissionResult = usePermission(permission, resourceRef);
50
+ const app = useApp();
51
+ const { NotFoundErrorPage } = app.getComponents();
52
+ let shownElement = errorComponent === void 0 ? /* @__PURE__ */ React.createElement(NotFoundErrorPage, null) : errorComponent;
53
+ if (permissionResult.loading) {
54
+ shownElement = null;
55
+ } else if (permissionResult.allowed) {
56
+ shownElement = props.element;
57
+ }
58
+ return /* @__PURE__ */ React.createElement(Route, {
59
+ ...otherProps,
60
+ element: shownElement
61
+ });
62
+ };
63
+
64
+ export { IdentityPermissionApi, PermissionedRoute, permissionApiRef, usePermission };
65
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/apis/PermissionApi.ts","../src/apis/IdentityPermissionApi.ts","../src/hooks/usePermission.ts","../src/components/PermissionedRoute.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthorizeRequest,\n AuthorizeResponse,\n} from '@backstage/plugin-permission-common';\nimport { ApiRef, createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * This API is used by various frontend utilities that allow developers to implement authorization wihtin their frontend\n * plugins. A plugin developer will likely not have to interact with this API or its implementations directly, but\n * rather with the aforementioned utility components/hooks.\n * @public\n */\nexport type PermissionApi = {\n authorize(request: AuthorizeRequest): Promise<AuthorizeResponse>;\n};\n\n/**\n * A Backstage ApiRef for the Permission API. See https://backstage.io/docs/api/utility-apis for more information on\n * Backstage ApiRefs.\n * @public\n */\nexport const permissionApiRef: ApiRef<PermissionApi> = createApiRef({\n id: 'plugin.permission.api',\n});\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';\nimport { PermissionApi } from './PermissionApi';\nimport {\n AuthorizeRequest,\n AuthorizeResponse,\n PermissionClient,\n} from '@backstage/plugin-permission-common';\nimport { Config } from '@backstage/config';\n\n/**\n * The default implementation of the PermissionApi, which simply calls the authorize method of the given\n * {@link @backstage/plugin-permission-common#PermissionClient}.\n * @public\n */\nexport class IdentityPermissionApi implements PermissionApi {\n private constructor(\n private readonly permissionClient: PermissionClient,\n private readonly identityApi: IdentityApi,\n ) {}\n\n static create(options: {\n configApi: Config;\n discoveryApi: DiscoveryApi;\n identityApi: IdentityApi;\n }) {\n const { configApi, discoveryApi, identityApi } = options;\n const permissionClient = new PermissionClient({ discoveryApi, configApi });\n return new IdentityPermissionApi(permissionClient, identityApi);\n }\n\n async authorize(request: AuthorizeRequest): Promise<AuthorizeResponse> {\n const response = await this.permissionClient.authorize([request], {\n token: await this.identityApi.getIdToken(),\n });\n return response[0];\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useAsync } from 'react-use';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { permissionApiRef } from '../apis';\nimport {\n AuthorizeResult,\n Permission,\n} from '@backstage/plugin-permission-common';\n\n/** @public */\nexport type AsyncPermissionResult = {\n loading: boolean;\n allowed: boolean;\n error?: Error;\n};\n\n/**\n * React hook utlity for authorization. Given a {@link @backstage/plugin-permission-common#Permission} and an optional\n * resourceRef, it will return whether or not access is allowed (for the given resource, if resourceRef is provided). See\n * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for more details.\n * @public\n */\nexport const usePermission = (\n permission: Permission,\n resourceRef?: string,\n): AsyncPermissionResult => {\n const permissionApi = useApi(permissionApiRef);\n\n const { loading, error, value } = useAsync(async () => {\n const { result } = await permissionApi.authorize({\n permission,\n resourceRef,\n });\n\n return result;\n }, [permissionApi, permission, resourceRef]);\n\n if (loading) {\n return { loading: true, allowed: false };\n }\n if (error) {\n return { error, loading: false, allowed: false };\n }\n return { loading: false, allowed: value === AuthorizeResult.ALLOW };\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { ComponentProps, ReactElement } from 'react';\nimport { Route } from 'react-router';\nimport { useApp } from '@backstage/core-plugin-api';\nimport { usePermission } from '../hooks';\nimport { Permission } from '@backstage/plugin-permission-common';\n\n/**\n * Returns a React Router Route which only renders the element when authorized. If unauthorized, the Route will render a\n * NotFoundErrorPage (see {@link @backstage/core-app-api#AppComponents}).\n *\n * @public\n */\nexport const PermissionedRoute = (\n props: ComponentProps<typeof Route> & {\n permission: Permission;\n resourceRef?: string;\n errorComponent?: ReactElement | null;\n },\n) => {\n const { permission, resourceRef, errorComponent, ...otherProps } = props;\n const permissionResult = usePermission(permission, resourceRef);\n const app = useApp();\n const { NotFoundErrorPage } = app.getComponents();\n\n let shownElement: ReactElement | null | undefined =\n errorComponent === undefined ? <NotFoundErrorPage /> : errorComponent;\n\n if (permissionResult.loading) {\n shownElement = null;\n } else if (permissionResult.allowed) {\n shownElement = props.element;\n }\n\n return <Route {...otherProps} element={shownElement} />;\n};\n"],"names":[],"mappings":";;;;;;MAqCa,mBAA0C,aAAa;AAAA,EAClE,IAAI;AAAA;;4BCRsD;AAAA,EAClD,YACW,kBACA,aACjB;AAFiB;AACA;AAAA;AAAA,SAGZ,OAAO,SAIX;AACD,UAAM,EAAE,WAAW,cAAc,gBAAgB;AACjD,UAAM,mBAAmB,IAAI,iBAAiB,EAAE,cAAc;AAC9D,WAAO,IAAI,sBAAsB,kBAAkB;AAAA;AAAA,QAG/C,UAAU,SAAuD;AACrE,UAAM,WAAW,MAAM,KAAK,iBAAiB,UAAU,CAAC,UAAU;AAAA,MAChE,OAAO,MAAM,KAAK,YAAY;AAAA;AAEhC,WAAO,SAAS;AAAA;AAAA;;MCbP,gBAAgB,CAC3B,YACA,gBAC0B;AAC1B,QAAM,gBAAgB,OAAO;AAE7B,QAAM,EAAE,SAAS,OAAO,UAAU,SAAS,YAAY;AACrD,UAAM,EAAE,WAAW,MAAM,cAAc,UAAU;AAAA,MAC/C;AAAA,MACA;AAAA;AAGF,WAAO;AAAA,KACN,CAAC,eAAe,YAAY;AAE/B,MAAI,SAAS;AACX,WAAO,EAAE,SAAS,MAAM,SAAS;AAAA;AAEnC,MAAI,OAAO;AACT,WAAO,EAAE,OAAO,SAAS,OAAO,SAAS;AAAA;AAE3C,SAAO,EAAE,SAAS,OAAO,SAAS,UAAU,gBAAgB;AAAA;;MC9BjD,oBAAoB,CAC/B,UAKG;AACH,QAAM,EAAE,YAAY,aAAa,mBAAmB,eAAe;AACnE,QAAM,mBAAmB,cAAc,YAAY;AACnD,QAAM,MAAM;AACZ,QAAM,EAAE,sBAAsB,IAAI;AAElC,MAAI,eACF,mBAAmB,6CAAa,mBAAD,QAAwB;AAEzD,MAAI,iBAAiB,SAAS;AAC5B,mBAAe;AAAA,aACN,iBAAiB,SAAS;AACnC,mBAAe,MAAM;AAAA;AAGvB,6CAAQ,OAAD;AAAA,OAAW;AAAA,IAAY,SAAS;AAAA;AAAA;;;;"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@backstage/plugin-permission-react",
3
+ "version": "0.0.0-nightly-202111922557",
4
+ "main": "dist/index.esm.js",
5
+ "types": "dist/index.d.ts",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.esm.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "homepage": "https://backstage.io",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/backstage/backstage",
16
+ "directory": "plugins/permission-react"
17
+ },
18
+ "keywords": [
19
+ "backstage"
20
+ ],
21
+ "scripts": {
22
+ "build": "backstage-cli build",
23
+ "lint": "backstage-cli lint",
24
+ "test": "backstage-cli test",
25
+ "prepack": "backstage-cli prepack",
26
+ "postpack": "backstage-cli postpack",
27
+ "clean": "backstage-cli clean"
28
+ },
29
+ "dependencies": {
30
+ "@backstage/config": "^0.1.11",
31
+ "@backstage/core-plugin-api": "^0.0.0-nightly-202111922557",
32
+ "@backstage/plugin-permission-common": "^0.2.0",
33
+ "cross-fetch": "^3.0.6",
34
+ "react-router": "6.0.0-beta.0",
35
+ "react-use": "^17.2.4"
36
+ },
37
+ "peerDependencies": {
38
+ "@types/react": "^16.13.1 || ^17.0.0",
39
+ "react": "^16.13.1 || ^17.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@backstage/cli": "^0.0.0-nightly-202111922557",
43
+ "@backstage/test-utils": "^0.0.0-nightly-202111922557",
44
+ "@testing-library/jest-dom": "^5.10.1",
45
+ "@testing-library/react": "^11.2.5",
46
+ "@types/jest": "^26.0.7"
47
+ },
48
+ "files": [
49
+ "dist"
50
+ ]
51
+ }