diff --git a/.changeset/tough-planes-jump.md b/.changeset/tough-planes-jump.md new file mode 100644 index 0000000000..ebbec65159 --- /dev/null +++ b/.changeset/tough-planes-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Support `anyOf`, `oneOf` and `allOf` schemas in the scaffolder template. diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/schema.test.ts b/plugins/scaffolder/src/components/MultistepJsonForm/schema.test.ts index b83725c2bb..64dd705952 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/schema.test.ts +++ b/plugins/scaffolder/src/components/MultistepJsonForm/schema.test.ts @@ -70,4 +70,220 @@ describe('transformSchemaToProps', () => { uiSchema: expectedUiSchema, }); }); + + it('transforms schema with anyOf fields', () => { + const inputSchema = { + type: 'object', + anyOf: [ + { + properties: { + field3: { + type: 'string', + default: 'Value 1', + 'ui:readonly': true, + }, + }, + }, + { + properties: { + field3: { + type: 'string', + default: 'Value 2', + 'ui:readonly': true, + }, + }, + }, + ], + oneOf: [ + { + properties: { + field4: { + type: 'string', + default: 'Value 1', + 'ui:readonly': true, + }, + }, + }, + ], + allOf: [ + { + properties: { + field5: { + type: 'string', + default: 'Value 1', + 'ui:readonly': true, + }, + }, + }, + ], + properties: { + field1: { + type: 'object', + anyOf: [ + { + properties: { + field3: { + type: 'string', + default: 'Value 1', + 'ui:readonly': true, + }, + }, + }, + { + properties: { + field3: { + type: 'string', + default: 'Value 2', + 'ui:readonly': true, + }, + }, + }, + ], + oneOf: [ + { + properties: { + field4: { + type: 'string', + default: 'Value 1', + 'ui:readonly': true, + }, + }, + }, + ], + allOf: [ + { + properties: { + field5: { + type: 'string', + default: 'Value 1', + 'ui:readonly': true, + }, + }, + }, + ], + }, + field2: { + type: 'string', + 'ui:derp': 'xerp', + }, + }, + }; + const expectedSchema = { + type: 'object', + anyOf: [ + { + properties: { + field3: { + type: 'string', + default: 'Value 1', + }, + }, + }, + { + properties: { + field3: { + type: 'string', + default: 'Value 2', + }, + }, + }, + ], + oneOf: [ + { + properties: { + field4: { + type: 'string', + default: 'Value 1', + }, + }, + }, + ], + allOf: [ + { + properties: { + field5: { + type: 'string', + default: 'Value 1', + }, + }, + }, + ], + properties: { + field1: { + type: 'object', + anyOf: [ + { + properties: { + field3: { + type: 'string', + default: 'Value 1', + }, + }, + }, + { + properties: { + field3: { + type: 'string', + default: 'Value 2', + }, + }, + }, + ], + oneOf: [ + { + properties: { + field4: { + type: 'string', + default: 'Value 1', + }, + }, + }, + ], + allOf: [ + { + properties: { + field5: { + type: 'string', + default: 'Value 1', + }, + }, + }, + ], + }, + field2: { + type: 'string', + }, + }, + }; + const expectedUiSchema = { + field3: { + 'ui:readonly': true, + }, + field4: { + 'ui:readonly': true, + }, + field5: { + 'ui:readonly': true, + }, + field1: { + field3: { + 'ui:readonly': true, + }, + field4: { + 'ui:readonly': true, + }, + field5: { + 'ui:readonly': true, + }, + }, + field2: { + 'ui:derp': 'xerp', + }, + }; + + expect(transformSchemaToProps(inputSchema)).toEqual({ + schema: expectedSchema, + uiSchema: expectedUiSchema, + }); + }); }); diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts b/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts index e591589bd8..b4aa3e309d 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts +++ b/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts @@ -26,7 +26,7 @@ function extractUiSchema(schema: JsonObject, uiSchema: JsonObject) { return; } - const { properties } = schema; + const { properties, anyOf, oneOf, allOf } = schema; for (const propName in schema) { if (!schema.hasOwnProperty(propName)) { @@ -39,22 +39,47 @@ function extractUiSchema(schema: JsonObject, uiSchema: JsonObject) { } } - if (!isObject(properties)) { - return; + if (isObject(properties)) { + for (const propName in properties) { + if (!properties.hasOwnProperty(propName)) { + continue; + } + + const schemaNode = properties[propName]; + if (!isObject(schemaNode)) { + continue; + } + const innerUiSchema = {}; + uiSchema[propName] = innerUiSchema; + extractUiSchema(schemaNode, innerUiSchema); + } } - for (const propName in properties) { - if (!properties.hasOwnProperty(propName)) { - continue; + if (Array.isArray(anyOf)) { + for (const schemaNode of anyOf) { + if (!isObject(schemaNode)) { + continue; + } + extractUiSchema(schemaNode, uiSchema); } + } - const schemaNode = properties[propName]; - if (!isObject(schemaNode)) { - continue; + if (Array.isArray(oneOf)) { + for (const schemaNode of oneOf) { + if (!isObject(schemaNode)) { + continue; + } + extractUiSchema(schemaNode, uiSchema); + } + } + + if (Array.isArray(allOf)) { + for (const schemaNode of allOf) { + if (!isObject(schemaNode)) { + continue; + } + extractUiSchema(schemaNode, uiSchema); } - const innerUiSchema = {}; - uiSchema[propName] = innerUiSchema; - extractUiSchema(schemaNode, innerUiSchema); } }