Skip to content
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

Core Data: Add the 'getEntitiesConfig' resolver #65871

Merged
merged 4 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading