@wordpress/core-data 4.7.0 → 4.10.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 (95) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +56 -56
  3. package/build/actions.js.map +1 -1
  4. package/build/batch/create-batch.js +1 -1
  5. package/build/batch/create-batch.js.map +1 -1
  6. package/build/batch/default-processor.js +13 -7
  7. package/build/batch/default-processor.js.map +1 -1
  8. package/build/entities.js +49 -35
  9. package/build/entities.js.map +1 -1
  10. package/build/entity-provider.js.map +1 -1
  11. package/build/entity-types/entities.js +6 -0
  12. package/build/entity-types/entities.js.map +1 -0
  13. package/build/hooks/use-entity-record.js.map +1 -1
  14. package/build/hooks/use-query-select.js.map +1 -1
  15. package/build/hooks/use-resource-permissions.js +94 -0
  16. package/build/hooks/use-resource-permissions.js.map +1 -0
  17. package/build/index.js +28 -1
  18. package/build/index.js.map +1 -1
  19. package/build/queried-data/selectors.js.map +1 -1
  20. package/build/resolvers.js +4 -14
  21. package/build/resolvers.js.map +1 -1
  22. package/build/selectors.js +45 -8
  23. package/build/selectors.js.map +1 -1
  24. package/build/utils/forward-resolver.js.map +1 -1
  25. package/build/utils/on-sub-key.js.map +1 -1
  26. package/build/utils/with-weak-map-cache.js +1 -7
  27. package/build/utils/with-weak-map-cache.js.map +1 -1
  28. package/build-module/actions.js.map +1 -1
  29. package/build-module/batch/create-batch.js +2 -2
  30. package/build-module/batch/create-batch.js.map +1 -1
  31. package/build-module/batch/default-processor.js +12 -5
  32. package/build-module/batch/default-processor.js.map +1 -1
  33. package/build-module/entities.js +49 -35
  34. package/build-module/entities.js.map +1 -1
  35. package/build-module/entity-provider.js.map +1 -1
  36. package/build-module/entity-types/entities.js +2 -0
  37. package/build-module/entity-types/entities.js.map +1 -0
  38. package/build-module/hooks/use-entity-record.js.map +1 -1
  39. package/build-module/hooks/use-query-select.js.map +1 -1
  40. package/build-module/hooks/use-resource-permissions.js +82 -0
  41. package/build-module/hooks/use-resource-permissions.js.map +1 -0
  42. package/build-module/index.js +3 -0
  43. package/build-module/index.js.map +1 -1
  44. package/build-module/queried-data/selectors.js.map +1 -1
  45. package/build-module/resolvers.js +5 -15
  46. package/build-module/resolvers.js.map +1 -1
  47. package/build-module/selectors.js +40 -4
  48. package/build-module/selectors.js.map +1 -1
  49. package/build-module/utils/forward-resolver.js.map +1 -1
  50. package/build-module/utils/on-sub-key.js.map +1 -1
  51. package/build-module/utils/with-weak-map-cache.js +1 -6
  52. package/build-module/utils/with-weak-map-cache.js.map +1 -1
  53. package/package.json +12 -12
  54. package/src/actions.js +389 -372
  55. package/src/batch/create-batch.js +2 -2
  56. package/src/batch/default-processor.js +10 -5
  57. package/src/entities.ts +357 -135
  58. package/src/entity-provider.js +4 -6
  59. package/src/entity-types/attachment.ts +4 -3
  60. package/src/entity-types/comment.ts +4 -3
  61. package/src/entity-types/entities.ts +130 -0
  62. package/src/entity-types/index.ts +115 -20
  63. package/src/entity-types/menu-location.ts +4 -3
  64. package/src/entity-types/nav-menu-item.ts +4 -3
  65. package/src/entity-types/nav-menu.ts +3 -3
  66. package/src/entity-types/page.ts +3 -3
  67. package/src/entity-types/plugin.ts +3 -3
  68. package/src/entity-types/post.ts +3 -3
  69. package/src/entity-types/settings.ts +3 -3
  70. package/src/entity-types/sidebar.ts +4 -3
  71. package/src/entity-types/taxonomy.ts +4 -3
  72. package/src/entity-types/theme.ts +3 -3
  73. package/src/entity-types/type.ts +3 -3
  74. package/src/entity-types/user.ts +3 -3
  75. package/src/entity-types/widget-type.ts +4 -3
  76. package/src/entity-types/widget.ts +3 -3
  77. package/src/entity-types/wp-template-part.ts +4 -3
  78. package/src/entity-types/wp-template.ts +4 -3
  79. package/src/fetch/test/__experimental-fetch-link-suggestions.js +2 -4
  80. package/src/hooks/test/use-query-select.js +4 -2
  81. package/src/hooks/test/use-resource-permissions.js +115 -0
  82. package/src/hooks/use-entity-record.ts +0 -1
  83. package/src/hooks/use-query-select.ts +26 -24
  84. package/src/hooks/use-resource-permissions.ts +120 -0
  85. package/src/index.js +3 -0
  86. package/src/locks/test/selectors.js +2 -1
  87. package/src/queried-data/selectors.js +2 -8
  88. package/src/resolvers.js +344 -326
  89. package/src/selectors.ts +347 -194
  90. package/src/test/reducer.js +5 -4
  91. package/src/test/resolvers.js +1 -3
  92. package/src/test/selectors.js +1 -2
  93. package/src/utils/forward-resolver.js +6 -5
  94. package/src/utils/on-sub-key.js +20 -20
  95. package/src/utils/with-weak-map-cache.js +1 -6
@@ -0,0 +1,115 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import triggerFetch from '@wordpress/api-fetch';
5
+ import { createRegistry, RegistryProvider } from '@wordpress/data';
6
+
7
+ jest.mock( '@wordpress/api-fetch' );
8
+
9
+ /**
10
+ * External dependencies
11
+ */
12
+ import { act, render } from '@testing-library/react';
13
+
14
+ /**
15
+ * Internal dependencies
16
+ */
17
+ import { store as coreDataStore } from '../../index';
18
+ import useResourcePermissions from '../use-resource-permissions';
19
+
20
+ describe( 'useResourcePermissions', () => {
21
+ let registry;
22
+ beforeEach( () => {
23
+ jest.useFakeTimers();
24
+
25
+ registry = createRegistry();
26
+ registry.register( coreDataStore );
27
+
28
+ triggerFetch.mockImplementation( () => ( {
29
+ headers: {
30
+ get: () => ( {
31
+ allow: 'POST',
32
+ } ),
33
+ },
34
+ } ) );
35
+ } );
36
+
37
+ afterEach( () => {
38
+ jest.runOnlyPendingTimers();
39
+ jest.useRealTimers();
40
+ } );
41
+
42
+ it( 'retrieves the relevant permissions for a key-less resource', async () => {
43
+ let data;
44
+ const TestComponent = () => {
45
+ data = useResourcePermissions( 'widgets' );
46
+ return <div />;
47
+ };
48
+ render(
49
+ <RegistryProvider value={ registry }>
50
+ <TestComponent />
51
+ </RegistryProvider>
52
+ );
53
+ expect( data ).toEqual( [
54
+ false,
55
+ {
56
+ status: 'IDLE',
57
+ isResolving: false,
58
+ canCreate: false,
59
+ },
60
+ ] );
61
+
62
+ // Required to make sure no updates happen outside of act()
63
+ await act( async () => {
64
+ jest.advanceTimersByTime( 1 );
65
+ } );
66
+
67
+ expect( data ).toEqual( [
68
+ true,
69
+ {
70
+ status: 'SUCCESS',
71
+ isResolving: false,
72
+ canCreate: true,
73
+ },
74
+ ] );
75
+ } );
76
+
77
+ it( 'retrieves the relevant permissions for a resource with a key', async () => {
78
+ let data;
79
+ const TestComponent = () => {
80
+ data = useResourcePermissions( 'widgets', 1 );
81
+ return <div />;
82
+ };
83
+ render(
84
+ <RegistryProvider value={ registry }>
85
+ <TestComponent />
86
+ </RegistryProvider>
87
+ );
88
+ expect( data ).toEqual( [
89
+ false,
90
+ {
91
+ status: 'IDLE',
92
+ isResolving: false,
93
+ canCreate: false,
94
+ canUpdate: false,
95
+ canDelete: false,
96
+ },
97
+ ] );
98
+
99
+ // Required to make sure no updates happen outside of act()
100
+ await act( async () => {
101
+ jest.advanceTimersByTime( 1 );
102
+ } );
103
+
104
+ expect( data ).toEqual( [
105
+ true,
106
+ {
107
+ status: 'SUCCESS',
108
+ isResolving: false,
109
+ canCreate: true,
110
+ canUpdate: false,
111
+ canDelete: false,
112
+ },
113
+ ] );
114
+ } );
115
+ } );
@@ -9,7 +9,6 @@ import deprecated from '@wordpress/deprecated';
9
9
  import useQuerySelect from './use-query-select';
10
10
  import { store as coreStore } from '../';
11
11
  import type { Status } from './constants';
12
- import useEntityRecords from './use-entity-records';
13
12
 
14
13
  export interface EntityRecordResolution< RecordType > {
15
14
  /** The requested entity record */
@@ -102,34 +102,36 @@ const enrichSelectors = memoize( ( ( selectors ) => {
102
102
  continue;
103
103
  }
104
104
  Object.defineProperty( resolvers, selectorName, {
105
- get: () => ( ...args: unknown[] ) => {
106
- const { getIsResolving, hasFinishedResolution } = selectors;
107
- const isResolving = !! getIsResolving( selectorName, args );
108
- const hasResolved =
109
- ! isResolving &&
110
- hasFinishedResolution( selectorName, args );
111
- const data = selectors[ selectorName ]( ...args );
105
+ get:
106
+ () =>
107
+ ( ...args: unknown[] ) => {
108
+ const { getIsResolving, hasFinishedResolution } = selectors;
109
+ const isResolving = !! getIsResolving( selectorName, args );
110
+ const hasResolved =
111
+ ! isResolving &&
112
+ hasFinishedResolution( selectorName, args );
113
+ const data = selectors[ selectorName ]( ...args );
112
114
 
113
- let status;
114
- if ( isResolving ) {
115
- status = Status.Resolving;
116
- } else if ( hasResolved ) {
117
- if ( data ) {
118
- status = Status.Success;
115
+ let status;
116
+ if ( isResolving ) {
117
+ status = Status.Resolving;
118
+ } else if ( hasResolved ) {
119
+ if ( data ) {
120
+ status = Status.Success;
121
+ } else {
122
+ status = Status.Error;
123
+ }
119
124
  } else {
120
- status = Status.Error;
125
+ status = Status.Idle;
121
126
  }
122
- } else {
123
- status = Status.Idle;
124
- }
125
127
 
126
- return {
127
- data,
128
- status,
129
- isResolving,
130
- hasResolved,
131
- };
132
- },
128
+ return {
129
+ data,
130
+ status,
131
+ isResolving,
132
+ hasResolved,
133
+ };
134
+ },
133
135
  } );
134
136
  }
135
137
  return resolvers;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { store as coreStore } from '../';
5
+ import { Status } from './constants';
6
+ import useQuerySelect from './use-query-select';
7
+
8
+ interface GlobalResourcePermissionsResolution {
9
+ /** Can the current user create new resources of this type? */
10
+ canCreate: boolean;
11
+ }
12
+ interface SpecificResourcePermissionsResolution {
13
+ /** Can the current user update resources of this type? */
14
+ canUpdate: boolean;
15
+ /** Can the current user delete resources of this type? */
16
+ canDelete: boolean;
17
+ }
18
+ interface ResolutionDetails {
19
+ /** Resolution status */
20
+ status: Status;
21
+ /**
22
+ * Is the data still being resolved?
23
+ */
24
+ isResolving: boolean;
25
+ }
26
+
27
+ /**
28
+ * Is the data resolved by now?
29
+ */
30
+ type HasResolved = boolean;
31
+
32
+ type ResourcePermissionsResolution< IdType > = [
33
+ HasResolved,
34
+ ResolutionDetails &
35
+ GlobalResourcePermissionsResolution &
36
+ ( IdType extends void ? SpecificResourcePermissionsResolution : {} )
37
+ ];
38
+
39
+ /**
40
+ * Resolves resource permissions.
41
+ *
42
+ * @param resource The resource in question, e.g. media.
43
+ * @param id ID of a specific resource entry, if needed, e.g. 10.
44
+ *
45
+ * @example
46
+ * ```js
47
+ * import { useResourcePermissions } from '@wordpress/core-data';
48
+ *
49
+ * function PagesList() {
50
+ * const { canCreate, isResolving } = useResourcePermissions( 'pages' );
51
+ *
52
+ * if ( isResolving ) {
53
+ * return 'Loading ...';
54
+ * }
55
+ *
56
+ * return (
57
+ * <div>
58
+ * {canCreate ? (<button>+ Create a new page</button>) : false}
59
+ * // ...
60
+ * </div>
61
+ * );
62
+ * }
63
+ *
64
+ * // Rendered in the application:
65
+ * // <PagesList />
66
+ * ```
67
+ *
68
+ * In the above example, when `PagesList` is rendered into an
69
+ * application, the appropriate permissions and the resolution details will be retrieved from
70
+ * the store state using `canUser()`, or resolved if missing.
71
+ *
72
+ * @return Entity records data.
73
+ * @template IdType
74
+ */
75
+ export default function __experimentalUseResourcePermissions< IdType = void >(
76
+ resource: string,
77
+ id?: IdType
78
+ ): ResourcePermissionsResolution< IdType > {
79
+ return useQuerySelect(
80
+ ( resolve ) => {
81
+ const { canUser } = resolve( coreStore );
82
+ const create = canUser( 'create', resource );
83
+ if ( ! id ) {
84
+ return [
85
+ create.hasResolved,
86
+ {
87
+ status: create.status,
88
+ isResolving: create.isResolving,
89
+ canCreate: create.hasResolved && create.data,
90
+ },
91
+ ];
92
+ }
93
+
94
+ const update = canUser( 'update', resource, id );
95
+ const _delete = canUser( 'delete', resource, id );
96
+ const isResolving =
97
+ create.isResolving || update.isResolving || _delete.isResolving;
98
+ const hasResolved =
99
+ create.hasResolved && update.hasResolved && _delete.hasResolved;
100
+
101
+ let status = Status.Idle;
102
+ if ( isResolving ) {
103
+ status = Status.Resolving;
104
+ } else if ( hasResolved ) {
105
+ status = Status.Success;
106
+ }
107
+ return [
108
+ hasResolved,
109
+ {
110
+ status,
111
+ isResolving,
112
+ canCreate: hasResolved && create.data,
113
+ canUpdate: hasResolved && update.data,
114
+ canDelete: hasResolved && _delete.data,
115
+ },
116
+ ];
117
+ },
118
+ [ resource, id ]
119
+ );
120
+ }
package/src/index.js CHANGED
@@ -68,6 +68,9 @@ export const store = createReduxStore( STORE_NAME, storeConfig() );
68
68
  register( store );
69
69
 
70
70
  export { default as EntityProvider } from './entity-provider';
71
+ export { default as useEntityRecord } from './hooks/use-entity-record';
72
+ export { default as useEntityRecords } from './hooks/use-entity-records';
73
+ export { default as __experimentalUseResourcePermissions } from './hooks/use-resource-permissions';
71
74
  export * from './entity-provider';
72
75
  export * from './entity-types';
73
76
  export * from './fetch';
@@ -186,7 +186,8 @@ describe( 'isLockAvailable', () => {
186
186
  exclusive: true,
187
187
  },
188
188
  ],
189
- children: {},
189
+ children:
190
+ {},
190
191
  },
191
192
  },
192
193
  },
@@ -28,14 +28,8 @@ const queriedItemsCacheByState = new WeakMap();
28
28
  * @return {?Array} Query items.
29
29
  */
30
30
  function getQueriedItemsUncached( state, query ) {
31
- const {
32
- stableKey,
33
- page,
34
- perPage,
35
- include,
36
- fields,
37
- context,
38
- } = getQueryParts( query );
31
+ const { stableKey, page, perPage, include, fields, context } =
32
+ getQueryParts( query );
39
33
  let itemIds;
40
34
 
41
35
  if ( state.queries?.[ context ]?.[ stableKey ] ) {