diff --git a/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/GroupsImPartOfPicker.tsx b/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/GroupsImPartOfPicker.tsx deleted file mode 100644 index eb3d2e423e..0000000000 --- a/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/GroupsImPartOfPicker.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { identityApiRef, useApi } from '@backstage/core-plugin-api'; -import useAsync from 'react-use/lib/useAsync'; -import { - TextField, - MenuItem, - Select, - FormControl, - InputLabel, -} from '@material-ui/core'; -import { - GroupsImPartOfPickerProps, - GroupsImPartOfPickerSchema, -} from './schema'; - -export { GroupsImPartOfPickerSchema }; - -export const GroupsImPartOfPicker = (props: GroupsImPartOfPickerProps) => { - const { - schema: { title = 'Group', description = 'A group you are part of' }, - required, - } = props; - - const identityApi = useApi(identityApiRef); - const { loading, value: identityRefs } = useAsync(async () => { - const identity = await identityApi.getBackstageIdentity(); - return identity.ownershipEntityRefs; - }); - - const [selectedGroup, setSelectedGroup] = React.useState(''); - - const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { - setSelectedGroup(event.target.value as string); - }; - - if (loading) { - return ( - - ); - } - - return ( - - {title} - - - ); -}; diff --git a/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/OwnershipEntityRefPicker.tsx b/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/OwnershipEntityRefPicker.tsx new file mode 100644 index 0000000000..80a870e1ed --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/OwnershipEntityRefPicker.tsx @@ -0,0 +1,93 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useEffect, useState } from 'react'; +import { identityApiRef, useApi } from '@backstage/core-plugin-api'; +import { TextField, FormControl } from '@material-ui/core'; +import { + OwnershipEntityRefPickerProps, + OwnershipEntityRefPickerSchema, +} from './schema'; +import { Autocomplete } from '@material-ui/lab'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { NotFoundError } from '@backstage/errors'; + +export { OwnershipEntityRefPickerSchema }; + +export const OwnershipEntityRefPicker = ( + props: OwnershipEntityRefPickerProps, +) => { + const { + schema: { title = 'Group', description = 'A group you are part of' }, + required, + rawErrors, + formData, + } = props; + + const identityApi = useApi(identityApiRef); + const catalogApi = useApi(catalogApiRef); + const [groups, setGroups] = useState([]); + const [selectedGroup, setSelectedGroup] = useState(''); + + useEffect(() => { + const fetchUserGroups = async () => { + const identity = await identityApi.getBackstageIdentity(); + const userIdentity = identity.ownershipEntityRefs; + + if (!userIdentity) { + throw new NotFoundError('No ownership entity refs found'); + } + + const userOwnedGroups = await catalogApi.getEntities({ + filter: { + kind: ['Group'], + 'relations.hasMember': userIdentity, + }, + }); + const groupValues = userOwnedGroups.items.map(item => item.metadata.name); + setGroups(groupValues); + }; + + fetchUserGroups(); + }, [identityApi, catalogApi]); + + return ( + 0 && !formData} + > + setSelectedGroup(value || '')} + getOptionLabel={group => group} + renderInput={params => ( + + )} + /> + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/index.ts similarity index 89% rename from plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/index.ts rename to plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/index.ts index 960f5de5ef..2e744ef6e9 100644 --- a/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/index.ts +++ b/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/index.ts @@ -15,6 +15,6 @@ */ export { - GroupsImPartOfPickerSchema, - type GroupsImPartOfPickerUiOptions, + OwnershipEntityRefPickerSchema, + type OwnershipEntityRefPickerUiOptions, } from './schema'; diff --git a/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/schema.ts b/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/schema.ts similarity index 68% rename from plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/schema.ts rename to plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/schema.ts index 839aa349a4..9236113356 100644 --- a/plugins/scaffolder/src/components/fields/GroupsImPartOfPicker/schema.ts +++ b/plugins/scaffolder/src/components/fields/OwnershipEntityRefPicker/schema.ts @@ -17,7 +17,7 @@ import { z } from 'zod'; import { makeFieldSchemaFromZod } from '../utils'; -export const GroupsImPartOfPickerFieldSchema = makeFieldSchemaFromZod( +export const OwnershipEntityRefPickerFieldSchema = makeFieldSchemaFromZod( z.string(), z.object({ title: z.string().optional(), @@ -25,9 +25,9 @@ export const GroupsImPartOfPickerFieldSchema = makeFieldSchemaFromZod( }), ); -export type GroupsImPartOfPickerUiOptions = - typeof GroupsImPartOfPickerFieldSchema.uiOptionsType; -export type GroupsImPartOfPickerProps = - typeof GroupsImPartOfPickerFieldSchema.type; -export const GroupsImPartOfPickerSchema = - GroupsImPartOfPickerFieldSchema.schema; +export type OwnershipEntityRefPickerUiOptions = + typeof OwnershipEntityRefPickerFieldSchema.uiOptionsType; +export type OwnershipEntityRefPickerProps = + typeof OwnershipEntityRefPickerFieldSchema.type; +export const OwnershipEntityRefPickerSchema = + OwnershipEntityRefPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index c9f23a00b7..67bb126ede 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -18,5 +18,5 @@ export * from './OwnerPicker'; export * from './RepoUrlPicker'; export * from './OwnedEntityPicker'; export * from './EntityTagsPicker'; -export * from './GroupsImPartOfPicker'; +export * from './OwnershipEntityRefPicker'; export { type FieldSchema, makeFieldSchemaFromZod } from './utils'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 9c027610a5..dae89266d0 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -40,9 +40,9 @@ import { OwnedEntityPickerSchema, } from '../components/fields/OwnedEntityPicker/OwnedEntityPicker'; import { - GroupsImPartOfPicker, - GroupsImPartOfPickerSchema, -} from '../components/fields/GroupsImPartOfPicker/GroupsImPartOfPicker'; + OwnershipEntityRefPicker, + OwnershipEntityRefPickerSchema, +} from '../components/fields/OwnershipEntityRefPicker/OwnershipEntityRefPicker'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { @@ -78,8 +78,8 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ schema: OwnedEntityPickerSchema, }, { - component: GroupsImPartOfPicker, - name: 'GroupsImPartOfPicker', - schema: GroupsImPartOfPickerSchema, + component: OwnershipEntityRefPicker, + name: 'OwnershipEntityRefPicker', + schema: OwnershipEntityRefPickerSchema, }, ]; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 5817c4046f..7ec9717bdc 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -27,7 +27,7 @@ export { EntityTagsPickerFieldExtension, OwnerPickerFieldExtension, OwnedEntityPickerFieldExtension, - GroupsImPartOfPickerFieldExtension, + OwnershipEntityRefPickerFieldExtension, RepoUrlPickerFieldExtension, ScaffolderPage, scaffolderPlugin, diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index 6e43959ea0..b190cf982a 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -65,9 +65,9 @@ import { editRouteRef, } from './routes'; import { - GroupsImPartOfPicker, - GroupsImPartOfPickerSchema, -} from './components/fields/GroupsImPartOfPicker/GroupsImPartOfPicker'; + OwnershipEntityRefPicker, + OwnershipEntityRefPickerSchema, +} from './components/fields/OwnershipEntityRefPicker/OwnershipEntityRefPicker'; /** * The main plugin export for the scaffolder. @@ -167,11 +167,11 @@ export const OwnerPickerFieldExtension = scaffolderPlugin.provide( * * @public */ -export const GroupsImPartOfPickerFieldExtension = scaffolderPlugin.provide( +export const OwnershipEntityRefPickerFieldExtension = scaffolderPlugin.provide( createScaffolderFieldExtension({ - component: GroupsImPartOfPicker, - name: 'GroupsImPartOfPicker', - schema: GroupsImPartOfPickerSchema, + component: OwnershipEntityRefPicker, + name: 'OwnershipEntityRefPicker', + schema: OwnershipEntityRefPickerSchema, }), );