Skip to content

Commit

Permalink
Core Data: Add the 'getEntitiesConfig' resolver (WordPress#65871)
Browse files Browse the repository at this point in the history
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: ellatrix <[email protected]>
Co-authored-by: youknowriad <[email protected]>
  • Loading branch information
4 people authored Oct 30, 2024
1 parent f0ef1ac commit 5432049
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 259 deletions.
20 changes: 10 additions & 10 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import deprecated from '@wordpress/deprecated';
*/
import { getNestedValue, setNestedValue } from './utils';
import { receiveItems, removeItems, receiveQueriedItems } from './queried-data';
import { getOrLoadEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
import { DEFAULT_ENTITY_KEY } from './entities';
import { createBatch } from './batch';
import { STORE_NAME } from './name';
import { getSyncProvider } from './sync';
Expand Down Expand Up @@ -285,8 +285,8 @@ export const deleteEntityRecord =
query,
{ __unstableFetch = apiFetch, throwOnError = false } = {}
) =>
async ( { dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
async ( { dispatch, resolveSelect } ) => {
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.kind === kind && config.name === name
);
Expand Down Expand Up @@ -503,7 +503,7 @@ export const saveEntityRecord =
} = {}
) =>
async ( { select, resolveSelect, dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.kind === kind && config.name === name
);
Expand Down Expand Up @@ -780,11 +780,11 @@ export const __experimentalBatch =
*/
export const saveEditedEntityRecord =
( kind, name, recordId, options ) =>
async ( { select, dispatch } ) => {
async ( { select, dispatch, resolveSelect } ) => {
if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) {
return;
}
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.kind === kind && config.name === name
);
Expand Down Expand Up @@ -813,7 +813,7 @@ export const saveEditedEntityRecord =
*/
export const __experimentalSaveSpecifiedEntityEdits =
( kind, name, recordId, itemsToSave, options ) =>
async ( { select, dispatch } ) => {
async ( { select, dispatch, resolveSelect } ) => {
if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) {
return;
}
Expand All @@ -828,7 +828,7 @@ export const __experimentalSaveSpecifiedEntityEdits =
setNestedValue( editsToSave, item, getNestedValue( edits, item ) );
}

const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.kind === kind && config.name === name
);
Expand Down Expand Up @@ -973,8 +973,8 @@ export function receiveDefaultTemplateId( query, templateId ) {
*/
export const receiveRevisions =
( kind, name, recordKey, records, query, invalidateCache = false, meta ) =>
async ( { dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
async ( { dispatch, resolveSelect } ) => {
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.kind === kind && config.name === name
);
Expand Down
64 changes: 0 additions & 64 deletions packages/core-data/src/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@ import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
import { RichTextData } from '@wordpress/rich-text';

/**
* Internal dependencies
*/
import { addEntities } from './actions';
import { getSyncProvider } from './sync';

export const DEFAULT_ENTITY_KEY = 'id';

const POST_RAW_ATTRIBUTES = [ 'title', 'excerpt', 'content' ];

export const rootEntitiesConfig = [
Expand Down Expand Up @@ -458,60 +451,3 @@ export const getMethodName = ( kind, name, prefix = 'get' ) => {
const suffix = pascalCase( name );
return `${ prefix }${ kindPrefix }${ suffix }`;
};

function registerSyncConfigs( configs ) {
configs.forEach( ( { syncObjectType, syncConfig } ) => {
getSyncProvider().register( syncObjectType, syncConfig );
const editSyncConfig = { ...syncConfig };
delete editSyncConfig.fetch;
getSyncProvider().register( syncObjectType + '--edit', editSyncConfig );
} );
}

/**
* Loads the entities into the store.
*
* Note: The `name` argument is used for `root` entities requiring additional server data.
*
* @param {string} kind Kind
* @param {string} name Name
* @return {(thunkArgs: object) => Promise<Array>} Entities
*/
export const getOrLoadEntitiesConfig =
( kind, name ) =>
async ( { select, dispatch } ) => {
let configs = select.getEntitiesConfig( kind );
const hasConfig = !! select.getEntityConfig( kind, name );

if ( configs?.length > 0 && hasConfig ) {
if ( window.__experimentalEnableSync ) {
if ( globalThis.IS_GUTENBERG_PLUGIN ) {
registerSyncConfigs( configs );
}
}

return configs;
}

const loader = additionalEntityConfigLoaders.find( ( l ) => {
if ( ! name || ! l.name ) {
return l.kind === kind;
}

return l.kind === kind && l.name === name;
} );
if ( ! loader ) {
return [];
}

configs = await loader.loadEntities();
if ( window.__experimentalEnableSync ) {
if ( globalThis.IS_GUTENBERG_PLUGIN ) {
registerSyncConfigs( configs );
}
}

dispatch( addEntities( configs ) );

return configs;
};
11 changes: 9 additions & 2 deletions packages/core-data/src/hooks/test/use-entity-record.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,14 @@ describe( 'useEntityRecord', () => {
await act(
() => new Promise( ( resolve ) => setTimeout( resolve, 0 ) )
);
expect( triggerFetch ).toHaveBeenCalledTimes( 1 );
await waitFor( () =>
expect( triggerFetch ).toHaveBeenCalledWith( {
path: '/wp/v2/widgets/1?context=edit',
parse: false,
} )
);
// Clear the fetch call history.
triggerFetch.mockReset();

rerender( <UI enabled={ false } /> );

Expand All @@ -157,6 +164,6 @@ describe( 'useEntityRecord', () => {
await act(
() => new Promise( ( resolve ) => setTimeout( resolve, 0 ) )
);
expect( triggerFetch ).toHaveBeenCalledTimes( 1 );
expect( triggerFetch ).toHaveBeenCalledTimes( 0 );
} );
} );
86 changes: 57 additions & 29 deletions packages/core-data/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import apiFetch from '@wordpress/api-fetch';
* Internal dependencies
*/
import { STORE_NAME } from './name';
import { getOrLoadEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
import { additionalEntityConfigLoaders, DEFAULT_ENTITY_KEY } from './entities';
import {
forwardResolver,
getNormalizedCommaSeparable,
Expand Down Expand Up @@ -64,8 +64,8 @@ export const getCurrentUser =
*/
export const getEntityRecord =
( kind, name, key = '', query ) =>
async ( { select, dispatch, registry } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
async ( { select, dispatch, registry, resolveSelect } ) => {
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.name === name && config.kind === kind
);
Expand Down Expand Up @@ -230,8 +230,8 @@ export const getEditedEntityRecord = forwardResolver( 'getEntityRecord' );
*/
export const getEntityRecords =
( kind, name, query = {} ) =>
async ( { dispatch, registry } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
async ( { dispatch, registry, resolveSelect } ) => {
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.name === name && config.kind === kind
);
Expand Down Expand Up @@ -431,19 +431,36 @@ export const getEmbedPreview =
*/
export const canUser =
( requestedAction, resource, id ) =>
async ( { dispatch, registry } ) => {
async ( { dispatch, registry, resolveSelect } ) => {
if ( ! ALLOWED_RESOURCE_ACTIONS.includes( requestedAction ) ) {
throw new Error( `'${ requestedAction }' is not a valid action.` );
}

const { hasStartedResolution } = registry.select( STORE_NAME );

// Prevent resolving the same resource twice.
for ( const relatedAction of ALLOWED_RESOURCE_ACTIONS ) {
if ( relatedAction === requestedAction ) {
continue;
}
const isAlreadyResolving = hasStartedResolution( 'canUser', [
relatedAction,
resource,
id,
] );
if ( isAlreadyResolving ) {
return;
}
}

let resourcePath = null;
if ( typeof resource === 'object' ) {
if ( ! resource.kind || ! resource.name ) {
throw new Error( 'The entity resource object is not valid.' );
}

const configs = await dispatch(
getOrLoadEntitiesConfig( resource.kind, resource.name )
const configs = await resolveSelect.getEntitiesConfig(
resource.kind
);
const entityConfig = configs.find(
( config ) =>
Expand All @@ -460,23 +477,6 @@ export const canUser =
resourcePath = `/wp/v2/${ resource }` + ( id ? '/' + id : '' );
}

const { hasStartedResolution } = registry.select( STORE_NAME );

// Prevent resolving the same resource twice.
for ( const relatedAction of ALLOWED_RESOURCE_ACTIONS ) {
if ( relatedAction === requestedAction ) {
continue;
}
const isAlreadyResolving = hasStartedResolution( 'canUser', [
relatedAction,
resource,
id,
] );
if ( isAlreadyResolving ) {
return;
}
}

let response;
try {
response = await apiFetch( {
Expand Down Expand Up @@ -823,8 +823,8 @@ export const getDefaultTemplateId =
*/
export const getRevisions =
( kind, name, recordKey, query = {} ) =>
async ( { dispatch, registry } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
async ( { dispatch, registry, resolveSelect } ) => {
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.name === name && config.kind === kind
);
Expand Down Expand Up @@ -944,8 +944,8 @@ getRevisions.shouldInvalidate = ( action, kind, name, recordKey ) =>
*/
export const getRevision =
( kind, name, recordKey, revisionKey, query ) =>
async ( { dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
async ( { dispatch, resolveSelect } ) => {
const configs = await resolveSelect.getEntitiesConfig( kind );
const entityConfig = configs.find(
( config ) => config.name === name && config.kind === kind
);
Expand Down Expand Up @@ -1017,3 +1017,31 @@ export const getRegisteredPostMeta =
);
}
};

/**
* Requests entity configs for the given kind from the REST API.
*
* @param {string} kind Entity kind.
*/
export const getEntitiesConfig =
( kind ) =>
async ( { dispatch } ) => {
const loader = additionalEntityConfigLoaders.find(
( l ) => l.kind === kind
);

if ( ! loader ) {
return;
}

try {
const configs = await loader.loadEntities();
if ( ! configs.length ) {
return;
}

dispatch.addEntities( configs );
} catch {
// Do nothing if the request comes back with an API error.
}
};
Loading

0 comments on commit 5432049

Please sign in to comment.