From 27ec8f65c929e7e96ecb73aa1097fad5f55e0d1c Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Fri, 13 May 2022 18:00:14 +0800 Subject: [PATCH] Avoid persisting preference every time the sidebar tab is changed (#40923) * Turn complementary areas into a standard action/selector/reducer, unhooking it from the preferences store * Handle visibility in selectors, and resolve issues with actions and reducer * Update test description * My site editor general sidebar active by default * Revert "My site editor general sidebar active by default" This reverts commit 334734ce3d1f1347888dab903a5881bf6520f83b. * Preserve site editor behavior as best as possible by denoting a default area * Use an explicit action when setting up the site editor app to denote the default action * Migrate any stored data * Remove DISABLE_COMPLEMENTARY_AREA handling in interface reducer --- .../edit-site/src/components/sidebar/index.js | 2 + packages/edit-site/src/index.js | 6 ++ packages/interface/src/store/actions.js | 49 +++++++++-- packages/interface/src/store/index.js | 3 +- packages/interface/src/store/reducer.js | 35 ++++++++ packages/interface/src/store/selectors.js | 21 ++++- packages/interface/src/store/test/actions.js | 2 +- packages/preferences-persistence/src/index.js | 5 +- .../convert-complementary-areas.js | 16 ++++ .../preferences-package-data/index.js | 8 ++ .../test/convert-complementary-areas.js | 36 ++++++++ .../preferences-package-data/test/index.js | 84 +++++++++++++++++++ 12 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 packages/interface/src/store/reducer.js create mode 100644 packages/preferences-persistence/src/migrations/preferences-package-data/convert-complementary-areas.js create mode 100644 packages/preferences-persistence/src/migrations/preferences-package-data/index.js create mode 100644 packages/preferences-persistence/src/migrations/preferences-package-data/test/convert-complementary-areas.js create mode 100644 packages/preferences-persistence/src/migrations/preferences-package-data/test/index.js diff --git a/packages/edit-site/src/components/sidebar/index.js b/packages/edit-site/src/components/sidebar/index.js index b08e2b15f1539..74c64cdbcb13d 100644 --- a/packages/edit-site/src/components/sidebar/index.js +++ b/packages/edit-site/src/components/sidebar/index.js @@ -46,6 +46,7 @@ export function SidebarComplementaryAreaFills() { [] ); const { enableComplementaryArea } = useDispatch( interfaceStore ); + useEffect( () => { if ( ! isEditorSidebarOpened ) return; if ( hasBlockSelection ) { @@ -54,6 +55,7 @@ export function SidebarComplementaryAreaFills() { enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); } }, [ hasBlockSelection, isEditorSidebarOpened ] ); + let sidebarName = sidebar; if ( ! isEditorSidebarOpened ) { sidebarName = hasBlockSelection ? SIDEBAR_BLOCK : SIDEBAR_TEMPLATE; diff --git a/packages/edit-site/src/index.js b/packages/edit-site/src/index.js index 2451f4cff3592..8129241ad45a4 100644 --- a/packages/edit-site/src/index.js +++ b/packages/edit-site/src/index.js @@ -13,6 +13,7 @@ import { __experimentalFetchUrlData as fetchUrlData, } from '@wordpress/core-data'; import { store as editorStore } from '@wordpress/editor'; +import { store as interfaceStore } from '@wordpress/interface'; import { store as preferencesStore } from '@wordpress/preferences'; import { __ } from '@wordpress/i18n'; import { store as viewportStore } from '@wordpress/viewport'; @@ -77,6 +78,11 @@ export function reinitializeEditor( target, settings ) { dispatch( editSiteStore ).setIsListViewOpened( true ); } + dispatch( interfaceStore ).setDefaultComplementaryArea( + 'core/edit-site', + 'edit-site/template' + ); + dispatch( editSiteStore ).updateSettings( settings ); // Keep the defaultTemplateTypes in the core/editor settings too, diff --git a/packages/interface/src/store/actions.js b/packages/interface/src/store/actions.js index d130d62b74308..52d1fc67552ba 100644 --- a/packages/interface/src/store/actions.js +++ b/packages/interface/src/store/actions.js @@ -4,21 +4,50 @@ import deprecated from '@wordpress/deprecated'; import { store as preferencesStore } from '@wordpress/preferences'; +/** + * Set a default complementary area. + * + * @param {string} scope Complementary area scope. + * @param {string} area Area identifier. + * + * @return {Object} Action object. + */ +export const setDefaultComplementaryArea = ( scope, area ) => ( { + type: 'SET_DEFAULT_COMPLEMENTARY_AREA', + scope, + area, +} ); + /** * Enable the complementary area. * * @param {string} scope Complementary area scope. * @param {string} area Area identifier. */ -export const enableComplementaryArea = ( scope, area ) => ( { registry } ) => { +export const enableComplementaryArea = ( scope, area ) => ( { + registry, + dispatch, +} ) => { // Return early if there's no area. if ( ! area ) { return; } - registry - .dispatch( preferencesStore ) - .set( scope, 'complementaryArea', area ); + const isComplementaryAreaVisible = registry + .select( preferencesStore ) + .get( scope, 'isComplementaryAreaVisible' ); + + if ( ! isComplementaryAreaVisible ) { + registry + .dispatch( preferencesStore ) + .set( scope, 'isComplementaryAreaVisible', true ); + } + + dispatch( { + type: 'ENABLE_COMPLEMENTARY_AREA', + scope, + area, + } ); }; /** @@ -27,9 +56,15 @@ export const enableComplementaryArea = ( scope, area ) => ( { registry } ) => { * @param {string} scope Complementary area scope. */ export const disableComplementaryArea = ( scope ) => ( { registry } ) => { - registry - .dispatch( preferencesStore ) - .set( scope, 'complementaryArea', null ); + const isComplementaryAreaVisible = registry + .select( preferencesStore ) + .get( scope, 'isComplementaryAreaVisible' ); + + if ( isComplementaryAreaVisible ) { + registry + .dispatch( preferencesStore ) + .set( scope, 'isComplementaryAreaVisible', false ); + } }; /** diff --git a/packages/interface/src/store/index.js b/packages/interface/src/store/index.js index a08420a02f542..817cdc22767e5 100644 --- a/packages/interface/src/store/index.js +++ b/packages/interface/src/store/index.js @@ -8,6 +8,7 @@ import { createReduxStore, register } from '@wordpress/data'; */ import * as actions from './actions'; import * as selectors from './selectors'; +import reducer from './reducer'; import { STORE_NAME } from './constants'; /** @@ -18,7 +19,7 @@ import { STORE_NAME } from './constants'; * @type {Object} */ export const store = createReduxStore( STORE_NAME, { - reducer: () => {}, + reducer, actions, selectors, } ); diff --git a/packages/interface/src/store/reducer.js b/packages/interface/src/store/reducer.js new file mode 100644 index 0000000000000..433f71d15bcc5 --- /dev/null +++ b/packages/interface/src/store/reducer.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { combineReducers } from '@wordpress/data'; + +export function complementaryAreas( state = {}, action ) { + switch ( action.type ) { + case 'SET_DEFAULT_COMPLEMENTARY_AREA': { + const { scope, area } = action; + + // If there's already an area, don't overwrite it. + if ( state[ scope ] ) { + return state; + } + + return { + ...state, + [ scope ]: area, + }; + } + case 'ENABLE_COMPLEMENTARY_AREA': { + const { scope, area } = action; + return { + ...state, + [ scope ]: area, + }; + } + } + + return state; +} + +export default combineReducers( { + complementaryAreas, +} ); diff --git a/packages/interface/src/store/selectors.js b/packages/interface/src/store/selectors.js index 84312676f7017..13b5915e17aac 100644 --- a/packages/interface/src/store/selectors.js +++ b/packages/interface/src/store/selectors.js @@ -11,11 +11,28 @@ import { store as preferencesStore } from '@wordpress/preferences'; * @param {Object} state Global application state. * @param {string} scope Item scope. * - * @return {string} The complementary area that is active in the given scope. + * @return {string | null | undefined} The complementary area that is active in the given scope. */ export const getActiveComplementaryArea = createRegistrySelector( ( select ) => ( state, scope ) => { - return select( preferencesStore ).get( scope, 'complementaryArea' ); + const isComplementaryAreaVisible = select( preferencesStore ).get( + scope, + 'isComplementaryAreaVisible' + ); + + // Return `undefined` to indicate that the user has never toggled + // visibility, this is the vanilla default. Other code relies on this + // nuance in the return value. + if ( isComplementaryAreaVisible === undefined ) { + return undefined; + } + + // Return `null` to indicate the user hid the complementary area. + if ( ! isComplementaryAreaVisible ) { + return null; + } + + return state?.complementaryAreas?.[ scope ]; } ); diff --git a/packages/interface/src/store/test/actions.js b/packages/interface/src/store/test/actions.js index 2ee4075a53e63..91a57c0f1fcb2 100644 --- a/packages/interface/src/store/test/actions.js +++ b/packages/interface/src/store/test/actions.js @@ -54,7 +54,7 @@ describe( 'actions', () => { } ); describe( 'disableComplementaryArea', () => { - it( 'removes any assignment to a complementary area', () => { + it( 'results in the complementary area being inactive', () => { registry .dispatch( interfaceStore ) .enableComplementaryArea( 'my-plugin', 'custom-sidebar' ); diff --git a/packages/preferences-persistence/src/index.js b/packages/preferences-persistence/src/index.js index a28fc411ece77..2b1bcdd10fb03 100644 --- a/packages/preferences-persistence/src/index.js +++ b/packages/preferences-persistence/src/index.js @@ -3,6 +3,7 @@ */ import create from './create'; import convertLegacyLocalStorageData from './migrations/legacy-local-storage-data'; +import convertPreferencesPackageData from './migrations/preferences-package-data'; export { create }; @@ -34,9 +35,9 @@ export function __unstableCreatePersistenceLayer( serverData, userId ) { let preloadedData; if ( serverData && serverModified >= localModified ) { - preloadedData = serverData; + preloadedData = convertPreferencesPackageData( serverData ); } else if ( localData ) { - preloadedData = localData; + preloadedData = convertPreferencesPackageData( localData ); } else { // Check if there is data in the legacy format from the old persistence system. preloadedData = convertLegacyLocalStorageData( userId ); diff --git a/packages/preferences-persistence/src/migrations/preferences-package-data/convert-complementary-areas.js b/packages/preferences-persistence/src/migrations/preferences-package-data/convert-complementary-areas.js new file mode 100644 index 0000000000000..8db83db84e3d8 --- /dev/null +++ b/packages/preferences-persistence/src/migrations/preferences-package-data/convert-complementary-areas.js @@ -0,0 +1,16 @@ +export default function convertComplementaryAreas( state ) { + return Object.keys( state ).reduce( ( stateAccumulator, scope ) => { + const scopeData = state[ scope ]; + + // If a complementary area is truthy, convert it to the `isComplementaryAreaVisible` boolean. + if ( scopeData?.complementaryArea ) { + const updatedScopeData = { ...scopeData }; + delete updatedScopeData.complementaryArea; + updatedScopeData.isComplementaryAreaVisible = true; + stateAccumulator[ scope ] = updatedScopeData; + return stateAccumulator; + } + + return stateAccumulator; + }, state ); +} diff --git a/packages/preferences-persistence/src/migrations/preferences-package-data/index.js b/packages/preferences-persistence/src/migrations/preferences-package-data/index.js new file mode 100644 index 0000000000000..91efe2dac88f7 --- /dev/null +++ b/packages/preferences-persistence/src/migrations/preferences-package-data/index.js @@ -0,0 +1,8 @@ +/** + * Internal dependencies + */ +import convertComplementaryAreas from './convert-complementary-areas'; + +export default function convertPreferencesPackageData( data ) { + return convertComplementaryAreas( data ); +} diff --git a/packages/preferences-persistence/src/migrations/preferences-package-data/test/convert-complementary-areas.js b/packages/preferences-persistence/src/migrations/preferences-package-data/test/convert-complementary-areas.js new file mode 100644 index 0000000000000..fcb31c3dc38dd --- /dev/null +++ b/packages/preferences-persistence/src/migrations/preferences-package-data/test/convert-complementary-areas.js @@ -0,0 +1,36 @@ +/** + * Internal dependencies + */ +import convertComplementaryAreas from '../convert-complementary-areas'; + +describe( 'convertComplementaryAreas', () => { + it( 'converts the `complementaryArea` property in each scope to an `isComplementaryAreaVisible` boolean', () => { + const input = { + 'core/customize-widgets': { + complementaryArea: 'edit-post/block', + }, + 'core/edit-site': { + complementaryArea: 'edit-site/template', + }, + 'core/edit-post': { + complementaryArea: 'edit-post/block', + }, + 'core/edit-widgets': {}, + }; + + const expectedOutput = { + 'core/customize-widgets': { + isComplementaryAreaVisible: true, + }, + 'core/edit-site': { + isComplementaryAreaVisible: true, + }, + 'core/edit-post': { + isComplementaryAreaVisible: true, + }, + 'core/edit-widgets': {}, + }; + + expect( convertComplementaryAreas( input ) ).toEqual( expectedOutput ); + } ); +} ); diff --git a/packages/preferences-persistence/src/migrations/preferences-package-data/test/index.js b/packages/preferences-persistence/src/migrations/preferences-package-data/test/index.js new file mode 100644 index 0000000000000..c96f8d1b0ab35 --- /dev/null +++ b/packages/preferences-persistence/src/migrations/preferences-package-data/test/index.js @@ -0,0 +1,84 @@ +/** + * Internal dependencies + */ +import convertPreferencesPackageData from '../'; + +const input = { + 'core/customize-widgets': { + welcomeGuide: false, + fixedToolbar: true, + }, + 'core/edit-widgets': { + welcomeGuide: false, + fixedToolbar: true, + showBlockBreadcrumbs: false, + complementaryArea: 'edit-widgets/block-areas', + }, + 'core/edit-post': { + welcomeGuide: false, + fixedToolbar: true, + fullscreenMode: false, + hiddenBlockTypes: [ 'core/audio', 'core/cover' ], + editorMode: 'visual', + preferredStyleVariations: { + 'core/quote': 'large', + }, + inactivePanels: [], + openPanels: [ 'post-status' ], + pinnedItems: { + 'my-sidebar-plugin/title-sidebar': false, + }, + }, + 'core/edit-site': { + welcomeGuide: false, + welcomeGuideStyles: false, + fixedToolbar: true, + complementaryArea: 'edit-site/global-styles', + }, +}; + +describe( 'convertPreferencesPackageData', () => { + it( 'converts data to the expected format', () => { + expect( convertPreferencesPackageData( input ) ) + .toMatchInlineSnapshot( ` + Object { + "core/customize-widgets": Object { + "fixedToolbar": true, + "welcomeGuide": false, + }, + "core/edit-post": Object { + "editorMode": "visual", + "fixedToolbar": true, + "fullscreenMode": false, + "hiddenBlockTypes": Array [ + "core/audio", + "core/cover", + ], + "inactivePanels": Array [], + "openPanels": Array [ + "post-status", + ], + "pinnedItems": Object { + "my-sidebar-plugin/title-sidebar": false, + }, + "preferredStyleVariations": Object { + "core/quote": "large", + }, + "welcomeGuide": false, + }, + "core/edit-site": Object { + "fixedToolbar": true, + "isComplementaryAreaVisible": true, + "welcomeGuide": false, + "welcomeGuideStyles": false, + }, + "core/edit-widgets": Object { + "fixedToolbar": true, + "isComplementaryAreaVisible": true, + "showBlockBreadcrumbs": false, + "welcomeGuide": false, + }, + } + ` ); + } ); +} );