@wordpress/core-data 6.30.0 → 6.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/build/actions.js +5 -5
- package/build/actions.js.map +1 -1
- package/build/entities.js +84 -44
- package/build/entities.js.map +1 -1
- package/build/hooks/use-query-select.js +15 -16
- package/build/hooks/use-query-select.js.map +1 -1
- package/build/index.js +16 -10
- package/build/index.js.map +1 -1
- package/build/queried-data/selectors.js +9 -0
- package/build/queried-data/selectors.js.map +1 -1
- package/build/resolvers.js +7 -6
- package/build/resolvers.js.map +1 -1
- package/build/selectors.js +5 -0
- package/build/selectors.js.map +1 -1
- package/build-module/actions.js +5 -5
- package/build-module/actions.js.map +1 -1
- package/build-module/entities.js +84 -44
- package/build-module/entities.js.map +1 -1
- package/build-module/hooks/use-query-select.js +15 -16
- package/build-module/hooks/use-query-select.js.map +1 -1
- package/build-module/index.js +17 -11
- package/build-module/index.js.map +1 -1
- package/build-module/queried-data/selectors.js +8 -0
- package/build-module/queried-data/selectors.js.map +1 -1
- package/build-module/resolvers.js +7 -6
- package/build-module/resolvers.js.map +1 -1
- package/build-module/selectors.js +6 -1
- package/build-module/selectors.js.map +1 -1
- package/build-types/entities.d.ts +26 -52
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/queried-data/selectors.d.ts +1 -0
- package/build-types/queried-data/selectors.d.ts.map +1 -1
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/selectors.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/actions.js +5 -5
- package/src/entities.js +84 -54
- package/src/hooks/test/use-entity-record.js +3 -0
- package/src/hooks/test/use-entity-records.js +2 -0
- package/src/hooks/test/use-query-select.js +3 -0
- package/src/hooks/use-query-select.ts +21 -16
- package/src/index.js +27 -13
- package/src/queried-data/selectors.js +6 -0
- package/src/resolvers.js +8 -5
- package/src/selectors.ts +10 -1
- package/src/test/entities.js +19 -10
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/core-data",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.31.0",
|
|
4
4
|
"description": "Access to and manipulation of core WordPress entities.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -31,21 +31,21 @@
|
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/runtime": "^7.16.0",
|
|
34
|
-
"@wordpress/api-fetch": "^6.
|
|
35
|
-
"@wordpress/block-editor": "^12.
|
|
36
|
-
"@wordpress/blocks": "^12.
|
|
37
|
-
"@wordpress/compose": "^6.
|
|
38
|
-
"@wordpress/data": "^9.
|
|
39
|
-
"@wordpress/deprecated": "^3.
|
|
40
|
-
"@wordpress/element": "^5.
|
|
41
|
-
"@wordpress/html-entities": "^3.
|
|
42
|
-
"@wordpress/i18n": "^4.
|
|
43
|
-
"@wordpress/is-shallow-equal": "^4.
|
|
44
|
-
"@wordpress/private-apis": "^0.
|
|
45
|
-
"@wordpress/rich-text": "^6.
|
|
46
|
-
"@wordpress/sync": "^0.
|
|
47
|
-
"@wordpress/undo-manager": "^0.
|
|
48
|
-
"@wordpress/url": "^3.
|
|
34
|
+
"@wordpress/api-fetch": "^6.51.0",
|
|
35
|
+
"@wordpress/block-editor": "^12.22.0",
|
|
36
|
+
"@wordpress/blocks": "^12.31.0",
|
|
37
|
+
"@wordpress/compose": "^6.31.0",
|
|
38
|
+
"@wordpress/data": "^9.24.0",
|
|
39
|
+
"@wordpress/deprecated": "^3.54.0",
|
|
40
|
+
"@wordpress/element": "^5.31.0",
|
|
41
|
+
"@wordpress/html-entities": "^3.54.0",
|
|
42
|
+
"@wordpress/i18n": "^4.54.0",
|
|
43
|
+
"@wordpress/is-shallow-equal": "^4.54.0",
|
|
44
|
+
"@wordpress/private-apis": "^0.36.0",
|
|
45
|
+
"@wordpress/rich-text": "^6.31.0",
|
|
46
|
+
"@wordpress/sync": "^0.16.0",
|
|
47
|
+
"@wordpress/undo-manager": "^0.14.0",
|
|
48
|
+
"@wordpress/url": "^3.55.0",
|
|
49
49
|
"change-case": "^4.1.2",
|
|
50
50
|
"equivalent-key-map": "^0.2.2",
|
|
51
51
|
"fast-deep-equal": "^3.1.3",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"publishConfig": {
|
|
61
61
|
"access": "public"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "ffc07735d0abfb3f69e91d48f25b7fe8d1ef92d2"
|
|
64
64
|
}
|
package/src/actions.js
CHANGED
|
@@ -286,7 +286,7 @@ export const deleteEntityRecord =
|
|
|
286
286
|
{ __unstableFetch = apiFetch, throwOnError = false } = {}
|
|
287
287
|
) =>
|
|
288
288
|
async ( { dispatch } ) => {
|
|
289
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
289
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
290
290
|
const entityConfig = configs.find(
|
|
291
291
|
( config ) => config.kind === kind && config.name === name
|
|
292
292
|
);
|
|
@@ -503,7 +503,7 @@ export const saveEntityRecord =
|
|
|
503
503
|
} = {}
|
|
504
504
|
) =>
|
|
505
505
|
async ( { select, resolveSelect, dispatch } ) => {
|
|
506
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
506
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
507
507
|
const entityConfig = configs.find(
|
|
508
508
|
( config ) => config.kind === kind && config.name === name
|
|
509
509
|
);
|
|
@@ -780,7 +780,7 @@ export const saveEditedEntityRecord =
|
|
|
780
780
|
if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) {
|
|
781
781
|
return;
|
|
782
782
|
}
|
|
783
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
783
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
784
784
|
const entityConfig = configs.find(
|
|
785
785
|
( config ) => config.kind === kind && config.name === name
|
|
786
786
|
);
|
|
@@ -824,7 +824,7 @@ export const __experimentalSaveSpecifiedEntityEdits =
|
|
|
824
824
|
setNestedValue( editsToSave, item, getNestedValue( edits, item ) );
|
|
825
825
|
}
|
|
826
826
|
|
|
827
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
827
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
828
828
|
const entityConfig = configs.find(
|
|
829
829
|
( config ) => config.kind === kind && config.name === name
|
|
830
830
|
);
|
|
@@ -948,7 +948,7 @@ export function receiveDefaultTemplateId( query, templateId ) {
|
|
|
948
948
|
export const receiveRevisions =
|
|
949
949
|
( kind, name, recordKey, records, query, invalidateCache = false, meta ) =>
|
|
950
950
|
async ( { dispatch } ) => {
|
|
951
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
951
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
952
952
|
const entityConfig = configs.find(
|
|
953
953
|
( config ) => config.kind === kind && config.name === name
|
|
954
954
|
);
|
package/src/entities.js
CHANGED
|
@@ -39,6 +39,9 @@ export const rootEntitiesConfig = [
|
|
|
39
39
|
'url',
|
|
40
40
|
].join( ',' ),
|
|
41
41
|
},
|
|
42
|
+
// The entity doesn't support selecting multiple records.
|
|
43
|
+
// The property is maintained for backward compatibility.
|
|
44
|
+
plural: '__unstableBases',
|
|
42
45
|
syncConfig: {
|
|
43
46
|
fetch: async () => {
|
|
44
47
|
return apiFetch( { path: '/' } );
|
|
@@ -58,33 +61,6 @@ export const rootEntitiesConfig = [
|
|
|
58
61
|
syncObjectType: 'root/base',
|
|
59
62
|
getSyncObjectId: () => 'index',
|
|
60
63
|
},
|
|
61
|
-
{
|
|
62
|
-
label: __( 'Site' ),
|
|
63
|
-
name: 'site',
|
|
64
|
-
kind: 'root',
|
|
65
|
-
baseURL: '/wp/v2/settings',
|
|
66
|
-
getTitle: ( record ) => {
|
|
67
|
-
return record?.title ?? __( 'Site Title' );
|
|
68
|
-
},
|
|
69
|
-
syncConfig: {
|
|
70
|
-
fetch: async () => {
|
|
71
|
-
return apiFetch( { path: '/wp/v2/settings' } );
|
|
72
|
-
},
|
|
73
|
-
applyChangesToDoc: ( doc, changes ) => {
|
|
74
|
-
const document = doc.getMap( 'document' );
|
|
75
|
-
Object.entries( changes ).forEach( ( [ key, value ] ) => {
|
|
76
|
-
if ( document.get( key ) !== value ) {
|
|
77
|
-
document.set( key, value );
|
|
78
|
-
}
|
|
79
|
-
} );
|
|
80
|
-
},
|
|
81
|
-
fromCRDTDoc: ( doc ) => {
|
|
82
|
-
return doc.getMap( 'document' ).toJSON();
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
syncObjectType: 'root/site',
|
|
86
|
-
getSyncObjectId: () => 'index',
|
|
87
|
-
},
|
|
88
64
|
{
|
|
89
65
|
label: __( 'Post Type' ),
|
|
90
66
|
name: 'postType',
|
|
@@ -92,6 +68,7 @@ export const rootEntitiesConfig = [
|
|
|
92
68
|
key: 'slug',
|
|
93
69
|
baseURL: '/wp/v2/types',
|
|
94
70
|
baseURLParams: { context: 'edit' },
|
|
71
|
+
plural: 'postTypes',
|
|
95
72
|
syncConfig: {
|
|
96
73
|
fetch: async ( id ) => {
|
|
97
74
|
return apiFetch( {
|
|
@@ -220,6 +197,7 @@ export const rootEntitiesConfig = [
|
|
|
220
197
|
kind: 'root',
|
|
221
198
|
baseURL: '/wp/v2/themes',
|
|
222
199
|
baseURLParams: { context: 'edit' },
|
|
200
|
+
plural: 'themes',
|
|
223
201
|
key: 'stylesheet',
|
|
224
202
|
},
|
|
225
203
|
{
|
|
@@ -228,6 +206,7 @@ export const rootEntitiesConfig = [
|
|
|
228
206
|
kind: 'root',
|
|
229
207
|
baseURL: '/wp/v2/plugins',
|
|
230
208
|
baseURLParams: { context: 'edit' },
|
|
209
|
+
plural: 'plugins',
|
|
231
210
|
key: 'plugin',
|
|
232
211
|
},
|
|
233
212
|
{
|
|
@@ -244,6 +223,12 @@ export const rootEntitiesConfig = [
|
|
|
244
223
|
export const additionalEntityConfigLoaders = [
|
|
245
224
|
{ kind: 'postType', loadEntities: loadPostTypeEntities },
|
|
246
225
|
{ kind: 'taxonomy', loadEntities: loadTaxonomyEntities },
|
|
226
|
+
{
|
|
227
|
+
kind: 'root',
|
|
228
|
+
name: 'site',
|
|
229
|
+
plural: 'sites',
|
|
230
|
+
loadEntities: loadSiteEntity,
|
|
231
|
+
},
|
|
247
232
|
];
|
|
248
233
|
|
|
249
234
|
/**
|
|
@@ -401,39 +386,76 @@ async function loadTaxonomyEntities() {
|
|
|
401
386
|
}
|
|
402
387
|
|
|
403
388
|
/**
|
|
404
|
-
* Returns the entity
|
|
389
|
+
* Returns the Site entity.
|
|
390
|
+
*
|
|
391
|
+
* @return {Promise} Entity promise
|
|
392
|
+
*/
|
|
393
|
+
async function loadSiteEntity() {
|
|
394
|
+
const entity = {
|
|
395
|
+
label: __( 'Site' ),
|
|
396
|
+
name: 'site',
|
|
397
|
+
kind: 'root',
|
|
398
|
+
baseURL: '/wp/v2/settings',
|
|
399
|
+
syncConfig: {
|
|
400
|
+
fetch: async () => {
|
|
401
|
+
return apiFetch( { path: '/wp/v2/settings' } );
|
|
402
|
+
},
|
|
403
|
+
applyChangesToDoc: ( doc, changes ) => {
|
|
404
|
+
const document = doc.getMap( 'document' );
|
|
405
|
+
Object.entries( changes ).forEach( ( [ key, value ] ) => {
|
|
406
|
+
if ( document.get( key ) !== value ) {
|
|
407
|
+
document.set( key, value );
|
|
408
|
+
}
|
|
409
|
+
} );
|
|
410
|
+
},
|
|
411
|
+
fromCRDTDoc: ( doc ) => {
|
|
412
|
+
return doc.getMap( 'document' ).toJSON();
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
syncObjectType: 'root/site',
|
|
416
|
+
getSyncObjectId: () => 'index',
|
|
417
|
+
meta: {},
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const site = await apiFetch( {
|
|
421
|
+
path: entity.baseURL,
|
|
422
|
+
method: 'OPTIONS',
|
|
423
|
+
} );
|
|
424
|
+
|
|
425
|
+
const labels = {};
|
|
426
|
+
Object.entries( site?.schema?.properties ?? {} ).forEach(
|
|
427
|
+
( [ key, value ] ) => {
|
|
428
|
+
// Ignore properties `title` and `type` keys.
|
|
429
|
+
if ( typeof value === 'object' && value.title ) {
|
|
430
|
+
labels[ key ] = value.title;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
return [ { ...entity, meta: { labels } } ];
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Returns the entity's getter method name given its kind and name or plural name.
|
|
405
440
|
*
|
|
406
441
|
* @example
|
|
407
442
|
* ```js
|
|
408
443
|
* const nameSingular = getMethodName( 'root', 'theme', 'get' );
|
|
409
444
|
* // nameSingular is getRootTheme
|
|
410
445
|
*
|
|
411
|
-
* const namePlural = getMethodName( 'root', '
|
|
446
|
+
* const namePlural = getMethodName( 'root', 'themes', 'set' );
|
|
412
447
|
* // namePlural is setRootThemes
|
|
413
448
|
* ```
|
|
414
449
|
*
|
|
415
|
-
* @param {string}
|
|
416
|
-
* @param {string}
|
|
417
|
-
* @param {string}
|
|
418
|
-
* @param {boolean} usePlural Whether to use the plural form or not.
|
|
450
|
+
* @param {string} kind Entity kind.
|
|
451
|
+
* @param {string} name Entity name or plural name.
|
|
452
|
+
* @param {string} prefix Function prefix.
|
|
419
453
|
*
|
|
420
454
|
* @return {string} Method name
|
|
421
455
|
*/
|
|
422
|
-
export const getMethodName = (
|
|
423
|
-
kind,
|
|
424
|
-
name,
|
|
425
|
-
prefix = 'get',
|
|
426
|
-
usePlural = false
|
|
427
|
-
) => {
|
|
428
|
-
const entityConfig = rootEntitiesConfig.find(
|
|
429
|
-
( config ) => config.kind === kind && config.name === name
|
|
430
|
-
);
|
|
456
|
+
export const getMethodName = ( kind, name, prefix = 'get' ) => {
|
|
431
457
|
const kindPrefix = kind === 'root' ? '' : pascalCase( kind );
|
|
432
|
-
const
|
|
433
|
-
const suffix =
|
|
434
|
-
usePlural && 'plural' in entityConfig && entityConfig?.plural
|
|
435
|
-
? pascalCase( entityConfig.plural )
|
|
436
|
-
: nameSuffix;
|
|
458
|
+
const suffix = pascalCase( name );
|
|
437
459
|
return `${ prefix }${ kindPrefix }${ suffix }`;
|
|
438
460
|
};
|
|
439
461
|
|
|
@@ -447,17 +469,21 @@ function registerSyncConfigs( configs ) {
|
|
|
447
469
|
}
|
|
448
470
|
|
|
449
471
|
/**
|
|
450
|
-
* Loads the
|
|
472
|
+
* Loads the entities into the store.
|
|
451
473
|
*
|
|
452
|
-
*
|
|
474
|
+
* Note: The `name` argument is used for `root` entities requiring additional server data.
|
|
453
475
|
*
|
|
476
|
+
* @param {string} kind Kind
|
|
477
|
+
* @param {string} name Name
|
|
454
478
|
* @return {(thunkArgs: object) => Promise<Array>} Entities
|
|
455
479
|
*/
|
|
456
480
|
export const getOrLoadEntitiesConfig =
|
|
457
|
-
( kind ) =>
|
|
481
|
+
( kind, name ) =>
|
|
458
482
|
async ( { select, dispatch } ) => {
|
|
459
483
|
let configs = select.getEntitiesConfig( kind );
|
|
460
|
-
|
|
484
|
+
const hasConfig = !! select.getEntityConfig( kind, name );
|
|
485
|
+
|
|
486
|
+
if ( configs?.length > 0 && hasConfig ) {
|
|
461
487
|
if ( window.__experimentalEnableSync ) {
|
|
462
488
|
if ( process.env.IS_GUTENBERG_PLUGIN ) {
|
|
463
489
|
registerSyncConfigs( configs );
|
|
@@ -467,9 +493,13 @@ export const getOrLoadEntitiesConfig =
|
|
|
467
493
|
return configs;
|
|
468
494
|
}
|
|
469
495
|
|
|
470
|
-
const loader = additionalEntityConfigLoaders.find(
|
|
471
|
-
(
|
|
472
|
-
|
|
496
|
+
const loader = additionalEntityConfigLoaders.find( ( l ) => {
|
|
497
|
+
if ( ! name || ! l.name ) {
|
|
498
|
+
return l.kind === kind;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return l.kind === kind && l.name === name;
|
|
502
|
+
} );
|
|
473
503
|
if ( ! loader ) {
|
|
474
504
|
return [];
|
|
475
505
|
}
|
|
@@ -51,6 +51,7 @@ describe( 'useEntityRecord', () => {
|
|
|
51
51
|
record: undefined,
|
|
52
52
|
save: expect.any( Function ),
|
|
53
53
|
hasResolved: false,
|
|
54
|
+
hasStarted: false,
|
|
54
55
|
isResolving: false,
|
|
55
56
|
status: 'IDLE',
|
|
56
57
|
} );
|
|
@@ -70,6 +71,7 @@ describe( 'useEntityRecord', () => {
|
|
|
70
71
|
record: { hello: 'world', id: 1 },
|
|
71
72
|
save: expect.any( Function ),
|
|
72
73
|
hasResolved: true,
|
|
74
|
+
hasStarted: true,
|
|
73
75
|
isResolving: false,
|
|
74
76
|
status: 'SUCCESS',
|
|
75
77
|
} );
|
|
@@ -99,6 +101,7 @@ describe( 'useEntityRecord', () => {
|
|
|
99
101
|
record: { hello: 'world', id: 1 },
|
|
100
102
|
save: expect.any( Function ),
|
|
101
103
|
hasResolved: true,
|
|
104
|
+
hasStarted: true,
|
|
102
105
|
isResolving: false,
|
|
103
106
|
status: 'SUCCESS',
|
|
104
107
|
} )
|
|
@@ -49,6 +49,7 @@ describe( 'useEntityRecords', () => {
|
|
|
49
49
|
expect( data ).toEqual( {
|
|
50
50
|
records: null,
|
|
51
51
|
hasResolved: false,
|
|
52
|
+
hasStarted: false,
|
|
52
53
|
isResolving: false,
|
|
53
54
|
status: 'IDLE',
|
|
54
55
|
totalItems: null,
|
|
@@ -65,6 +66,7 @@ describe( 'useEntityRecords', () => {
|
|
|
65
66
|
expect( data ).toEqual( {
|
|
66
67
|
records: TEST_RECORDS,
|
|
67
68
|
hasResolved: true,
|
|
69
|
+
hasStarted: true,
|
|
68
70
|
isResolving: false,
|
|
69
71
|
status: 'SUCCESS',
|
|
70
72
|
totalItems: null,
|
|
@@ -116,6 +116,7 @@ describe( 'useQuerySelect', () => {
|
|
|
116
116
|
data: 'bar',
|
|
117
117
|
isResolving: false,
|
|
118
118
|
hasResolved: false,
|
|
119
|
+
hasStarted: false,
|
|
119
120
|
status: 'IDLE',
|
|
120
121
|
} );
|
|
121
122
|
} );
|
|
@@ -165,6 +166,7 @@ describe( 'useQuerySelect', () => {
|
|
|
165
166
|
data: 10,
|
|
166
167
|
isResolving: false,
|
|
167
168
|
hasResolved: false,
|
|
169
|
+
hasStarted: false,
|
|
168
170
|
status: 'IDLE',
|
|
169
171
|
} );
|
|
170
172
|
|
|
@@ -180,6 +182,7 @@ describe( 'useQuerySelect', () => {
|
|
|
180
182
|
data: 15,
|
|
181
183
|
isResolving: false,
|
|
182
184
|
hasResolved: true,
|
|
185
|
+
hasStarted: true,
|
|
183
186
|
status: 'SUCCESS',
|
|
184
187
|
} )
|
|
185
188
|
);
|
|
@@ -21,7 +21,7 @@ interface QuerySelectResponse< Data > {
|
|
|
21
21
|
/** the requested selector return value */
|
|
22
22
|
data: Data;
|
|
23
23
|
|
|
24
|
-
/** is the record still being resolved? Via the `
|
|
24
|
+
/** is the record still being resolved? Via the `isResolving` meta-selector */
|
|
25
25
|
isResolving: boolean;
|
|
26
26
|
|
|
27
27
|
/** was the resolution started? Via the `hasStartedResolution` meta-selector */
|
|
@@ -108,31 +108,36 @@ const enrichSelectors = memoize( ( ( selectors ) => {
|
|
|
108
108
|
get:
|
|
109
109
|
() =>
|
|
110
110
|
( ...args: unknown[] ) => {
|
|
111
|
-
const { getIsResolving, hasFinishedResolution } = selectors;
|
|
112
|
-
const isResolving = !! getIsResolving( selectorName, args );
|
|
113
|
-
const hasResolved =
|
|
114
|
-
! isResolving &&
|
|
115
|
-
hasFinishedResolution( selectorName, args );
|
|
116
111
|
const data = selectors[ selectorName ]( ...args );
|
|
112
|
+
const resolutionStatus = selectors.getResolutionState(
|
|
113
|
+
selectorName,
|
|
114
|
+
args
|
|
115
|
+
)?.status;
|
|
117
116
|
|
|
118
117
|
let status;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
switch ( resolutionStatus ) {
|
|
119
|
+
case 'resolving':
|
|
120
|
+
status = Status.Resolving;
|
|
121
|
+
break;
|
|
122
|
+
case 'finished':
|
|
123
123
|
status = Status.Success;
|
|
124
|
-
|
|
124
|
+
break;
|
|
125
|
+
case 'error':
|
|
125
126
|
status = Status.Error;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
break;
|
|
128
|
+
case undefined:
|
|
129
|
+
status = Status.Idle;
|
|
130
|
+
break;
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
return {
|
|
132
134
|
data,
|
|
133
135
|
status,
|
|
134
|
-
isResolving,
|
|
135
|
-
|
|
136
|
+
isResolving: status === Status.Resolving,
|
|
137
|
+
hasStarted: status !== Status.Idle,
|
|
138
|
+
hasResolved:
|
|
139
|
+
status === Status.Success ||
|
|
140
|
+
status === Status.Error,
|
|
136
141
|
};
|
|
137
142
|
},
|
|
138
143
|
} );
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,11 @@ import * as privateSelectors from './private-selectors';
|
|
|
12
12
|
import * as actions from './actions';
|
|
13
13
|
import * as resolvers from './resolvers';
|
|
14
14
|
import createLocksActions from './locks/actions';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
rootEntitiesConfig,
|
|
17
|
+
additionalEntityConfigLoaders,
|
|
18
|
+
getMethodName,
|
|
19
|
+
} from './entities';
|
|
16
20
|
import { STORE_NAME } from './name';
|
|
17
21
|
import { unlock } from './private-apis';
|
|
18
22
|
|
|
@@ -20,29 +24,39 @@ import { unlock } from './private-apis';
|
|
|
20
24
|
// (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
|
|
21
25
|
// Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy...
|
|
22
26
|
// The "kind" and the "name" of the entity are combined to generate these shortcuts.
|
|
27
|
+
const entitiesConfig = [
|
|
28
|
+
...rootEntitiesConfig,
|
|
29
|
+
...additionalEntityConfigLoaders.filter( ( config ) => !! config.name ),
|
|
30
|
+
];
|
|
23
31
|
|
|
24
|
-
const entitySelectors =
|
|
25
|
-
const { kind, name } = entity;
|
|
32
|
+
const entitySelectors = entitiesConfig.reduce( ( result, entity ) => {
|
|
33
|
+
const { kind, name, plural } = entity;
|
|
26
34
|
result[ getMethodName( kind, name ) ] = ( state, key, query ) =>
|
|
27
35
|
selectors.getEntityRecord( state, kind, name, key, query );
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
|
|
37
|
+
if ( plural ) {
|
|
38
|
+
result[ getMethodName( kind, plural, 'get' ) ] = ( state, query ) =>
|
|
39
|
+
selectors.getEntityRecords( state, kind, name, query );
|
|
40
|
+
}
|
|
30
41
|
return result;
|
|
31
42
|
}, {} );
|
|
32
43
|
|
|
33
|
-
const entityResolvers =
|
|
34
|
-
const { kind, name } = entity;
|
|
44
|
+
const entityResolvers = entitiesConfig.reduce( ( result, entity ) => {
|
|
45
|
+
const { kind, name, plural } = entity;
|
|
35
46
|
result[ getMethodName( kind, name ) ] = ( key, query ) =>
|
|
36
47
|
resolvers.getEntityRecord( kind, name, key, query );
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
|
|
49
|
+
if ( plural ) {
|
|
50
|
+
const pluralMethodName = getMethodName( kind, plural, 'get' );
|
|
51
|
+
result[ pluralMethodName ] = ( ...args ) =>
|
|
52
|
+
resolvers.getEntityRecords( kind, name, ...args );
|
|
53
|
+
result[ pluralMethodName ].shouldInvalidate = ( action ) =>
|
|
54
|
+
resolvers.getEntityRecords.shouldInvalidate( action, kind, name );
|
|
55
|
+
}
|
|
42
56
|
return result;
|
|
43
57
|
}, {} );
|
|
44
58
|
|
|
45
|
-
const entityActions =
|
|
59
|
+
const entityActions = entitiesConfig.reduce( ( result, entity ) => {
|
|
46
60
|
const { kind, name } = entity;
|
|
47
61
|
result[ getMethodName( kind, name, 'save' ) ] = ( record, options ) =>
|
|
48
62
|
actions.saveEntityRecord( kind, name, record, options );
|
|
@@ -126,3 +126,9 @@ export function getQueriedTotalItems( state, query = {} ) {
|
|
|
126
126
|
|
|
127
127
|
return state.queries?.[ context ]?.[ stableKey ]?.meta?.totalItems ?? null;
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
export function getQueriedTotalPages( state, query = {} ) {
|
|
131
|
+
const { stableKey, context } = getQueryParts( query );
|
|
132
|
+
|
|
133
|
+
return state.queries?.[ context ]?.[ stableKey ]?.meta?.totalPages ?? null;
|
|
134
|
+
}
|
package/src/resolvers.js
CHANGED
|
@@ -59,7 +59,7 @@ export const getCurrentUser =
|
|
|
59
59
|
export const getEntityRecord =
|
|
60
60
|
( kind, name, key = '', query ) =>
|
|
61
61
|
async ( { select, dispatch } ) => {
|
|
62
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
62
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
63
63
|
const entityConfig = configs.find(
|
|
64
64
|
( config ) => config.name === name && config.kind === kind
|
|
65
65
|
);
|
|
@@ -194,7 +194,7 @@ export const getEditedEntityRecord = forwardResolver( 'getEntityRecord' );
|
|
|
194
194
|
export const getEntityRecords =
|
|
195
195
|
( kind, name, query = {} ) =>
|
|
196
196
|
async ( { dispatch } ) => {
|
|
197
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
197
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
198
198
|
const entityConfig = configs.find(
|
|
199
199
|
( config ) => config.name === name && config.kind === kind
|
|
200
200
|
);
|
|
@@ -238,6 +238,9 @@ export const getEntityRecords =
|
|
|
238
238
|
totalItems: parseInt(
|
|
239
239
|
response.headers.get( 'X-WP-Total' )
|
|
240
240
|
),
|
|
241
|
+
totalPages: parseInt(
|
|
242
|
+
response.headers.get( 'X-WP-TotalPages' )
|
|
243
|
+
),
|
|
241
244
|
};
|
|
242
245
|
} else {
|
|
243
246
|
records = Object.values( await apiFetch( { path } ) );
|
|
@@ -426,7 +429,7 @@ export const canUser =
|
|
|
426
429
|
export const canUserEditEntityRecord =
|
|
427
430
|
( kind, name, recordId ) =>
|
|
428
431
|
async ( { dispatch } ) => {
|
|
429
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
432
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
430
433
|
const entityConfig = configs.find(
|
|
431
434
|
( config ) => config.name === name && config.kind === kind
|
|
432
435
|
);
|
|
@@ -723,7 +726,7 @@ export const getDefaultTemplateId =
|
|
|
723
726
|
export const getRevisions =
|
|
724
727
|
( kind, name, recordKey, query = {} ) =>
|
|
725
728
|
async ( { dispatch } ) => {
|
|
726
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
729
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
727
730
|
const entityConfig = configs.find(
|
|
728
731
|
( config ) => config.name === name && config.kind === kind
|
|
729
732
|
);
|
|
@@ -848,7 +851,7 @@ getRevisions.shouldInvalidate = ( action, kind, name, recordKey ) =>
|
|
|
848
851
|
export const getRevision =
|
|
849
852
|
( kind, name, recordKey, revisionKey, query ) =>
|
|
850
853
|
async ( { dispatch } ) => {
|
|
851
|
-
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
854
|
+
const configs = await dispatch( getOrLoadEntitiesConfig( kind, name ) );
|
|
852
855
|
const entityConfig = configs.find(
|
|
853
856
|
( config ) => config.name === name && config.kind === kind
|
|
854
857
|
);
|
package/src/selectors.ts
CHANGED
|
@@ -14,7 +14,11 @@ import deprecated from '@wordpress/deprecated';
|
|
|
14
14
|
* Internal dependencies
|
|
15
15
|
*/
|
|
16
16
|
import { STORE_NAME } from './name';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
getQueriedItems,
|
|
19
|
+
getQueriedTotalItems,
|
|
20
|
+
getQueriedTotalPages,
|
|
21
|
+
} from './queried-data';
|
|
18
22
|
import { DEFAULT_ENTITY_KEY } from './entities';
|
|
19
23
|
import {
|
|
20
24
|
getNormalizedCommaSeparable,
|
|
@@ -623,6 +627,11 @@ export const getEntityRecordsTotalPages = (
|
|
|
623
627
|
if ( query.per_page === -1 ) return 1;
|
|
624
628
|
const totalItems = getQueriedTotalItems( queriedState, query );
|
|
625
629
|
if ( ! totalItems ) return totalItems;
|
|
630
|
+
// If `per_page` is not set and the query relies on the defaults of the
|
|
631
|
+
// REST endpoint, get the info from query's meta.
|
|
632
|
+
if ( ! query.per_page ) {
|
|
633
|
+
return getQueriedTotalPages( queriedState, query );
|
|
634
|
+
}
|
|
626
635
|
return Math.ceil( totalItems / query.per_page );
|
|
627
636
|
};
|
|
628
637
|
|
package/src/test/entities.js
CHANGED
|
@@ -27,14 +27,8 @@ describe( 'getMethodName', () => {
|
|
|
27
27
|
expect( methodName ).toEqual( 'setPostType' );
|
|
28
28
|
} );
|
|
29
29
|
|
|
30
|
-
it( 'should use the plural form', () => {
|
|
31
|
-
const methodName = getMethodName( 'root', 'postType', 'get', true );
|
|
32
|
-
|
|
33
|
-
expect( methodName ).toEqual( 'getPostTypes' );
|
|
34
|
-
} );
|
|
35
|
-
|
|
36
30
|
it( 'should use the given plural form', () => {
|
|
37
|
-
const methodName = getMethodName( 'root', '
|
|
31
|
+
const methodName = getMethodName( 'root', 'taxonomies', 'get' );
|
|
38
32
|
|
|
39
33
|
expect( methodName ).toEqual( 'getTaxonomies' );
|
|
40
34
|
} );
|
|
@@ -58,9 +52,16 @@ describe( 'getKindEntities', () => {
|
|
|
58
52
|
const dispatch = jest.fn();
|
|
59
53
|
const select = {
|
|
60
54
|
getEntitiesConfig: jest.fn( () => entities ),
|
|
55
|
+
getEntityConfig: jest.fn( () => ( {
|
|
56
|
+
kind: 'postType',
|
|
57
|
+
name: 'post',
|
|
58
|
+
} ) ),
|
|
61
59
|
};
|
|
62
60
|
const entities = [ { kind: 'postType' } ];
|
|
63
|
-
await getOrLoadEntitiesConfig(
|
|
61
|
+
await getOrLoadEntitiesConfig(
|
|
62
|
+
'postType',
|
|
63
|
+
'post'
|
|
64
|
+
)( { dispatch, select } );
|
|
64
65
|
expect( dispatch ).not.toHaveBeenCalled();
|
|
65
66
|
} );
|
|
66
67
|
|
|
@@ -68,8 +69,12 @@ describe( 'getKindEntities', () => {
|
|
|
68
69
|
const dispatch = jest.fn();
|
|
69
70
|
const select = {
|
|
70
71
|
getEntitiesConfig: jest.fn( () => [] ),
|
|
72
|
+
getEntityConfig: jest.fn( () => undefined ),
|
|
71
73
|
};
|
|
72
|
-
await getOrLoadEntitiesConfig(
|
|
74
|
+
await getOrLoadEntitiesConfig(
|
|
75
|
+
'unknownKind',
|
|
76
|
+
undefined
|
|
77
|
+
)( { dispatch, select } );
|
|
73
78
|
expect( dispatch ).not.toHaveBeenCalled();
|
|
74
79
|
} );
|
|
75
80
|
|
|
@@ -88,10 +93,14 @@ describe( 'getKindEntities', () => {
|
|
|
88
93
|
const dispatch = jest.fn();
|
|
89
94
|
const select = {
|
|
90
95
|
getEntitiesConfig: jest.fn( () => [] ),
|
|
96
|
+
getEntityConfig: jest.fn( () => undefined ),
|
|
91
97
|
};
|
|
92
98
|
triggerFetch.mockImplementation( () => fetchedEntities );
|
|
93
99
|
|
|
94
|
-
await getOrLoadEntitiesConfig(
|
|
100
|
+
await getOrLoadEntitiesConfig(
|
|
101
|
+
'postType',
|
|
102
|
+
'post'
|
|
103
|
+
)( { dispatch, select } );
|
|
95
104
|
expect( dispatch ).toHaveBeenCalledTimes( 1 );
|
|
96
105
|
expect( dispatch.mock.calls[ 0 ][ 0 ].type ).toBe( 'ADD_ENTITIES' );
|
|
97
106
|
expect( dispatch.mock.calls[ 0 ][ 0 ].entities.length ).toBe( 1 );
|