-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Migrate site editor to use new preferences package #39158
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
Conversation
|
Near the end of my day and I haven't tested this yet, and also tests are likely to fail, so keeping this a draft until I can finish it off tomorrow. |
|
Size Change: +3.11 kB (0%) Total Size: 1.16 MB
ℹ️ View Unchanged
|
3e23219 to
6088be3
Compare
| /** | ||
| * Helper for getting a preference from the preferences store. | ||
| * | ||
| * This is only present so that `getSettings` doesn't need to be made a | ||
| * registry selector. | ||
| * | ||
| * It's unstable because the selector needs to be exported and so part of the | ||
| * public API to work. | ||
| */ | ||
| export const __unstableGetPreference = createRegistrySelector( | ||
| ( select ) => ( state, name ) => | ||
| select( preferencesStore ).get( 'core/edit-site', name ) | ||
| ); |
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 the part I'm most unhappy with. Ideally any helper is internal only, but the registry selector needs to be exported to work.
The separate selector is also needed for the memoized getSettings selector.
If there's a different way to do this that anyone knows of, that'd be great.
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.
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 think we may just have to inline this function so that
isFeatureActive,getSettingsare registry selectors that callselect( preferencesStore ).getdirectly.
If you insist on having a getPreference for code re-use (I'd argue it's maybe not worth it since it's only one line) then getPreference could accept select as an argument.
const getPreference = ( select, name ) =>
select( preferencesStore ).get( 'core/edit-site', name );
export const isFeatureActive = createRegistrySelector(
( select ) => ( state, featureName ) => {
return !! getPreference( select, featureName );
}
);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 thing that makes it difficult is the second argument to createSelector (which is used for memoizing getSettings) is one of the places __unstableGetPreference needs to be used. That has no way to access select from what I can see:
gutenberg/packages/edit-site/src/store/selectors.js
Lines 105 to 151 in c366a96
| /** | |
| * Returns the settings, taking into account active features and permissions. | |
| * | |
| * @param {Object} state Global application state. | |
| * @param {Function} setIsInserterOpen Setter for the open state of the global inserter. | |
| * | |
| * @return {Object} Settings. | |
| */ | |
| export const getSettings = createSelector( | |
| ( state, setIsInserterOpen ) => { | |
| const settings = { | |
| ...state.settings, | |
| outlineMode: true, | |
| focusMode: !! __unstableGetPreference( state, 'focusMode' ), | |
| hasFixedToolbar: !! __unstableGetPreference( | |
| state, | |
| 'fixedToolbar' | |
| ), | |
| __experimentalSetIsInserterOpened: setIsInserterOpen, | |
| __experimentalReusableBlocks: getReusableBlocks( state ), | |
| __experimentalPreferPatternsOnRoot: | |
| 'wp_template' === getEditedPostType( state ), | |
| }; | |
| const canUserCreateMedia = getCanUserCreateMedia( state ); | |
| if ( ! canUserCreateMedia ) { | |
| return settings; | |
| } | |
| settings.mediaUpload = ( { onError, ...rest } ) => { | |
| uploadMedia( { | |
| wpAllowedMimeTypes: state.settings.allowedMimeTypes, | |
| onError: ( { message } ) => onError( message ), | |
| ...rest, | |
| } ); | |
| }; | |
| return settings; | |
| }, | |
| ( state ) => [ | |
| getCanUserCreateMedia( state ), | |
| state.settings, | |
| __unstableGetPreference( state, 'focusMode' ), | |
| __unstableGetPreference( state, 'fixedToolbar' ), | |
| getReusableBlocks( state ), | |
| getEditedPostType( state ), | |
| ] | |
| ); |
I suppose it would be possible to import select from the data store for this purpose. I don't know whether that's an ok practice.
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'm afraid there are only two options available:
- export the
__unstableGetPreferenceselector as part of the public API. The only reason we need to do that is that the code that initializes the public selectors assigns to theselector.registryfield. - wrap all the selectors that use
__unstableGetPreferencewithcreateRegistrySelectorand inline the helper.
import
selectfrom the data store for this purpose
That would mean that the store can be ever registered only with the default registry and never any other one. Because such an import would hardcode a reference to the default registry to the selector.
createRegistrySelector will already fail when you try to register its store with two registries -- because they will fight over the selector.registry field, both assigning to them. We'll need to rethink the entire concept at some point.
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 thing that makes it difficult is the second argument to
createSelector
Ah nuts 🥜
We'll need to rethink the entire concept at some point.
Yeah. I wonder if we can do something similar to thunks where selectors (and the second argument of createSelector) can return a function which is passed an object containing registry, select, etc.
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.
That would mean that the store can be ever registered only with the default registry and never any other one. Because such an import would hardcode a reference to the default registry to the selector.
I see. I remember there being a reason for avoiding this practice, but couldn't remember what it was.
Seems like making it __unstable is probably the best trade-off for now. Thanks for all the feedback.
eeb7311 to
14a27e9
Compare
14a27e9 to
c366a96
Compare
noisysocks
left a comment
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.
Works a treat 👍 and look at all that red! 📉
| import { store as editSiteStore } from '../../../store'; | ||
| import { store as preferencesStore } from '@wordpress/preferences'; | ||
|
|
||
| export default function WelcomeGuideMenuItem() { |
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.
Why can't we use a PreferenceToggleMenuItem instead of WelcomeGuideMenuItem? Because we don't want to show a tick ✔️?
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.
Yep, it would also have the wrong aria role (menuitemcheckbox vs plain menuitem)
| reducer, | ||
| actions, | ||
| selectors, | ||
| persist: [ 'preferences' ], |
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.
🎉
| } | ||
|
|
||
| describe( 'actions', () => { | ||
| describe( 'toggleFeature', () => { |
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.
Maybe it's worth keeping a unit test for toggleFeature around? I'm not sure. On the one hand, it would be a very dumb test that barely tests anything. On the other hand, we can't ever delete toggleFeature and so it's all that we would have to ensure that there aren't any typos inside toggleFeature.
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 think I was just happy to delete stuff. 😄
I'll add a commit that brings it back.
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.
Done in 94eef52.
I've only added back the action test as its easier to test a registry selector there, but I've expanded the test so that it does more testing of the selector.
| select: jest.fn( () => ( { getEntityRecords } ) ), | ||
| }; | ||
|
|
||
| describe( 'isFeatureActive', () => { |
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.
Same again here.
Description
Addresses some of #31965
Migrates the site editor to use the new preferences package (introduced in #38873). Previously this package had its own preferences implementation, but now it uses a common package, which should speed up the process of implementing new preferences.
The main goal here is that nothing is different from a user perspective.
Testing Instructions
trunkopen the site editor and dismiss the welcome guideChecklist:
*.native.jsfiles for terms that need renaming or removal).