@wordpress/core-data 7.41.2-next.v.202603161435.0 → 7.43.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 +3 -1
- package/build/awareness/post-editor-awareness.cjs +12 -5
- package/build/awareness/post-editor-awareness.cjs.map +2 -2
- package/build/entities.cjs +30 -5
- package/build/entities.cjs.map +2 -2
- package/build/hooks/use-post-editor-awareness-state.cjs +1 -1
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/private-actions.cjs +10 -0
- package/build/private-actions.cjs.map +2 -2
- package/build/private-selectors.cjs +20 -3
- package/build/private-selectors.cjs.map +2 -2
- package/build/queried-data/get-query-parts.cjs +8 -0
- package/build/queried-data/get-query-parts.cjs.map +2 -2
- package/build/queried-data/reducer.cjs +15 -9
- package/build/queried-data/reducer.cjs.map +2 -2
- package/build/queried-data/selectors.cjs +10 -2
- package/build/queried-data/selectors.cjs.map +2 -2
- package/build/reducer.cjs +22 -3
- package/build/reducer.cjs.map +2 -2
- package/build/resolvers.cjs +16 -8
- package/build/resolvers.cjs.map +2 -2
- package/build/selectors.cjs +16 -8
- package/build/selectors.cjs.map +2 -2
- package/build/sync.cjs +3 -0
- package/build/sync.cjs.map +2 -2
- package/build/types.cjs.map +2 -2
- package/build/utils/block-selection-history.cjs +1 -1
- package/build/utils/block-selection-history.cjs.map +2 -2
- package/build/utils/crdt-blocks.cjs +66 -5
- package/build/utils/crdt-blocks.cjs.map +2 -2
- package/build/utils/crdt-selection.cjs +4 -1
- package/build/utils/crdt-selection.cjs.map +2 -2
- package/build/utils/crdt-text.cjs +52 -0
- package/build/utils/crdt-text.cjs.map +7 -0
- package/build/utils/crdt-user-selections.cjs +1 -1
- package/build/utils/crdt-user-selections.cjs.map +2 -2
- package/build/utils/crdt-utils.cjs +54 -2
- package/build/utils/crdt-utils.cjs.map +2 -2
- package/build/utils/crdt.cjs +9 -23
- package/build/utils/crdt.cjs.map +2 -2
- package/build/utils/index.cjs +0 -3
- package/build/utils/index.cjs.map +2 -2
- package/build-module/awareness/post-editor-awareness.mjs +12 -5
- package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
- package/build-module/entities.mjs +30 -5
- package/build-module/entities.mjs.map +2 -2
- package/build-module/hooks/use-post-editor-awareness-state.mjs +1 -1
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/private-actions.mjs +9 -0
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/private-selectors.mjs +19 -3
- package/build-module/private-selectors.mjs.map +2 -2
- package/build-module/queried-data/get-query-parts.mjs +8 -0
- package/build-module/queried-data/get-query-parts.mjs.map +2 -2
- package/build-module/queried-data/reducer.mjs +15 -9
- package/build-module/queried-data/reducer.mjs.map +2 -2
- package/build-module/queried-data/selectors.mjs +10 -2
- package/build-module/queried-data/selectors.mjs.map +2 -2
- package/build-module/reducer.mjs +20 -2
- package/build-module/reducer.mjs.map +2 -2
- package/build-module/resolvers.mjs +14 -7
- package/build-module/resolvers.mjs.map +2 -2
- package/build-module/selectors.mjs +16 -9
- package/build-module/selectors.mjs.map +2 -2
- package/build-module/sync.mjs +2 -0
- package/build-module/sync.mjs.map +2 -2
- package/build-module/types.mjs.map +2 -2
- package/build-module/utils/block-selection-history.mjs +5 -2
- package/build-module/utils/block-selection-history.mjs.map +2 -2
- package/build-module/utils/crdt-blocks.mjs +65 -5
- package/build-module/utils/crdt-blocks.mjs.map +2 -2
- package/build-module/utils/crdt-selection.mjs +8 -2
- package/build-module/utils/crdt-selection.mjs.map +2 -2
- package/build-module/utils/crdt-text.mjs +26 -0
- package/build-module/utils/crdt-text.mjs.map +7 -0
- package/build-module/utils/crdt-user-selections.mjs +2 -2
- package/build-module/utils/crdt-user-selections.mjs.map +2 -2
- package/build-module/utils/crdt-utils.mjs +51 -1
- package/build-module/utils/crdt-utils.mjs.map +2 -2
- package/build-module/utils/crdt.mjs +10 -23
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-module/utils/index.mjs +8 -10
- package/build-module/utils/index.mjs.map +2 -2
- package/build-types/awareness/post-editor-awareness.d.ts +2 -2
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/private-actions.d.ts +10 -0
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/private-selectors.d.ts +11 -4
- package/build-types/private-selectors.d.ts.map +1 -1
- package/build-types/queried-data/get-query-parts.d.ts +13 -14
- package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
- package/build-types/queried-data/reducer.d.ts +11 -5
- package/build-types/queried-data/reducer.d.ts.map +1 -1
- package/build-types/queried-data/selectors.d.ts.map +1 -1
- package/build-types/reducer.d.ts +11 -0
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/resolvers.d.ts +3 -0
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/selectors.d.ts +1 -0
- package/build-types/selectors.d.ts.map +1 -1
- package/build-types/sync.d.ts +2 -2
- package/build-types/sync.d.ts.map +1 -1
- package/build-types/types.d.ts +4 -2
- package/build-types/types.d.ts.map +1 -1
- package/build-types/utils/block-selection-history.d.ts.map +1 -1
- package/build-types/utils/crdt-blocks.d.ts +11 -0
- package/build-types/utils/crdt-blocks.d.ts.map +1 -1
- package/build-types/utils/crdt-selection.d.ts.map +1 -1
- package/build-types/utils/crdt-text.d.ts +16 -0
- package/build-types/utils/crdt-text.d.ts.map +1 -0
- package/build-types/utils/crdt-user-selections.d.ts +1 -2
- package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
- package/build-types/utils/crdt-utils.d.ts +20 -0
- package/build-types/utils/crdt-utils.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts +6 -7
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/build-types/utils/index.d.ts +0 -1
- package/build-types/utils/test/crdt-utils.d.ts +2 -0
- package/build-types/utils/test/crdt-utils.d.ts.map +1 -0
- package/package.json +18 -18
- package/src/awareness/post-editor-awareness.ts +13 -6
- package/src/awareness/test/post-editor-awareness.ts +15 -10
- package/src/entities.js +36 -5
- package/src/hooks/test/use-post-editor-awareness-state.ts +3 -3
- package/src/hooks/use-post-editor-awareness-state.ts +1 -1
- package/src/private-actions.js +18 -0
- package/src/private-selectors.ts +37 -4
- package/src/queried-data/get-query-parts.js +14 -7
- package/src/queried-data/reducer.js +28 -15
- package/src/queried-data/selectors.js +11 -3
- package/src/queried-data/test/get-query-parts.js +34 -0
- package/src/queried-data/test/reducer.js +78 -8
- package/src/queried-data/test/selectors.js +171 -0
- package/src/reducer.js +31 -0
- package/src/resolvers.js +23 -7
- package/src/selectors.ts +20 -19
- package/src/sync.ts +2 -0
- package/src/test/entities.js +185 -1
- package/src/types.ts +8 -2
- package/src/utils/block-selection-history.ts +5 -2
- package/src/utils/crdt-blocks.ts +115 -5
- package/src/utils/crdt-selection.ts +8 -2
- package/src/utils/crdt-text.ts +43 -0
- package/src/utils/crdt-user-selections.ts +13 -13
- package/src/utils/crdt-utils.ts +99 -0
- package/src/utils/crdt.ts +18 -30
- package/src/utils/index.js +0 -1
- package/src/utils/test/crdt-blocks.ts +199 -0
- package/src/utils/test/crdt-user-selections.ts +5 -0
- package/src/utils/test/crdt-utils.ts +387 -0
- package/src/utils/test/crdt.ts +229 -54
- package/build/utils/is-raw-attribute.cjs +0 -29
- package/build/utils/is-raw-attribute.cjs.map +0 -7
- package/build-module/utils/is-raw-attribute.mjs +0 -8
- package/build-module/utils/is-raw-attribute.mjs.map +0 -7
- package/build-types/utils/is-raw-attribute.d.ts +0 -10
- package/build-types/utils/is-raw-attribute.d.ts.map +0 -1
- package/src/utils/is-raw-attribute.js +0 -11
- package/src/utils/test/is-raw-attribute.js +0 -22
|
@@ -32,15 +32,23 @@ const queriedItemsCacheByState = new WeakMap();
|
|
|
32
32
|
* @return {?Array} Query items.
|
|
33
33
|
*/
|
|
34
34
|
function getQueriedItemsUncached( state, query ) {
|
|
35
|
-
const {
|
|
36
|
-
|
|
35
|
+
const {
|
|
36
|
+
stableKey,
|
|
37
|
+
page,
|
|
38
|
+
perPage,
|
|
39
|
+
offset: queryOffset,
|
|
40
|
+
include,
|
|
41
|
+
fields,
|
|
42
|
+
context,
|
|
43
|
+
} = getQueryParts( query );
|
|
37
44
|
|
|
38
45
|
const itemIds = state.queries?.[ context ]?.[ stableKey ]?.itemIds;
|
|
39
46
|
if ( ! itemIds ) {
|
|
40
47
|
return null;
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
const startOffset =
|
|
50
|
+
const startOffset =
|
|
51
|
+
perPage === -1 ? 0 : queryOffset ?? ( page - 1 ) * perPage;
|
|
44
52
|
const endOffset =
|
|
45
53
|
perPage === -1
|
|
46
54
|
? itemIds.length
|
|
@@ -11,6 +11,7 @@ describe( 'getQueryParts', () => {
|
|
|
11
11
|
context: 'default',
|
|
12
12
|
page: 2,
|
|
13
13
|
perPage: 2,
|
|
14
|
+
offset: null,
|
|
14
15
|
stableKey: '',
|
|
15
16
|
fields: null,
|
|
16
17
|
include: null,
|
|
@@ -28,6 +29,7 @@ describe( 'getQueryParts', () => {
|
|
|
28
29
|
context: 'default',
|
|
29
30
|
page: 1,
|
|
30
31
|
perPage: 10,
|
|
32
|
+
offset: null,
|
|
31
33
|
stableKey: 'include=1',
|
|
32
34
|
fields: null,
|
|
33
35
|
include: [ 1 ],
|
|
@@ -43,6 +45,7 @@ describe( 'getQueryParts', () => {
|
|
|
43
45
|
context: 'default',
|
|
44
46
|
page: 1,
|
|
45
47
|
perPage: 10,
|
|
48
|
+
offset: null,
|
|
46
49
|
stableKey: '%3F=%26&b=2',
|
|
47
50
|
fields: null,
|
|
48
51
|
include: null,
|
|
@@ -56,6 +59,7 @@ describe( 'getQueryParts', () => {
|
|
|
56
59
|
context: 'default',
|
|
57
60
|
page: 1,
|
|
58
61
|
perPage: 10,
|
|
62
|
+
offset: null,
|
|
59
63
|
stableKey: 'a%5B0%5D=1&a%5B1%5D=2',
|
|
60
64
|
fields: null,
|
|
61
65
|
include: null,
|
|
@@ -71,6 +75,7 @@ describe( 'getQueryParts', () => {
|
|
|
71
75
|
context: 'default',
|
|
72
76
|
page: 1,
|
|
73
77
|
perPage: 10,
|
|
78
|
+
offset: null,
|
|
74
79
|
stableKey: 'b=2',
|
|
75
80
|
fields: null,
|
|
76
81
|
include: null,
|
|
@@ -84,6 +89,7 @@ describe( 'getQueryParts', () => {
|
|
|
84
89
|
context: 'default',
|
|
85
90
|
page: 1,
|
|
86
91
|
perPage: -1,
|
|
92
|
+
offset: null,
|
|
87
93
|
stableKey: 'b=2',
|
|
88
94
|
fields: null,
|
|
89
95
|
include: null,
|
|
@@ -97,6 +103,7 @@ describe( 'getQueryParts', () => {
|
|
|
97
103
|
context: 'default',
|
|
98
104
|
page: 1,
|
|
99
105
|
perPage: 10,
|
|
106
|
+
offset: null,
|
|
100
107
|
stableKey: '_fields=id%2Ctitle',
|
|
101
108
|
fields: [ 'id', 'title' ],
|
|
102
109
|
include: null,
|
|
@@ -109,10 +116,37 @@ describe( 'getQueryParts', () => {
|
|
|
109
116
|
expect( parts ).toEqual( {
|
|
110
117
|
page: 1,
|
|
111
118
|
perPage: 10,
|
|
119
|
+
offset: null,
|
|
112
120
|
stableKey: '',
|
|
113
121
|
include: null,
|
|
114
122
|
fields: null,
|
|
115
123
|
context: 'view',
|
|
116
124
|
} );
|
|
117
125
|
} );
|
|
126
|
+
|
|
127
|
+
it( 'extracts offset and excludes it from stableKey', () => {
|
|
128
|
+
const parts = getQueryParts( {
|
|
129
|
+
per_page: 50,
|
|
130
|
+
offset: 100,
|
|
131
|
+
} );
|
|
132
|
+
|
|
133
|
+
expect( parts ).toEqual( {
|
|
134
|
+
context: 'default',
|
|
135
|
+
page: 1,
|
|
136
|
+
perPage: 50,
|
|
137
|
+
offset: 100,
|
|
138
|
+
stableKey: '',
|
|
139
|
+
fields: null,
|
|
140
|
+
include: null,
|
|
141
|
+
} );
|
|
142
|
+
} );
|
|
143
|
+
|
|
144
|
+
it( 'ignores non-numeric offset values', () => {
|
|
145
|
+
const parts = getQueryParts( {
|
|
146
|
+
per_page: 10,
|
|
147
|
+
offset: 'abc',
|
|
148
|
+
} );
|
|
149
|
+
|
|
150
|
+
expect( parts.offset ).toBeNull();
|
|
151
|
+
} );
|
|
118
152
|
} );
|
|
@@ -11,7 +11,10 @@ import { removeItems } from '../actions';
|
|
|
11
11
|
|
|
12
12
|
describe( 'getMergedItemIds', () => {
|
|
13
13
|
it( 'should receive a page', () => {
|
|
14
|
-
const result = getMergedItemIds( [], [ 4, 5, 6 ],
|
|
14
|
+
const result = getMergedItemIds( [], [ 4, 5, 6 ], {
|
|
15
|
+
page: 2,
|
|
16
|
+
perPage: 3,
|
|
17
|
+
} );
|
|
15
18
|
|
|
16
19
|
expect( result ).toEqual( [
|
|
17
20
|
undefined,
|
|
@@ -32,46 +35,68 @@ describe( 'getMergedItemIds', () => {
|
|
|
32
35
|
5,
|
|
33
36
|
6,
|
|
34
37
|
] );
|
|
35
|
-
const result = getMergedItemIds( original, [ 1, 2, 3 ],
|
|
38
|
+
const result = getMergedItemIds( original, [ 1, 2, 3 ], {
|
|
39
|
+
page: 1,
|
|
40
|
+
perPage: 3,
|
|
41
|
+
} );
|
|
36
42
|
|
|
37
43
|
expect( result ).toEqual( [ 1, 2, 3, 4, 5, 6 ] );
|
|
38
44
|
} );
|
|
39
45
|
|
|
40
46
|
it( 'should replace with new page', () => {
|
|
41
47
|
const original = deepFreeze( [ 1, 2, 3, 4, 5, 6 ] );
|
|
42
|
-
const result = getMergedItemIds( original, [ 'replaced', 5, 6 ],
|
|
48
|
+
const result = getMergedItemIds( original, [ 'replaced', 5, 6 ], {
|
|
49
|
+
page: 2,
|
|
50
|
+
perPage: 3,
|
|
51
|
+
} );
|
|
43
52
|
|
|
44
53
|
expect( result ).toEqual( [ 1, 2, 3, 'replaced', 5, 6 ] );
|
|
45
54
|
} );
|
|
46
55
|
|
|
47
56
|
it( 'should append a new partial page', () => {
|
|
48
57
|
const original = deepFreeze( [ 1, 2, 3, 4, 5, 6 ] );
|
|
49
|
-
const result = getMergedItemIds( original, [ 7 ],
|
|
58
|
+
const result = getMergedItemIds( original, [ 7 ], {
|
|
59
|
+
page: 3,
|
|
60
|
+
perPage: 3,
|
|
61
|
+
} );
|
|
50
62
|
|
|
51
63
|
expect( result ).toEqual( [ 1, 2, 3, 4, 5, 6, 7 ] );
|
|
52
64
|
} );
|
|
53
65
|
|
|
54
66
|
it( 'should return a copy of nextItemIds if it represents all ids (single id removed) (page=1 and perPage=-1)', () => {
|
|
55
67
|
const original = deepFreeze( [ 1, 2, 3 ] );
|
|
56
|
-
const result = getMergedItemIds( original, [ 1, 3 ],
|
|
68
|
+
const result = getMergedItemIds( original, [ 1, 3 ], {
|
|
69
|
+
page: 1,
|
|
70
|
+
perPage: -1,
|
|
71
|
+
} );
|
|
57
72
|
|
|
58
73
|
expect( result ).toEqual( [ 1, 3 ] );
|
|
59
74
|
} );
|
|
60
75
|
|
|
61
76
|
it( 'should return a copy of nextItemIds if it represents all ids (single id removed and another one added) (page=1 and perPage=-1)', () => {
|
|
62
77
|
const original = deepFreeze( [ 1, 2, 3 ] );
|
|
63
|
-
const result = getMergedItemIds( original, [ 1, 3, 4 ],
|
|
78
|
+
const result = getMergedItemIds( original, [ 1, 3, 4 ], {
|
|
79
|
+
page: 1,
|
|
80
|
+
perPage: -1,
|
|
81
|
+
} );
|
|
64
82
|
|
|
65
83
|
expect( result ).toEqual( [ 1, 3, 4 ] );
|
|
66
84
|
} );
|
|
85
|
+
|
|
67
86
|
it( 'should update a page properly if less items are provided than previously stored', () => {
|
|
68
87
|
let original = deepFreeze( [ 1, 2, 3 ] );
|
|
69
|
-
let result = getMergedItemIds( original, [ 1, 2 ],
|
|
88
|
+
let result = getMergedItemIds( original, [ 1, 2 ], {
|
|
89
|
+
page: 1,
|
|
90
|
+
perPage: 3,
|
|
91
|
+
} );
|
|
70
92
|
|
|
71
93
|
expect( result ).toEqual( [ 1, 2 ] );
|
|
72
94
|
|
|
73
95
|
original = deepFreeze( [ 1, 2, 3, 4, 5, 6 ] );
|
|
74
|
-
result = getMergedItemIds( original, [ 9 ],
|
|
96
|
+
result = getMergedItemIds( original, [ 9 ], {
|
|
97
|
+
page: 2,
|
|
98
|
+
perPage: 2,
|
|
99
|
+
} );
|
|
75
100
|
|
|
76
101
|
expect( result ).toEqual( [ 1, 2, 9, undefined, 5, 6 ] );
|
|
77
102
|
} );
|
|
@@ -197,6 +222,51 @@ describe( 'reducer', () => {
|
|
|
197
222
|
} );
|
|
198
223
|
} );
|
|
199
224
|
|
|
225
|
+
it( 'receives a sparse subset of items at given offsets', () => {
|
|
226
|
+
const original = deepFreeze( {
|
|
227
|
+
items: { default: {} },
|
|
228
|
+
queries: {},
|
|
229
|
+
itemIsComplete: { default: {} },
|
|
230
|
+
} );
|
|
231
|
+
const state = [
|
|
232
|
+
{
|
|
233
|
+
type: 'RECEIVE_ITEMS',
|
|
234
|
+
query: { offset: 1, per_page: 2 },
|
|
235
|
+
items: [
|
|
236
|
+
{ id: 2, name: 'def' },
|
|
237
|
+
{ id: 3, name: 'ghi' },
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
type: 'RECEIVE_ITEMS',
|
|
242
|
+
query: { offset: 4, per_page: 2 },
|
|
243
|
+
items: [
|
|
244
|
+
{ id: 5, name: 'mno' },
|
|
245
|
+
{ id: 6, name: 'pqr' },
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
].reduce( reducer, original );
|
|
249
|
+
|
|
250
|
+
expect( state ).toEqual( {
|
|
251
|
+
items: {
|
|
252
|
+
default: {
|
|
253
|
+
2: { id: 2, name: 'def' },
|
|
254
|
+
3: { id: 3, name: 'ghi' },
|
|
255
|
+
5: { id: 5, name: 'mno' },
|
|
256
|
+
6: { id: 6, name: 'pqr' },
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
itemIsComplete: {
|
|
260
|
+
default: { 2: true, 3: true, 5: true, 6: true },
|
|
261
|
+
},
|
|
262
|
+
queries: {
|
|
263
|
+
default: {
|
|
264
|
+
'': { itemIds: [ undefined, 2, 3, undefined, 5, 6 ] },
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
} );
|
|
268
|
+
} );
|
|
269
|
+
|
|
200
270
|
it( 'deletes an item', () => {
|
|
201
271
|
const kind = 'root';
|
|
202
272
|
const name = 'menu';
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Internal dependencies
|
|
3
3
|
*/
|
|
4
4
|
import { getQueriedItems } from '../selectors';
|
|
5
|
+
import { getMergedItemIds } from '../reducer';
|
|
5
6
|
|
|
6
7
|
describe( 'getQueriedItems', () => {
|
|
7
8
|
it( 'should return null if requesting but no item IDs', () => {
|
|
@@ -264,4 +265,174 @@ describe( 'getQueriedItems', () => {
|
|
|
264
265
|
const result = getQueriedItems( state, { per_page: 3 } );
|
|
265
266
|
expect( result ).toBe( null );
|
|
266
267
|
} );
|
|
268
|
+
|
|
269
|
+
it( 'should return items for offset-based query on the last partial page', () => {
|
|
270
|
+
// Infinite scroll scenario: 103 total items, perPage=50, and the
|
|
271
|
+
// last batch starts at offset=100. The API returns 3 items (items
|
|
272
|
+
// 101-103). X-WP-Total is 103 (the global count). The selector
|
|
273
|
+
// should recognise this as a complete response since
|
|
274
|
+
// 103 - 100 = 3 expected items.
|
|
275
|
+
const state = {
|
|
276
|
+
items: {
|
|
277
|
+
default: {
|
|
278
|
+
101: { id: 101 },
|
|
279
|
+
102: { id: 102 },
|
|
280
|
+
103: { id: 103 },
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
itemIsComplete: {
|
|
284
|
+
default: { 101: true, 102: true, 103: true },
|
|
285
|
+
},
|
|
286
|
+
queries: {
|
|
287
|
+
default: {
|
|
288
|
+
'': {
|
|
289
|
+
itemIds: getMergedItemIds( [], [ 101, 102, 103 ], {
|
|
290
|
+
offset: 100,
|
|
291
|
+
perPage: 50,
|
|
292
|
+
} ),
|
|
293
|
+
meta: { totalItems: 103 },
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const result = getQueriedItems( state, {
|
|
300
|
+
per_page: 50,
|
|
301
|
+
offset: 100,
|
|
302
|
+
} );
|
|
303
|
+
expect( result ).toEqual( [ { id: 101 }, { id: 102 }, { id: 103 } ] );
|
|
304
|
+
} );
|
|
305
|
+
|
|
306
|
+
it( 'should return null for offset-based query when items are still missing', () => {
|
|
307
|
+
// Offset=50, perPage=50, totalItems=200: the API should return
|
|
308
|
+
// 50 items for this batch but only 2 are stored so far.
|
|
309
|
+
const state = {
|
|
310
|
+
items: {
|
|
311
|
+
default: {
|
|
312
|
+
51: { id: 51 },
|
|
313
|
+
52: { id: 52 },
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
itemIsComplete: {
|
|
317
|
+
default: { 51: true, 52: true },
|
|
318
|
+
},
|
|
319
|
+
queries: {
|
|
320
|
+
default: {
|
|
321
|
+
'': {
|
|
322
|
+
itemIds: getMergedItemIds( [], [ 51, 52 ], {
|
|
323
|
+
offset: 50,
|
|
324
|
+
perPage: 50,
|
|
325
|
+
} ),
|
|
326
|
+
meta: { totalItems: 200 },
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const result = getQueriedItems( state, {
|
|
333
|
+
per_page: 50,
|
|
334
|
+
offset: 50,
|
|
335
|
+
} );
|
|
336
|
+
expect( result ).toBe( null );
|
|
337
|
+
} );
|
|
338
|
+
|
|
339
|
+
it( 'should return null for offset query when items are still missing', () => {
|
|
340
|
+
// Query Block scenario: offset=3 with per_page=10. The effective
|
|
341
|
+
// total is totalItems - offset = 47. Only 5 items are stored, so
|
|
342
|
+
// the data is still incomplete.
|
|
343
|
+
const state = {
|
|
344
|
+
items: {
|
|
345
|
+
default: {
|
|
346
|
+
4: { id: 4 },
|
|
347
|
+
5: { id: 5 },
|
|
348
|
+
6: { id: 6 },
|
|
349
|
+
7: { id: 7 },
|
|
350
|
+
8: { id: 8 },
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
itemIsComplete: {
|
|
354
|
+
default: { 4: true, 5: true, 6: true, 7: true, 8: true },
|
|
355
|
+
},
|
|
356
|
+
queries: {
|
|
357
|
+
default: {
|
|
358
|
+
'': {
|
|
359
|
+
itemIds: getMergedItemIds( [], [ 4, 5, 6, 7, 8 ], {
|
|
360
|
+
offset: 3,
|
|
361
|
+
perPage: 10,
|
|
362
|
+
} ),
|
|
363
|
+
meta: { totalItems: 50 },
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const result = getQueriedItems( state, {
|
|
370
|
+
per_page: 10,
|
|
371
|
+
offset: 3,
|
|
372
|
+
} );
|
|
373
|
+
expect( result ).toBe( null );
|
|
374
|
+
} );
|
|
375
|
+
|
|
376
|
+
it( 'should treat offset=0 the same as no offset', () => {
|
|
377
|
+
// The Query Block defaults to offset=0. Since
|
|
378
|
+
// effectiveTotal = totalItems - 0 = totalItems, this should
|
|
379
|
+
// behave identically to a query without offset.
|
|
380
|
+
const state = {
|
|
381
|
+
items: {
|
|
382
|
+
default: {
|
|
383
|
+
1: { id: 1 },
|
|
384
|
+
2: { id: 2 },
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
itemIsComplete: {
|
|
388
|
+
default: { 1: true, 2: true },
|
|
389
|
+
},
|
|
390
|
+
queries: {
|
|
391
|
+
default: {
|
|
392
|
+
'': {
|
|
393
|
+
itemIds: [ 1, 2 ],
|
|
394
|
+
meta: { totalItems: 5 },
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// 2 items stored, but 5 total exist — should return null.
|
|
401
|
+
const result = getQueriedItems( state, {
|
|
402
|
+
per_page: 3,
|
|
403
|
+
offset: 0,
|
|
404
|
+
} );
|
|
405
|
+
expect( result ).toBe( null );
|
|
406
|
+
} );
|
|
407
|
+
|
|
408
|
+
it( 'should return empty array when offset equals totalItems', () => {
|
|
409
|
+
// Edge case: offset lands exactly at the end (e.g. 84 items,
|
|
410
|
+
// per_page=7, offset=84). The API returns 0 items and that is
|
|
411
|
+
// a complete response — effectiveTotal is 0.
|
|
412
|
+
const state = {
|
|
413
|
+
items: {
|
|
414
|
+
default: {},
|
|
415
|
+
},
|
|
416
|
+
itemIsComplete: {
|
|
417
|
+
default: {},
|
|
418
|
+
},
|
|
419
|
+
queries: {
|
|
420
|
+
default: {
|
|
421
|
+
'': {
|
|
422
|
+
itemIds: getMergedItemIds( [], [], {
|
|
423
|
+
offset: 84,
|
|
424
|
+
perPage: 7,
|
|
425
|
+
} ),
|
|
426
|
+
meta: { totalItems: 84 },
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const result = getQueriedItems( state, {
|
|
433
|
+
per_page: 7,
|
|
434
|
+
offset: 84,
|
|
435
|
+
} );
|
|
436
|
+
expect( result ).toEqual( [] );
|
|
437
|
+
} );
|
|
267
438
|
} );
|
package/src/reducer.js
CHANGED
|
@@ -16,6 +16,7 @@ import { createUndoManager } from '@wordpress/undo-manager';
|
|
|
16
16
|
import { ifMatchingAction, replaceAction } from './utils';
|
|
17
17
|
import { reducer as queriedDataReducer } from './queried-data';
|
|
18
18
|
import { rootEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
|
|
19
|
+
import { ConnectionErrorCode } from './sync';
|
|
19
20
|
|
|
20
21
|
/** @typedef {import('./types').AnyFunction} AnyFunction */
|
|
21
22
|
|
|
@@ -706,6 +707,35 @@ export function collaborationSupported( state = true, action ) {
|
|
|
706
707
|
switch ( action.type ) {
|
|
707
708
|
case 'SET_COLLABORATION_SUPPORTED':
|
|
708
709
|
return action.supported;
|
|
710
|
+
|
|
711
|
+
case 'SET_SYNC_CONNECTION_STATUS':
|
|
712
|
+
if (
|
|
713
|
+
ConnectionErrorCode.DOCUMENT_SIZE_LIMIT_EXCEEDED ===
|
|
714
|
+
action.status?.error?.code
|
|
715
|
+
) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return state;
|
|
720
|
+
}
|
|
721
|
+
return state;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Reducer managing view configs, keyed by `kind/name`.
|
|
726
|
+
*
|
|
727
|
+
* @param {Object} state Current state.
|
|
728
|
+
* @param {Object} action Dispatched action.
|
|
729
|
+
*
|
|
730
|
+
* @return {Object} Updated state.
|
|
731
|
+
*/
|
|
732
|
+
export function viewConfigs( state = {}, action ) {
|
|
733
|
+
switch ( action.type ) {
|
|
734
|
+
case 'RECEIVE_VIEW_CONFIG':
|
|
735
|
+
return {
|
|
736
|
+
...state,
|
|
737
|
+
[ `${ action.kind }/${ action.name }` ]: action.config,
|
|
738
|
+
};
|
|
709
739
|
}
|
|
710
740
|
return state;
|
|
711
741
|
}
|
|
@@ -734,4 +764,5 @@ export default combineReducers( {
|
|
|
734
764
|
editorAssets,
|
|
735
765
|
syncConnectionStatuses,
|
|
736
766
|
collaborationSupported,
|
|
767
|
+
viewConfigs,
|
|
737
768
|
} );
|
package/src/resolvers.js
CHANGED
|
@@ -991,11 +991,12 @@ export const getDefaultTemplateId =
|
|
|
991
991
|
const id = window?.__experimentalTemplateActivate
|
|
992
992
|
? template?.wp_id || template?.id
|
|
993
993
|
: template?.id;
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
994
|
+
|
|
995
|
+
registry.batch( () => {
|
|
996
|
+
dispatch.receiveDefaultTemplateId( query, id || '' );
|
|
997
|
+
// Endpoint may return an empty object if no template is found.
|
|
998
|
+
if ( id ) {
|
|
999
|
+
template.id = id;
|
|
999
1000
|
dispatch.receiveEntityRecords(
|
|
1000
1001
|
'postType',
|
|
1001
1002
|
template.type,
|
|
@@ -1007,8 +1008,8 @@ export const getDefaultTemplateId =
|
|
|
1007
1008
|
template.type,
|
|
1008
1009
|
id,
|
|
1009
1010
|
] );
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1011
|
+
}
|
|
1012
|
+
} );
|
|
1012
1013
|
};
|
|
1013
1014
|
|
|
1014
1015
|
getDefaultTemplateId.shouldInvalidate = ( action ) => {
|
|
@@ -1320,3 +1321,18 @@ export const getEditorAssets =
|
|
|
1320
1321
|
} );
|
|
1321
1322
|
dispatch.receiveEditorAssets( assets );
|
|
1322
1323
|
};
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* Requests view config for a given entity type from the REST API.
|
|
1327
|
+
*
|
|
1328
|
+
* @param {string} kind Entity kind.
|
|
1329
|
+
* @param {string} name Entity name.
|
|
1330
|
+
*/
|
|
1331
|
+
export const getViewConfig =
|
|
1332
|
+
( kind, name ) =>
|
|
1333
|
+
async ( { dispatch } ) => {
|
|
1334
|
+
const config = await apiFetch( {
|
|
1335
|
+
path: addQueryArgs( '/wp/v2/view-config', { kind, name } ),
|
|
1336
|
+
} );
|
|
1337
|
+
dispatch.receiveViewConfig( kind, name, config );
|
|
1338
|
+
};
|
package/src/selectors.ts
CHANGED
|
@@ -20,7 +20,6 @@ import { DEFAULT_ENTITY_KEY } from './entities';
|
|
|
20
20
|
import { getUndoManager } from './private-selectors';
|
|
21
21
|
import {
|
|
22
22
|
getNormalizedCommaSeparable,
|
|
23
|
-
isRawAttribute,
|
|
24
23
|
setNestedValue,
|
|
25
24
|
isNumericID,
|
|
26
25
|
getUserPermissionCacheKey,
|
|
@@ -55,6 +54,7 @@ export interface State {
|
|
|
55
54
|
editorAssets: Record< string, any > | null;
|
|
56
55
|
syncConnectionStatuses?: Record< string, ConnectionStatus >;
|
|
57
56
|
collaborationSupported: boolean;
|
|
57
|
+
viewConfigs: Record< string, Record< string, any > >;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
type EntityRecordKey = string | number;
|
|
@@ -523,25 +523,26 @@ export const getRawEntityRecord = createSelector(
|
|
|
523
523
|
name,
|
|
524
524
|
key
|
|
525
525
|
);
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
526
|
+
const config = getEntityConfig( state, kind, name );
|
|
527
|
+
if ( ! record || ! config?.rawAttributes?.length ) {
|
|
528
|
+
return record;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Because edits are the "raw" attribute values,
|
|
532
|
+
// we return those from record selectors to make rendering,
|
|
533
|
+
// comparisons, and joins with edits easier.
|
|
534
|
+
return Object.fromEntries(
|
|
535
|
+
Object.keys( record ).map( ( _key ) => {
|
|
536
|
+
if ( config.rawAttributes.includes( _key ) ) {
|
|
537
|
+
const rawValue = record[ _key ]?.raw;
|
|
538
|
+
return [
|
|
539
|
+
_key,
|
|
540
|
+
rawValue !== undefined ? rawValue : record[ _key ],
|
|
541
|
+
];
|
|
541
542
|
}
|
|
542
|
-
return
|
|
543
|
-
}
|
|
544
|
-
);
|
|
543
|
+
return [ _key, record[ _key ] ];
|
|
544
|
+
} )
|
|
545
|
+
) as EntityRecord;
|
|
545
546
|
},
|
|
546
547
|
(
|
|
547
548
|
state: State,
|
package/src/sync.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { unlock } from './lock-unlock';
|
|
13
13
|
|
|
14
14
|
const {
|
|
15
|
+
ConnectionErrorCode,
|
|
15
16
|
createSyncManager,
|
|
16
17
|
Delta,
|
|
17
18
|
CRDT_DOC_META_PERSISTENCE_KEY,
|
|
@@ -22,6 +23,7 @@ const {
|
|
|
22
23
|
} = unlock( syncPrivateApis );
|
|
23
24
|
|
|
24
25
|
export {
|
|
26
|
+
ConnectionErrorCode,
|
|
25
27
|
Delta,
|
|
26
28
|
CRDT_DOC_META_PERSISTENCE_KEY,
|
|
27
29
|
CRDT_RECORD_MAP_KEY,
|