@backstage/plugin-catalog-react 1.3.0-next.2 → 1.4.0-next.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,51 @@
1
1
  # @backstage/plugin-catalog-react
2
2
 
3
+ ## 1.4.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0a5b73b292: Add possibility to re-use EntityPicker for filters with multiple select.
8
+
9
+ ### Patch Changes
10
+
11
+ - 928a12a9b3: Internal refactor of `/alpha` exports.
12
+ - Updated dependencies
13
+ - @backstage/catalog-client@1.4.0-next.0
14
+ - @backstage/core-plugin-api@1.4.1-next.0
15
+ - @backstage/catalog-model@1.2.1-next.0
16
+ - @backstage/plugin-catalog-common@1.0.12-next.0
17
+ - @backstage/core-components@0.12.5-next.0
18
+ - @backstage/errors@1.1.4
19
+ - @backstage/integration@1.4.2
20
+ - @backstage/theme@0.2.17
21
+ - @backstage/types@1.0.2
22
+ - @backstage/version-bridge@1.0.3
23
+ - @backstage/plugin-permission-common@0.7.3
24
+ - @backstage/plugin-permission-react@0.4.11-next.0
25
+
26
+ ## 1.3.0
27
+
28
+ ### Minor Changes
29
+
30
+ - 929e1afe1b: Add `initialFilter` prop to EntityLifecyclePicker. This allows you to set an initial lifecycle for the catalog.
31
+ - fab93c2fe8: Aligned buttons on "Unregister entity" dialog to keep them on the same line
32
+
33
+ ### Patch Changes
34
+
35
+ - Updated dependencies
36
+ - @backstage/core-components@0.12.4
37
+ - @backstage/catalog-model@1.2.0
38
+ - @backstage/theme@0.2.17
39
+ - @backstage/core-plugin-api@1.4.0
40
+ - @backstage/catalog-client@1.3.1
41
+ - @backstage/errors@1.1.4
42
+ - @backstage/integration@1.4.2
43
+ - @backstage/types@1.0.2
44
+ - @backstage/version-bridge@1.0.3
45
+ - @backstage/plugin-catalog-common@1.0.11
46
+ - @backstage/plugin-permission-common@0.7.3
47
+ - @backstage/plugin-permission-react@0.4.10
48
+
3
49
  ## 1.3.0-next.2
4
50
 
5
51
  ### Patch Changes
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-react",
3
- "version": "1.3.0-next.2",
4
- "main": "../dist/index.esm.js",
5
- "types": "../dist/index.alpha.d.ts"
3
+ "version": "1.4.0-next.0",
4
+ "main": "../dist/alpha.esm.js",
5
+ "module": "../dist/alpha.esm.js",
6
+ "types": "../dist/alpha.d.ts"
6
7
  }
@@ -0,0 +1,32 @@
1
+ import { Entity } from '@backstage/catalog-model';
2
+ import { ResourcePermission } from '@backstage/plugin-permission-common';
3
+
4
+ /**
5
+ * Returns true if the `owner` argument is a direct owner on the `entity` argument.
6
+ *
7
+ * @alpha
8
+ * @remarks
9
+ *
10
+ * Note that this ownership is not the same as using the claims in the auth-resolver, it only will take into account ownership as expressed by direct entity relations.
11
+ * It doesn't know anything about the additional groups that a user might belong to which the claims contain.
12
+ */
13
+ declare function isOwnerOf(owner: Entity, entity: Entity): boolean;
14
+
15
+ /**
16
+ * A thin wrapper around the
17
+ * {@link @backstage/plugin-permission-react#usePermission} hook which uses the
18
+ * current entity in context to make an authorization request for the given
19
+ * {@link @backstage/plugin-catalog-common#CatalogEntityPermission}.
20
+ *
21
+ * Note: this hook blocks the permission request until the entity has loaded in
22
+ * context. If you have the entityRef and need concurrent requests, use the
23
+ * `usePermission` hook directly.
24
+ * @alpha
25
+ */
26
+ declare function useEntityPermission(permission: ResourcePermission<'catalog-entity'>): {
27
+ loading: boolean;
28
+ allowed: boolean;
29
+ error?: Error;
30
+ };
31
+
32
+ export { isOwnerOf, useEntityPermission };
@@ -0,0 +1,78 @@
1
+ import { parseEntityRef, getCompoundEntityRef, stringifyEntityRef, RELATION_MEMBER_OF, RELATION_OWNED_BY } from '@backstage/catalog-model';
2
+ import { usePermission } from '@backstage/plugin-permission-react';
3
+ import '@backstage/core-plugin-api';
4
+ import { createVersionedContext, useVersionedContext } from '@backstage/version-bridge';
5
+ import 'react';
6
+
7
+ function getEntityRelations(entity, relationType, filter) {
8
+ var _a;
9
+ let entityNames = ((_a = entity == null ? void 0 : entity.relations) == null ? void 0 : _a.filter((r) => r.type === relationType).map((r) => parseEntityRef(r.targetRef))) || [];
10
+ if (filter == null ? void 0 : filter.kind) {
11
+ entityNames = entityNames.filter(
12
+ (e) => e.kind.toLocaleLowerCase("en-US") === filter.kind.toLocaleLowerCase("en-US")
13
+ );
14
+ }
15
+ return entityNames;
16
+ }
17
+
18
+ function isOwnerOf(owner, entity) {
19
+ const possibleOwners = new Set(
20
+ [
21
+ ...getEntityRelations(owner, RELATION_MEMBER_OF, { kind: "group" }),
22
+ ...owner ? [getCompoundEntityRef(owner)] : []
23
+ ].map(stringifyEntityRef)
24
+ );
25
+ const owners = getEntityRelations(entity, RELATION_OWNED_BY).map(
26
+ stringifyEntityRef
27
+ );
28
+ for (const ownerItem of owners) {
29
+ if (possibleOwners.has(ownerItem)) {
30
+ return true;
31
+ }
32
+ }
33
+ return false;
34
+ }
35
+
36
+ createVersionedContext(
37
+ "entity-context"
38
+ );
39
+ function useAsyncEntity() {
40
+ const versionedHolder = useVersionedContext(
41
+ "entity-context"
42
+ );
43
+ if (!versionedHolder) {
44
+ throw new Error("Entity context is not available");
45
+ }
46
+ const value = versionedHolder.atVersion(1);
47
+ if (!value) {
48
+ throw new Error("EntityContext v1 not available");
49
+ }
50
+ const { entity, loading, error, refresh } = value;
51
+ return { entity, loading, error, refresh };
52
+ }
53
+
54
+ function useEntityPermission(permission) {
55
+ const {
56
+ entity,
57
+ loading: loadingEntity,
58
+ error: entityError
59
+ } = useAsyncEntity();
60
+ const {
61
+ allowed,
62
+ loading: loadingPermission,
63
+ error: permissionError
64
+ } = usePermission({
65
+ permission,
66
+ resourceRef: entity ? stringifyEntityRef(entity) : void 0
67
+ });
68
+ if (loadingEntity || loadingPermission) {
69
+ return { loading: true, allowed: false };
70
+ }
71
+ if (entityError) {
72
+ return { loading: false, allowed: false, error: entityError };
73
+ }
74
+ return { loading: false, allowed, error: permissionError };
75
+ }
76
+
77
+ export { isOwnerOf, useEntityPermission };
78
+ //# sourceMappingURL=alpha.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpha.esm.js","sources":["../src/utils/getEntityRelations.ts","../src/utils/isOwnerOf.ts","../src/hooks/useEntity.tsx","../src/hooks/useEntityPermission.ts"],"sourcesContent":["/*\n * Copyright 2020 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 Entity,\n CompoundEntityRef,\n parseEntityRef,\n} from '@backstage/catalog-model';\n\n// TODO(freben): This should be returning entity refs instead\n/**\n * Get the related entity references.\n *\n * @public\n */\nexport function getEntityRelations(\n entity: Entity | undefined,\n relationType: string,\n filter?: { kind: string },\n): CompoundEntityRef[] {\n let entityNames =\n entity?.relations\n ?.filter(r => r.type === relationType)\n .map(r => parseEntityRef(r.targetRef)) || [];\n\n if (filter?.kind) {\n entityNames = entityNames.filter(\n e =>\n e.kind.toLocaleLowerCase('en-US') ===\n filter.kind.toLocaleLowerCase('en-US'),\n );\n }\n\n return entityNames;\n}\n","/*\n * Copyright 2020 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 Entity,\n getCompoundEntityRef,\n RELATION_MEMBER_OF,\n RELATION_OWNED_BY,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { getEntityRelations } from './getEntityRelations';\n\n/**\n * Returns true if the `owner` argument is a direct owner on the `entity` argument.\n *\n * @alpha\n * @remarks\n *\n * Note that this ownership is not the same as using the claims in the auth-resolver, it only will take into account ownership as expressed by direct entity relations.\n * It doesn't know anything about the additional groups that a user might belong to which the claims contain.\n */\nexport function isOwnerOf(owner: Entity, entity: Entity) {\n const possibleOwners = new Set(\n [\n ...getEntityRelations(owner, RELATION_MEMBER_OF, { kind: 'group' }),\n ...(owner ? [getCompoundEntityRef(owner)] : []),\n ].map(stringifyEntityRef),\n );\n\n const owners = getEntityRelations(entity, RELATION_OWNED_BY).map(\n stringifyEntityRef,\n );\n\n for (const ownerItem of owners) {\n if (possibleOwners.has(ownerItem)) {\n return true;\n }\n }\n\n return false;\n}\n","/*\n * Copyright 2020 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 */\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { AnalyticsContext } from '@backstage/core-plugin-api';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n useVersionedContext,\n} from '@backstage/version-bridge';\nimport React, { ReactNode } from 'react';\n\n/** @public */\nexport type EntityLoadingStatus<TEntity extends Entity = Entity> = {\n entity?: TEntity;\n loading: boolean;\n error?: Error;\n refresh?: VoidFunction;\n};\n\n// This context has support for multiple concurrent versions of this package.\n// It is currently used in parallel with the old context in order to provide\n// a smooth transition, but will eventually be the only context we use.\nconst NewEntityContext = createVersionedContext<{ 1: EntityLoadingStatus }>(\n 'entity-context',\n);\n\n/**\n * Properties for the AsyncEntityProvider component.\n *\n * @public\n */\nexport interface AsyncEntityProviderProps {\n children: ReactNode;\n entity?: Entity;\n loading: boolean;\n error?: Error;\n refresh?: VoidFunction;\n}\n\n/**\n * Provides a loaded entity to be picked up by the `useEntity` hook.\n *\n * @public\n */\nexport const AsyncEntityProvider = ({\n children,\n entity,\n loading,\n error,\n refresh,\n}: AsyncEntityProviderProps) => {\n const value = { entity, loading, error, refresh };\n // We provide both the old and the new context, since\n // consumers might be doing things like `useContext(EntityContext)`\n return (\n <NewEntityContext.Provider value={createVersionedValueMap({ 1: value })}>\n <AnalyticsContext\n attributes={{\n ...(entity ? { entityRef: stringifyEntityRef(entity) } : undefined),\n }}\n >\n {children}\n </AnalyticsContext>\n </NewEntityContext.Provider>\n );\n};\n\n/**\n * Properties for the EntityProvider component.\n *\n * @public\n */\nexport interface EntityProviderProps {\n children: ReactNode;\n entity?: Entity;\n}\n\n/**\n * Provides an entity to be picked up by the `useEntity` hook.\n *\n * @public\n */\nexport const EntityProvider = (props: EntityProviderProps) => (\n <AsyncEntityProvider\n entity={props.entity}\n loading={!Boolean(props.entity)}\n error={undefined}\n refresh={undefined}\n children={props.children}\n />\n);\n\n/**\n * Grab the current entity from the context, throws if the entity has not yet been loaded\n * or is not available.\n *\n * @public\n */\nexport function useEntity<TEntity extends Entity = Entity>(): {\n entity: TEntity;\n} {\n const versionedHolder = useVersionedContext<{ 1: EntityLoadingStatus }>(\n 'entity-context',\n );\n\n if (!versionedHolder) {\n throw new Error('Entity context is not available');\n }\n\n const value = versionedHolder.atVersion(1);\n if (!value) {\n throw new Error('EntityContext v1 not available');\n }\n\n if (!value.entity) {\n throw new Error(\n 'useEntity hook is being called outside of an EntityLayout where the entity has not been loaded. If this is intentional, please use useAsyncEntity instead.',\n );\n }\n\n return { entity: value.entity as TEntity };\n}\n\n/**\n * Grab the current entity from the context, provides loading state and errors, and the ability to refresh.\n *\n * @public\n */\nexport function useAsyncEntity<\n TEntity extends Entity = Entity,\n>(): EntityLoadingStatus<TEntity> {\n const versionedHolder = useVersionedContext<{ 1: EntityLoadingStatus }>(\n 'entity-context',\n );\n\n if (!versionedHolder) {\n throw new Error('Entity context is not available');\n }\n const value = versionedHolder.atVersion(1);\n if (!value) {\n throw new Error('EntityContext v1 not available');\n }\n\n const { entity, loading, error, refresh } = value;\n return { entity: entity as TEntity, loading, error, refresh };\n}\n","/*\n * Copyright 2022 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 { stringifyEntityRef } from '@backstage/catalog-model';\nimport { ResourcePermission } from '@backstage/plugin-permission-common';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { useAsyncEntity } from './useEntity';\n\n/**\n * A thin wrapper around the\n * {@link @backstage/plugin-permission-react#usePermission} hook which uses the\n * current entity in context to make an authorization request for the given\n * {@link @backstage/plugin-catalog-common#CatalogEntityPermission}.\n *\n * Note: this hook blocks the permission request until the entity has loaded in\n * context. If you have the entityRef and need concurrent requests, use the\n * `usePermission` hook directly.\n * @alpha\n */\nexport function useEntityPermission(\n // TODO(joeporpeglia) Replace with `CatalogEntityPermission` when the issue described in\n // https://github.com/backstage/backstage/pull/10128 is fixed.\n permission: ResourcePermission<'catalog-entity'>,\n): {\n loading: boolean;\n allowed: boolean;\n error?: Error;\n} {\n const {\n entity,\n loading: loadingEntity,\n error: entityError,\n } = useAsyncEntity();\n const {\n allowed,\n loading: loadingPermission,\n error: permissionError,\n } = usePermission({\n permission,\n resourceRef: entity ? stringifyEntityRef(entity) : undefined,\n });\n\n if (loadingEntity || loadingPermission) {\n return { loading: true, allowed: false };\n }\n if (entityError) {\n return { loading: false, allowed: false, error: entityError };\n }\n return { loading: false, allowed, error: permissionError };\n}\n"],"names":[],"mappings":"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"}