@wordpress/core-data 4.2.0 → 4.4.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 (147) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +68 -11
  3. package/build/actions.js +61 -41
  4. package/build/actions.js.map +1 -1
  5. package/build/batch/default-processor.js +1 -1
  6. package/build/batch/default-processor.js.map +1 -1
  7. package/build/entities.js +36 -23
  8. package/build/entities.js.map +1 -1
  9. package/build/entity-provider.js +46 -44
  10. package/build/entity-provider.js.map +1 -1
  11. package/build/entity-types/{base-entity-types.js → base-entity-records.js} +9 -9
  12. package/build/entity-types/base-entity-records.js.map +1 -0
  13. package/build/fetch/__experimental-fetch-link-suggestions.js +48 -11
  14. package/build/fetch/__experimental-fetch-link-suggestions.js.map +1 -1
  15. package/build/fetch/__experimental-fetch-url-data.js +1 -1
  16. package/build/fetch/__experimental-fetch-url-data.js.map +1 -1
  17. package/build/hooks/use-entity-record.js +15 -5
  18. package/build/hooks/use-entity-record.js.map +1 -1
  19. package/build/hooks/use-entity-records.js +14 -2
  20. package/build/hooks/use-entity-records.js.map +1 -1
  21. package/build/hooks/use-query-select.js.map +1 -1
  22. package/build/index.js +9 -21
  23. package/build/index.js.map +1 -1
  24. package/build/queried-data/actions.js +4 -4
  25. package/build/queried-data/actions.js.map +1 -1
  26. package/build/queried-data/get-query-parts.js +7 -3
  27. package/build/queried-data/get-query-parts.js.map +1 -1
  28. package/build/queried-data/reducer.js +8 -6
  29. package/build/queried-data/reducer.js.map +1 -1
  30. package/build/reducer.js +77 -25
  31. package/build/reducer.js.map +1 -1
  32. package/build/resolvers.js +48 -24
  33. package/build/resolvers.js.map +1 -1
  34. package/build/selectors.js +122 -55
  35. package/build/selectors.js.map +1 -1
  36. package/build/types.js +6 -0
  37. package/build/types.js.map +1 -0
  38. package/build/utils/conservative-map-item.js +1 -1
  39. package/build/utils/conservative-map-item.js.map +1 -1
  40. package/build/utils/if-matching-action.js +4 -2
  41. package/build/utils/if-matching-action.js.map +1 -1
  42. package/build/utils/is-raw-attribute.js +1 -1
  43. package/build/utils/is-raw-attribute.js.map +1 -1
  44. package/build/utils/on-sub-key.js +3 -1
  45. package/build/utils/on-sub-key.js.map +1 -1
  46. package/build/utils/replace-action.js +4 -2
  47. package/build/utils/replace-action.js.map +1 -1
  48. package/build-module/actions.js +62 -42
  49. package/build-module/actions.js.map +1 -1
  50. package/build-module/batch/default-processor.js +1 -1
  51. package/build-module/batch/default-processor.js.map +1 -1
  52. package/build-module/entities.js +32 -19
  53. package/build-module/entities.js.map +1 -1
  54. package/build-module/entity-provider.js +47 -45
  55. package/build-module/entity-provider.js.map +1 -1
  56. package/build-module/entity-types/{base-entity-types.js → base-entity-records.js} +7 -7
  57. package/build-module/entity-types/base-entity-records.js.map +1 -0
  58. package/build-module/fetch/__experimental-fetch-link-suggestions.js +48 -11
  59. package/build-module/fetch/__experimental-fetch-link-suggestions.js.map +1 -1
  60. package/build-module/fetch/__experimental-fetch-url-data.js +1 -1
  61. package/build-module/fetch/__experimental-fetch-url-data.js.map +1 -1
  62. package/build-module/hooks/use-entity-record.js +15 -5
  63. package/build-module/hooks/use-entity-record.js.map +1 -1
  64. package/build-module/hooks/use-entity-records.js +14 -2
  65. package/build-module/hooks/use-entity-records.js.map +1 -1
  66. package/build-module/hooks/use-query-select.js.map +1 -1
  67. package/build-module/index.js +10 -22
  68. package/build-module/index.js.map +1 -1
  69. package/build-module/queried-data/actions.js +4 -4
  70. package/build-module/queried-data/actions.js.map +1 -1
  71. package/build-module/queried-data/get-query-parts.js +7 -3
  72. package/build-module/queried-data/get-query-parts.js.map +1 -1
  73. package/build-module/queried-data/reducer.js +8 -6
  74. package/build-module/queried-data/reducer.js.map +1 -1
  75. package/build-module/reducer.js +75 -26
  76. package/build-module/reducer.js.map +1 -1
  77. package/build-module/resolvers.js +42 -24
  78. package/build-module/resolvers.js.map +1 -1
  79. package/build-module/selectors.js +114 -55
  80. package/build-module/selectors.js.map +1 -1
  81. package/build-module/types.js +2 -0
  82. package/build-module/types.js.map +1 -0
  83. package/build-module/utils/conservative-map-item.js +1 -1
  84. package/build-module/utils/conservative-map-item.js.map +1 -1
  85. package/build-module/utils/if-matching-action.js +4 -2
  86. package/build-module/utils/if-matching-action.js.map +1 -1
  87. package/build-module/utils/is-raw-attribute.js +1 -1
  88. package/build-module/utils/is-raw-attribute.js.map +1 -1
  89. package/build-module/utils/on-sub-key.js +3 -1
  90. package/build-module/utils/on-sub-key.js.map +1 -1
  91. package/build-module/utils/replace-action.js +4 -2
  92. package/build-module/utils/replace-action.js.map +1 -1
  93. package/package.json +11 -11
  94. package/src/actions.js +62 -42
  95. package/src/batch/default-processor.js +1 -0
  96. package/src/{entities.js → entities.ts} +50 -21
  97. package/src/entity-provider.js +50 -44
  98. package/src/entity-types/attachment.ts +5 -5
  99. package/src/entity-types/{base-entity-types.ts → base-entity-records.ts} +5 -5
  100. package/src/entity-types/comment.ts +5 -5
  101. package/src/entity-types/helpers.ts +1 -1
  102. package/src/entity-types/index.ts +4 -4
  103. package/src/entity-types/menu-location.ts +5 -5
  104. package/src/entity-types/nav-menu-item.ts +10 -5
  105. package/src/entity-types/nav-menu.ts +5 -5
  106. package/src/entity-types/navigation-area.ts +5 -5
  107. package/src/entity-types/page.ts +5 -5
  108. package/src/entity-types/plugin.ts +10 -5
  109. package/src/entity-types/post.ts +5 -5
  110. package/src/entity-types/settings.ts +10 -5
  111. package/src/entity-types/sidebar.ts +6 -7
  112. package/src/entity-types/taxonomy.ts +5 -5
  113. package/src/entity-types/theme.ts +5 -5
  114. package/src/entity-types/type.ts +5 -5
  115. package/src/entity-types/user.ts +10 -5
  116. package/src/entity-types/widget-type.ts +5 -5
  117. package/src/entity-types/widget.ts +5 -5
  118. package/src/entity-types/wp-template-part.ts +5 -5
  119. package/src/entity-types/wp-template.ts +5 -5
  120. package/src/fetch/__experimental-fetch-link-suggestions.js +56 -20
  121. package/src/fetch/__experimental-fetch-url-data.js +1 -0
  122. package/src/fetch/test/__experimental-fetch-link-suggestions.js +39 -1
  123. package/src/hooks/use-entity-record.ts +19 -8
  124. package/src/hooks/use-entity-records.ts +23 -6
  125. package/src/hooks/use-query-select.ts +12 -7
  126. package/src/index.js +10 -15
  127. package/src/locks/test/selectors.js +4 -4
  128. package/src/queried-data/actions.js +4 -4
  129. package/src/queried-data/get-query-parts.js +5 -5
  130. package/src/queried-data/reducer.js +6 -6
  131. package/src/reducer.js +67 -24
  132. package/src/resolvers.js +39 -30
  133. package/src/{selectors.js → selectors.ts} +118 -57
  134. package/src/test/actions.js +138 -33
  135. package/src/test/entities.js +11 -11
  136. package/src/test/reducer.js +4 -4
  137. package/src/test/resolvers.js +5 -5
  138. package/src/test/selectors.js +22 -22
  139. package/src/types.ts +3 -0
  140. package/src/utils/conservative-map-item.js +1 -1
  141. package/src/utils/if-matching-action.js +4 -2
  142. package/src/utils/is-raw-attribute.js +1 -1
  143. package/src/utils/on-sub-key.js +3 -1
  144. package/src/utils/replace-action.js +4 -2
  145. package/src/utils/test/is-raw-attribute.js +4 -4
  146. package/build/entity-types/base-entity-types.js.map +0 -1
  147. package/build-module/entity-types/base-entity-types.js.map +0 -1
@@ -51,7 +51,7 @@ export function getMergedItemIds( itemIds, nextItemIds, page, perPage ) {
51
51
  // If later page has already been received, default to the larger known
52
52
  // size of the existing array, else calculate as extending the existing.
53
53
  const size = Math.max(
54
- itemIds.length,
54
+ itemIds?.length ?? 0,
55
55
  nextItemIdsStartIndex + nextItemIds.length
56
56
  );
57
57
 
@@ -66,7 +66,7 @@ export function getMergedItemIds( itemIds, nextItemIds, page, perPage ) {
66
66
 
67
67
  mergedItemIds[ i ] = isInNextItemsRange
68
68
  ? nextItemIds[ i - nextItemIdsStartIndex ]
69
- : itemIds[ i ];
69
+ : itemIds?.[ i ];
70
70
  }
71
71
 
72
72
  return mergedItemIds;
@@ -116,10 +116,10 @@ export function items( state = {}, action ) {
116
116
  * In such cases, completeness is used as an indication of whether it would be
117
117
  * safe to use queried data for a non-`_fields`-limited request.
118
118
  *
119
- * @param {Object<string,boolean>} state Current state.
120
- * @param {Object} action Dispatched action.
119
+ * @param {Object<string,Object<string,boolean>>} state Current state.
120
+ * @param {Object} action Dispatched action.
121
121
  *
122
- * @return {Object<string,boolean>} Next state.
122
+ * @return {Object<string,Object<string,boolean>>} Next state.
123
123
  */
124
124
  export function itemIsComplete( state = {}, action ) {
125
125
  switch ( action.type ) {
@@ -130,7 +130,7 @@ export function itemIsComplete( state = {}, action ) {
130
130
  // An item is considered complete if it is received without an associated
131
131
  // fields query. Ideally, this would be implemented in such a way where the
132
132
  // complete aggregate of all fields would satisfy completeness. Since the
133
- // fields are not consistent across all entity types, this would require
133
+ // fields are not consistent across all entities, this would require
134
134
  // introspection on the REST schema for each entity to know which fields
135
135
  // compose a complete item for that entity.
136
136
  const queryParts = query ? getQueryParts( query ) : {};
package/src/reducer.js CHANGED
@@ -14,7 +14,9 @@ import isShallowEqual from '@wordpress/is-shallow-equal';
14
14
  */
15
15
  import { ifMatchingAction, replaceAction } from './utils';
16
16
  import { reducer as queriedDataReducer } from './queried-data';
17
- import { defaultEntities, DEFAULT_ENTITY_KEY } from './entities';
17
+ import { rootEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
18
+
19
+ /** @typedef {import('./types').AnyFunction} AnyFunction */
18
20
 
19
21
  /**
20
22
  * Reducer managing terms state. Keyed by taxonomy slug, the value is either
@@ -105,10 +107,10 @@ export function taxonomies( state = [], action ) {
105
107
  /**
106
108
  * Reducer managing the current theme.
107
109
  *
108
- * @param {string} state Current state.
109
- * @param {Object} action Dispatched action.
110
+ * @param {string|undefined} state Current state.
111
+ * @param {Object} action Dispatched action.
110
112
  *
111
- * @return {string} Updated state.
113
+ * @return {string|undefined} Updated state.
112
114
  */
113
115
  export function currentTheme( state = undefined, action ) {
114
116
  switch ( action.type ) {
@@ -122,10 +124,10 @@ export function currentTheme( state = undefined, action ) {
122
124
  /**
123
125
  * Reducer managing the current global styles id.
124
126
  *
125
- * @param {string} state Current state.
126
- * @param {Object} action Dispatched action.
127
+ * @param {string|undefined} state Current state.
128
+ * @param {Object} action Dispatched action.
127
129
  *
128
- * @return {string} Updated state.
130
+ * @return {string|undefined} Updated state.
129
131
  */
130
132
  export function currentGlobalStylesId( state = undefined, action ) {
131
133
  switch ( action.type ) {
@@ -139,10 +141,10 @@ export function currentGlobalStylesId( state = undefined, action ) {
139
141
  /**
140
142
  * Reducer managing the theme base global styles.
141
143
  *
142
- * @param {string} state Current state.
143
- * @param {Object} action Dispatched action.
144
+ * @param {Record<string, object>} state Current state.
145
+ * @param {Object} action Dispatched action.
144
146
  *
145
- * @return {string} Updated state.
147
+ * @return {Record<string, object>} Updated state.
146
148
  */
147
149
  export function themeBaseGlobalStyles( state = {}, action ) {
148
150
  switch ( action.type ) {
@@ -159,10 +161,10 @@ export function themeBaseGlobalStyles( state = {}, action ) {
159
161
  /**
160
162
  * Reducer managing the theme global styles variations.
161
163
  *
162
- * @param {string} state Current state.
163
- * @param {Object} action Dispatched action.
164
+ * @param {Record<string, object>} state Current state.
165
+ * @param {Object} action Dispatched action.
164
166
  *
165
- * @return {string} Updated state.
167
+ * @return {Record<string, object>} Updated state.
166
168
  */
167
169
  export function themeGlobalStyleVariations( state = {}, action ) {
168
170
  switch ( action.type ) {
@@ -185,7 +187,7 @@ export function themeGlobalStyleVariations( state = {}, action ) {
185
187
  *
186
188
  * @param {Object} entityConfig Entity config.
187
189
  *
188
- * @return {Function} Reducer.
190
+ * @return {AnyFunction} Reducer.
189
191
  */
190
192
  function entity( entityConfig ) {
191
193
  return flowRight( [
@@ -335,7 +337,7 @@ function entity( entityConfig ) {
335
337
  *
336
338
  * @return {Object} Updated state.
337
339
  */
338
- export function entitiesConfig( state = defaultEntities, action ) {
340
+ export function entitiesConfig( state = rootEntitiesConfig, action ) {
339
341
  switch ( action.type ) {
340
342
  case 'ADD_ENTITIES':
341
343
  return [ ...state, ...action.entities ];
@@ -380,10 +382,10 @@ export const entities = ( state = {}, action ) => {
380
382
  );
381
383
  }
382
384
 
383
- const newData = entitiesDataReducer( state.data, action );
385
+ const newData = entitiesDataReducer( state.records, action );
384
386
 
385
387
  if (
386
- newData === state.data &&
388
+ newData === state.records &&
387
389
  newConfig === state.config &&
388
390
  entitiesDataReducer === state.reducer
389
391
  ) {
@@ -392,22 +394,38 @@ export const entities = ( state = {}, action ) => {
392
394
 
393
395
  return {
394
396
  reducer: entitiesDataReducer,
395
- data: newData,
397
+ records: newData,
396
398
  config: newConfig,
397
399
  };
398
400
  };
399
401
 
400
402
  /**
401
- * Reducer keeping track of entity edit undo history.
403
+ * @typedef {Object} UndoStateMeta
402
404
  *
403
- * @param {Object} state Current state.
404
- * @param {Object} action Dispatched action.
405
+ * @property {number} offset Where in the undo stack we are.
406
+ * @property {Object} [flattenedUndo] Flattened form of undo stack.
407
+ */
408
+
409
+ /** @typedef {Array<Object> & UndoStateMeta} UndoState */
410
+
411
+ /**
412
+ * @type {UndoState}
405
413
  *
406
- * @return {Object} Updated state.
414
+ * @todo Given how we use this we might want to make a custom class for it.
407
415
  */
408
- const UNDO_INITIAL_STATE = [];
409
- UNDO_INITIAL_STATE.offset = 0;
416
+ const UNDO_INITIAL_STATE = Object.assign( [], { offset: 0 } );
417
+
418
+ /** @type {Object} */
410
419
  let lastEditAction;
420
+
421
+ /**
422
+ * Reducer keeping track of entity edit undo history.
423
+ *
424
+ * @param {UndoState} state Current state.
425
+ * @param {Object} action Dispatched action.
426
+ *
427
+ * @return {UndoState} Updated state.
428
+ */
411
429
  export function undo( state = UNDO_INITIAL_STATE, action ) {
412
430
  switch ( action.type ) {
413
431
  case 'EDIT_ENTITY_RECORD':
@@ -439,8 +457,11 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
439
457
  }
440
458
  }
441
459
 
460
+ /** @type {UndoState} */
442
461
  let nextState;
462
+
443
463
  if ( isUndoOrRedo ) {
464
+ // @ts-ignore we might consider using Object.assign({}, state)
444
465
  nextState = [ ...state ];
445
466
  nextState.offset =
446
467
  state.offset + ( action.meta.isUndo ? -1 : 1 );
@@ -480,6 +501,7 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
480
501
  ( key ) => ! action.transientEdits[ key ]
481
502
  )
482
503
  ) {
504
+ // @ts-ignore we might consider using Object.assign({}, state)
483
505
  nextState = [ ...state ];
484
506
  nextState.flattenedUndo = {
485
507
  ...state.flattenedUndo,
@@ -491,6 +513,7 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
491
513
 
492
514
  // Clear potential redos, because this only supports linear history.
493
515
  nextState =
516
+ // @ts-ignore this needs additional cleanup, probably involving code-level changes
494
517
  nextState || state.slice( 0, state.offset || undefined );
495
518
  nextState.offset = nextState.offset || 0;
496
519
  nextState.pop();
@@ -592,6 +615,24 @@ export function autosaves( state = {}, action ) {
592
615
  return state;
593
616
  }
594
617
 
618
+ export function blockPatterns( state = [], action ) {
619
+ switch ( action.type ) {
620
+ case 'RECEIVE_BLOCK_PATTERNS':
621
+ return action.patterns;
622
+ }
623
+
624
+ return state;
625
+ }
626
+
627
+ export function blockPatternCategories( state = [], action ) {
628
+ switch ( action.type ) {
629
+ case 'RECEIVE_BLOCK_PATTERN_CATEGORIES':
630
+ return action.categories;
631
+ }
632
+
633
+ return state;
634
+ }
635
+
595
636
  export default combineReducers( {
596
637
  terms,
597
638
  users,
@@ -606,4 +647,6 @@ export default combineReducers( {
606
647
  embedPreviews,
607
648
  userPermissions,
608
649
  autosaves,
650
+ blockPatterns,
651
+ blockPatternCategories,
609
652
  } );
package/src/resolvers.js CHANGED
@@ -13,7 +13,7 @@ import apiFetch from '@wordpress/api-fetch';
13
13
  * Internal dependencies
14
14
  */
15
15
  import { STORE_NAME } from './name';
16
- import { getKindEntities, DEFAULT_ENTITY_KEY } from './entities';
16
+ import { getOrLoadEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
17
17
  import { forwardResolver, getNormalizedCommaSeparable } from './utils';
18
18
 
19
19
  /**
@@ -52,15 +52,15 @@ export const getEntityRecord = ( kind, name, key = '', query ) => async ( {
52
52
  select,
53
53
  dispatch,
54
54
  } ) => {
55
- const entities = await dispatch( getKindEntities( kind ) );
56
- const entity = find( entities, { kind, name } );
57
- if ( ! entity || entity?.__experimentalNoFetch ) {
55
+ const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
56
+ const entityConfig = find( configs, { kind, name } );
57
+ if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
58
58
  return;
59
59
  }
60
60
 
61
61
  const lock = await dispatch.__unstableAcquireStoreLock(
62
62
  STORE_NAME,
63
- [ 'entities', 'data', kind, name, key ],
63
+ [ 'entities', 'records', kind, name, key ],
64
64
  { exclusive: false }
65
65
  );
66
66
 
@@ -73,7 +73,7 @@ export const getEntityRecord = ( kind, name, key = '', query ) => async ( {
73
73
  ...query,
74
74
  _fields: uniq( [
75
75
  ...( getNormalizedCommaSeparable( query._fields ) || [] ),
76
- entity.key || DEFAULT_ENTITY_KEY,
76
+ entityConfig.key || DEFAULT_ENTITY_KEY,
77
77
  ] ).join(),
78
78
  };
79
79
  }
@@ -85,10 +85,13 @@ export const getEntityRecord = ( kind, name, key = '', query ) => async ( {
85
85
  // for how the request is made to the REST API.
86
86
 
87
87
  // eslint-disable-next-line @wordpress/no-unused-vars-before-return
88
- const path = addQueryArgs( entity.baseURL + ( key ? '/' + key : '' ), {
89
- ...entity.baseURLParams,
90
- ...query,
91
- } );
88
+ const path = addQueryArgs(
89
+ entityConfig.baseURL + ( key ? '/' + key : '' ),
90
+ {
91
+ ...entityConfig.baseURLParams,
92
+ ...query,
93
+ }
94
+ );
92
95
 
93
96
  if ( query !== undefined ) {
94
97
  query = { ...query, include: [ key ] };
@@ -104,10 +107,6 @@ export const getEntityRecord = ( kind, name, key = '', query ) => async ( {
104
107
 
105
108
  const record = await apiFetch( { path } );
106
109
  dispatch.receiveEntityRecords( kind, name, record, query );
107
- } catch ( error ) {
108
- // We need a way to handle and access REST API errors in state
109
- // Until then, catching the error ensures the resolver is marked as resolved.
110
- // See similar implementation in `getEntityRecords()`.
111
110
  } finally {
112
111
  dispatch.__unstableReleaseStoreLock( lock );
113
112
  }
@@ -133,15 +132,15 @@ export const getEditedEntityRecord = forwardResolver( 'getEntityRecord' );
133
132
  export const getEntityRecords = ( kind, name, query = {} ) => async ( {
134
133
  dispatch,
135
134
  } ) => {
136
- const entities = await dispatch( getKindEntities( kind ) );
137
- const entity = find( entities, { kind, name } );
138
- if ( ! entity || entity?.__experimentalNoFetch ) {
135
+ const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
136
+ const entityConfig = find( configs, { kind, name } );
137
+ if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
139
138
  return;
140
139
  }
141
140
 
142
141
  const lock = await dispatch.__unstableAcquireStoreLock(
143
142
  STORE_NAME,
144
- [ 'entities', 'data', kind, name ],
143
+ [ 'entities', 'records', kind, name ],
145
144
  { exclusive: false }
146
145
  );
147
146
 
@@ -154,13 +153,13 @@ export const getEntityRecords = ( kind, name, query = {} ) => async ( {
154
153
  ...query,
155
154
  _fields: uniq( [
156
155
  ...( getNormalizedCommaSeparable( query._fields ) || [] ),
157
- entity.key || DEFAULT_ENTITY_KEY,
156
+ entityConfig.key || DEFAULT_ENTITY_KEY,
158
157
  ] ).join(),
159
158
  };
160
159
  }
161
160
 
162
- const path = addQueryArgs( entity.baseURL, {
163
- ...entity.baseURLParams,
161
+ const path = addQueryArgs( entityConfig.baseURL, {
162
+ ...entityConfig.baseURLParams,
164
163
  ...query,
165
164
  } );
166
165
 
@@ -186,7 +185,7 @@ export const getEntityRecords = ( kind, name, query = {} ) => async ( {
186
185
  // resolve the `getEntityRecord` selector in addition to `getEntityRecords`.
187
186
  // See https://github.com/WordPress/gutenberg/pull/26575
188
187
  if ( ! query?._fields && ! query.context ) {
189
- const key = entity.key || DEFAULT_ENTITY_KEY;
188
+ const key = entityConfig.key || DEFAULT_ENTITY_KEY;
190
189
  const resolutionsArgs = records
191
190
  .filter( ( record ) => record[ key ] )
192
191
  .map( ( record ) => [ kind, name, record[ key ] ] );
@@ -202,10 +201,6 @@ export const getEntityRecords = ( kind, name, query = {} ) => async ( {
202
201
  args: resolutionsArgs,
203
202
  } );
204
203
  }
205
- } catch ( error ) {
206
- // We need a way to handle and access REST API errors in state
207
- // Until then, catching the error ensures the resolver is marked as resolved.
208
- // See similar implementation in `getEntityRecord()`.
209
204
  } finally {
210
205
  dispatch.__unstableReleaseStoreLock( lock );
211
206
  }
@@ -312,13 +307,13 @@ export const canUser = ( action, resource, id ) => async ( { dispatch } ) => {
312
307
  export const canUserEditEntityRecord = ( kind, name, recordId ) => async ( {
313
308
  dispatch,
314
309
  } ) => {
315
- const entities = await dispatch( getKindEntities( kind ) );
316
- const entity = find( entities, { kind, name } );
317
- if ( ! entity ) {
310
+ const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
311
+ const entityConfig = find( configs, { kind, name } );
312
+ if ( ! entityConfig ) {
318
313
  return;
319
314
  }
320
315
 
321
- const resource = entity.__unstable_rest_base;
316
+ const resource = entityConfig.__unstable_rest_base;
322
317
  await dispatch( canUser( 'update', resource, recordId ) );
323
318
  };
324
319
 
@@ -458,3 +453,17 @@ export const __experimentalGetCurrentThemeGlobalStylesVariations = () => async (
458
453
  variations
459
454
  );
460
455
  };
456
+
457
+ export const getBlockPatterns = () => async ( { dispatch } ) => {
458
+ const patterns = await apiFetch( {
459
+ path: '/__experimental/block-patterns/patterns',
460
+ } );
461
+ dispatch( { type: 'RECEIVE_BLOCK_PATTERNS', patterns } );
462
+ };
463
+
464
+ export const getBlockPatternCategories = () => async ( { dispatch } ) => {
465
+ const categories = await apiFetch( {
466
+ path: '/__experimental/block-patterns/categories',
467
+ } );
468
+ dispatch( { type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES', categories } );
469
+ };