-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Rework EditorThemeStore to be stored in CoreData #16282
Conversation
Generated by 🚫 dangerJS |
You can trigger optional UI/connected tests for these changes by visiting CircleCI here. |
|
||
/// Stores a n MD5 checksum representing the stored data. Used for a comparison to decide if the data has changed. | ||
/// | ||
@NSManaged public var checksum: String |
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.
📓 GSS doesn't really have a notion of a version to indicate if there are changes or not. I don't want to trigger a theme change if the data hasn't been modified. So Instead I generate and store a checksum to compare change sets.
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.
Is this regarding avoiding re-renders after the async fetch response after the editor loads? My reason for asking is, I wonder if we should handle that on the JS side (either instead of or in addition to this). Benefits there are that with a partial change would only re-render the dependent components.
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.
Is this regarding avoiding re-renders after the async fetch response after the editor loads?
Yup, in the old model, we were using a combination of the theme name and version number for the theme as a key to meet the same goal. Since themes that support FSE can be more easily modified without a change to the underlying theme, I felt that the original structure wouldn't be workable, so I updated this now since it's tied to the CoreDataModel changes.
My reason for asking is, I wonder if we should handle that on the JS side (either instead of or in addition to this).
This is a good discussion topic to revisit. Just to align on expectations, plan, and set the scope that this PR is focused on updating the underlying storing mechanism for custom colors and gradients, this is not intended to touch the expectations RN is making about the received data.
With that out of the way :). I would love to continue this conversation and let this PR move forward. We can tackle any outcomes in a future iteration, but let me know if that plan doesn't work.
Apologies for the novella; this would be a great chat over a cup of coffee ☕
Personally, I would be against starting with the instead
mindset, but I would want to ask that question again after seeing a POC for the addition to
mindset. Where we should do the check was briefly discussed in slack on the initial implementation. We felt handling this on the JS side would start to become very complicated, and although doable, we weren't sure any of us had a plan that would make it feel clean. If a parent object were to be updated like the main canvas, then TMK of RN all of the child components have to re-render given RN's base architecture. So to handle conditional renders, we would need to build in a mechanism at each layer so it can decide if it should rerender or not. We also don't expect the theme to change frequently, so I feel the work to support that wouldn't be worth the effort of taking it on globally on the Native side. If you have a vision for handling this, I would love to see a sample branch with a POC when you have time. It would help me learn a lot.
That approach to handle it on the RN side also raised a few questions about how we wanted the Bridge to communicate its expectations.
We created the bridge with two interfaces related to accepting these initial settings.
The first is the intialProperties which accepts basic theme data. I'm using "theme" to refer to custom colors and gradients because that's all we currently use, but I believe this structure works for font sizes as well, and we can examine other use cases as they arise.
The Bridge accepts that the data provided in [intialProperties](https://github.com/WordPress/gutenberg/blob/661548ae5f1965f5fbff1c40b54fd37fa57a6b79/packages/react-native-bridge/ios/Gutenberg.swift#L82-L89 might be stale data and offers the mechanism updateTheme to provide a way for the Native Side to say that it now has fresh data.
I'm not sure what the best interface would be if we shifted the "ownership" of the detecting changes to the Editor.
If we had the editor decide if it should apply those changes or not, the current interface would no longer be a guarantee that the new settings being sent are actually applied. If we removed the acceptance that the initial properties could be stale, this would increase the editor's load time.
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.
Apologies for the novella; this would be a great chat over a cup of coffee coffee
No need for apologies! Thanks for taking the time to write out your thoughts here, it's great to get your perspective on this. And btw, I am having a cup of coffee as I read this and write a response, so this is like an async chat over a cup of coffee 😄 ☕ ☕
Personally, I would be against starting with the instead mindset, but I would want to ask that question again after seeing a POC for the addition to mindset. Where we should do the check was briefly discussed in slack on the initial implementation. We felt handling this on the JS side would start to become very complicated, and although doable, we weren't sure any of us had a plan that would make it feel clean.
That makes sense. Especially so if the relevant optimizations are not already present on the JS side. Even if they were, though, the checksum here would still add value, I think, since it could "preempt" such calculations, and in many cases avoid them entirely.
If you have a vision for handling this, I would love to see a sample branch with a POC when you have time. It would help me learn a lot.
I know there have been some recent improvements regarding re-renders of the whole block-list, but also that there were still plenty of things that could use improvements there. My vision for handling this is that we'd have our various HOCs / providers optimized in such a way that this kind of thing is not even a concern. Ideally, we should be able to pass whatever necessary props / data to the main container component, and only necessary updates to the hierarchy would take place. But, I fully understand we may not be there yet at the moment, since out-of-the-box things like memo
won't fly for our recursive and often stateful child components.
In the context of this PR, which is more about theme settings specifically, I also agree that if there was much needed work to make this performant on the RN side, the payoff wouldn't be worth it, since the changes would likely affect many blocks in the editor (i.e. close to an all-or-nothing re-render anyway). My mindset about this is oriented toward the needs for editor settings in general, which seem to be more frequently cropping up. My thinking is that sometime in the near future, we might have a setting which is updated independently from the theme settings. Imagine, for example, if we had a flag in the settings with a new value in the endpoint response. In that case we'd want to avoid the full re-render that a theme update would trigger. We could implement custom logic in Swift and Kotlin to condition that, but it'd be great if the app was already optimized to be idempotent with that granularity.
With all that said, there is nothing in this PR that is incompatible with the ideal RN optimizations, so please consider this discussion as entirely non-blocking. It seems that the complications on the RN side were already discussed at the outset, so any improvements there probably deserve their own space for discussion. And thanks again for elaborating in detail about your thought process!
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.
this is like an async chat over a cup of coffee 😄 ☕ ☕
😄 I have my coffee now too.
may not be there yet at the moment, since out-of-the-box things like memo won't fly for our recursive and often stateful child components.
Yeah if we can take on this problem then we'd really be able to optimize the codebase. That would be awesome.
Thank you for bringing up those other ides and responses :)
|
||
/// Stores a date indicating the last time stamp that the settings were modified. | ||
/// | ||
@NSManaged public var lastUpdated: Date |
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.
📓 This is unused but I'm storing it because I would like to eventually be smarter about how often we're fetching the theme.
self.checksum = { | ||
guard let parsedTheme = parsedTheme else { return "" } | ||
let encoder = JSONEncoder() | ||
encoder.outputFormatting = .sortedKeys |
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.
📓 While generating the checksum, this guarantees that the keys are ordered consistently.
|
||
/// Stores a unique key associated to the `value`. | ||
/// | ||
@NSManaged public var slug: String |
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.
I appreciate that this is being implemented in a somewhat general way, with thought of future settings. I recently learned that there will be a need for an experimental feature flag setting for the Gallery block refactor work as well: https://github.com/WordPress/gutenberg/pull/25940/files#diff-e6bd94e1847aea4b70a6cc1ac9b2471dd3d882f6cbf1ab51438e23b02ca5194fR114-R128, but I'm not sure it fits this model, since there is no slug. Then again, there is no REST API yet for that, so perhaps id
could be passed as slug 🤔 .
In any case, I'm mentioning here because there seem to a be a few upcoming cases with similar requirements (patterns will also need something similar, for example).
Edit
Nvm, just saw this comment. So, the element is meant to be general, but only a part of the BlockEditorSettings
, which could easily store the additional experimental flag as well. Does that sound right?
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.
So, the element is meant to be general, but only a part of the
BlockEditorSettings
, which could easily store the additional experimental flag as well. Does that sound right?
Yup this is meant to be a more generic container for the arrays that come down from the call /wp/v2/themes?status=active
and the one being added to /wp-block-editor/v1/settings
in wordpress-mobile/gutenberg-mobile#3163 the parent object is the BlockEditorSettings
The main uses I see for BlockEditorSettingElement
are colors, gradients, and font sizes. If we got to a use case that doesn't have a need for one of the required values then we can provide an empty string. This would all be about how the consumer decides to use the stored data.
I recently learned that there will be a need for an experimental feature flag setting for the Gallery block refactor work as well ... Then again, there is no REST API yet for that, so perhaps
id
could be passed asslug
🤔 .
Let's dig into this use case more once we have an idea about how it will be delivered to the app. If it's included in the call /wp-block-editor/v1/settings
my recommendation would be to add it to BlockEditorSettings
but let's see.
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.
Great work @chipsnyder 👍
I tested this on an iPhone SE 2020 with iOS 14.4.1 and all work as expected:
✅ Default Colors
✅ Default Gradients
✅ Custom Colors
✅ Custom Gradients
✅ Offline Support
The code and the tests LGTM 🎉
Thank you for paving the way for the Android implementation 🙇
Fixes wordpress-mobile/gutenberg-mobile#3163
This change fundamentally reworks how the
EditorThemeStore
works so this should solve the issue around #16014 as well.Related PRs:
Description
This PR reworks the current approach used to fetch and cache the Editor theme defined in
theme_supports
and reworks it into a structure that more closely aligns with the Android implementation. This doesn't do anything for GSS yet but I did add a few things in preparation for that set of work which I'll build once this merges.To test:
This can be tested by running the regression test suite:
Core Migrations
develop
has the same CoreData model as the latest release so installing this build over a build fromdevelop
or the last release will be sufficient for testing any migrations.Regression Notes
Potential unintended areas of impact
The only other possible area would be CoreData migration conflicts.
What I did to test those areas of impact (or what existing automated tests I relied on)
Same as the testing notes.
What automated tests I added (or what prevented me from doing so)
Added unit tests around the affected code.
PR submission checklist:
RELEASE-NOTES.txt
if necessary.