@wordpress/core-data 7.49.1 → 7.50.1-next.v.202607070741.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/entities.cjs +10 -0
- package/build/entities.cjs.map +2 -2
- package/build/private-actions.cjs +4 -0
- package/build/private-actions.cjs.map +2 -2
- package/build/resolvers.cjs +2 -1
- package/build/resolvers.cjs.map +2 -2
- package/build/utils/crdt-blocks.cjs.map +2 -2
- package/build/utils/crdt.cjs +7 -2
- package/build/utils/crdt.cjs.map +2 -2
- package/build-module/entities.mjs +10 -0
- package/build-module/entities.mjs.map +2 -2
- package/build-module/private-actions.mjs +4 -0
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/resolvers.mjs +2 -1
- package/build-module/resolvers.mjs.map +2 -2
- package/build-module/utils/crdt-blocks.mjs.map +2 -2
- package/build-module/utils/crdt.mjs +7 -2
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-types/entities.d.ts +17 -0
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/utils/crdt-blocks.d.ts +1 -0
- package/build-types/utils/crdt-blocks.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/package.json +19 -18
- package/src/entities.js +10 -0
- package/src/private-actions.js +4 -0
- package/src/resolvers.js +6 -1
- package/src/test/private-actions.js +38 -1
- package/src/test/resolvers.js +45 -0
- package/src/utils/crdt-blocks.ts +1 -0
- package/src/utils/crdt.ts +18 -2
- package/src/utils/test/crdt-blocks.ts +58 -0
- package/src/utils/test/crdt.ts +47 -0
|
@@ -6,9 +6,14 @@ import apiFetch from '@wordpress/api-fetch';
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
|
-
import { editMediaEntity } from '../private-actions';
|
|
9
|
+
import { editMediaEntity, setCollaborationSupported } from '../private-actions';
|
|
10
|
+
import { getSyncManager, hasSyncManager } from '../sync';
|
|
10
11
|
|
|
11
12
|
jest.mock( '@wordpress/api-fetch' );
|
|
13
|
+
jest.mock( '../sync', () => ( {
|
|
14
|
+
getSyncManager: jest.fn(),
|
|
15
|
+
hasSyncManager: jest.fn(),
|
|
16
|
+
} ) );
|
|
12
17
|
|
|
13
18
|
describe( 'editMediaEntity', () => {
|
|
14
19
|
let dispatch;
|
|
@@ -211,3 +216,35 @@ describe( 'editMediaEntity', () => {
|
|
|
211
216
|
expect( result ).toBeUndefined();
|
|
212
217
|
} );
|
|
213
218
|
} );
|
|
219
|
+
|
|
220
|
+
describe( 'setCollaborationSupported', () => {
|
|
221
|
+
afterEach( () => {
|
|
222
|
+
getSyncManager.mockReset();
|
|
223
|
+
hasSyncManager.mockReset();
|
|
224
|
+
} );
|
|
225
|
+
|
|
226
|
+
it( 'unloads sync and resets sync undo state when disabling collaboration', () => {
|
|
227
|
+
const syncManager = {
|
|
228
|
+
unloadAll: jest.fn(),
|
|
229
|
+
};
|
|
230
|
+
const dispatch = Object.assign( jest.fn(), {
|
|
231
|
+
__unstableNotifySyncUndoManagerChange: jest.fn(),
|
|
232
|
+
} );
|
|
233
|
+
hasSyncManager.mockReturnValue( true );
|
|
234
|
+
getSyncManager.mockReturnValue( syncManager );
|
|
235
|
+
|
|
236
|
+
setCollaborationSupported( false )( { dispatch } );
|
|
237
|
+
|
|
238
|
+
expect( dispatch ).toHaveBeenCalledWith( {
|
|
239
|
+
type: 'SET_COLLABORATION_SUPPORTED',
|
|
240
|
+
supported: false,
|
|
241
|
+
} );
|
|
242
|
+
expect( syncManager.unloadAll ).toHaveBeenCalledTimes( 1 );
|
|
243
|
+
expect(
|
|
244
|
+
dispatch.__unstableNotifySyncUndoManagerChange
|
|
245
|
+
).toHaveBeenCalledWith( {
|
|
246
|
+
hasUndo: false,
|
|
247
|
+
hasRedo: false,
|
|
248
|
+
} );
|
|
249
|
+
} );
|
|
250
|
+
} );
|
package/src/test/resolvers.js
CHANGED
|
@@ -183,6 +183,51 @@ describe( 'getEntityRecord', () => {
|
|
|
183
183
|
);
|
|
184
184
|
} );
|
|
185
185
|
|
|
186
|
+
it( 'does not load entity with sync manager when collaboration is unsupported', async () => {
|
|
187
|
+
const POST_RECORD = { id: 1, title: 'Test Post' };
|
|
188
|
+
const POST_RESPONSE = {
|
|
189
|
+
json: () => Promise.resolve( POST_RECORD ),
|
|
190
|
+
};
|
|
191
|
+
const ENTITIES_WITH_SYNC = [
|
|
192
|
+
{
|
|
193
|
+
name: 'post',
|
|
194
|
+
kind: 'postType',
|
|
195
|
+
baseURL: '/wp/v2/posts',
|
|
196
|
+
baseURLParams: { context: 'edit' },
|
|
197
|
+
syncConfig: {},
|
|
198
|
+
},
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
const resolveSelectWithSync = {
|
|
202
|
+
getEntitiesConfig: jest.fn( () => ENTITIES_WITH_SYNC ),
|
|
203
|
+
};
|
|
204
|
+
const select = {
|
|
205
|
+
isCollaborationSupported: jest.fn( () => false ),
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
triggerFetch.mockImplementation( () => POST_RESPONSE );
|
|
209
|
+
|
|
210
|
+
await getEntityRecord(
|
|
211
|
+
'postType',
|
|
212
|
+
'post',
|
|
213
|
+
1
|
|
214
|
+
)( {
|
|
215
|
+
select,
|
|
216
|
+
dispatch,
|
|
217
|
+
registry,
|
|
218
|
+
resolveSelect: resolveSelectWithSync,
|
|
219
|
+
} );
|
|
220
|
+
|
|
221
|
+
expect( syncManager.load ).not.toHaveBeenCalled();
|
|
222
|
+
expect( select.isCollaborationSupported ).toHaveBeenCalledTimes( 1 );
|
|
223
|
+
expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith(
|
|
224
|
+
'postType',
|
|
225
|
+
'post',
|
|
226
|
+
POST_RECORD,
|
|
227
|
+
undefined
|
|
228
|
+
);
|
|
229
|
+
} );
|
|
230
|
+
|
|
186
231
|
it( 'notifies core-data when the sync undo manager stack changes', async () => {
|
|
187
232
|
const POST_RECORD = { id: 1, title: 'Test Post' };
|
|
188
233
|
const POST_RESPONSE = {
|
package/src/utils/crdt-blocks.ts
CHANGED
package/src/utils/crdt.ts
CHANGED
|
@@ -345,8 +345,24 @@ function parseCursorSelection( selection?: WPSelection ): MergeCursorPosition {
|
|
|
345
345
|
: null;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
function defaultGetChangesFromCRDTDoc(
|
|
349
|
-
|
|
348
|
+
function defaultGetChangesFromCRDTDoc(
|
|
349
|
+
crdtDoc: CRDTDoc,
|
|
350
|
+
editedRecord: ObjectData
|
|
351
|
+
): ObjectData {
|
|
352
|
+
const docRecord = getRootMap( crdtDoc, CRDT_RECORD_MAP_KEY ).toJSON();
|
|
353
|
+
|
|
354
|
+
/*
|
|
355
|
+
* Only report properties that differ from the edited record. Reporting
|
|
356
|
+
* unchanged properties as edits marks the record dirty: `Y.Map.toJSON()`
|
|
357
|
+
* returns fresh object instances, so without this comparison every synced
|
|
358
|
+
* update (e.g. from another tab) re-dispatches the entire record as edits.
|
|
359
|
+
* See https://github.com/WordPress/gutenberg/issues/79907.
|
|
360
|
+
*/
|
|
361
|
+
return Object.fromEntries(
|
|
362
|
+
Object.entries( docRecord ).filter( ( [ key, newValue ] ) =>
|
|
363
|
+
haveValuesChanged( editedRecord?.[ key ], newValue )
|
|
364
|
+
)
|
|
365
|
+
);
|
|
350
366
|
}
|
|
351
367
|
|
|
352
368
|
/**
|
|
@@ -165,6 +165,64 @@ describe( 'crdt-blocks', () => {
|
|
|
165
165
|
expect( content.toString() ).toBe( 'Hello World' );
|
|
166
166
|
} );
|
|
167
167
|
|
|
168
|
+
it( 'syncs innerContent of static inner-content blocks into the Y.Doc', () => {
|
|
169
|
+
const incomingBlocks: Block[] = [
|
|
170
|
+
{
|
|
171
|
+
name: 'core/html',
|
|
172
|
+
attributes: {},
|
|
173
|
+
innerBlocks: [
|
|
174
|
+
{
|
|
175
|
+
name: 'core/paragraph',
|
|
176
|
+
attributes: { content: 'Editable' },
|
|
177
|
+
innerBlocks: [],
|
|
178
|
+
clientId: 'inner-1',
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
innerContent: [ '<div class="banner">', null, '</div>' ],
|
|
182
|
+
clientId: 'html-1',
|
|
183
|
+
},
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
mergeCrdtBlocks( yblocks, incomingBlocks, null );
|
|
187
|
+
|
|
188
|
+
const block = yblocks.get( 0 );
|
|
189
|
+
expect( block.get( 'innerContent' ) ).toEqual( [
|
|
190
|
+
'<div class="banner">',
|
|
191
|
+
null,
|
|
192
|
+
'</div>',
|
|
193
|
+
] );
|
|
194
|
+
} );
|
|
195
|
+
|
|
196
|
+
it( 'updates innerContent when the static markup changes', () => {
|
|
197
|
+
const initialBlocks: Block[] = [
|
|
198
|
+
{
|
|
199
|
+
name: 'core/html',
|
|
200
|
+
attributes: {},
|
|
201
|
+
innerBlocks: [],
|
|
202
|
+
innerContent: [ '<p>one</p>' ],
|
|
203
|
+
clientId: 'html-1',
|
|
204
|
+
},
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
mergeCrdtBlocks( yblocks, initialBlocks, null );
|
|
208
|
+
|
|
209
|
+
const updatedBlocks: Block[] = [
|
|
210
|
+
{
|
|
211
|
+
name: 'core/html',
|
|
212
|
+
attributes: {},
|
|
213
|
+
innerBlocks: [],
|
|
214
|
+
innerContent: [ '<p>two</p>' ],
|
|
215
|
+
clientId: 'html-1',
|
|
216
|
+
},
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
mergeCrdtBlocks( yblocks, updatedBlocks, null );
|
|
220
|
+
|
|
221
|
+
expect( yblocks.get( 0 ).get( 'innerContent' ) ).toEqual( [
|
|
222
|
+
'<p>two</p>',
|
|
223
|
+
] );
|
|
224
|
+
} );
|
|
225
|
+
|
|
168
226
|
it( 'updates existing blocks when content changes', () => {
|
|
169
227
|
const initialBlocks: Block[] = [
|
|
170
228
|
{
|
package/src/utils/test/crdt.ts
CHANGED
|
@@ -68,6 +68,7 @@ import { CRDT_RECORD_MAP_KEY } from '../../sync';
|
|
|
68
68
|
import {
|
|
69
69
|
applyPostChangesToCRDTDoc,
|
|
70
70
|
defaultCollectionSyncConfig,
|
|
71
|
+
defaultSyncConfig,
|
|
71
72
|
getPostChangesFromCRDTDoc,
|
|
72
73
|
POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
73
74
|
type PostChanges,
|
|
@@ -93,6 +94,52 @@ const defaultSyncedProperties = new Set< string >( [
|
|
|
93
94
|
'title',
|
|
94
95
|
] );
|
|
95
96
|
|
|
97
|
+
describe( 'defaultSyncConfig', () => {
|
|
98
|
+
// Regression test for https://github.com/WordPress/gutenberg/issues/79907:
|
|
99
|
+
// reporting unchanged properties as changes marks resolved records
|
|
100
|
+
// (e.g. taxonomy terms) as dirty whenever a synced update arrives.
|
|
101
|
+
it( 'getChangesFromCRDTDoc returns no changes when the document matches the edited record', () => {
|
|
102
|
+
const doc = new Y.Doc();
|
|
103
|
+
const record = {
|
|
104
|
+
id: 1,
|
|
105
|
+
name: 'Uncategorized',
|
|
106
|
+
slug: 'uncategorized',
|
|
107
|
+
meta: [],
|
|
108
|
+
_links: { self: [ { href: 'https://example.com' } ] },
|
|
109
|
+
};
|
|
110
|
+
defaultSyncConfig.applyChangesToCRDTDoc( doc, record );
|
|
111
|
+
|
|
112
|
+
// The edited record deep-equals the document contents, but
|
|
113
|
+
// `Y.Map.toJSON()` returns fresh object instances.
|
|
114
|
+
const changes = defaultSyncConfig.getChangesFromCRDTDoc( doc, {
|
|
115
|
+
...record,
|
|
116
|
+
meta: [],
|
|
117
|
+
_links: { self: [ { href: 'https://example.com' } ] },
|
|
118
|
+
} );
|
|
119
|
+
|
|
120
|
+
expect( changes ).toEqual( {} );
|
|
121
|
+
doc.destroy();
|
|
122
|
+
} );
|
|
123
|
+
|
|
124
|
+
it( 'getChangesFromCRDTDoc returns only the properties that differ from the edited record', () => {
|
|
125
|
+
const doc = new Y.Doc();
|
|
126
|
+
defaultSyncConfig.applyChangesToCRDTDoc( doc, {
|
|
127
|
+
id: 1,
|
|
128
|
+
name: 'Renamed category',
|
|
129
|
+
slug: 'uncategorized',
|
|
130
|
+
} );
|
|
131
|
+
|
|
132
|
+
const changes = defaultSyncConfig.getChangesFromCRDTDoc( doc, {
|
|
133
|
+
id: 1,
|
|
134
|
+
name: 'Uncategorized',
|
|
135
|
+
slug: 'uncategorized',
|
|
136
|
+
} );
|
|
137
|
+
|
|
138
|
+
expect( changes ).toEqual( { name: 'Renamed category' } );
|
|
139
|
+
doc.destroy();
|
|
140
|
+
} );
|
|
141
|
+
} );
|
|
142
|
+
|
|
96
143
|
describe( 'defaultCollectionSyncConfig', () => {
|
|
97
144
|
it( 'has no-op applyChangesToCRDTDoc', () => {
|
|
98
145
|
const doc = new Y.Doc();
|