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
ContextProviderExtension: use spread operator instead of clonedeep #6243
Conversation
… sanitize extension
/kind bug |
I believe you should create a BZ for this |
Until the repo is setup to block without bugzillas, there is no requirement to do that unless you're backporting. |
@@ -45,7 +45,7 @@ export class PluginStore { | |||
this.extensions = _.flatMap( | |||
plugins.map((p) => | |||
p.extensions.map((e, index) => | |||
Object.freeze(augmentExtension(sanitizeExtension(_.cloneDeep(e)), p.name, index)), | |||
Object.freeze(augmentExtension(sanitizeExtension({ ...e }), p.name, index)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The premise of this change makes me uncomfortable. Something is "hoping" for the mutation in order to work. That's a bigger issue we should look to fix at some point (doesn't need to block this fix).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewballantyne @glekner @sahil143
ContextProvider
extensions directly reference React Context.Provider
component via their Provider
property.
According to docs, _.cloneDeep
clones arrays, array buffers, booleans, date objects, maps, numbers, Object objects, regexes, sets, strings, symbols, and typed arrays.
Debugging shows that Context.Provider
component references the Context
object. Since _.cloneDeep
works recursively, this seems to break the link between Context.Provider
and the original Context
object, which explains why it's not updated at runtime.
TL;DR we can use _.clone
instead of _.cloneDeep
or keep using object spread { ...e }
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting 🤔 -- both shallow spreads/clones and deep clones change the object reference ... but something nested within the data is being referenced instead. Object mutations are tricky beasts, as long as we don't get into a practice of doing it, we can take some assumptions here.
I find it odd that we freeze the object (MDN docs), which I'm finding out doesn't actually prevent mutations of nested values 🤔 , so it's mutable after the fact too?
const obj = {
prop: {
value: {
item: 42
}
}
};
Object.freeze(obj);
try {
obj.prop.value.item = 33;
// Throws an error in strict mode
} catch(e) {}
console.log(obj.prop.value.item);
// output: 33
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah doh! I guess I assumed it would be recursive, but it makes sense that it is not. It's freezing the top level object and it's direct prosperities but each property that is an object is a new object that needs to be frozen.
EDIT: which is explained here if I read the whole MDN page lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object mutations are tricky beasts, as long as we don't get into a practice of doing it, we can take some assumptions here.
Right, we currently assume that static plugins won't modify extension objects in any way within their plugin.tsx
module.
I find it odd that we freeze the object (MDN docs), which I'm finding out doesn't actually prevent mutations of nested values , so it's mutable after the fact too?
Yes, Object.freeze
affects only the properties declared directly on that object. So we're basically enforcing that extension's type
, properties
and flags
(plus computed ones pluginName
and uid
) cannot be changed.
Maybe we should do a deep freeze instead of just the regular one. That way, even if a plugin tries to modify some nested property like e.properties.foo
it would stay the same. We can do this as part of #6101.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, wonder if we should just fix the mutations within this file @vojtechszocs for a little QoL... we don't need to do it part of this PR though.
Replace with spreads against the original object... it's still a mutation, but it's a smaller scoped one? Again, not sure if this is anything more than academic heh.
I can see guided tour in developer perspective with this fix. |
/lgtm |
/retest Please review the full test history for this PR and help us cut down flakes. |
/retest |
/retest Please review the full test history for this PR and help us cut down flakes. |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: sahil143, vojtechszocs The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Fixes: https://issues.redhat.com/browse/ODC-4430
Analysis: The guided tour was not working because of some issue with ContextProvider extension.
Solution: using spread operator instead of lodash cloneDeep while sanitizing extension seems to fix it.
Browser: