diff --git a/CHANGELOG.md b/CHANGELOG.md index 72d8836c49..c4d8267cbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ should change the heading of the (upcoming) version to include a major version b ## @rjsf/core - Feature for ui:submitButtonOptions on the submit button for forms (https://github.com/rjsf-team/react-jsonschema-form/pull/2640) - Fix `ui:orderable` and `ui:removable` in arrays (#2797) +- - Fix for nested allOf blocks with multiple if/then/else statements failing to render correctly (https://github.com/rjsf-team/react-jsonschema-form/pull/2839) ## Dev / docs / playground - Enable ui options in playground, to demonstrate submit button options (https://github.com/rjsf-team/react-jsonschema-form/pull/2640) diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index c313515eaa..28063c7b57 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -767,6 +767,33 @@ export function retrieveSchema(schema, rootSchema = {}, formData = {}) { return resolveCondition(schema, rootSchema, formData); } + // For each level of the dependency, we need to recursively determine the appropriate resolved schema given the current state of formData. + // Otherwise, nested allOf subschemas will not be correctly displayed. + if (resolvedSchema.properties) { + const properties = {}; + + Object.entries(resolvedSchema.properties).forEach(entries => { + const propName = entries[0]; + const propSchema = entries[1]; + const rawPropData = formData && formData[propName]; + const propData = isObject(rawPropData) ? rawPropData : {}; + const resolvedPropSchema = retrieveSchema( + propSchema, + rootSchema, + propData + ); + + properties[propName] = resolvedPropSchema; + + if ( + propSchema !== resolvedPropSchema && + resolvedSchema.properties !== properties + ) { + resolvedSchema = { ...resolvedSchema, properties }; + } + }); + } + if ("allOf" in schema) { try { resolvedSchema = mergeAllOf({ diff --git a/packages/core/test/utils_test.js b/packages/core/test/utils_test.js index a9854c2147..005e287731 100644 --- a/packages/core/test/utils_test.js +++ b/packages/core/test/utils_test.js @@ -2540,6 +2540,151 @@ describe("utils", () => { required: ["animal", "food"], }); }); + it("should resolve multiple conditions in nested allOf blocks", () => { + const schema = { + type: "object", + properties: { + Animal: { + default: "Cat", + enum: ["Cat", "Dog"], + title: "Animal", + type: "string", + }, + }, + allOf: [ + { + if: { + required: ["Animal"], + properties: { + Animal: { + const: "Cat", + }, + }, + }, + then: { + properties: { + Tail: { + default: "Long", + enum: ["Long", "Short", "None"], + title: "Tail length", + type: "string", + }, + }, + required: ["Tail"], + }, + }, + { + if: { + required: ["Animal"], + properties: { + Animal: { + const: "Dog", + }, + }, + }, + then: { + properties: { + Breed: { + title: "Breed", + properties: { + BreedName: { + default: "Alsatian", + enum: ["Alsatian", "Dalmation"], + title: "Breed name", + type: "string", + }, + }, + allOf: [ + { + if: { + required: ["BreedName"], + properties: { + BreedName: { + const: "Alsatian", + }, + }, + }, + then: { + properties: { + Fur: { + default: "brown", + enum: ["black", "brown"], + title: "Fur", + type: "string", + }, + }, + required: ["Fur"], + }, + }, + { + if: { + required: ["BreedName"], + properties: { + BreedName: { + const: "Dalmation", + }, + }, + }, + then: { + properties: { + Spots: { + default: "small", + enum: ["large", "small"], + title: "Spots", + type: "string", + }, + }, + required: ["Spots"], + }, + }, + ], + required: ["BreedName"], + }, + }, + }, + }, + ], + required: ["Animal"], + }; + const definitions = {}; + const formData = { + Animal: "Dog", + Breed: { + BreedName: "Dalmation", + }, + }; + + expect(retrieveSchema(schema, { definitions }, formData)).eql({ + type: "object", + properties: { + Animal: { + default: "Cat", + enum: ["Cat", "Dog"], + title: "Animal", + type: "string", + }, + Breed: { + properties: { + BreedName: { + default: "Alsatian", + enum: ["Alsatian", "Dalmation"], + title: "Breed name", + type: "string", + }, + Spots: { + default: "small", + enum: ["large", "small"], + title: "Spots", + type: "string", + }, + }, + required: ["BreedName", "Spots"], + title: "Breed", + }, + }, + required: ["Animal"], + }); + }); it("should resolve $ref", () => { const schema = { type: "object",