Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(@rjsf/core): Nested allOf blocks with multiple if/then/else statements fail to render correctly #2839

Merged

Conversation

stuartwilkes
Copy link
Contributor

@stuartwilkes stuartwilkes commented Apr 29, 2022

Reasons for making this change

As described here, if an allOf block is present at multiple levels within a schema, and the nested allOf block implements multiple if/then/else statements, the nested dependency is not correctly rendered.

This PR takes the patch provided in the linked thread and implements it within the library to fix the issue as described. It also provides a test for the issue.

The current behaviour can be seen as failing in this playground

Checklist

  • I'm updating documentation
  • I'm adding or updating code
    • I've added and/or updated tests. I've run npm run test:update to update snapshots, if needed.
    • I've updated docs if needed
    • I've updated the changelog with a description of the PR
  • I'm adding a new feature
    • I've updated the playground with an example use of the feature

@stuartwilkes stuartwilkes changed the title a Nested allOf blocks with multiple if/then/else statements fail to render correctly Apr 29, 2022
@stuartwilkes stuartwilkes changed the title Nested allOf blocks with multiple if/then/else statements fail to render correctly fix(@rjsf/core): Nested allOf blocks with multiple if/then/else statements fail to render correctly Apr 29, 2022
if (
propSchema !== resolvedPropSchema &&
resolvedSchema.properties !== properties &&
properties !== null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think properties !== null check is redundand, isn't?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, you're right - this was a holdover from when I was addressing an issue that caused the patch to fail this test

@@ -767,6 +767,31 @@ export function retrieveSchema(schema, rootSchema = {}, formData = {}) {
return resolveCondition(schema, rootSchema, formData);
}

if (resolvedSchema.properties) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment clarifying why we have to do this new step, and what exactly we're doing? It's hard to follow exactly what's going on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like "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"?

@AlimovSV wrote the original code here, so may want to word this more appropriately?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finding the right words is not my best side :) I like your description

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickgros Hopefully this comment resolves your query...


if (
propSchema !== resolvedPropSchema &&
resolvedSchema.properties !== properties
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like properties will always be a different object than resolvedSchema.properties, since you declared a new properties object on line 771. So I think this would always be true.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is possible ONLY when the recursive call of retrieveSchema returns a modified schema for the specific property. Otherwise resolvedSchema will be returned unchanged.

Copy link
Contributor

@nickgros nickgros May 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I follow that retrieveSchema could return the value referenced by propSchema under certain conditions. I think we need a deep equality check for the second condition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of this check is to reduce creation of shallow copy for the retrieved schemas. So if a schema isn't computed schema (doesn't have any if/then/else) it will be returned unchanged (and reference equality check will be enough for this condition)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if I'm being unclear, but essentially I don't think you will ever have referential equality between resolvedSchema.properties and properties because properties is always a new object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, let me explain. Before loop we initialize properties variable as a new object, you right. And during the iteration (first time when we meet propSchema !== resolvedPropSchema) the condition resolvedSchema.properties !== properties will be truthy, you right too. But after we make a shallow copy of the schema with new properties container resolvedSchema = { ...resolvedSchema, properties }; during any next iteration resolvedSchema.properties !== properties will be falsy and we will not make shallow copy. The bonuse is: when resolvedSchema doesn't contain properties with computed schema we do not make shallow copy at all and return the unmodified object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ I finally see it now! Thank you for this explanation (and for bearing with me)!

Copy link
Contributor

@nickgros nickgros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me if tests are passing. I'd like another set of eyes since our schema resolution utils are so complicated

@nickgros nickgros merged commit 36ee173 into rjsf-team:master May 6, 2022
@AlimovSV AlimovSV mentioned this pull request Jul 12, 2022
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants