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 => (