Skip to content

Commit 7b8db97

Browse files
getdavedraganescuscruffianjsnajdr
authored andcommitted
Make Navigation fallback selector private (#51413)
* Move selector to become private * adds basic lock functionality * remove useless lock-unlock file * map private selectors to resolvers * Unlock the other usage * only create one fallback per session * Fix core-data duplicate private opt-in * Data: bind resolvers to selectors individually, support private selectors --------- Co-authored-by: Andrei Draganescu <andrei.draganescu@automattic.com> Co-authored-by: scruffian <ben@scruffian.com> Co-authored-by: Jarda Snajdr <jsnajdr@gmail.com>
1 parent d4d0106 commit 7b8db97

File tree

8 files changed

+75
-84
lines changed

8 files changed

+75
-84
lines changed

docs/reference-guides/data/data-core.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -329,18 +329,6 @@ _Returns_
329329

330330
- `any`: The entity record's save error.
331331

332-
### getNavigationFallbackId
333-
334-
Retrieve the fallback Navigation.
335-
336-
_Parameters_
337-
338-
- _state_ `State`: Data state.
339-
340-
_Returns_
341-
342-
- `EntityRecordKey | undefined`: The ID for the fallback Navigation post.
343-
344332
### getRawEntityRecord
345333

346334
Returns the entity's record object by key, with its attributes mapped to their raw values.

packages/block-library/src/navigation/edit/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ import ManageMenusButton from './manage-menus-button';
6969
import MenuInspectorControls from './menu-inspector-controls';
7070
import DeletedNavigationWarning from './deleted-navigation-warning';
7171
import { unlock } from '../../lock-unlock';
72-
7372
const { useBlockEditingMode } = unlock( blockEditorPrivateApis );
7473

7574
function Navigation( {
@@ -224,7 +223,7 @@ function Navigation( {
224223
// that automatically saves the menu as an entity when changes are made to the inner blocks.
225224
const hasUnsavedBlocks = hasUncontrolledInnerBlocks && ! isEntityAvailable;
226225

227-
const { getNavigationFallbackId } = useSelect( coreStore );
226+
const { getNavigationFallbackId } = unlock( useSelect( coreStore ) );
228227

229228
const navigationFallbackId = ! ( ref || hasUnsavedBlocks )
230229
? getNavigationFallbackId()

packages/core-data/README.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -506,18 +506,6 @@ _Returns_
506506

507507
- `any`: The entity record's save error.
508508

509-
### getNavigationFallbackId
510-
511-
Retrieve the fallback Navigation.
512-
513-
_Parameters_
514-
515-
- _state_ `State`: Data state.
516-
517-
_Returns_
518-
519-
- `EntityRecordKey | undefined`: The ID for the fallback Navigation post.
520-
521509
### getRawEntityRecord
522510

523511
Returns the entity's record object by key, with its attributes mapped to their raw values.

packages/core-data/src/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import * as resolvers from './resolvers';
1313
import createLocksActions from './locks/actions';
1414
import { rootEntitiesConfig, getMethodName } from './entities';
1515
import { STORE_NAME } from './name';
16+
import { unlock } from './private-apis';
17+
import { getNavigationFallbackId } from './private-selectors';
1618

1719
// The entity selectors/resolvers and actions are shortcuts to their generic equivalents
1820
// (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
@@ -62,7 +64,10 @@ const storeConfig = () => ( {
6264
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
6365
*/
6466
export const store = createReduxStore( STORE_NAME, storeConfig() );
65-
register( store );
67+
unlock( store ).registerPrivateSelectors( {
68+
getNavigationFallbackId,
69+
} );
70+
register( store ); // Register store after unlocking private selectors to allow resolvers to use them.
6671

6772
export { default as EntityProvider } from './entity-provider';
6873
export * from './entity-provider';

packages/core-data/src/private-selectors.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import type { State, UndoEdit } from './selectors';
55

66
type Optional< T > = T | undefined;
7+
type EntityRecordKey = string | number;
78

89
/**
910
* Returns the previous edit from the current undo offset
@@ -28,3 +29,15 @@ export function getUndoEdits( state: State ): Optional< UndoEdit[] > {
2829
export function getRedoEdits( state: State ): Optional< UndoEdit[] > {
2930
return state.undo.list[ state.undo.list.length + state.undo.offset ];
3031
}
32+
33+
/**
34+
* Retrieve the fallback Navigation.
35+
*
36+
* @param state Data state.
37+
* @return The ID for the fallback Navigation post.
38+
*/
39+
export function getNavigationFallbackId(
40+
state: State
41+
): EntityRecordKey | undefined {
42+
return state.navigationFallbackId;
43+
}

packages/core-data/src/selectors.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,18 +1257,6 @@ export function getBlockPatternCategories( state: State ): Array< any > {
12571257
return state.blockPatternCategories;
12581258
}
12591259

1260-
/**
1261-
* Retrieve the fallback Navigation.
1262-
*
1263-
* @param state Data state.
1264-
* @return The ID for the fallback Navigation post.
1265-
*/
1266-
export function getNavigationFallbackId(
1267-
state: State
1268-
): EntityRecordKey | undefined {
1269-
return state.navigationFallbackId;
1270-
}
1271-
12721260
/**
12731261
* Returns the revisions of the current global styles theme.
12741262
*

packages/data/src/redux-store/index.js

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ function createBindingCache( bind ) {
105105
const cache = new WeakMap();
106106

107107
return {
108-
get( item ) {
108+
get( item, itemName ) {
109109
let boundItem = cache.get( item );
110110
if ( ! boundItem ) {
111-
boundItem = bind( item );
111+
boundItem = bind( item, itemName );
112112
cache.set( item, boundItem );
113113
}
114114
return boundItem;
@@ -198,7 +198,7 @@ export default function createReduxStore( key, options ) {
198198
get: ( target, prop ) => {
199199
const privateAction = privateActions[ prop ];
200200
return privateAction
201-
? boundPrivateActions.get( privateAction )
201+
? boundPrivateActions.get( privateAction, prop )
202202
: actions[ prop ];
203203
},
204204
} );
@@ -210,16 +210,32 @@ export default function createReduxStore( key, options ) {
210210

211211
lock( actions, allActions );
212212

213-
function bindSelector( selector ) {
213+
const resolvers = options.resolvers
214+
? mapResolvers( options.resolvers )
215+
: {};
216+
217+
function bindSelector( selector, selectorName ) {
214218
if ( selector.isRegistrySelector ) {
215219
selector.registry = registry;
216220
}
217221
const boundSelector = ( ...args ) => {
218222
const state = store.__unstableOriginalGetState();
219223
return selector( state.root, ...args );
220224
};
221-
boundSelector.hasResolver = false;
222-
return boundSelector;
225+
226+
const resolver = resolvers[ selectorName ];
227+
if ( ! resolver ) {
228+
boundSelector.hasResolver = false;
229+
return boundSelector;
230+
}
231+
232+
return mapSelectorWithResolver(
233+
boundSelector,
234+
selectorName,
235+
resolver,
236+
store,
237+
resolversCache
238+
);
223239
}
224240

225241
function bindMetadataSelector( selector ) {
@@ -231,35 +247,26 @@ export default function createReduxStore( key, options ) {
231247
return boundSelector;
232248
}
233249

234-
let selectors = {
250+
const selectors = {
235251
...mapValues( metadataSelectors, bindMetadataSelector ),
236252
...mapValues( options.selectors, bindSelector ),
237253
};
238254

239-
let resolvers;
240-
if ( options.resolvers ) {
241-
resolvers = mapResolvers( options.resolvers );
242-
selectors = mapSelectorsWithResolvers(
243-
selectors,
244-
resolvers,
245-
store,
246-
resolversCache
247-
);
248-
}
249-
250255
const boundPrivateSelectors = createBindingCache( bindSelector );
251256

252257
// Pre-bind the private selectors that have been registered by the time of
253258
// instantiation, so that registry selectors are bound to the registry.
254-
for ( const privateSelector of Object.values( privateSelectors ) ) {
255-
boundPrivateSelectors.get( privateSelector );
259+
for ( const [ selectorName, selector ] of Object.entries(
260+
privateSelectors
261+
) ) {
262+
boundPrivateSelectors.get( selector, selectorName );
256263
}
257264

258265
const allSelectors = new Proxy( () => {}, {
259266
get: ( target, prop ) => {
260267
const privateSelector = privateSelectors[ prop ];
261268
return privateSelector
262-
? boundPrivateSelectors.get( privateSelector )
269+
? boundPrivateSelectors.get( privateSelector, prop )
263270
: selectors[ prop ];
264271
},
265272
} );
@@ -509,22 +516,24 @@ function mapResolvers( resolvers ) {
509516
}
510517

511518
/**
512-
* Returns resolvers with matched selectors for a given namespace.
519+
* Returns a selector with a matched resolver.
513520
* Resolvers are side effects invoked once per argument set of a given selector call,
514521
* used in ensuring that the data needs for the selector are satisfied.
515522
*
516-
* @param {Object} selectors The current selectors to be modified.
517-
* @param {Object} resolvers Resolvers to register.
523+
* @param {Object} selector The selector function to be bound.
524+
* @param {string} selectorName The selector name.
525+
* @param {Object} resolver Resolver to call.
518526
* @param {Object} store The redux store to which the resolvers should be mapped.
519527
* @param {Object} resolversCache Resolvers Cache.
520528
*/
521-
function mapSelectorsWithResolvers(
522-
selectors,
523-
resolvers,
529+
function mapSelectorWithResolver(
530+
selector,
531+
selectorName,
532+
resolver,
524533
store,
525534
resolversCache
526535
) {
527-
function fulfillSelector( resolver, selectorName, args ) {
536+
function fulfillSelector( args ) {
528537
const state = store.getState();
529538

530539
if (
@@ -570,17 +579,10 @@ function mapSelectorsWithResolvers(
570579
}, 0 );
571580
}
572581

573-
return mapValues( selectors, ( selector, selectorName ) => {
574-
const resolver = resolvers[ selectorName ];
575-
if ( ! resolver ) {
576-
return selector;
577-
}
578-
579-
const selectorResolver = ( ...args ) => {
580-
fulfillSelector( resolver, selectorName, args );
581-
return selector( ...args );
582-
};
583-
selectorResolver.hasResolver = true;
584-
return selectorResolver;
585-
} );
582+
const selectorResolver = ( ...args ) => {
583+
fulfillSelector( args );
584+
return selector( ...args );
585+
};
586+
selectorResolver.hasResolver = true;
587+
return selectorResolver;
586588
}

packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/index.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { PRELOADED_NAVIGATION_MENUS_QUERY } from './constants';
2121
import { useLink } from '../routes/link';
2222
import SingleNavigationMenu from '../sidebar-navigation-screen-navigation-menu/single-navigation-menu';
2323
import useNavigationMenuHandlers from '../sidebar-navigation-screen-navigation-menu/use-navigation-menu-handlers';
24+
import { unlock } from '../../lock-unlock';
2425

2526
// Copied from packages/block-library/src/navigation/edit/navigation-menu-selector.js.
2627
function buildMenuLabel( title, id, status ) {
@@ -41,6 +42,9 @@ function buildMenuLabel( title, id, status ) {
4142
);
4243
}
4344

45+
// Save a boolean to prevent us creating a fallback more than once per session.
46+
let hasCreatedFallback = false;
47+
4448
export default function SidebarNavigationScreenNavigationMenus() {
4549
const {
4650
records: navigationMenus,
@@ -55,18 +59,22 @@ export default function SidebarNavigationScreenNavigationMenus() {
5559
const isLoading =
5660
isResolvingNavigationMenus && ! hasResolvedNavigationMenus;
5761

58-
const getNavigationFallbackId = useSelect(
59-
( select ) => select( coreStore ).getNavigationFallbackId
60-
);
62+
const { getNavigationFallbackId } = unlock( useSelect( coreStore ) );
6163

6264
const firstNavigationMenu = navigationMenus?.[ 0 ];
6365

66+
// Save a boolean to prevent us creating a fallback more than once per session.
67+
if ( firstNavigationMenu ) {
68+
hasCreatedFallback = true;
69+
}
70+
6471
// If there is no navigation menu found
6572
// then trigger fallback algorithm to create one.
6673
if (
6774
! firstNavigationMenu &&
6875
! isResolvingNavigationMenus &&
69-
hasResolvedNavigationMenus
76+
hasResolvedNavigationMenus &&
77+
! hasCreatedFallback
7078
) {
7179
getNavigationFallbackId();
7280
}

0 commit comments

Comments
 (0)