@wordpress/core-data 4.13.0 → 4.14.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 +6 -0
- package/README.md +75 -4
- package/build/entities.js +7 -5
- package/build/entities.js.map +1 -1
- package/build/hooks/index.js +14 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/use-entity-record.js +8 -6
- package/build/hooks/use-entity-record.js.map +1 -1
- package/build/hooks/use-resource-permissions.js +72 -11
- package/build/hooks/use-resource-permissions.js.map +1 -1
- package/build/index.js +1 -28
- package/build/index.js.map +1 -1
- package/build/resolvers.js +17 -21
- package/build/resolvers.js.map +1 -1
- package/build-module/entities.js +7 -6
- package/build-module/entities.js.map +1 -1
- package/build-module/hooks/index.js +1 -0
- package/build-module/hooks/index.js.map +1 -1
- package/build-module/hooks/use-entity-record.js +8 -6
- package/build-module/hooks/use-entity-record.js.map +1 -1
- package/build-module/hooks/use-resource-permissions.js +68 -10
- package/build-module/hooks/use-resource-permissions.js.map +1 -1
- package/build-module/index.js +0 -3
- package/build-module/index.js.map +1 -1
- package/build-module/resolvers.js +17 -21
- package/build-module/resolvers.js.map +1 -1
- package/package.json +12 -11
- package/src/entities.ts +8 -6
- package/src/entity-types/theme.ts +4 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/test/use-entity-record.js +41 -1
- package/src/hooks/test/use-resource-permissions.js +32 -36
- package/src/hooks/use-entity-record.ts +16 -6
- package/src/hooks/use-resource-permissions.ts +82 -20
- package/src/index.js +0 -3
- package/src/resolvers.js +36 -24
|
@@ -71,7 +71,38 @@ describe( 'useEntityRecord', () => {
|
|
|
71
71
|
|
|
72
72
|
expect( data ).toEqual( {
|
|
73
73
|
edit: expect.any( Function ),
|
|
74
|
-
editedRecord: {},
|
|
74
|
+
editedRecord: { hello: 'world', id: 1 },
|
|
75
|
+
hasEdits: false,
|
|
76
|
+
record: { hello: 'world', id: 1 },
|
|
77
|
+
save: expect.any( Function ),
|
|
78
|
+
hasResolved: true,
|
|
79
|
+
isResolving: false,
|
|
80
|
+
status: 'SUCCESS',
|
|
81
|
+
} );
|
|
82
|
+
} );
|
|
83
|
+
|
|
84
|
+
it( 'applies edits to the entity record', async () => {
|
|
85
|
+
// Provide response
|
|
86
|
+
triggerFetch.mockImplementation( () => TEST_RECORD );
|
|
87
|
+
|
|
88
|
+
let widget;
|
|
89
|
+
const TestComponent = () => {
|
|
90
|
+
widget = useEntityRecord( 'root', 'widget', 1 );
|
|
91
|
+
return <div />;
|
|
92
|
+
};
|
|
93
|
+
render(
|
|
94
|
+
<RegistryProvider value={ registry }>
|
|
95
|
+
<TestComponent />
|
|
96
|
+
</RegistryProvider>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
await act( async () => {
|
|
100
|
+
jest.advanceTimersByTime( 1 );
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
expect( widget ).toEqual( {
|
|
104
|
+
edit: expect.any( Function ),
|
|
105
|
+
editedRecord: { hello: 'world', id: 1 },
|
|
75
106
|
hasEdits: false,
|
|
76
107
|
record: { hello: 'world', id: 1 },
|
|
77
108
|
save: expect.any( Function ),
|
|
@@ -79,5 +110,14 @@ describe( 'useEntityRecord', () => {
|
|
|
79
110
|
isResolving: false,
|
|
80
111
|
status: 'SUCCESS',
|
|
81
112
|
} );
|
|
113
|
+
|
|
114
|
+
await act( async () => {
|
|
115
|
+
widget.edit( { hello: 'foo' } );
|
|
116
|
+
jest.advanceTimersByTime( 1 );
|
|
117
|
+
} );
|
|
118
|
+
|
|
119
|
+
expect( widget.hasEdits ).toEqual( true );
|
|
120
|
+
expect( widget.record ).toEqual( { hello: 'world', id: 1 } );
|
|
121
|
+
expect( widget.editedRecord ).toEqual( { hello: 'foo', id: 1 } );
|
|
82
122
|
} );
|
|
83
123
|
} );
|
|
@@ -50,28 +50,26 @@ describe( 'useResourcePermissions', () => {
|
|
|
50
50
|
<TestComponent />
|
|
51
51
|
</RegistryProvider>
|
|
52
52
|
);
|
|
53
|
-
expect( data ).toEqual(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
] );
|
|
53
|
+
expect( data ).toEqual( {
|
|
54
|
+
status: 'IDLE',
|
|
55
|
+
isResolving: false,
|
|
56
|
+
hasResolved: false,
|
|
57
|
+
canCreate: false,
|
|
58
|
+
canRead: false,
|
|
59
|
+
} );
|
|
61
60
|
|
|
62
61
|
// Required to make sure no updates happen outside of act()
|
|
63
62
|
await act( async () => {
|
|
64
63
|
jest.advanceTimersByTime( 1 );
|
|
65
64
|
} );
|
|
66
65
|
|
|
67
|
-
expect( data ).toEqual(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
] );
|
|
66
|
+
expect( data ).toEqual( {
|
|
67
|
+
status: 'SUCCESS',
|
|
68
|
+
isResolving: false,
|
|
69
|
+
hasResolved: true,
|
|
70
|
+
canCreate: true,
|
|
71
|
+
canRead: false,
|
|
72
|
+
} );
|
|
75
73
|
} );
|
|
76
74
|
|
|
77
75
|
it( 'retrieves the relevant permissions for a resource with a key', async () => {
|
|
@@ -85,31 +83,29 @@ describe( 'useResourcePermissions', () => {
|
|
|
85
83
|
<TestComponent />
|
|
86
84
|
</RegistryProvider>
|
|
87
85
|
);
|
|
88
|
-
expect( data ).toEqual(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
] );
|
|
86
|
+
expect( data ).toEqual( {
|
|
87
|
+
status: 'IDLE',
|
|
88
|
+
isResolving: false,
|
|
89
|
+
hasResolved: false,
|
|
90
|
+
canCreate: false,
|
|
91
|
+
canRead: false,
|
|
92
|
+
canUpdate: false,
|
|
93
|
+
canDelete: false,
|
|
94
|
+
} );
|
|
98
95
|
|
|
99
96
|
// Required to make sure no updates happen outside of act()
|
|
100
97
|
await act( async () => {
|
|
101
98
|
jest.advanceTimersByTime( 1 );
|
|
102
99
|
} );
|
|
103
100
|
|
|
104
|
-
expect( data ).toEqual(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
] );
|
|
101
|
+
expect( data ).toEqual( {
|
|
102
|
+
status: 'SUCCESS',
|
|
103
|
+
isResolving: false,
|
|
104
|
+
hasResolved: true,
|
|
105
|
+
canCreate: true,
|
|
106
|
+
canRead: false,
|
|
107
|
+
canUpdate: false,
|
|
108
|
+
canDelete: false,
|
|
109
|
+
} );
|
|
114
110
|
} );
|
|
115
111
|
} );
|
|
@@ -84,8 +84,8 @@ export interface Options {
|
|
|
84
84
|
*
|
|
85
85
|
* @example
|
|
86
86
|
* ```js
|
|
87
|
-
* import { useState } from '@wordpress/data';
|
|
88
87
|
* import { useDispatch } from '@wordpress/data';
|
|
88
|
+
* import { useCallback } from '@wordpress/element';
|
|
89
89
|
* import { __ } from '@wordpress/i18n';
|
|
90
90
|
* import { TextControl } from '@wordpress/components';
|
|
91
91
|
* import { store as noticeStore } from '@wordpress/notices';
|
|
@@ -93,17 +93,19 @@ export interface Options {
|
|
|
93
93
|
*
|
|
94
94
|
* function PageRenameForm( { id } ) {
|
|
95
95
|
* const page = useEntityRecord( 'postType', 'page', id );
|
|
96
|
-
* const [ title, setTitle ] = useState( () => page.record.title.rendered );
|
|
97
96
|
* const { createSuccessNotice, createErrorNotice } =
|
|
98
97
|
* useDispatch( noticeStore );
|
|
99
98
|
*
|
|
99
|
+
* const setTitle = useCallback( ( title ) => {
|
|
100
|
+
* page.edit( { title } );
|
|
101
|
+
* }, [ page.edit ] );
|
|
102
|
+
*
|
|
100
103
|
* if ( page.isResolving ) {
|
|
101
104
|
* return 'Loading...';
|
|
102
105
|
* }
|
|
103
106
|
*
|
|
104
107
|
* async function onRename( event ) {
|
|
105
108
|
* event.preventDefault();
|
|
106
|
-
* page.edit( { title } );
|
|
107
109
|
* try {
|
|
108
110
|
* await page.save();
|
|
109
111
|
* createSuccessNotice( __( 'Page renamed.' ), {
|
|
@@ -118,7 +120,7 @@ export interface Options {
|
|
|
118
120
|
* <form onSubmit={ onRename }>
|
|
119
121
|
* <TextControl
|
|
120
122
|
* label={ __( 'Name' ) }
|
|
121
|
-
* value={ title }
|
|
123
|
+
* value={ page.editedRecord.title }
|
|
122
124
|
* onChange={ setTitle }
|
|
123
125
|
* />
|
|
124
126
|
* <button type="submit">{ __( 'Save' ) }</button>
|
|
@@ -161,8 +163,16 @@ export default function useEntityRecord< RecordType >(
|
|
|
161
163
|
|
|
162
164
|
const { editedRecord, hasEdits } = useSelect(
|
|
163
165
|
( select ) => ( {
|
|
164
|
-
editedRecord: select( coreStore ).getEditedEntityRecord(
|
|
165
|
-
|
|
166
|
+
editedRecord: select( coreStore ).getEditedEntityRecord(
|
|
167
|
+
kind,
|
|
168
|
+
name,
|
|
169
|
+
recordId
|
|
170
|
+
),
|
|
171
|
+
hasEdits: select( coreStore ).hasEditsForEntityRecord(
|
|
172
|
+
kind,
|
|
173
|
+
name,
|
|
174
|
+
recordId
|
|
175
|
+
),
|
|
166
176
|
} ),
|
|
167
177
|
[ kind, name, recordId ]
|
|
168
178
|
);
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import deprecated from '@wordpress/deprecated';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* Internal dependencies
|
|
3
8
|
*/
|
|
@@ -65,6 +70,36 @@ type ResourcePermissionsResolution< IdType > = [
|
|
|
65
70
|
* // <PagesList />
|
|
66
71
|
* ```
|
|
67
72
|
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```js
|
|
75
|
+
* import { useResourcePermissions } from '@wordpress/core-data';
|
|
76
|
+
*
|
|
77
|
+
* function Page({ pageId }) {
|
|
78
|
+
* const {
|
|
79
|
+
* canCreate,
|
|
80
|
+
* canUpdate,
|
|
81
|
+
* canDelete,
|
|
82
|
+
* isResolving
|
|
83
|
+
* } = useResourcePermissions( 'pages', pageId );
|
|
84
|
+
*
|
|
85
|
+
* if ( isResolving ) {
|
|
86
|
+
* return 'Loading ...';
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* return (
|
|
90
|
+
* <div>
|
|
91
|
+
* {canCreate ? (<button>+ Create a new page</button>) : false}
|
|
92
|
+
* {canUpdate ? (<button>Edit page</button>) : false}
|
|
93
|
+
* {canDelete ? (<button>Delete page</button>) : false}
|
|
94
|
+
* // ...
|
|
95
|
+
* </div>
|
|
96
|
+
* );
|
|
97
|
+
* }
|
|
98
|
+
*
|
|
99
|
+
* // Rendered in the application:
|
|
100
|
+
* // <Page pageId={ 15 } />
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
68
103
|
* In the above example, when `PagesList` is rendered into an
|
|
69
104
|
* application, the appropriate permissions and the resolution details will be retrieved from
|
|
70
105
|
* the store state using `canUser()`, or resolved if missing.
|
|
@@ -72,7 +107,7 @@ type ResourcePermissionsResolution< IdType > = [
|
|
|
72
107
|
* @return Entity records data.
|
|
73
108
|
* @template IdType
|
|
74
109
|
*/
|
|
75
|
-
export default function
|
|
110
|
+
export default function useResourcePermissions< IdType = void >(
|
|
76
111
|
resource: string,
|
|
77
112
|
id?: IdType
|
|
78
113
|
): ResourcePermissionsResolution< IdType > {
|
|
@@ -81,22 +116,39 @@ export default function __experimentalUseResourcePermissions< IdType = void >(
|
|
|
81
116
|
const { canUser } = resolve( coreStore );
|
|
82
117
|
const create = canUser( 'create', resource );
|
|
83
118
|
if ( ! id ) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
119
|
+
const read = canUser( 'read', resource );
|
|
120
|
+
|
|
121
|
+
const isResolving = create.isResolving || read.isResolving;
|
|
122
|
+
const hasResolved = create.hasResolved && read.hasResolved;
|
|
123
|
+
let status = Status.Idle;
|
|
124
|
+
if ( isResolving ) {
|
|
125
|
+
status = Status.Resolving;
|
|
126
|
+
} else if ( hasResolved ) {
|
|
127
|
+
status = Status.Success;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
status,
|
|
132
|
+
isResolving,
|
|
133
|
+
hasResolved,
|
|
134
|
+
canCreate: create.hasResolved && create.data,
|
|
135
|
+
canRead: read.hasResolved && read.data,
|
|
136
|
+
};
|
|
92
137
|
}
|
|
93
138
|
|
|
139
|
+
const read = canUser( 'read', resource, id );
|
|
94
140
|
const update = canUser( 'update', resource, id );
|
|
95
141
|
const _delete = canUser( 'delete', resource, id );
|
|
96
142
|
const isResolving =
|
|
97
|
-
|
|
143
|
+
read.isResolving ||
|
|
144
|
+
create.isResolving ||
|
|
145
|
+
update.isResolving ||
|
|
146
|
+
_delete.isResolving;
|
|
98
147
|
const hasResolved =
|
|
99
|
-
|
|
148
|
+
read.hasResolved &&
|
|
149
|
+
create.hasResolved &&
|
|
150
|
+
update.hasResolved &&
|
|
151
|
+
_delete.hasResolved;
|
|
100
152
|
|
|
101
153
|
let status = Status.Idle;
|
|
102
154
|
if ( isResolving ) {
|
|
@@ -104,17 +156,27 @@ export default function __experimentalUseResourcePermissions< IdType = void >(
|
|
|
104
156
|
} else if ( hasResolved ) {
|
|
105
157
|
status = Status.Success;
|
|
106
158
|
}
|
|
107
|
-
return
|
|
159
|
+
return {
|
|
160
|
+
status,
|
|
161
|
+
isResolving,
|
|
108
162
|
hasResolved,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
canDelete: hasResolved && _delete.data,
|
|
115
|
-
},
|
|
116
|
-
];
|
|
163
|
+
canRead: hasResolved && read.data,
|
|
164
|
+
canCreate: hasResolved && create.data,
|
|
165
|
+
canUpdate: hasResolved && update.data,
|
|
166
|
+
canDelete: hasResolved && _delete.data,
|
|
167
|
+
};
|
|
117
168
|
},
|
|
118
169
|
[ resource, id ]
|
|
119
170
|
);
|
|
120
171
|
}
|
|
172
|
+
|
|
173
|
+
export function __experimentalUseResourcePermissions(
|
|
174
|
+
resource: string,
|
|
175
|
+
id?: unknown
|
|
176
|
+
) {
|
|
177
|
+
deprecated( `wp.data.__experimentalUseResourcePermissions`, {
|
|
178
|
+
alternative: 'wp.data.useResourcePermissions',
|
|
179
|
+
since: '6.1',
|
|
180
|
+
} );
|
|
181
|
+
return useResourcePermissions( resource, id );
|
|
182
|
+
}
|
package/src/index.js
CHANGED
|
@@ -68,9 +68,6 @@ 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';
|
|
74
71
|
export * from './entity-provider';
|
|
75
72
|
export * from './entity-types';
|
|
76
73
|
export * from './fetch';
|
package/src/resolvers.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { camelCase
|
|
4
|
+
import { camelCase } from 'change-case';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
@@ -57,7 +57,9 @@ export const getEntityRecord =
|
|
|
57
57
|
( kind, name, key = '', query ) =>
|
|
58
58
|
async ( { select, dispatch } ) => {
|
|
59
59
|
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
60
|
-
const entityConfig = find(
|
|
60
|
+
const entityConfig = configs.find(
|
|
61
|
+
( config ) => config.name === name && config.kind === kind
|
|
62
|
+
);
|
|
61
63
|
if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
@@ -75,11 +77,13 @@ export const getEntityRecord =
|
|
|
75
77
|
// the ID.
|
|
76
78
|
query = {
|
|
77
79
|
...query,
|
|
78
|
-
_fields:
|
|
79
|
-
...
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
_fields: [
|
|
81
|
+
...new Set( [
|
|
82
|
+
...( getNormalizedCommaSeparable( query._fields ) ||
|
|
83
|
+
[] ),
|
|
84
|
+
entityConfig.key || DEFAULT_ENTITY_KEY,
|
|
85
|
+
] ),
|
|
86
|
+
].join(),
|
|
83
87
|
};
|
|
84
88
|
}
|
|
85
89
|
|
|
@@ -139,7 +143,9 @@ export const getEntityRecords =
|
|
|
139
143
|
( kind, name, query = {} ) =>
|
|
140
144
|
async ( { dispatch } ) => {
|
|
141
145
|
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
142
|
-
const entityConfig = find(
|
|
146
|
+
const entityConfig = configs.find(
|
|
147
|
+
( config ) => config.name === name && config.kind === kind
|
|
148
|
+
);
|
|
143
149
|
if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
|
|
144
150
|
return;
|
|
145
151
|
}
|
|
@@ -157,11 +163,13 @@ export const getEntityRecords =
|
|
|
157
163
|
// the ID.
|
|
158
164
|
query = {
|
|
159
165
|
...query,
|
|
160
|
-
_fields:
|
|
161
|
-
...
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
_fields: [
|
|
167
|
+
...new Set( [
|
|
168
|
+
...( getNormalizedCommaSeparable( query._fields ) ||
|
|
169
|
+
[] ),
|
|
170
|
+
entityConfig.key || DEFAULT_ENTITY_KEY,
|
|
171
|
+
] ),
|
|
172
|
+
].join(),
|
|
165
173
|
};
|
|
166
174
|
}
|
|
167
175
|
|
|
@@ -307,7 +315,8 @@ export const canUser =
|
|
|
307
315
|
// only return the result, without including response properties like the headers.
|
|
308
316
|
const allowHeader = response.headers?.get( 'allow' );
|
|
309
317
|
const key = [ action, resource, id ].filter( Boolean ).join( '/' );
|
|
310
|
-
const isAllowed =
|
|
318
|
+
const isAllowed =
|
|
319
|
+
allowHeader?.includes?.( method ) || allowHeader?.allow === method;
|
|
311
320
|
dispatch.receiveUserPermission( key, isAllowed );
|
|
312
321
|
};
|
|
313
322
|
|
|
@@ -323,7 +332,9 @@ export const canUserEditEntityRecord =
|
|
|
323
332
|
( kind, name, recordId ) =>
|
|
324
333
|
async ( { dispatch } ) => {
|
|
325
334
|
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
|
|
326
|
-
const entityConfig = find(
|
|
335
|
+
const entityConfig = configs.find(
|
|
336
|
+
( config ) => config.name === name && config.kind === kind
|
|
337
|
+
);
|
|
327
338
|
if ( ! entityConfig ) {
|
|
328
339
|
return;
|
|
329
340
|
}
|
|
@@ -427,13 +438,9 @@ export const __experimentalGetCurrentGlobalStylesId =
|
|
|
427
438
|
'theme',
|
|
428
439
|
{ status: 'active' }
|
|
429
440
|
);
|
|
430
|
-
const globalStylesURL =
|
|
431
|
-
0
|
|
432
|
-
|
|
433
|
-
'wp:user-global-styles',
|
|
434
|
-
0,
|
|
435
|
-
'href',
|
|
436
|
-
] );
|
|
441
|
+
const globalStylesURL =
|
|
442
|
+
activeThemes?.[ 0 ]?._links?.[ 'wp:user-global-styles' ]?.[ 0 ]
|
|
443
|
+
?.href;
|
|
437
444
|
if ( globalStylesURL ) {
|
|
438
445
|
const globalStylesObject = await apiFetch( {
|
|
439
446
|
url: globalStylesURL,
|
|
@@ -476,8 +483,13 @@ export const getBlockPatterns =
|
|
|
476
483
|
const restPatterns = await apiFetch( {
|
|
477
484
|
path: '/wp/v2/block-patterns/patterns',
|
|
478
485
|
} );
|
|
479
|
-
const patterns = map(
|
|
480
|
-
|
|
486
|
+
const patterns = restPatterns?.map( ( pattern ) =>
|
|
487
|
+
Object.fromEntries(
|
|
488
|
+
Object.entries( pattern ).map( ( [ key, value ] ) => [
|
|
489
|
+
camelCase( key ),
|
|
490
|
+
value,
|
|
491
|
+
] )
|
|
492
|
+
)
|
|
481
493
|
);
|
|
482
494
|
dispatch( { type: 'RECEIVE_BLOCK_PATTERNS', patterns } );
|
|
483
495
|
};
|