diff --git a/packages/data/src/plugins/persistence/index.js b/packages/data/src/plugins/persistence/index.js index 0bf50f768269d..8a3eb27df01e7 100644 --- a/packages/data/src/plugins/persistence/index.js +++ b/packages/data/src/plugins/persistence/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { merge, isPlainObject } from 'lodash'; +import { merge, isPlainObject, reduce } from 'lodash'; /** * Internal dependencies @@ -402,6 +402,122 @@ export function migrateThirdPartyFeaturePreferencesToPreferencesStore( } } +/** + * Migrates interface 'enableItems' data to the preferences store. + * + * The interface package stores this data in this format: + * ```js + * { + * enableItems: { + * singleEnableItems: { + * complementaryArea: { + * 'core/edit-post': 'edit-post/document', + * 'core/edit-site': 'edit-site/global-styles', + * } + * }, + * multipleEnableItems: { + * pinnedItems: { + * 'core/edit-post': { + * 'plugin-1': true, + * }, + * 'core/edit-site': { + * 'plugin-2': true, + * }, + * }, + * } + * } + * } + * ``` + * and it should be migrated it to: + * ```js + * { + * 'core/edit-post': { + * complementaryArea: 'edit-post/document', + * pinnedItems: { + * 'plugin-1': true, + * }, + * }, + * 'core/edit-site': { + * complementaryArea: 'edit-site/global-styles', + * pinnedItems: { + * 'plugin-2': true, + * }, + * }, + * } + * ``` + * + * @param {Object} persistence The persistence interface. + */ +export function migrateInterfaceEnableItemsToPreferencesStore( persistence ) { + const interfaceStoreName = 'core/interface'; + const preferencesStoreName = 'core/preferences'; + const state = persistence.get(); + const sourceEnableItems = state[ interfaceStoreName ]?.enableItems; + + // There's nothing to migrate, exit early. + if ( ! sourceEnableItems ) { + return; + } + + const allPreferences = state[ preferencesStoreName ]?.preferences ?? {}; + + // First convert complementaryAreas into the right format. + // Use the existing preferences as the accumulator so that the data is + // merged. + const sourceComplementaryAreas = + sourceEnableItems?.singleEnableItems?.complementaryArea; + const convertedComplementaryAreas = reduce( + sourceComplementaryAreas, + ( accumulator, data, scope ) => { + // Don't overwrite any existing data in the preferences store. + if ( accumulator[ scope ]?.complementaryArea ) { + return accumulator; + } + + return { + ...accumulator, + [ scope ]: { + ...accumulator[ scope ], + complementaryArea: data, + }, + }; + }, + allPreferences + ); + + // Next feed the converted complementary areas back into a reducer that + // converts the pinned items, resulting in the fully migrated data. + const sourcePinnedItems = + sourceEnableItems?.multipleEnableItems?.pinnedItems; + const allConvertedData = reduce( + sourcePinnedItems, + ( accumulator, data, scope ) => { + // Don't overwrite any existing data in the preferences store. + if ( accumulator[ scope ]?.pinnedItems ) { + return accumulator; + } + + return { + ...accumulator, + [ scope ]: { + ...accumulator[ scope ], + pinnedItems: data, + }, + }; + }, + convertedComplementaryAreas + ); + + persistence.set( preferencesStoreName, { + preferences: allConvertedData, + } ); + + // Remove migrated preferences. + persistence.set( interfaceStoreName, { + enableItems: undefined, + } ); +} + persistencePlugin.__unstableMigrate = ( pluginOptions ) => { const persistence = createPersistenceInterface( pluginOptions ); @@ -445,6 +561,7 @@ persistencePlugin.__unstableMigrate = ( pluginOptions ) => { 'core/edit-site', 'editorMode' ); + migrateInterfaceEnableItemsToPreferencesStore( persistence ); }; export default persistencePlugin; diff --git a/packages/data/src/plugins/persistence/test/index.js b/packages/data/src/plugins/persistence/test/index.js index 704c9231615ae..ca327155b9712 100644 --- a/packages/data/src/plugins/persistence/test/index.js +++ b/packages/data/src/plugins/persistence/test/index.js @@ -12,6 +12,7 @@ import plugin, { migrateFeaturePreferencesToPreferencesStore, migrateThirdPartyFeaturePreferencesToPreferencesStore, migrateIndividualPreferenceToPreferencesStore, + migrateInterfaceEnableItemsToPreferencesStore, } from '../'; import objectStorage from '../storage/object'; import { createRegistry } from '../../../'; @@ -923,3 +924,122 @@ describe( 'migrateThirdPartyFeaturePreferencesToPreferencesStore', () => { } ); } ); } ); + +describe( 'migrateInterfaceEnableItemsToPreferencesStore', () => { + it( 'migrates enableItems to the preferences store', () => { + const persistenceInterface = createPersistenceInterface( { + storageKey: 'test-username', + } ); + + persistenceInterface.set( 'core/interface', { + enableItems: { + singleEnableItems: { + complementaryArea: { + 'core/edit-post': 'edit-post/document', + 'core/edit-site': 'edit-site/global-styles', + }, + }, + multipleEnableItems: { + pinnedItems: { + 'core/edit-post': { + 'plugin-1': true, + }, + 'core/edit-site': { + 'plugin-2': true, + }, + }, + }, + }, + } ); + + migrateInterfaceEnableItemsToPreferencesStore( persistenceInterface ); + + expect( persistenceInterface.get() ).toEqual( { + 'core/preferences': { + preferences: { + 'core/edit-post': { + complementaryArea: 'edit-post/document', + pinnedItems: { + 'plugin-1': true, + }, + }, + 'core/edit-site': { + complementaryArea: 'edit-site/global-styles', + pinnedItems: { + 'plugin-2': true, + }, + }, + }, + }, + 'core/interface': { + enableItems: undefined, + }, + } ); + } ); + + it( 'merges pinnedItems and complementaryAreas with existing preferences store data', () => { + const persistenceInterface = createPersistenceInterface( { + storageKey: 'test-username', + } ); + + persistenceInterface.set( 'core/interface', { + enableItems: { + singleEnableItems: { + complementaryArea: { + 'core/edit-post': 'edit-post/document', + 'core/edit-site': 'edit-site/global-styles', + }, + }, + multipleEnableItems: { + pinnedItems: { + 'core/edit-post': { + 'plugin-1': true, + }, + 'core/edit-site': { + 'plugin-2': true, + }, + }, + }, + }, + } ); + + persistenceInterface.set( 'core/preferences', { + preferences: { + 'core/edit-post': { + preferenceA: 1, + preferenceB: 2, + }, + 'core/edit-site': { + preferenceC: true, + }, + }, + } ); + + migrateInterfaceEnableItemsToPreferencesStore( persistenceInterface ); + + expect( persistenceInterface.get() ).toEqual( { + 'core/preferences': { + preferences: { + 'core/edit-post': { + preferenceA: 1, + preferenceB: 2, + complementaryArea: 'edit-post/document', + pinnedItems: { + 'plugin-1': true, + }, + }, + 'core/edit-site': { + preferenceC: true, + complementaryArea: 'edit-site/global-styles', + pinnedItems: { + 'plugin-2': true, + }, + }, + }, + }, + 'core/interface': { + enableItems: undefined, + }, + } ); + } ); +} );