diff --git a/.changeset/lovely-toys-wonder.md b/.changeset/lovely-toys-wonder.md new file mode 100644 index 0000000000000..ec3cc2764ccf6 --- /dev/null +++ b/.changeset/lovely-toys-wonder.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +EntityPicker can require an existing entity be selected by disallowing arbitrary values diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx index b7e72e35838ac..3dc609a63b4d1 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx @@ -20,7 +20,7 @@ import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { FieldProps } from '@rjsf/core'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { EntityPicker } from './EntityPicker'; +import { EntityPicker, allowArbitraryValues } from './EntityPicker'; const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ apiVersion: 'backstage.io/v1beta1', @@ -136,3 +136,37 @@ describe('', () => { }); }); }); + +describe('allowArbitraryValues', () => { + describe('without ui:options', () => { + it('defaults to true', () => { + const uiSchema = {}; + const result = allowArbitraryValues(uiSchema); + expect(result).toBe(true); + }); + }); + + describe('without ui:options.allowArbitraryValues', () => { + it('defaults to true', () => { + const uiSchema = { 'ui:options': {} }; + const result = allowArbitraryValues(uiSchema); + expect(result).toBe(true); + }); + }); + + describe('with ui:options.allowArbitraryValues set to true', () => { + it('is true', () => { + const uiSchema = { 'ui:options': { allowArbitraryValues: true } }; + const result = allowArbitraryValues(uiSchema); + expect(result).toBe(true); + }); + }); + + describe('with ui:options.allowArbitraryValues set to false', () => { + it('is false', () => { + const uiSchema = { 'ui:options': { allowArbitraryValues: false } }; + const result = allowArbitraryValues(uiSchema); + expect(result).toBe(false); + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index a8ef524a1376d..f3a599de3ef58 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -21,10 +21,13 @@ import { 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 { FieldProps, UiSchema } from '@rjsf/core'; import React from 'react'; import { useAsync } from 'react-use'; +export const allowArbitraryValues = (uiSchema: UiSchema): boolean => + (uiSchema['ui:options']?.allowArbitraryValues as boolean) ?? true; + export const EntityPicker = ({ onChange, schema: { title = 'Entity', description = 'An entity from the catalog' }, @@ -65,7 +68,7 @@ export const EntityPicker = ({ onChange={onSelect} options={entityRefs || []} autoSelect - freeSolo + freeSolo={allowArbitraryValues(uiSchema)} renderInput={params => (