diff --git a/plugins/scaffolder-backend/sample-templates/remote-templates.yaml b/plugins/scaffolder-backend/sample-templates/remote-templates.yaml index a812c9ce52..8959676d60 100644 --- a/plugins/scaffolder-backend/sample-templates/remote-templates.yaml +++ b/plugins/scaffolder-backend/sample-templates/remote-templates.yaml @@ -11,3 +11,4 @@ spec: - https://github.com/backstage/software-templates/blob/main/scaffolder-templates/pull-request/template.yaml - https://github.com/backstage/software-templates/blob/main/scaffolder-templates/react-ssr-template/template.yaml - https://github.com/backstage/software-templates/blob/main/scaffolder-templates/springboot-grpc-template/template.yaml + - https://github.com/Parsifal-M/backstage-testing-grounds/blob/main/templates/template.yaml diff --git a/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/OwnedGroupsPicker.test.tsx b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/OwnedGroupsPicker.test.tsx new file mode 100644 index 0000000000..eb2f165350 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/OwnedGroupsPicker.test.tsx @@ -0,0 +1,15 @@ +/* + * 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. + */ diff --git a/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/OwnedGroupsPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/OwnedGroupsPicker.tsx new file mode 100644 index 0000000000..5123adff84 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/OwnedGroupsPicker.tsx @@ -0,0 +1,81 @@ +/* + * 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 { EntityPicker } from '../EntityPicker/EntityPicker'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import { OwnedGroupsPickerProps } from './schema'; +import { TextField } from '@material-ui/core'; + +export { OwnedGroupsPickerSchema } from './schema'; + +export const OwnedGroupsPicker = (props: OwnedGroupsPickerProps) => { + const { + schema: { title = 'Group', description = 'A group from the catalog' }, + uiSchema, + required, + } = props; + + const identityApi = useApi(identityApiRef); + const { loading, value: identityRefs } = useAsync(async () => { + const identity = await identityApi.getBackstageIdentity(); + return identity.userEntityRef; + }); + + const catalogFilter = { + kind: 'group', + ['relations.hasMember']: identityRefs || [], + }; + + const groupUiSchema = { + ...uiSchema, + 'ui:options': { + catalogFilter, + defaultKind: 'group', + }, + }; + + if (loading) { + return ( + ( + + )} + options={[]} + /> + ); + } + + return ( + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/index.ts new file mode 100644 index 0000000000..673213ae65 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export { + OwnedGroupsPickerFieldSchema, + type OwnedGroupsPickerUiOptions, +} from './schema'; diff --git a/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/schema.ts b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/schema.ts new file mode 100644 index 0000000000..6f771db5e6 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedGroupsPicker/schema.ts @@ -0,0 +1,47 @@ +/* + * 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 { z } from 'zod'; +import { makeFieldSchemaFromZod } from '../utils'; +import { entityQueryFilterExpressionSchema } from '../EntityPicker/schema'; + +export const OwnedGroupsPickerFieldSchema = makeFieldSchemaFromZod( + z.string(), + z.object({ + defaultKind: z + .string() + .optional() + .describe( + 'The default entity kind. Options of this kind will not be prefixed.', + ), + defaultNamespace: z + .union([z.string(), z.literal(false)]) + .optional() + .describe( + 'The default namespace. Options with this namespace will not be prefixed.', + ), + catalogFilter: z + .array(entityQueryFilterExpressionSchema) + .or(entityQueryFilterExpressionSchema) + .optional() + .describe('List of key-value filter expression for entities'), + }), +); + +export type OwnedGroupsPickerUiOptions = + typeof OwnedGroupsPickerFieldSchema.uiOptionsType; +export type OwnedGroupsPickerProps = typeof OwnedGroupsPickerFieldSchema.type; +export const OwnedGroupsPickerSchema = OwnedGroupsPickerFieldSchema.schema; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index 8d86f601ce..aeab13bd12 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -18,4 +18,5 @@ export * from './OwnerPicker'; export * from './RepoUrlPicker'; export * from './OwnedEntityPicker'; export * from './EntityTagsPicker'; +export * from './OwnedGroupsPicker'; export { type FieldSchema, makeFieldSchemaFromZod } from './utils'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index c6ab5276d0..a6984e5a49 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -39,6 +39,10 @@ import { OwnedEntityPicker, OwnedEntityPickerSchema, } from '../components/fields/OwnedEntityPicker/OwnedEntityPicker'; +import { + OwnedGroupsPicker, + OwnedGroupsPickerSchema, +} from '../components/fields/OwnedGroupsPicker/OwnedGroupsPicker'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ { @@ -73,4 +77,9 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS = [ name: 'OwnedEntityPicker', schema: OwnedEntityPickerSchema, }, + { + component: OwnedGroupsPicker, + name: 'OwnedGroupsPicker', + schema: OwnedGroupsPickerSchema, + }, ]; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index bc56629a2c..ff1b0c42f5 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -27,6 +27,7 @@ export { EntityTagsPickerFieldExtension, OwnerPickerFieldExtension, OwnedEntityPickerFieldExtension, + OwnedGroupsFieldExtension, RepoUrlPickerFieldExtension, ScaffolderPage, scaffolderPlugin, diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index dfe87a3780..3b921f91f0 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -64,6 +64,10 @@ import { actionsRouteRef, editRouteRef, } from './routes'; +import { + OwnedGroupsPicker, + OwnedGroupsPickerSchema, +} from './components/fields/OwnedGroupsPicker/OwnedGroupsPicker'; /** * The main plugin export for the scaffolder. @@ -158,6 +162,19 @@ export const OwnerPickerFieldExtension = scaffolderPlugin.provide( }), ); +/** + * A field extension for picking users and groups out of the Catalog. + * + * @public + */ +export const OwnedGroupsFieldExtension = scaffolderPlugin.provide( + createScaffolderFieldExtension({ + component: OwnedGroupsPicker, + name: 'OwnedGroupsPicker', + schema: OwnedGroupsPickerSchema, + }), +); + /** * The Router and main entrypoint to the Scaffolder plugin. *