From 0f645a7947e42437349b35981c1f0d5636b2a485 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Fri, 10 Dec 2021 02:47:21 +0530 Subject: [PATCH 1/7] add OwnedEntityPicker field Signed-off-by: mufaddal motiwala --- .changeset/perfect-buses-collect.md | 5 + .../OwnedEntityPicker.test.tsx | 137 ++++++++++++++++++ .../OwnedEntityPicker/OwnedEntityPicker.tsx | 86 +++++++++++ .../fields/OwnedEntityPicker/index.ts | 16 ++ .../scaffolder/src/components/fields/index.ts | 1 + plugins/scaffolder/src/extensions/default.ts | 5 + plugins/scaffolder/src/index.ts | 2 + plugins/scaffolder/src/plugin.ts | 8 + 8 files changed, 260 insertions(+) create mode 100644 .changeset/perfect-buses-collect.md create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts diff --git a/.changeset/perfect-buses-collect.md b/.changeset/perfect-buses-collect.md new file mode 100644 index 0000000000..cd7b8164cf --- /dev/null +++ b/.changeset/perfect-buses-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added OwnedEntityPicker field which displays Owned Entities in options diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx new file mode 100644 index 0000000000..ef6fc1b648 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx @@ -0,0 +1,137 @@ +/* + * 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 { Entity } from '@backstage/catalog-model'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { FieldProps } from '@rjsf/core'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { OwnedEntityPicker } from './OwnedEntityPicker'; + +const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ + apiVersion: 'backstage.io/v1beta1', + kind, + metadata: { namespace, name }, +}); + +describe('', () => { + let entities: Entity[]; + const onChange = jest.fn(); + const schema = {}; + const required = false; + let uiSchema: { + 'ui:options': { allowedKinds?: string[]; defaultKind?: string }; + }; + const rawErrors: string[] = []; + const formData = undefined; + + let props: FieldProps; + + const catalogApi: jest.Mocked = { + getLocationById: jest.fn(), + getEntityByName: jest.fn(), + getEntities: jest.fn(async () => ({ items: entities })), + addLocation: jest.fn(), + getLocationByEntity: jest.fn(), + removeEntityByUid: jest.fn(), + } as any; + let Wrapper: React.ComponentType; + + beforeEach(() => { + entities = [ + makeEntity('Group', 'default', 'team-a'), + makeEntity('Group', 'default', 'squad-b'), + ]; + + Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ); + }); + + afterEach(() => jest.resetAllMocks()); + + describe('without allowedKinds', () => { + beforeEach(() => { + uiSchema = { 'ui:options': {} }; + props = { + onChange, + schema, + required, + uiSchema, + rawErrors, + formData, + } as unknown as FieldProps; + + catalogApi.getEntities.mockResolvedValue({ items: entities }); + }); + + it('searches for all entities', async () => { + await renderInTestApp( + + + , + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith(undefined); + }); + + it('updates even if there is not an exact match', async () => { + const { getByLabelText } = await renderInTestApp( + + + , + ); + const input = getByLabelText('Entity'); + + userEvent.type(input, 'squ'); + input.blur(); + + expect(onChange).toHaveBeenCalledWith('squ'); + }); + }); + + describe('with allowedKinds', () => { + beforeEach(() => { + uiSchema = { 'ui:options': { allowedKinds: ['User'] } }; + props = { + onChange, + schema, + required, + uiSchema, + rawErrors, + formData, + } as unknown as FieldProps; + + catalogApi.getEntities.mockResolvedValue({ items: entities }); + }); + + it('searches for users and groups', async () => { + await renderInTestApp( + + + , + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: { + kind: ['User'], + }, + }); + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx new file mode 100644 index 0000000000..b73158ac60 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -0,0 +1,86 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import { + catalogApiRef, + formatEntityRefTitle, + useEntityOwnership, +} from '@backstage/plugin-catalog-react'; +import { TextField } from '@material-ui/core'; +import FormControl from '@material-ui/core/FormControl'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import { FieldProps } from '@rjsf/core'; +import React from 'react'; +import { useAsync } from 'react-use'; + +export const OwnedEntityPicker = ({ + onChange, + schema: { title = 'Entity', description = 'An entity from the catalog' }, + required, + uiSchema, + rawErrors, + formData, + idSchema, +}: FieldProps) => { + const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[]; + const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined; + const catalogApi = useApi(catalogApiRef); + const { isOwnedEntity } = useEntityOwnership(); + + const { value: entities, loading } = useAsync(() => + catalogApi.getEntities( + allowedKinds ? { filter: { kind: allowedKinds } } : undefined, + ), + ); + + const entityRefs = entities?.items + .map(e => + isOwnedEntity(e) ? formatEntityRefTitle(e, { defaultKind }) : null, + ) + .filter(n => n); + + const onSelect = (_: any, value: string | null) => { + onChange(value || ''); + }; + return ( + 0 && !formData} + > + ( + + )} + /> + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts new file mode 100644 index 0000000000..7cf5add6eb --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { OwnedEntityPicker } from './OwnedEntityPicker'; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index 5adc3d3141..299470e220 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -18,3 +18,4 @@ export * from './EntityPicker'; export * from './OwnerPicker'; export * from './RepoUrlPicker'; export * from './TextValuePicker'; +export * from './OwnedEntityPicker'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index be934546b3..12a29809e0 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -24,6 +24,7 @@ import { RepoUrlPicker, } from '../components/fields/RepoUrlPicker'; import { FieldExtensionOptions } from './types'; +import { OwnedEntityPicker } from '../components/fields/OwnedEntityPicker'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [ { @@ -44,4 +45,8 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [ component: OwnerPicker, name: 'OwnerPicker', }, + { + component: OwnedEntityPicker, + name: 'OwnedEntityPicker', + }, ]; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 0180c24b90..dfbd2af296 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -31,6 +31,7 @@ export { EntityPickerFieldExtension, EntityNamePickerFieldExtension, OwnerPickerFieldExtension, + OwnedEntityPickerFieldExtension, RepoUrlPickerFieldExtension, ScaffolderPage, scaffolderPlugin as plugin, @@ -42,6 +43,7 @@ export { OwnerPicker, RepoUrlPicker, TextValuePicker, + OwnedEntityPicker, } from './components/fields'; export { FavouriteTemplate } from './components/FavouriteTemplate'; export { TemplateList } from './components/TemplateList'; diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts index b6ef0ebe17..95cad50eba 100644 --- a/plugins/scaffolder/src/plugin.ts +++ b/plugins/scaffolder/src/plugin.ts @@ -35,6 +35,7 @@ import { discoveryApiRef, identityApiRef, } from '@backstage/core-plugin-api'; +import { OwnedEntityPicker } from './components/fields/OwnedEntityPicker'; export const scaffolderPlugin = createPlugin({ id: 'scaffolder', @@ -95,3 +96,10 @@ export const ScaffolderPage = scaffolderPlugin.provide( mountPoint: rootRouteRef, }), ); + +export const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide( + createScaffolderFieldExtension({ + component: OwnedEntityPicker, + name: 'OwnedEntityPicker', + }), +); From 121787e87ebd37d6ed218bf129399cb6c7573366 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Fri, 10 Dec 2021 15:47:07 +0530 Subject: [PATCH 2/7] added api report Signed-off-by: mufaddal motiwala --- plugins/scaffolder/api-report.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 73fd8fae72..45419e82eb 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -96,6 +96,24 @@ export type FieldExtensionOptions = { validation?: CustomFieldValidator; }; +// Warning: (ae-missing-release-tag) "OwnedEntityPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const OwnedEntityPicker: ({ + onChange, + schema: { title, description }, + required, + uiSchema, + rawErrors, + formData, + idSchema, +}: FieldProps) => JSX.Element; + +// Warning: (ae-missing-release-tag) "OwnedEntityPickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const OwnedEntityPickerFieldExtension: () => null; + // Warning: (ae-missing-release-tag) "OwnerPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) From 88bd7ef966ede89bffde162343a886499b759f85 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Mon, 13 Dec 2021 11:30:57 +0530 Subject: [PATCH 3/7] add a function for fetching user owned entities Signed-off-by: mufaddal motiwala --- .../OwnedEntityPicker/useOwnedEntities.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts new file mode 100644 index 0000000000..ecdfc5c90f --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts @@ -0,0 +1,60 @@ +/* + * 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 { + catalogApiRef, + loadCatalogOwnerRefs, + loadIdentityOwnerRefs, +} from '@backstage/plugin-catalog-react'; +import { identityApiRef, useApi } from '@backstage/core-plugin-api'; +import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { CatalogListResponse } from '@backstage/catalog-client'; +import { useAsync } from 'react-use'; +import { useMemo } from 'react'; + +export function useOwnedEntities(allowedKinds?: string[]): { + loading: boolean; + ownedEntities: CatalogListResponse | undefined; +} { + const identityApi = useApi(identityApiRef); + const catalogApi = useApi(catalogApiRef); + + const { loading, value: refs } = useAsync(async () => { + const identityRefs = await loadIdentityOwnerRefs(identityApi); + const catalogRefs = await loadCatalogOwnerRefs(catalogApi, identityRefs); + const catalogs = await catalogApi.getEntities( + allowedKinds + ? { + filter: { + kind: allowedKinds, + [`relations.${RELATION_OWNED_BY}`]: + [...identityRefs, ...catalogRefs] || [], + }, + } + : { + filter: { + [`relations.${RELATION_OWNED_BY}`]: + [...identityRefs, ...catalogRefs] || [], + }, + }, + ); + return catalogs; + }, []); + const ownedEntities = useMemo(() => { + return refs; + }, [refs]); + + return useMemo(() => ({ loading, ownedEntities }), [loading, ownedEntities]); +} From c0154e444b1bd27ebe46e20d367101d5655aec57 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Mon, 13 Dec 2021 11:31:23 +0530 Subject: [PATCH 4/7] change API for fetching user owned entities Signed-off-by: mufaddal motiwala --- .../OwnedEntityPicker/OwnedEntityPicker.tsx | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index b73158ac60..06b637a79c 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -13,18 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useApi } from '@backstage/core-plugin-api'; -import { - catalogApiRef, - formatEntityRefTitle, - useEntityOwnership, -} from '@backstage/plugin-catalog-react'; +import { formatEntityRefTitle } from '@backstage/plugin-catalog-react'; import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { FieldProps } from '@rjsf/core'; import React from 'react'; -import { useAsync } from 'react-use'; +import { useOwnedEntities } from './useOwnedEntities'; export const OwnedEntityPicker = ({ onChange, @@ -37,24 +32,16 @@ export const OwnedEntityPicker = ({ }: FieldProps) => { const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[]; const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined; - const catalogApi = useApi(catalogApiRef); - const { isOwnedEntity } = useEntityOwnership(); + const { ownedEntities, loading } = useOwnedEntities(allowedKinds); - const { value: entities, loading } = useAsync(() => - catalogApi.getEntities( - allowedKinds ? { filter: { kind: allowedKinds } } : undefined, - ), - ); - - const entityRefs = entities?.items - .map(e => - isOwnedEntity(e) ? formatEntityRefTitle(e, { defaultKind }) : null, - ) + const entityRefs = ownedEntities?.items + .map(e => formatEntityRefTitle(e, { defaultKind })) .filter(n => n); const onSelect = (_: any, value: string | null) => { onChange(value || ''); }; + return ( Date: Tue, 14 Dec 2021 23:45:33 +0530 Subject: [PATCH 5/7] add useOwnedEntites to catalog-react Signed-off-by: mufaddal motiwala --- .changeset/eleven-baboons-sparkle.md | 5 +++++ plugins/catalog-react/api-report.md | 7 +++++++ plugins/catalog-react/src/hooks/index.ts | 1 + .../src/hooks}/useOwnedEntities.ts | 15 +++++++++++++-- .../OwnedEntityPicker/OwnedEntityPicker.tsx | 6 ++++-- 5 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 .changeset/eleven-baboons-sparkle.md rename plugins/{scaffolder/src/components/fields/OwnedEntityPicker => catalog-react/src/hooks}/useOwnedEntities.ts (82%) diff --git a/.changeset/eleven-baboons-sparkle.md b/.changeset/eleven-baboons-sparkle.md new file mode 100644 index 0000000000..7dba4792bc --- /dev/null +++ b/.changeset/eleven-baboons-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': minor +--- + +added useOwnedEntities hook to get the list of entities of the logged-in user diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index c4aa254226..ef469e3b02 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -9,6 +9,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { AsyncState } from 'react-use/lib/useAsync'; import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client'; import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogListResponse } from '@backstage/catalog-client'; import { ComponentEntity } from '@backstage/catalog-model'; import { ComponentProps } from 'react'; import { Context } from 'react'; @@ -847,6 +848,12 @@ export function useEntityOwnership(): { // @public export function useEntityTypeFilter(): EntityTypeReturn; +// @public +export function useOwnedEntities(allowedKinds?: string[]): { + loading: boolean; + ownedEntities: CatalogListResponse | undefined; +}; + // Warning: (ae-missing-release-tag) "useOwnUser" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/plugins/catalog-react/src/hooks/index.ts b/plugins/catalog-react/src/hooks/index.ts index bbbca3a501..a6684732ce 100644 --- a/plugins/catalog-react/src/hooks/index.ts +++ b/plugins/catalog-react/src/hooks/index.ts @@ -42,3 +42,4 @@ export { useEntityOwnership, loadIdentityOwnerRefs, } from './useEntityOwnership'; +export { useOwnedEntities } from './useOwnedEntities'; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts b/plugins/catalog-react/src/hooks/useOwnedEntities.ts similarity index 82% rename from plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts rename to plugins/catalog-react/src/hooks/useOwnedEntities.ts index ecdfc5c90f..f9191364cb 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts +++ b/plugins/catalog-react/src/hooks/useOwnedEntities.ts @@ -13,17 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { catalogApiRef } from './../api'; import { - catalogApiRef, loadCatalogOwnerRefs, loadIdentityOwnerRefs, -} from '@backstage/plugin-catalog-react'; +} from './useEntityOwnership'; import { identityApiRef, useApi } from '@backstage/core-plugin-api'; import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; import { CatalogListResponse } from '@backstage/catalog-client'; import { useAsync } from 'react-use'; import { useMemo } from 'react'; +/** + * Takes the relevant parts of the Backstage identity, and translates them into + * a list of entities which are owned by the user. Takes an optional parameter + * to filter the entities based on allowedKinds + * + * @public + * + * @param allowedKinds - Array of allowed kinds to filter the entities + * @returns CatalogListResponse + */ export function useOwnedEntities(allowedKinds?: string[]): { loading: boolean; ownedEntities: CatalogListResponse | undefined; @@ -52,6 +62,7 @@ export function useOwnedEntities(allowedKinds?: string[]): { ); return catalogs; }, []); + const ownedEntities = useMemo(() => { return refs; }, [refs]); diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index 06b637a79c..3c2fc2b495 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { formatEntityRefTitle } from '@backstage/plugin-catalog-react'; +import { + formatEntityRefTitle, + useOwnedEntities, +} from '@backstage/plugin-catalog-react'; import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { FieldProps } from '@rjsf/core'; import React from 'react'; -import { useOwnedEntities } from './useOwnedEntities'; export const OwnedEntityPicker = ({ onChange, From 5ad82708fd1dd7b38ae8bc4b18a7792bc3d524df Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Wed, 15 Dec 2021 16:28:26 +0530 Subject: [PATCH 6/7] changed minor to patch Signed-off-by: mufaddal motiwala --- .changeset/eleven-baboons-sparkle.md | 2 +- .changeset/perfect-buses-collect.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/eleven-baboons-sparkle.md b/.changeset/eleven-baboons-sparkle.md index 7dba4792bc..e8c28af482 100644 --- a/.changeset/eleven-baboons-sparkle.md +++ b/.changeset/eleven-baboons-sparkle.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-catalog-react': minor +'@backstage/plugin-catalog-react': patch --- added useOwnedEntities hook to get the list of entities of the logged-in user diff --git a/.changeset/perfect-buses-collect.md b/.changeset/perfect-buses-collect.md index cd7b8164cf..e0df504087 100644 --- a/.changeset/perfect-buses-collect.md +++ b/.changeset/perfect-buses-collect.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder': minor +'@backstage/plugin-scaffolder': patch --- Added OwnedEntityPicker field which displays Owned Entities in options From 8d9ab4d7c1da0a8ea123fbdc92fe8fc74340cc57 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Wed, 15 Dec 2021 20:44:53 +0530 Subject: [PATCH 7/7] removed test case Signed-off-by: mufaddal motiwala --- .../OwnedEntityPicker.test.tsx | 137 ------------------ 1 file changed, 137 deletions(-) delete mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx deleted file mode 100644 index ef6fc1b648..0000000000 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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 { Entity } from '@backstage/catalog-model'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; -import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { FieldProps } from '@rjsf/core'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; -import { OwnedEntityPicker } from './OwnedEntityPicker'; - -const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ - apiVersion: 'backstage.io/v1beta1', - kind, - metadata: { namespace, name }, -}); - -describe('', () => { - let entities: Entity[]; - const onChange = jest.fn(); - const schema = {}; - const required = false; - let uiSchema: { - 'ui:options': { allowedKinds?: string[]; defaultKind?: string }; - }; - const rawErrors: string[] = []; - const formData = undefined; - - let props: FieldProps; - - const catalogApi: jest.Mocked = { - getLocationById: jest.fn(), - getEntityByName: jest.fn(), - getEntities: jest.fn(async () => ({ items: entities })), - addLocation: jest.fn(), - getLocationByEntity: jest.fn(), - removeEntityByUid: jest.fn(), - } as any; - let Wrapper: React.ComponentType; - - beforeEach(() => { - entities = [ - makeEntity('Group', 'default', 'team-a'), - makeEntity('Group', 'default', 'squad-b'), - ]; - - Wrapper = ({ children }: { children?: React.ReactNode }) => ( - - {children} - - ); - }); - - afterEach(() => jest.resetAllMocks()); - - describe('without allowedKinds', () => { - beforeEach(() => { - uiSchema = { 'ui:options': {} }; - props = { - onChange, - schema, - required, - uiSchema, - rawErrors, - formData, - } as unknown as FieldProps; - - catalogApi.getEntities.mockResolvedValue({ items: entities }); - }); - - it('searches for all entities', async () => { - await renderInTestApp( - - - , - ); - - expect(catalogApi.getEntities).toHaveBeenCalledWith(undefined); - }); - - it('updates even if there is not an exact match', async () => { - const { getByLabelText } = await renderInTestApp( - - - , - ); - const input = getByLabelText('Entity'); - - userEvent.type(input, 'squ'); - input.blur(); - - expect(onChange).toHaveBeenCalledWith('squ'); - }); - }); - - describe('with allowedKinds', () => { - beforeEach(() => { - uiSchema = { 'ui:options': { allowedKinds: ['User'] } }; - props = { - onChange, - schema, - required, - uiSchema, - rawErrors, - formData, - } as unknown as FieldProps; - - catalogApi.getEntities.mockResolvedValue({ items: entities }); - }); - - it('searches for users and groups', async () => { - await renderInTestApp( - - - , - ); - - expect(catalogApi.getEntities).toHaveBeenCalledWith({ - filter: { - kind: ['User'], - }, - }); - }); - }); -});