@plone/volto 14.0.0-alpha.35 → 14.0.0-alpha.36
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 +12 -0
- package/package.json +1 -1
- package/src/actions/vocabularies/vocabularies.js +6 -10
- package/src/actions/vocabularies/vocabularies.test.js +26 -0
- package/src/helpers/Blocks/Blocks.js +23 -14
- package/src/helpers/Blocks/Blocks.test.js +166 -0
- package/src/helpers/Extensions/withBlockSchemaEnhancer.js +77 -3
- package/src/helpers/index.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 14.0.0-alpha.36 (2021-11-25)
|
|
4
|
+
|
|
5
|
+
### Bugfix
|
|
6
|
+
|
|
7
|
+
- Fix regression in actions vocabularies calls because the change to use contextual schemas @sneridagh
|
|
8
|
+
- Include block schema enhancers (main block schema enhancer + variation schema enhancer) when calculating block default data @tiberiuichim
|
|
9
|
+
|
|
10
|
+
### Internal
|
|
11
|
+
|
|
12
|
+
- Fix references to old configuration style in apiExpanders documentation @tiberiuichim
|
|
13
|
+
- Add `applySchemaDefaults`, in addition to `applyBlockDefaults`, to allow reuse in object widgets and other advanced scenarios @tiberiuichim
|
|
14
|
+
|
|
3
15
|
## 14.0.0-alpha.35 (2021-11-24)
|
|
4
16
|
|
|
5
17
|
### Bugfix
|
package/package.json
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
GET_VOCABULARY,
|
|
8
8
|
GET_VOCABULARY_TOKEN_TITLE,
|
|
9
9
|
} from '@plone/volto/constants/ActionTypes';
|
|
10
|
-
import config from '@plone/volto/registry';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Get vocabulary given a URL (coming from a Schema) or from a vocabulary name.
|
|
@@ -18,11 +17,10 @@ import config from '@plone/volto/registry';
|
|
|
18
17
|
* @returns {Object} Get vocabulary action.
|
|
19
18
|
*/
|
|
20
19
|
export function getVocabulary(vocabNameOrURL, query = null, start = 0) {
|
|
21
|
-
const { settings } = config;
|
|
22
20
|
// In case we have a URL, we have to get the vocabulary name
|
|
23
|
-
const vocabulary =
|
|
24
|
-
vocabNameOrURL
|
|
25
|
-
vocabNameOrURL
|
|
21
|
+
const vocabulary = /(?<=\/@vocabularies\/)(.*)/.test(vocabNameOrURL)
|
|
22
|
+
? /(?<=\/@vocabularies\/)(.*)/.exec(vocabNameOrURL)[0]
|
|
23
|
+
: vocabNameOrURL;
|
|
26
24
|
let queryString = `b_start=${start}`;
|
|
27
25
|
if (query) {
|
|
28
26
|
queryString = `${queryString}&title=${query}`;
|
|
@@ -47,12 +45,10 @@ export function getVocabulary(vocabNameOrURL, query = null, start = 0) {
|
|
|
47
45
|
* @returns {Object} Get vocabulary action.
|
|
48
46
|
*/
|
|
49
47
|
export function getVocabularyTokenTitle(vocabNameOrURL, token = null) {
|
|
50
|
-
const { settings } = config;
|
|
51
48
|
// In case we have a URL, we have to get the vocabulary name
|
|
52
|
-
const vocabulary = vocabNameOrURL
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
);
|
|
49
|
+
const vocabulary = /(?<=\/@vocabularies\/)(.*)/.test(vocabNameOrURL)
|
|
50
|
+
? /(?<=\/@vocabularies\/)(.*)/.exec(vocabNameOrURL)[0]
|
|
51
|
+
: vocabNameOrURL;
|
|
56
52
|
|
|
57
53
|
return {
|
|
58
54
|
type: GET_VOCABULARY_TOKEN_TITLE,
|
|
@@ -15,5 +15,31 @@ describe('Vocabularies actions', () => {
|
|
|
15
15
|
`/@vocabularies/${vocabulary}?b_start=0&title=${query}`,
|
|
16
16
|
);
|
|
17
17
|
});
|
|
18
|
+
it('should create an action to get a vocabulary if a URL is passed', () => {
|
|
19
|
+
const vocabulary =
|
|
20
|
+
'http://localhost:8080/@vocabularies/plone.app.vocabularies.Keywords';
|
|
21
|
+
const query = 'john';
|
|
22
|
+
const action = getVocabulary(vocabulary, query);
|
|
23
|
+
|
|
24
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
|
25
|
+
expect(action.vocabulary).toEqual(vocabulary);
|
|
26
|
+
expect(action.request.op).toEqual('get');
|
|
27
|
+
expect(action.request.path).toEqual(
|
|
28
|
+
`/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
it('should create an action to get a vocabulary if a URL with path is passed', () => {
|
|
32
|
+
const vocabulary =
|
|
33
|
+
'http://localhost:8080/de/foo/bar/@vocabularies/plone.app.vocabularies.Keywords';
|
|
34
|
+
const query = 'john';
|
|
35
|
+
const action = getVocabulary(vocabulary, query);
|
|
36
|
+
|
|
37
|
+
expect(action.type).toEqual(GET_VOCABULARY);
|
|
38
|
+
expect(action.vocabulary).toEqual(vocabulary);
|
|
39
|
+
expect(action.request.op).toEqual('get');
|
|
40
|
+
expect(action.request.path).toEqual(
|
|
41
|
+
`/@vocabularies/plone.app.vocabularies.Keywords?b_start=0&title=${query}`,
|
|
42
|
+
);
|
|
43
|
+
});
|
|
18
44
|
});
|
|
19
45
|
});
|
|
@@ -7,6 +7,7 @@ import { omit, without, endsWith, find, keys } from 'lodash';
|
|
|
7
7
|
import move from 'lodash-move';
|
|
8
8
|
import { v4 as uuid } from 'uuid';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
10
|
+
import { applySchemaEnhancer } from '@plone/volto/helpers';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Get blocks field.
|
|
@@ -361,8 +362,27 @@ export function visitBlocks(content, callback) {
|
|
|
361
362
|
}
|
|
362
363
|
}
|
|
363
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Initializes data with the default values coming from schema
|
|
367
|
+
*/
|
|
368
|
+
export function applySchemaDefaults({ data = {}, schema }) {
|
|
369
|
+
const derivedData = {
|
|
370
|
+
...Object.keys(schema.properties).reduce((accumulator, currentField) => {
|
|
371
|
+
return schema.properties[currentField].default
|
|
372
|
+
? {
|
|
373
|
+
...accumulator,
|
|
374
|
+
[currentField]: schema.properties[currentField].default,
|
|
375
|
+
}
|
|
376
|
+
: accumulator;
|
|
377
|
+
}, {}),
|
|
378
|
+
...data,
|
|
379
|
+
};
|
|
380
|
+
return derivedData;
|
|
381
|
+
}
|
|
382
|
+
|
|
364
383
|
/**
|
|
365
384
|
* Apply the block's default (as defined in schema) to the block data.
|
|
385
|
+
*
|
|
366
386
|
* @function applyBlockDefaults
|
|
367
387
|
* @param {Object} params An object with data, intl and anything else
|
|
368
388
|
* @return {Object} Derived data, with the defaults extracted from the schema
|
|
@@ -373,22 +393,11 @@ export function applyBlockDefaults({ data, intl, ...rest }, blocksConfig) {
|
|
|
373
393
|
(blocksConfig || config.blocks.blocksConfig)[block_type] || {};
|
|
374
394
|
if (!blockSchema) return data;
|
|
375
395
|
|
|
376
|
-
|
|
396
|
+
let schema =
|
|
377
397
|
typeof blockSchema === 'function'
|
|
378
398
|
? blockSchema({ data, intl, ...rest })
|
|
379
399
|
: blockSchema;
|
|
400
|
+
schema = applySchemaEnhancer({ schema, formData: data, intl });
|
|
380
401
|
|
|
381
|
-
|
|
382
|
-
...Object.keys(schema.properties).reduce((accumulator, currentField) => {
|
|
383
|
-
return schema.properties[currentField].default
|
|
384
|
-
? {
|
|
385
|
-
...accumulator,
|
|
386
|
-
[currentField]: schema.properties[currentField].default,
|
|
387
|
-
}
|
|
388
|
-
: accumulator;
|
|
389
|
-
}, {}),
|
|
390
|
-
...data,
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
return derivedData;
|
|
402
|
+
return applySchemaDefaults({ data, schema });
|
|
394
403
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
previousBlockId,
|
|
16
16
|
visitBlocks,
|
|
17
17
|
applyBlockDefaults,
|
|
18
|
+
applySchemaDefaults,
|
|
18
19
|
} from './Blocks';
|
|
19
20
|
|
|
20
21
|
import config from '@plone/volto/registry';
|
|
@@ -54,6 +55,111 @@ config.blocks.blocksConfig.text = {
|
|
|
54
55
|
}),
|
|
55
56
|
};
|
|
56
57
|
|
|
58
|
+
config.blocks.blocksConfig.enhancedBlock = {
|
|
59
|
+
id: 'enhancedBlock',
|
|
60
|
+
title: 'Text',
|
|
61
|
+
group: 'text',
|
|
62
|
+
restricted: false,
|
|
63
|
+
mostUsed: false,
|
|
64
|
+
blockHasOwnFocusManagement: true,
|
|
65
|
+
blockHasValue: (data) => {
|
|
66
|
+
const isEmpty =
|
|
67
|
+
!data.text ||
|
|
68
|
+
(data.text?.blocks?.length === 1 && data.text.blocks[0].text === '');
|
|
69
|
+
return !isEmpty;
|
|
70
|
+
},
|
|
71
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
72
|
+
schema.fieldsets[0].fields.push('extra');
|
|
73
|
+
schema.properties.extra = { default: 'Extra value' };
|
|
74
|
+
return schema;
|
|
75
|
+
},
|
|
76
|
+
variations: [
|
|
77
|
+
{
|
|
78
|
+
id: 'firstVariation',
|
|
79
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
80
|
+
schema.fieldsets[0].fields.push('extraVariationField');
|
|
81
|
+
schema.properties['extraVariationField'] = {
|
|
82
|
+
default: 'Extra variation field',
|
|
83
|
+
};
|
|
84
|
+
return schema;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
blockSchema: ({ data }) => ({
|
|
89
|
+
fieldsets: [
|
|
90
|
+
{
|
|
91
|
+
id: 'default',
|
|
92
|
+
fields: ['title', 'description', 'nonDefault'],
|
|
93
|
+
title: 'Default',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
properties: {
|
|
97
|
+
title: {
|
|
98
|
+
default: 'Default title',
|
|
99
|
+
},
|
|
100
|
+
description: {
|
|
101
|
+
default: 'Default description',
|
|
102
|
+
},
|
|
103
|
+
nonDefault: {
|
|
104
|
+
title: 'Non default',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
config.blocks.blocksConfig.enhancedBlockCase2 = {
|
|
111
|
+
id: 'enhancedBlockCase2',
|
|
112
|
+
title: 'Text',
|
|
113
|
+
group: 'text',
|
|
114
|
+
restricted: false,
|
|
115
|
+
mostUsed: false,
|
|
116
|
+
blockHasOwnFocusManagement: true,
|
|
117
|
+
blockHasValue: (data) => {
|
|
118
|
+
const isEmpty =
|
|
119
|
+
!data.text ||
|
|
120
|
+
(data.text?.blocks?.length === 1 && data.text.blocks[0].text === '');
|
|
121
|
+
return !isEmpty;
|
|
122
|
+
},
|
|
123
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
124
|
+
schema.fieldsets[0].fields.push('extra');
|
|
125
|
+
schema.properties.extra = {
|
|
126
|
+
default: 'Extra value from block schema enhancer',
|
|
127
|
+
};
|
|
128
|
+
return schema;
|
|
129
|
+
},
|
|
130
|
+
variations: [
|
|
131
|
+
{
|
|
132
|
+
id: 'firstVariation',
|
|
133
|
+
schemaEnhancer: ({ schema, formData }) => {
|
|
134
|
+
schema.properties['extra'] = {
|
|
135
|
+
default: 'Extra variation field',
|
|
136
|
+
};
|
|
137
|
+
return schema;
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
blockSchema: ({ data }) => ({
|
|
142
|
+
fieldsets: [
|
|
143
|
+
{
|
|
144
|
+
id: 'default',
|
|
145
|
+
fields: ['title', 'description', 'nonDefault'],
|
|
146
|
+
title: 'Default',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
properties: {
|
|
150
|
+
title: {
|
|
151
|
+
default: 'Default title',
|
|
152
|
+
},
|
|
153
|
+
description: {
|
|
154
|
+
default: 'Default description',
|
|
155
|
+
},
|
|
156
|
+
nonDefault: {
|
|
157
|
+
title: 'Non default',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
};
|
|
162
|
+
|
|
57
163
|
config.settings.defaultBlockType = 'text';
|
|
58
164
|
|
|
59
165
|
describe('Blocks', () => {
|
|
@@ -383,6 +489,21 @@ describe('Blocks', () => {
|
|
|
383
489
|
});
|
|
384
490
|
});
|
|
385
491
|
|
|
492
|
+
describe('applySchemaDefaults', () => {
|
|
493
|
+
it('Sets data according to schema default values', () => {
|
|
494
|
+
const data = {
|
|
495
|
+
'@type': 'text',
|
|
496
|
+
description: 'already filled',
|
|
497
|
+
};
|
|
498
|
+
const schema = config.blocks.blocksConfig.text.blockSchema({ data });
|
|
499
|
+
expect(applySchemaDefaults({ schema, data })).toEqual({
|
|
500
|
+
'@type': 'text',
|
|
501
|
+
title: 'Default title',
|
|
502
|
+
description: 'already filled',
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
|
|
386
507
|
describe('applyBlockDefaults', () => {
|
|
387
508
|
it('Sets data according to schema default values', () => {
|
|
388
509
|
const data = {
|
|
@@ -406,5 +527,50 @@ describe('Blocks', () => {
|
|
|
406
527
|
description: 'already filled',
|
|
407
528
|
});
|
|
408
529
|
});
|
|
530
|
+
|
|
531
|
+
it('Supports block schema enhancers', () => {
|
|
532
|
+
const data = {
|
|
533
|
+
'@type': 'enhancedBlock',
|
|
534
|
+
description: 'already filled',
|
|
535
|
+
// variation: 'firstVariation',
|
|
536
|
+
};
|
|
537
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
538
|
+
'@type': 'enhancedBlock',
|
|
539
|
+
title: 'Default title',
|
|
540
|
+
description: 'already filled',
|
|
541
|
+
extra: 'Extra value',
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
it('Supports block schema enhancers coming from variations', () => {
|
|
546
|
+
const data = {
|
|
547
|
+
'@type': 'enhancedBlock',
|
|
548
|
+
description: 'already filled',
|
|
549
|
+
variation: 'firstVariation',
|
|
550
|
+
};
|
|
551
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
552
|
+
'@type': 'enhancedBlock',
|
|
553
|
+
title: 'Default title',
|
|
554
|
+
description: 'already filled',
|
|
555
|
+
extra: 'Extra value',
|
|
556
|
+
extraVariationField: 'Extra variation field',
|
|
557
|
+
variation: 'firstVariation',
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it('Block schema enhancers override variations', () => {
|
|
562
|
+
const data = {
|
|
563
|
+
'@type': 'enhancedBlockCase2',
|
|
564
|
+
description: 'already filled',
|
|
565
|
+
variation: 'firstVariation',
|
|
566
|
+
};
|
|
567
|
+
expect(applyBlockDefaults({ data })).toEqual({
|
|
568
|
+
'@type': 'enhancedBlockCase2',
|
|
569
|
+
title: 'Default title',
|
|
570
|
+
description: 'already filled',
|
|
571
|
+
extra: 'Extra value from block schema enhancer',
|
|
572
|
+
variation: 'firstVariation',
|
|
573
|
+
});
|
|
574
|
+
});
|
|
409
575
|
});
|
|
410
576
|
});
|
|
@@ -59,6 +59,39 @@ export const addExtensionFieldToSchema = ({
|
|
|
59
59
|
return schema;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* A generic HOC that provides "schema enhancer functionality" for any custom
|
|
64
|
+
* block extension.
|
|
65
|
+
*
|
|
66
|
+
* This enables blocks to have additional "variations", beyond the usual
|
|
67
|
+
* `variations` field. This function is not directly used by Volto.
|
|
68
|
+
*
|
|
69
|
+
* To be used with a block configuration like:
|
|
70
|
+
*
|
|
71
|
+
* ```
|
|
72
|
+
* {
|
|
73
|
+
* id: 'someBlockId',
|
|
74
|
+
* extensions: {
|
|
75
|
+
* '<someExtensionName>': {
|
|
76
|
+
* items: [
|
|
77
|
+
* {
|
|
78
|
+
* id: 'selectFacet',
|
|
79
|
+
* title: 'Select',
|
|
80
|
+
* view: SelectFacet,
|
|
81
|
+
* isDefault: true,
|
|
82
|
+
* },
|
|
83
|
+
* {
|
|
84
|
+
* id: 'checkboxFacet',
|
|
85
|
+
* title: 'Checkbox',
|
|
86
|
+
* view: CheckboxFacet,
|
|
87
|
+
* isDefault: false,
|
|
88
|
+
* },
|
|
89
|
+
* ]
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
62
95
|
export const withBlockSchemaEnhancer = (
|
|
63
96
|
FormComponent,
|
|
64
97
|
extensionName = 'vendor',
|
|
@@ -111,6 +144,36 @@ export const withBlockSchemaEnhancer = (
|
|
|
111
144
|
return <FormComponent {...props} schema={schema} />;
|
|
112
145
|
};
|
|
113
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Apply block variation schema enhancers to the provided schema, using block
|
|
149
|
+
* information from the provided block data (as `formData`).
|
|
150
|
+
*
|
|
151
|
+
* Blocks can be enhanced with variations declared like:
|
|
152
|
+
*
|
|
153
|
+
* ```
|
|
154
|
+
* {
|
|
155
|
+
* id: 'searchBlock',
|
|
156
|
+
* schemaEnhancer: ({schema, formData, intl}) => schema,
|
|
157
|
+
* variations: [
|
|
158
|
+
* {
|
|
159
|
+
* id: 'facetsRightSide',
|
|
160
|
+
* title: 'Facets on right side',
|
|
161
|
+
* view: RightColumnFacets,
|
|
162
|
+
* isDefault: true,
|
|
163
|
+
* },
|
|
164
|
+
* {
|
|
165
|
+
* id: 'facetsLeftSide',
|
|
166
|
+
* title: 'Facets on left side',
|
|
167
|
+
* view: LeftColumnFacets,
|
|
168
|
+
* isDefault: false,
|
|
169
|
+
* schemaEnhancer: ({schema, formData, intl}) => schema,
|
|
170
|
+
* },
|
|
171
|
+
* ],
|
|
172
|
+
*
|
|
173
|
+
* ```
|
|
174
|
+
* Notice that each variation can declare an option schema enhancer, and each
|
|
175
|
+
* block supports an optional `schemaEnhancer` function.
|
|
176
|
+
*/
|
|
114
177
|
export const applySchemaEnhancer = ({
|
|
115
178
|
schema: originalSchema,
|
|
116
179
|
formData,
|
|
@@ -123,11 +186,15 @@ export const applySchemaEnhancer = ({
|
|
|
123
186
|
const variations = blocks?.blocksConfig[blockType]?.variations || [];
|
|
124
187
|
|
|
125
188
|
if (variations.length === 0) {
|
|
126
|
-
// No variations present but
|
|
127
|
-
//
|
|
189
|
+
// No variations present but we finalize the schema with a schemaEnhancer
|
|
190
|
+
// in the block config (if present)
|
|
128
191
|
schemaEnhancer = blocks.blocksConfig?.[blockType]?.schemaEnhancer;
|
|
129
192
|
if (schemaEnhancer)
|
|
130
|
-
schema = schemaEnhancer({
|
|
193
|
+
schema = schemaEnhancer({
|
|
194
|
+
schema: cloneDeep(originalSchema),
|
|
195
|
+
formData,
|
|
196
|
+
intl,
|
|
197
|
+
});
|
|
131
198
|
return schema || originalSchema;
|
|
132
199
|
}
|
|
133
200
|
|
|
@@ -148,6 +215,13 @@ export const applySchemaEnhancer = ({
|
|
|
148
215
|
return schema || originalSchema;
|
|
149
216
|
};
|
|
150
217
|
|
|
218
|
+
/**
|
|
219
|
+
* A HOC that enhances the incoming schema prop with block variations support
|
|
220
|
+
* by:
|
|
221
|
+
*
|
|
222
|
+
* - applies the selected variation's schema enhancer
|
|
223
|
+
* - adds the variation selection input (as a choice widget)
|
|
224
|
+
*/
|
|
151
225
|
export const withVariationSchemaEnhancer = (FormComponent) => (props) => {
|
|
152
226
|
const { formData, schema: originalSchema } = props;
|
|
153
227
|
const intl = useIntl();
|
package/src/helpers/index.js
CHANGED
|
@@ -50,6 +50,7 @@ export {
|
|
|
50
50
|
nextBlockId,
|
|
51
51
|
previousBlockId,
|
|
52
52
|
applyBlockDefaults,
|
|
53
|
+
applySchemaDefaults,
|
|
53
54
|
} from '@plone/volto/helpers/Blocks/Blocks';
|
|
54
55
|
export BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
|
|
55
56
|
export ScrollToTop from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
|