@backstage/plugin-permission-react 0.3.4 → 0.4.0

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 CHANGED
@@ -1,5 +1,40 @@
1
1
  # @backstage/plugin-permission-react
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5bdcb8c45d: **BREAKING**: More restrictive typing for `usePermission` hook and `PermissionedRoute` component. It's no longer possible to pass a `resourceRef` unless the permission is of type `ResourcePermission`.
8
+
9
+ ### Patch Changes
10
+
11
+ - c98d271466: Use updated types from `@backstage/plugin-permission-common`
12
+ - 322b69e46a: **BREAKING:** Make `IdentityPermissionApi#authorize` typing more strict, using `AuthorizePermissionRequest` and `AuthorizePermissionResponse`.
13
+ - Updated dependencies
14
+ - @backstage/plugin-permission-common@0.6.0
15
+ - @backstage/core-plugin-api@1.0.1
16
+
17
+ ## 0.4.0-next.1
18
+
19
+ ### Patch Changes
20
+
21
+ - 322b69e46a: **BREAKING:** Make `IdentityPermissionApi#authorize` typing more strict, using `AuthorizePermissionRequest` and `AuthorizePermissionResponse`.
22
+ - Updated dependencies
23
+ - @backstage/core-plugin-api@1.0.1-next.0
24
+ - @backstage/plugin-permission-common@0.6.0-next.1
25
+
26
+ ## 0.4.0-next.0
27
+
28
+ ### Minor Changes
29
+
30
+ - 5bdcb8c45d: **BREAKING**: More restrictive typing for `usePermission` hook and `PermissionedRoute` component. It's no longer possible to pass a `resourceRef` unless the permission is of type `ResourcePermission`.
31
+
32
+ ### Patch Changes
33
+
34
+ - c98d271466: Use updated types from `@backstage/plugin-permission-common`
35
+ - Updated dependencies
36
+ - @backstage/plugin-permission-common@0.6.0-next.0
37
+
3
38
  ## 0.3.4
4
39
 
5
40
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ComponentProps, ReactElement } from 'react';
2
2
  import { Route } from 'react-router';
3
- import { Permission, AuthorizeQuery, AuthorizeDecision } from '@backstage/plugin-permission-common';
3
+ import { Permission, ResourcePermission, EvaluatePermissionRequest, EvaluatePermissionResponse, AuthorizePermissionRequest, AuthorizePermissionResponse } from '@backstage/plugin-permission-common';
4
4
  import { ApiRef, DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
5
5
  import { Config } from '@backstage/config';
6
6
 
@@ -11,10 +11,14 @@ import { Config } from '@backstage/config';
11
11
  * @public
12
12
  */
13
13
  declare const PermissionedRoute: (props: ComponentProps<typeof Route> & {
14
- permission: Permission;
15
- resourceRef?: string;
16
14
  errorComponent?: ReactElement | null;
17
- }) => JSX.Element;
15
+ } & ({
16
+ permission: Exclude<Permission, ResourcePermission>;
17
+ resourceRef?: never;
18
+ } | {
19
+ permission: ResourcePermission;
20
+ resourceRef: string | undefined;
21
+ })) => JSX.Element;
18
22
 
19
23
  /** @public */
20
24
  declare type AsyncPermissionResult = {
@@ -23,19 +27,30 @@ declare type AsyncPermissionResult = {
23
27
  error?: Error;
24
28
  };
25
29
  /**
26
- * React hook utility for authorization. Given a
27
- * {@link @backstage/plugin-permission-common#Permission} and an optional
28
- * resourceRef, it will return whether or not access is allowed (for the given
29
- * resource, if resourceRef is provided). See
30
+ * React hook utility for authorization. Given either a non-resource
31
+ * {@link @backstage/plugin-permission-common#Permission} or a
32
+ * {@link @backstage/plugin-permission-common#ResourcePermission} and an
33
+ * optional resourceRef, it will return whether or not access is allowed (for
34
+ * the given resource, if resourceRef is provided). See
30
35
  * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for
31
36
  * more details.
32
37
  *
38
+ * The resourceRef field is optional to allow calling this hook with an
39
+ * entity that might be loading asynchronously, but when resourceRef is not
40
+ * supplied, the value of `allowed` will always be false.
41
+ *
33
42
  * Note: This hook uses stale-while-revalidate to help avoid flicker in UI
34
43
  * elements that would be conditionally rendered based on the `allowed` result
35
44
  * of this hook.
36
45
  * @public
37
46
  */
38
- declare const usePermission: (permission: Permission, resourceRef?: string | undefined) => AsyncPermissionResult;
47
+ declare function usePermission(input: {
48
+ permission: Exclude<Permission, ResourcePermission>;
49
+ resourceRef?: never;
50
+ } | {
51
+ permission: ResourcePermission;
52
+ resourceRef: string | undefined;
53
+ }): AsyncPermissionResult;
39
54
 
40
55
  /**
41
56
  * This API is used by various frontend utilities that allow developers to implement authorization within their frontend
@@ -44,7 +59,7 @@ declare const usePermission: (permission: Permission, resourceRef?: string | und
44
59
  * @public
45
60
  */
46
61
  declare type PermissionApi = {
47
- authorize(request: AuthorizeQuery): Promise<AuthorizeDecision>;
62
+ authorize(request: EvaluatePermissionRequest): Promise<EvaluatePermissionResponse>;
48
63
  };
49
64
  /**
50
65
  * A Backstage ApiRef for the Permission API. See https://backstage.io/docs/api/utility-apis for more information on
@@ -67,7 +82,7 @@ declare class IdentityPermissionApi implements PermissionApi {
67
82
  discovery: DiscoveryApi;
68
83
  identity: IdentityApi;
69
84
  }): IdentityPermissionApi;
70
- authorize(request: AuthorizeQuery): Promise<AuthorizeDecision>;
85
+ authorize(request: AuthorizePermissionRequest): Promise<AuthorizePermissionResponse>;
71
86
  }
72
87
 
73
88
  export { AsyncPermissionResult, IdentityPermissionApi, PermissionApi, PermissionedRoute, permissionApiRef, usePermission };
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Route } from 'react-router';
3
3
  import { createApiRef, useApi, useApp } from '@backstage/core-plugin-api';
4
- import { PermissionClient, AuthorizeResult } from '@backstage/plugin-permission-common';
4
+ import { PermissionClient, isResourcePermission, AuthorizeResult } from '@backstage/plugin-permission-common';
5
5
  import useSWR from 'swr';
6
6
 
7
7
  const permissionApiRef = createApiRef({
@@ -24,9 +24,12 @@ class IdentityPermissionApi {
24
24
  }
25
25
  }
26
26
 
27
- const usePermission = (permission, resourceRef) => {
27
+ function usePermission(input) {
28
28
  const permissionApi = useApi(permissionApiRef);
29
- const { data, error } = useSWR({ permission, resourceRef }, async (args) => {
29
+ const { data, error } = useSWR(input, async (args) => {
30
+ if (isResourcePermission(args.permission) && !args.resourceRef) {
31
+ return AuthorizeResult.DENY;
32
+ }
30
33
  const { result } = await permissionApi.authorize(args);
31
34
  return result;
32
35
  });
@@ -37,11 +40,11 @@ const usePermission = (permission, resourceRef) => {
37
40
  return { loading: true, allowed: false };
38
41
  }
39
42
  return { loading: false, allowed: data === AuthorizeResult.ALLOW };
40
- };
43
+ }
41
44
 
42
45
  const PermissionedRoute = (props) => {
43
46
  const { permission, resourceRef, errorComponent, ...otherProps } = props;
44
- const permissionResult = usePermission(permission, resourceRef);
47
+ const permissionResult = usePermission(isResourcePermission(permission) ? { permission, resourceRef } : { permission });
45
48
  const app = useApp();
46
49
  const { NotFoundErrorPage } = app.getComponents();
47
50
  let shownElement = errorComponent === void 0 ? /* @__PURE__ */ React.createElement(NotFoundErrorPage, null) : errorComponent;
@@ -1 +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 AuthorizeQuery,\n AuthorizeDecision,\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 within 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: AuthorizeQuery): Promise<AuthorizeDecision>;\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 AuthorizeQuery,\n AuthorizeDecision,\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 config: Config;\n discovery: DiscoveryApi;\n identity: IdentityApi;\n }) {\n const { config, discovery, identity } = options;\n const permissionClient = new PermissionClient({ discovery, config });\n return new IdentityPermissionApi(permissionClient, identity);\n }\n\n async authorize(request: AuthorizeQuery): Promise<AuthorizeDecision> {\n const response = await this.permissionClient.authorize(\n [request],\n await this.identityApi.getCredentials(),\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 { useApi } from '@backstage/core-plugin-api';\nimport { permissionApiRef } from '../apis';\nimport {\n AuthorizeResult,\n Permission,\n} from '@backstage/plugin-permission-common';\nimport useSWR from 'swr';\n\n/** @public */\nexport type AsyncPermissionResult = {\n loading: boolean;\n allowed: boolean;\n error?: Error;\n};\n\n/**\n * React hook utility for authorization. Given a\n * {@link @backstage/plugin-permission-common#Permission} and an optional\n * resourceRef, it will return whether or not access is allowed (for the given\n * resource, if resourceRef is provided). See\n * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for\n * more details.\n *\n * Note: This hook uses stale-while-revalidate to help avoid flicker in UI\n * elements that would be conditionally rendered based on the `allowed` result\n * of this hook.\n * @public\n */\nexport const usePermission = (\n permission: Permission,\n resourceRef?: string,\n): AsyncPermissionResult => {\n const permissionApi = useApi(permissionApiRef);\n const { data, error } = useSWR({ permission, resourceRef }, async args => {\n const { result } = await permissionApi.authorize(args);\n return result;\n });\n\n if (error) {\n return { error, loading: false, allowed: false };\n }\n if (data === undefined) {\n return { loading: true, allowed: false };\n }\n return { loading: false, allowed: data === 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":";;;;;;AAqCO,MAAM,mBAA0C,YAAa,CAAA;AAAA,EAClE,EAAI,EAAA,uBAAA;AAAA,CAAA;;ACRsD,MAAA,qBAAA,CAAA;AAAA,EAClD,WAAA,CACW,kBACA,WACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AAAA,GAAA;AAAA,EAAA,OAGZ,OAAO,OAIX,EAAA;AACD,IAAM,MAAA,EAAE,MAAQ,EAAA,SAAA,EAAW,QAAa,EAAA,GAAA,OAAA,CAAA;AACxC,IAAA,MAAM,gBAAmB,GAAA,IAAI,gBAAiB,CAAA,EAAE,SAAW,EAAA,MAAA,EAAA,CAAA,CAAA;AAC3D,IAAO,OAAA,IAAI,sBAAsB,gBAAkB,EAAA,QAAA,CAAA,CAAA;AAAA,GAAA;AAAA,EAAA,MAG/C,UAAU,OAAqD,EAAA;AACnE,IAAM,MAAA,QAAA,GAAW,MAAM,IAAK,CAAA,gBAAA,CAAiB,UAC3C,CAAC,OAAA,CAAA,EACD,MAAM,IAAA,CAAK,WAAY,CAAA,cAAA,EAAA,CAAA,CAAA;AAEzB,IAAA,OAAO,QAAS,CAAA,CAAA,CAAA,CAAA;AAAA,GAAA;AAAA;;ACPP,MAAA,aAAA,GAAgB,CAC3B,UAAA,EACA,WAC0B,KAAA;AAC1B,EAAA,MAAM,gBAAgB,MAAO,CAAA,gBAAA,CAAA,CAAA;AAC7B,EAAM,MAAA,EAAE,MAAM,KAAU,EAAA,GAAA,MAAA,CAAO,EAAE,UAAY,EAAA,WAAA,EAAA,EAAe,OAAM,IAAQ,KAAA;AACxE,IAAA,MAAM,EAAE,MAAA,EAAA,GAAW,MAAM,aAAA,CAAc,SAAU,CAAA,IAAA,CAAA,CAAA;AACjD,IAAO,OAAA,MAAA,CAAA;AAAA,GAAA,CAAA,CAAA;AAGT,EAAA,IAAI,KAAO,EAAA;AACT,IAAA,OAAO,EAAE,KAAA,EAAO,OAAS,EAAA,KAAA,EAAO,OAAS,EAAA,KAAA,EAAA,CAAA;AAAA,GAAA;AAE3C,EAAA,IAAI,SAAS,KAAW,CAAA,EAAA;AACtB,IAAO,OAAA,EAAE,OAAS,EAAA,IAAA,EAAM,OAAS,EAAA,KAAA,EAAA,CAAA;AAAA,GAAA;AAEnC,EAAA,OAAO,EAAE,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,SAAS,eAAgB,CAAA,KAAA,EAAA,CAAA;AAAA;;AChChD,MAAA,iBAAA,GAAoB,CAC/B,KAKG,KAAA;AACH,EAAA,MAAM,EAAE,UAAA,EAAY,WAAa,EAAA,cAAA,EAAA,GAAmB,UAAe,EAAA,GAAA,KAAA,CAAA;AACnE,EAAM,MAAA,gBAAA,GAAmB,cAAc,UAAY,EAAA,WAAA,CAAA,CAAA;AACnD,EAAA,MAAM,GAAM,GAAA,MAAA,EAAA,CAAA;AACZ,EAAM,MAAA,EAAE,sBAAsB,GAAI,CAAA,aAAA,EAAA,CAAA;AAElC,EAAA,IAAI,YACF,GAAA,cAAA,KAAmB,KAAY,CAAA,mBAAA,KAAA,CAAA,aAAA,CAAC,mBAAD,IAAwB,CAAA,GAAA,cAAA,CAAA;AAEzD,EAAA,IAAI,iBAAiB,OAAS,EAAA;AAC5B,IAAe,YAAA,GAAA,IAAA,CAAA;AAAA,GAAA,MAAA,IACN,iBAAiB,OAAS,EAAA;AACnC,IAAA,YAAA,GAAe,KAAM,CAAA,OAAA,CAAA;AAAA,GAAA;AAGvB,EAAA,2CAAQ,KAAD,EAAA;AAAA,IAAW,GAAA,UAAA;AAAA,IAAY,OAAS,EAAA,YAAA;AAAA,GAAA,CAAA,CAAA;AAAA;;;;"}
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 EvaluatePermissionRequest,\n EvaluatePermissionResponse,\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 within 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(\n request: EvaluatePermissionRequest,\n ): Promise<EvaluatePermissionResponse>;\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 AuthorizePermissionRequest,\n AuthorizePermissionResponse,\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 config: Config;\n discovery: DiscoveryApi;\n identity: IdentityApi;\n }) {\n const { config, discovery, identity } = options;\n const permissionClient = new PermissionClient({ discovery, config });\n return new IdentityPermissionApi(permissionClient, identity);\n }\n\n async authorize(\n request: AuthorizePermissionRequest,\n ): Promise<AuthorizePermissionResponse> {\n const response = await this.permissionClient.authorize(\n [request],\n await this.identityApi.getCredentials(),\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 { useApi } from '@backstage/core-plugin-api';\nimport { permissionApiRef } from '../apis';\nimport {\n AuthorizeResult,\n isResourcePermission,\n Permission,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport useSWR from 'swr';\n\n/** @public */\nexport type AsyncPermissionResult = {\n loading: boolean;\n allowed: boolean;\n error?: Error;\n};\n\n/**\n * React hook utility for authorization. Given either a non-resource\n * {@link @backstage/plugin-permission-common#Permission} or a\n * {@link @backstage/plugin-permission-common#ResourcePermission} and an\n * optional resourceRef, it will return whether or not access is allowed (for\n * the given resource, if resourceRef is provided). See\n * {@link @backstage/plugin-permission-common/PermissionClient#authorize} for\n * more details.\n *\n * The resourceRef field is optional to allow calling this hook with an\n * entity that might be loading asynchronously, but when resourceRef is not\n * supplied, the value of `allowed` will always be false.\n *\n * Note: This hook uses stale-while-revalidate to help avoid flicker in UI\n * elements that would be conditionally rendered based on the `allowed` result\n * of this hook.\n * @public\n */\nexport function usePermission(\n input:\n | {\n permission: Exclude<Permission, ResourcePermission>;\n resourceRef?: never;\n }\n | {\n permission: ResourcePermission;\n resourceRef: string | undefined;\n },\n): AsyncPermissionResult {\n const permissionApi = useApi(permissionApiRef);\n const { data, error } = useSWR(input, async (args: typeof input) => {\n // We could make the resourceRef parameter required to avoid this check, but\n // it would make using this hook difficult in situations where the entity\n // must be asynchronously loaded, so instead we short-circuit to a deny when\n // no resourceRef is supplied, on the assumption that the resourceRef is\n // still loading outside the hook.\n if (isResourcePermission(args.permission) && !args.resourceRef) {\n return AuthorizeResult.DENY;\n }\n\n const { result } = await permissionApi.authorize(args);\n return result;\n });\n\n if (error) {\n return { error, loading: false, allowed: false };\n }\n if (data === undefined) {\n return { loading: true, allowed: false };\n }\n return { loading: false, allowed: data === 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 {\n isResourcePermission,\n Permission,\n ResourcePermission,\n} 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 errorComponent?: ReactElement | null;\n } & (\n | {\n permission: Exclude<Permission, ResourcePermission>;\n resourceRef?: never;\n }\n | {\n permission: ResourcePermission;\n resourceRef: string | undefined;\n }\n ),\n) => {\n const { permission, resourceRef, errorComponent, ...otherProps } = props;\n\n const permissionResult = usePermission(\n isResourcePermission(permission)\n ? { permission, resourceRef }\n : { permission },\n );\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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-permission-react",
3
- "version": "0.3.4",
3
+ "version": "0.4.0",
4
4
  "main": "dist/index.esm.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@backstage/config": "^1.0.0",
35
- "@backstage/core-plugin-api": "^1.0.0",
36
- "@backstage/plugin-permission-common": "^0.5.3",
35
+ "@backstage/core-plugin-api": "^1.0.1",
36
+ "@backstage/plugin-permission-common": "^0.6.0",
37
37
  "cross-fetch": "^3.1.5",
38
38
  "react-router": "6.0.0-beta.0",
39
39
  "react-use": "^17.2.4",
@@ -44,8 +44,8 @@
44
44
  "react": "^16.13.1 || ^17.0.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@backstage/cli": "^0.16.0",
48
- "@backstage/test-utils": "^1.0.0",
47
+ "@backstage/cli": "^0.17.0",
48
+ "@backstage/test-utils": "^1.0.1",
49
49
  "@testing-library/jest-dom": "^5.10.1",
50
50
  "@testing-library/react": "^12.1.3",
51
51
  "@types/jest": "^26.0.7"
@@ -53,5 +53,5 @@
53
53
  "files": [
54
54
  "dist"
55
55
  ],
56
- "gitHead": "e9496f746b31600dbfac7fa76987479e66426257"
56
+ "gitHead": "e0e44c433319711c2fb8b175db411a621f7aaec2"
57
57
  }