@wordpress/core-data 6.22.0 → 6.24.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +77 -2
  3. package/build/actions.js +55 -0
  4. package/build/actions.js.map +1 -1
  5. package/build/entities.js +18 -3
  6. package/build/entities.js.map +1 -1
  7. package/build/entity-provider.js +7 -1
  8. package/build/entity-provider.js.map +1 -1
  9. package/build/entity-types/global-styles-revision.js +6 -0
  10. package/build/entity-types/global-styles-revision.js.map +1 -0
  11. package/build/entity-types/index.js.map +1 -1
  12. package/build/entity-types/post-revision.js +6 -0
  13. package/build/entity-types/post-revision.js.map +1 -0
  14. package/build/hooks/use-entity-record.js +16 -5
  15. package/build/hooks/use-entity-record.js.map +1 -1
  16. package/build/queried-data/reducer.js +3 -1
  17. package/build/queried-data/reducer.js.map +1 -1
  18. package/build/queried-data/selectors.js +3 -1
  19. package/build/queried-data/selectors.js.map +1 -1
  20. package/build/reducer.js +52 -4
  21. package/build/reducer.js.map +1 -1
  22. package/build/resolvers.js +131 -3
  23. package/build/resolvers.js.map +1 -1
  24. package/build/selectors.js +92 -1
  25. package/build/selectors.js.map +1 -1
  26. package/build-module/actions.js +52 -0
  27. package/build-module/actions.js.map +1 -1
  28. package/build-module/entities.js +18 -3
  29. package/build-module/entities.js.map +1 -1
  30. package/build-module/entity-provider.js +7 -1
  31. package/build-module/entity-provider.js.map +1 -1
  32. package/build-module/entity-types/global-styles-revision.js +2 -0
  33. package/build-module/entity-types/global-styles-revision.js.map +1 -0
  34. package/build-module/entity-types/index.js.map +1 -1
  35. package/build-module/entity-types/post-revision.js +2 -0
  36. package/build-module/entity-types/post-revision.js.map +1 -0
  37. package/build-module/hooks/use-entity-record.js +16 -5
  38. package/build-module/hooks/use-entity-record.js.map +1 -1
  39. package/build-module/queried-data/reducer.js +3 -1
  40. package/build-module/queried-data/reducer.js.map +1 -1
  41. package/build-module/queried-data/selectors.js +3 -1
  42. package/build-module/queried-data/selectors.js.map +1 -1
  43. package/build-module/reducer.js +51 -4
  44. package/build-module/reducer.js.map +1 -1
  45. package/build-module/resolvers.js +127 -2
  46. package/build-module/resolvers.js.map +1 -1
  47. package/build-module/selectors.js +88 -1
  48. package/build-module/selectors.js.map +1 -1
  49. package/build-types/actions.d.ts +14 -0
  50. package/build-types/actions.d.ts.map +1 -1
  51. package/build-types/entities.d.ts +23 -1
  52. package/build-types/entities.d.ts.map +1 -1
  53. package/build-types/entity-provider.d.ts.map +1 -1
  54. package/build-types/entity-types/global-styles-revision.d.ts +43 -0
  55. package/build-types/entity-types/global-styles-revision.d.ts.map +1 -0
  56. package/build-types/entity-types/index.d.ts +4 -2
  57. package/build-types/entity-types/index.d.ts.map +1 -1
  58. package/build-types/entity-types/post-revision.d.ts +76 -0
  59. package/build-types/entity-types/post-revision.d.ts.map +1 -0
  60. package/build-types/hooks/use-entity-record.d.ts.map +1 -1
  61. package/build-types/index.d.ts +19 -4
  62. package/build-types/index.d.ts.map +1 -1
  63. package/build-types/queried-data/selectors.d.ts.map +1 -1
  64. package/build-types/reducer.d.ts +10 -0
  65. package/build-types/reducer.d.ts.map +1 -1
  66. package/build-types/resolvers.d.ts +12 -0
  67. package/build-types/resolvers.d.ts.map +1 -1
  68. package/build-types/selectors.d.ts +54 -3
  69. package/build-types/selectors.d.ts.map +1 -1
  70. package/package.json +17 -17
  71. package/src/actions.js +61 -0
  72. package/src/entities.js +33 -1
  73. package/src/entity-provider.js +8 -1
  74. package/src/entity-types/global-styles-revision.ts +47 -0
  75. package/src/entity-types/index.ts +6 -0
  76. package/src/entity-types/post-revision.ts +93 -0
  77. package/src/hooks/test/use-entity-record.js +41 -0
  78. package/src/hooks/use-entity-record.ts +30 -18
  79. package/src/queried-data/reducer.js +3 -3
  80. package/src/queried-data/selectors.js +3 -1
  81. package/src/queried-data/test/reducer.js +11 -0
  82. package/src/reducer.js +68 -2
  83. package/src/resolvers.js +176 -2
  84. package/src/selectors.ts +141 -1
  85. package/src/test/entities.js +9 -0
  86. package/src/test/reducer.js +235 -0
  87. package/src/test/selectors.js +96 -0
  88. package/tsconfig.tsbuildinfo +1 -1
package/src/selectors.ts CHANGED
@@ -46,6 +46,7 @@ export interface State {
46
46
  users: UserState;
47
47
  navigationFallbackId: EntityRecordKey;
48
48
  userPatternCategories: Array< UserPatternCategory >;
49
+ defaultTemplates: Record< string, string >;
49
50
  }
50
51
 
51
52
  type EntityRecordKey = string | number;
@@ -61,6 +62,16 @@ interface QueriedData {
61
62
  queries: Record< ET.Context, Record< string, Array< number > > >;
62
63
  }
63
64
 
65
+ type RevisionRecord =
66
+ | Record< ET.Context, Record< number, ET.PostRevision > >
67
+ | Record< ET.Context, Record< number, ET.GlobalStylesRevision > >;
68
+
69
+ interface RevisionsQueriedData {
70
+ items: RevisionRecord;
71
+ itemIsComplete: Record< ET.Context, Record< number, boolean > >;
72
+ queries: Record< ET.Context, Record< string, Array< number > > >;
73
+ }
74
+
64
75
  interface EntityState< EntityRecord extends ET.EntityRecord > {
65
76
  edits: Record< string, Partial< EntityRecord > >;
66
77
  saving: Record<
@@ -69,6 +80,7 @@ interface EntityState< EntityRecord extends ET.EntityRecord > {
69
80
  >;
70
81
  deleting: Record< string, Partial< { pending: boolean; error: Error } > >;
71
82
  queriedData: QueriedData;
83
+ revisions?: RevisionsQueriedData;
72
84
  }
73
85
 
74
86
  interface EntityConfig {
@@ -81,6 +93,12 @@ interface UserState {
81
93
  byId: Record< EntityRecordKey, ET.User< 'edit' > >;
82
94
  }
83
95
 
96
+ type TemplateQuery = {
97
+ slug?: string;
98
+ is_custom?: boolean;
99
+ ignore_empty?: boolean;
100
+ };
101
+
84
102
  export interface UserPatternCategory {
85
103
  id: number;
86
104
  name: string;
@@ -1335,13 +1353,20 @@ export function getUserPatternCategories(
1335
1353
  /**
1336
1354
  * Returns the revisions of the current global styles theme.
1337
1355
  *
1338
- * @param state Data state.
1356
+ * @deprecated since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post.
1357
+ *
1358
+ * @param state Data state.
1339
1359
  *
1340
1360
  * @return The current global styles.
1341
1361
  */
1342
1362
  export function getCurrentThemeGlobalStylesRevisions(
1343
1363
  state: State
1344
1364
  ): Array< object > | null {
1365
+ deprecated( "select( 'core' ).getCurrentThemeGlobalStylesRevisions()", {
1366
+ since: '6.5.0',
1367
+ alternative:
1368
+ "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )",
1369
+ } );
1345
1370
  const currentGlobalStylesId =
1346
1371
  __experimentalGetCurrentGlobalStylesId( state );
1347
1372
 
@@ -1351,3 +1376,118 @@ export function getCurrentThemeGlobalStylesRevisions(
1351
1376
 
1352
1377
  return state.themeGlobalStyleRevisions[ currentGlobalStylesId ];
1353
1378
  }
1379
+
1380
+ /**
1381
+ * Returns the default template use to render a given query.
1382
+ *
1383
+ * @param state Data state.
1384
+ * @param query Query.
1385
+ *
1386
+ * @return The default template id for the given query.
1387
+ */
1388
+ export function getDefaultTemplateId(
1389
+ state: State,
1390
+ query: TemplateQuery
1391
+ ): string {
1392
+ return state.defaultTemplates[ JSON.stringify( query ) ];
1393
+ }
1394
+
1395
+ /**
1396
+ * Returns an entity's revisions.
1397
+ *
1398
+ * @param state State tree
1399
+ * @param kind Entity kind.
1400
+ * @param name Entity name.
1401
+ * @param recordKey The key of the entity record whose revisions you want to fetch.
1402
+ * @param query Optional query. If requesting specific
1403
+ * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]".
1404
+ *
1405
+ * @return Record.
1406
+ */
1407
+ export const getRevisions = (
1408
+ state: State,
1409
+ kind: string,
1410
+ name: string,
1411
+ recordKey: EntityRecordKey,
1412
+ query?: GetRecordsHttpQuery
1413
+ ): RevisionRecord[] | null => {
1414
+ const queriedStateRevisions =
1415
+ state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ];
1416
+ if ( ! queriedStateRevisions ) {
1417
+ return null;
1418
+ }
1419
+
1420
+ return getQueriedItems( queriedStateRevisions, query );
1421
+ };
1422
+
1423
+ /**
1424
+ * Returns a single, specific revision of a parent entity.
1425
+ *
1426
+ * @param state State tree
1427
+ * @param kind Entity kind.
1428
+ * @param name Entity name.
1429
+ * @param recordKey The key of the entity record whose revisions you want to fetch.
1430
+ * @param revisionKey The revision's key.
1431
+ * @param query Optional query. If requesting specific
1432
+ * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]".
1433
+ *
1434
+ * @return Record.
1435
+ */
1436
+ export const getRevision = createSelector(
1437
+ (
1438
+ state: State,
1439
+ kind: string,
1440
+ name: string,
1441
+ recordKey: EntityRecordKey,
1442
+ revisionKey: EntityRecordKey,
1443
+ query?: GetRecordsHttpQuery
1444
+ ): RevisionRecord | Record< PropertyKey, never > | undefined => {
1445
+ const queriedState =
1446
+ state.entities.records?.[ kind ]?.[ name ]?.revisions?.[
1447
+ recordKey
1448
+ ];
1449
+
1450
+ if ( ! queriedState ) {
1451
+ return undefined;
1452
+ }
1453
+
1454
+ const context = query?.context ?? 'default';
1455
+
1456
+ if ( query === undefined ) {
1457
+ // If expecting a complete item, validate that completeness.
1458
+ if ( ! queriedState.itemIsComplete[ context ]?.[ revisionKey ] ) {
1459
+ return undefined;
1460
+ }
1461
+
1462
+ return queriedState.items[ context ][ revisionKey ];
1463
+ }
1464
+
1465
+ const item = queriedState.items[ context ]?.[ revisionKey ];
1466
+ if ( item && query._fields ) {
1467
+ const filteredItem = {};
1468
+ const fields = getNormalizedCommaSeparable( query._fields ) ?? [];
1469
+
1470
+ for ( let f = 0; f < fields.length; f++ ) {
1471
+ const field = fields[ f ].split( '.' );
1472
+ let value = item;
1473
+ field.forEach( ( fieldName ) => {
1474
+ value = value?.[ fieldName ];
1475
+ } );
1476
+ setNestedValue( filteredItem, field, value );
1477
+ }
1478
+
1479
+ return filteredItem;
1480
+ }
1481
+
1482
+ return item;
1483
+ },
1484
+ ( state: State, kind, name, recordKey, revisionKey, query ) => {
1485
+ const context = query?.context ?? 'default';
1486
+ return [
1487
+ state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ]
1488
+ ?.items?.[ context ]?.[ revisionKey ],
1489
+ state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ]
1490
+ ?.itemIsComplete?.[ context ]?.[ revisionKey ],
1491
+ ];
1492
+ }
1493
+ );
@@ -80,6 +80,9 @@ describe( 'getKindEntities', () => {
80
80
  labels: {
81
81
  singular_name: 'post',
82
82
  },
83
+ supports: {
84
+ revisions: true,
85
+ },
83
86
  },
84
87
  ];
85
88
  const dispatch = jest.fn();
@@ -95,6 +98,12 @@ describe( 'getKindEntities', () => {
95
98
  expect( dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].baseURL ).toBe(
96
99
  '/wp/v2/posts'
97
100
  );
101
+ expect(
102
+ dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].getRevisionsUrl( 1 )
103
+ ).toBe( '/wp/v2/posts/1/revisions' );
104
+ expect(
105
+ dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].getRevisionsUrl( 1, 2 )
106
+ ).toBe( '/wp/v2/posts/1/revisions/2' );
98
107
  } );
99
108
  } );
100
109
 
@@ -139,6 +139,241 @@ describe( 'entities', () => {
139
139
  .map( ( [ , cfg ] ) => cfg )
140
140
  ).toEqual( [ { kind: 'postType', name: 'posts' } ] );
141
141
  } );
142
+
143
+ describe( 'entity revisions', () => {
144
+ const stateWithConfig = entities( undefined, {
145
+ type: 'ADD_ENTITIES',
146
+ entities: [
147
+ {
148
+ kind: 'root',
149
+ name: 'postType',
150
+ supports: { revisions: true },
151
+ },
152
+ ],
153
+ } );
154
+ it( 'appends revisions state', () => {
155
+ expect( stateWithConfig.records.root.postType ).toHaveProperty(
156
+ 'revisions',
157
+ {}
158
+ );
159
+ } );
160
+
161
+ it( 'returns with received revisions', () => {
162
+ const initialState = deepFreeze( {
163
+ config: stateWithConfig.config,
164
+ records: {},
165
+ } );
166
+ const state = entities( initialState, {
167
+ type: 'RECEIVE_ITEM_REVISIONS',
168
+ items: [ { id: 1, parent: 2 } ],
169
+ kind: 'root',
170
+ name: 'postType',
171
+ recordKey: 2,
172
+ } );
173
+ expect( state.records.root.postType.revisions ).toEqual( {
174
+ 2: {
175
+ items: {
176
+ default: {
177
+ 1: { id: 1, parent: 2 },
178
+ },
179
+ },
180
+ itemIsComplete: {
181
+ default: {
182
+ 1: true,
183
+ },
184
+ },
185
+ queries: {},
186
+ },
187
+ } );
188
+ } );
189
+
190
+ it( 'returns with appended received revisions at the parent level', () => {
191
+ const initialState = deepFreeze( {
192
+ config: stateWithConfig.config,
193
+ records: {
194
+ root: {
195
+ postType: {
196
+ revisions: {
197
+ 2: {
198
+ items: {
199
+ default: {
200
+ 1: { id: 1, parent: 2 },
201
+ },
202
+ },
203
+ itemIsComplete: {
204
+ default: {
205
+ 1: true,
206
+ },
207
+ },
208
+ queries: {},
209
+ },
210
+ },
211
+ },
212
+ },
213
+ },
214
+ } );
215
+ const state = entities( initialState, {
216
+ type: 'RECEIVE_ITEM_REVISIONS',
217
+ items: [ { id: 3, parent: 4 } ],
218
+ kind: 'root',
219
+ name: 'postType',
220
+ recordKey: 4,
221
+ } );
222
+ expect( state.records.root.postType.revisions ).toEqual( {
223
+ 2: {
224
+ items: {
225
+ default: {
226
+ 1: { id: 1, parent: 2 },
227
+ },
228
+ },
229
+ itemIsComplete: {
230
+ default: {
231
+ 1: true,
232
+ },
233
+ },
234
+ queries: {},
235
+ },
236
+ 4: {
237
+ items: {
238
+ default: {
239
+ 3: { id: 3, parent: 4 },
240
+ },
241
+ },
242
+ itemIsComplete: {
243
+ default: {
244
+ 3: true,
245
+ },
246
+ },
247
+ queries: {},
248
+ },
249
+ } );
250
+ } );
251
+
252
+ it( 'returns with appended received revision items', () => {
253
+ const initialState = deepFreeze( {
254
+ config: stateWithConfig.config,
255
+ records: {
256
+ root: {
257
+ postType: {
258
+ revisions: {
259
+ 2: {
260
+ items: {
261
+ default: {
262
+ 1: { id: 1, parent: 2 },
263
+ },
264
+ },
265
+ itemIsComplete: {
266
+ default: {
267
+ 1: true,
268
+ },
269
+ },
270
+ queries: {},
271
+ },
272
+ },
273
+ },
274
+ },
275
+ },
276
+ } );
277
+ const state = entities( initialState, {
278
+ type: 'RECEIVE_ITEM_REVISIONS',
279
+ items: [ { id: 7, parent: 2 } ],
280
+ kind: 'root',
281
+ name: 'postType',
282
+ recordKey: 2,
283
+ } );
284
+ expect( state.records.root.postType.revisions ).toEqual( {
285
+ 2: {
286
+ items: {
287
+ default: {
288
+ 1: { id: 1, parent: 2 },
289
+ 7: { id: 7, parent: 2 },
290
+ },
291
+ },
292
+ itemIsComplete: {
293
+ default: {
294
+ 1: true,
295
+ 7: true,
296
+ },
297
+ },
298
+ queries: {},
299
+ },
300
+ } );
301
+ } );
302
+
303
+ it( 'returns with removed revision items', () => {
304
+ const initialState = deepFreeze( {
305
+ config: stateWithConfig.config,
306
+ records: {
307
+ root: {
308
+ postType: {
309
+ revisions: {
310
+ 2: {
311
+ items: {
312
+ default: {
313
+ 1: { id: 1, parent: 2 },
314
+ },
315
+ },
316
+ itemIsComplete: {
317
+ default: {
318
+ 1: true,
319
+ },
320
+ },
321
+ queries: {},
322
+ },
323
+ 4: {
324
+ items: {
325
+ default: {
326
+ 3: { id: 3, parent: 4 },
327
+ },
328
+ },
329
+ itemIsComplete: {
330
+ default: {
331
+ 3: true,
332
+ },
333
+ },
334
+ queries: {},
335
+ },
336
+ 6: {
337
+ items: {
338
+ default: {
339
+ 9: { id: 11, parent: 6 },
340
+ },
341
+ },
342
+ itemIsComplete: {
343
+ default: {
344
+ 9: true,
345
+ },
346
+ },
347
+ queries: {},
348
+ },
349
+ },
350
+ },
351
+ },
352
+ },
353
+ } );
354
+ const state = entities( initialState, {
355
+ type: 'REMOVE_ITEMS',
356
+ itemIds: [ 4, 6 ],
357
+ kind: 'root',
358
+ name: 'postType',
359
+ } );
360
+ expect( state.records.root.postType.revisions ).toEqual( {
361
+ 2: {
362
+ items: {
363
+ default: {
364
+ 1: { id: 1, parent: 2 },
365
+ },
366
+ },
367
+ itemIsComplete: {
368
+ default: {
369
+ 1: true,
370
+ },
371
+ },
372
+ queries: {},
373
+ },
374
+ } );
375
+ } );
376
+ } );
142
377
  } );
143
378
 
144
379
  describe( 'embedPreviews()', () => {
@@ -22,6 +22,8 @@ import {
22
22
  getAutosave,
23
23
  getAutosaves,
24
24
  getCurrentUser,
25
+ getRevisions,
26
+ getRevision,
25
27
  } from '../selectors';
26
28
  // getEntityRecord and __experimentalGetEntityRecordNoResolver selectors share the same tests.
27
29
  describe.each( [
@@ -896,3 +898,97 @@ describe( 'getCurrentUser', () => {
896
898
  expect( getCurrentUser( state ) ).toEqual( currentUser );
897
899
  } );
898
900
  } );
901
+
902
+ describe( 'getRevisions', () => {
903
+ it( 'should return revisions', () => {
904
+ const state = deepFreeze( {
905
+ entities: {
906
+ records: {
907
+ postType: {
908
+ post: {
909
+ revisions: {
910
+ 1: {
911
+ items: {
912
+ default: {
913
+ 10: {
914
+ id: 10,
915
+ content: 'chicken',
916
+ author: 'bob',
917
+ parent: 1,
918
+ },
919
+ },
920
+ },
921
+ itemIsComplete: {
922
+ default: {
923
+ 10: true,
924
+ },
925
+ },
926
+ queries: {
927
+ default: {
928
+ '': { itemIds: [ 10 ] },
929
+ },
930
+ },
931
+ },
932
+ },
933
+ },
934
+ },
935
+ },
936
+ },
937
+ } );
938
+
939
+ expect( getRevisions( state, 'postType', 'post', 1 ) ).toEqual( [
940
+ {
941
+ id: 10,
942
+ content: 'chicken',
943
+ author: 'bob',
944
+ parent: 1,
945
+ },
946
+ ] );
947
+ } );
948
+ } );
949
+
950
+ describe( 'getRevision', () => {
951
+ it( 'should return a specific revision', () => {
952
+ const state = deepFreeze( {
953
+ entities: {
954
+ records: {
955
+ postType: {
956
+ post: {
957
+ revisions: {
958
+ 1: {
959
+ items: {
960
+ default: {
961
+ 10: {
962
+ id: 10,
963
+ content: 'chicken',
964
+ author: 'bob',
965
+ parent: 1,
966
+ },
967
+ },
968
+ },
969
+ itemIsComplete: {
970
+ default: {
971
+ 10: true,
972
+ },
973
+ },
974
+ queries: {
975
+ default: {
976
+ '': [ 10 ],
977
+ },
978
+ },
979
+ },
980
+ },
981
+ },
982
+ },
983
+ },
984
+ },
985
+ } );
986
+
987
+ expect( getRevision( state, 'postType', 'post', 1, 10 ) ).toEqual( {
988
+ id: 10,
989
+ content: 'chicken',
990
+ author: 'bob',
991
+ parent: 1,
992
+ } );
993
+ } );
994
+ } );