@plone/volto 18.10.1 → 18.11.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 (110) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +3 -3
  3. package/locales/ca/LC_MESSAGES/volto.po +46 -0
  4. package/locales/ca.json +1 -1
  5. package/locales/de/LC_MESSAGES/volto.po +46 -0
  6. package/locales/de.json +1 -1
  7. package/locales/en/LC_MESSAGES/volto.po +46 -0
  8. package/locales/en.json +1 -1
  9. package/locales/es/LC_MESSAGES/volto.po +46 -0
  10. package/locales/es.json +1 -1
  11. package/locales/eu/LC_MESSAGES/volto.po +46 -0
  12. package/locales/eu.json +1 -1
  13. package/locales/fi/LC_MESSAGES/volto.po +46 -0
  14. package/locales/fi.json +1 -1
  15. package/locales/fr/LC_MESSAGES/volto.po +46 -0
  16. package/locales/fr.json +1 -1
  17. package/locales/hi/LC_MESSAGES/volto.po +46 -0
  18. package/locales/hi.json +1 -1
  19. package/locales/it/LC_MESSAGES/volto.po +46 -0
  20. package/locales/it.json +1 -1
  21. package/locales/ja/LC_MESSAGES/volto.po +46 -0
  22. package/locales/ja.json +1 -1
  23. package/locales/nl/LC_MESSAGES/volto.po +46 -0
  24. package/locales/nl.json +1 -1
  25. package/locales/pt/LC_MESSAGES/volto.po +46 -0
  26. package/locales/pt.json +1 -1
  27. package/locales/pt_BR/LC_MESSAGES/volto.po +47 -1
  28. package/locales/pt_BR.json +1 -1
  29. package/locales/ro/LC_MESSAGES/volto.po +46 -0
  30. package/locales/ro.json +1 -1
  31. package/locales/ru/LC_MESSAGES/volto.po +5243 -0
  32. package/locales/ru.json +1 -0
  33. package/locales/volto.pot +47 -1
  34. package/locales/zh_CN/LC_MESSAGES/volto.po +46 -0
  35. package/locales/zh_CN.json +1 -1
  36. package/package.json +4 -4
  37. package/razzle.config.js +1 -1
  38. package/src/components/index.js +2 -0
  39. package/src/components/manage/Blocks/Block/BlocksForm.jsx +5 -1
  40. package/src/components/manage/Blocks/Search/components/SearchInput.jsx +11 -1
  41. package/src/components/manage/DragDropList/DragDropList.jsx +78 -33
  42. package/src/components/manage/Form/Field.jsx +38 -29
  43. package/src/components/manage/Form/Form.jsx +141 -69
  44. package/src/components/manage/Form/ModalForm.jsx +29 -0
  45. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +1 -1
  46. package/src/components/manage/Sidebar/ObjectBrowserNav.test.jsx +34 -13
  47. package/src/components/manage/Widgets/CheckboxGroupWidget.jsx +214 -0
  48. package/src/components/manage/Widgets/CheckboxGroupWidget.stories.jsx +39 -0
  49. package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +45 -0
  50. package/src/components/manage/Widgets/FileWidget.jsx +43 -2
  51. package/src/components/manage/Widgets/HiddenWidget.jsx +114 -0
  52. package/src/components/manage/Widgets/HiddenWidget.stories.jsx +20 -0
  53. package/src/components/manage/Widgets/HiddenWidget.test.jsx +32 -0
  54. package/src/components/manage/Widgets/ImageWidget.jsx +3 -0
  55. package/src/components/manage/Widgets/RadioGroupWidget.jsx +207 -0
  56. package/src/components/manage/Widgets/RadioGroupWidget.stories.jsx +39 -0
  57. package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +46 -0
  58. package/src/components/manage/Widgets/SchemaWidget.jsx +806 -320
  59. package/src/components/manage/Widgets/SelectWidget.jsx +38 -2
  60. package/src/components/manage/Widgets/StaticTextWidget.jsx +34 -0
  61. package/src/components/manage/Widgets/StaticTextWidget.stories.jsx +20 -0
  62. package/src/components/manage/Widgets/StaticTextWidget.test.jsx +25 -0
  63. package/src/components/manage/Widgets/TimeWidget.jsx +96 -0
  64. package/src/components/manage/Widgets/TimeWidget.stories.jsx +22 -0
  65. package/src/components/manage/Widgets/TimeWidget.test.jsx +35 -0
  66. package/src/components/manage/Widgets/index.tsx +35 -0
  67. package/src/components/theme/ContactForm/ContactForm.jsx +7 -4
  68. package/src/components/theme/Widgets/HiddenWidget.jsx +2 -0
  69. package/src/components/theme/Widgets/HiddenWidget.stories.jsx +25 -0
  70. package/src/components/theme/Widgets/HiddenWidget.test.jsx +11 -0
  71. package/src/components/theme/Widgets/StaticTextWidget.jsx +16 -0
  72. package/src/components/theme/Widgets/StaticTextWidget.stories.jsx +29 -0
  73. package/src/components/theme/Widgets/StaticTextWidget.test.jsx +32 -0
  74. package/src/config/Blocks.jsx +2 -0
  75. package/src/config/Widgets.jsx +14 -0
  76. package/src/constants/Languages.cjs +1 -0
  77. package/src/helpers/FormValidation/FormValidation.jsx +4 -0
  78. package/src/helpers/FormValidation/FormValidation.test.js +147 -31
  79. package/src/helpers/FormValidation/validators.ts +4 -1
  80. package/src/helpers/Utils/Utils.jsx +14 -2
  81. package/theme/themes/pastanaga/collections/form.overrides +4 -0
  82. package/theme/themes/pastanaga/elements/input.overrides +7 -0
  83. package/theme/themes/pastanaga/extras/sidebar.less +2 -0
  84. package/types/components/index.d.ts +1 -1
  85. package/types/components/manage/Widgets/CheckboxGroupWidget.d.ts +6 -0
  86. package/types/components/manage/Widgets/CheckboxGroupWidget.stories.d.ts +15 -0
  87. package/types/components/manage/Widgets/CheckboxGroupWidget.test.d.ts +1 -0
  88. package/types/components/manage/Widgets/HiddenWidget.d.ts +54 -0
  89. package/types/components/manage/Widgets/HiddenWidget.stories.d.ts +9 -0
  90. package/types/components/manage/Widgets/HiddenWidget.test.d.ts +1 -0
  91. package/types/components/manage/Widgets/RadioGroupWidget.d.ts +6 -0
  92. package/types/components/manage/Widgets/RadioGroupWidget.stories.d.ts +15 -0
  93. package/types/components/manage/Widgets/RadioGroupWidget.test.d.ts +1 -0
  94. package/types/components/manage/Widgets/StaticTextWidget.d.ts +18 -0
  95. package/types/components/manage/Widgets/StaticTextWidget.stories.d.ts +9 -0
  96. package/types/components/manage/Widgets/StaticTextWidget.test.d.ts +1 -0
  97. package/types/components/manage/Widgets/TimeWidget.d.ts +2 -0
  98. package/types/components/manage/Widgets/TimeWidget.stories.d.ts +8 -0
  99. package/types/components/manage/Widgets/TimeWidget.test.d.ts +1 -0
  100. package/types/components/manage/Widgets/index.d.ts +5 -0
  101. package/types/components/theme/Widgets/HiddenWidget.d.ts +6 -0
  102. package/types/components/theme/Widgets/HiddenWidget.stories.d.ts +8 -0
  103. package/types/components/theme/Widgets/HiddenWidget.test.d.ts +1 -0
  104. package/types/components/theme/Widgets/StaticTextWidget.d.ts +5 -0
  105. package/types/components/theme/Widgets/StaticTextWidget.stories.d.ts +8 -0
  106. package/types/components/theme/Widgets/StaticTextWidget.test.d.ts +1 -0
  107. package/types/config/Widgets.d.ts +14 -0
  108. package/types/constants/Languages.d.cts +1 -0
  109. package/types/helpers/FormValidation/validators.d.ts +1 -1
  110. package/types/helpers/Utils/Utils.d.ts +1 -1
@@ -8,17 +8,21 @@ import { connect } from 'react-redux';
8
8
  import { compose } from 'redux';
9
9
  import PropTypes from 'prop-types';
10
10
  import concat from 'lodash/concat';
11
+ import find from 'lodash/find';
11
12
  import findIndex from 'lodash/findIndex';
13
+ import isArray from 'lodash/isArray';
12
14
  import isString from 'lodash/isString';
13
- import map from 'lodash/map';
15
+ import keys from 'lodash/keys';
14
16
  import omit from 'lodash/omit';
15
17
  import slice from 'lodash/slice';
16
18
  import without from 'lodash/without';
17
19
  import move from 'lodash-move';
18
20
  import { Confirm, Form, Grid, Icon, Message, Segment } from 'semantic-ui-react';
19
21
  import { defineMessages, injectIntl } from 'react-intl';
22
+ import config from '@plone/volto/registry';
20
23
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
21
24
  import { slugify } from '@plone/volto/helpers/Utils/Utils';
25
+ import { getVocabulary } from '@plone/volto/actions/vocabularies/vocabularies';
22
26
 
23
27
  import SchemaWidgetFieldset from '@plone/volto/components/manage/Widgets/SchemaWidgetFieldset';
24
28
  import { Field, ModalForm } from '@plone/volto/components/manage/Form';
@@ -52,6 +56,14 @@ const messages = defineMessages({
52
56
  id: 'Default',
53
57
  defaultMessage: 'Default',
54
58
  },
59
+ defaultValue: {
60
+ id: 'Default value',
61
+ defaultMessage: 'Default value',
62
+ },
63
+ placeholder: {
64
+ id: 'Placeholder',
65
+ defaultMessage: 'Placeholder',
66
+ },
55
67
  idTitle: {
56
68
  id: 'Short Name',
57
69
  defaultMessage: 'Short Name',
@@ -96,6 +108,15 @@ const messages = defineMessages({
96
108
  id: 'Description',
97
109
  defaultMessage: 'Description',
98
110
  },
111
+ queryParameterName: {
112
+ id: 'Query Parameter Name',
113
+ defaultMessage: 'Query Parameter Name',
114
+ },
115
+ queryParameterNameDescription: {
116
+ id: 'Fills the value of the form field with the value supplied by a query parameter inside the URL with the given name.',
117
+ defaultMessage:
118
+ 'Fills the value of the form field with the value supplied by a query parameter inside the URL with the given name.',
119
+ },
99
120
  required: {
100
121
  id: 'Required',
101
122
  defaultMessage: 'Required',
@@ -116,6 +137,14 @@ const messages = defineMessages({
116
137
  id: 'maximum',
117
138
  defaultMessage: 'End of the range (including the value itself)',
118
139
  },
140
+ size: {
141
+ id: 'size',
142
+ defaultMessage: 'Maximum size of the file in bytes',
143
+ },
144
+ accept: {
145
+ id: 'accept',
146
+ defaultMessage: 'File types allowed',
147
+ },
119
148
  deleteFieldset: {
120
149
  id: 'Are you sure you want to delete this fieldset including all fields?',
121
150
  defaultMessage:
@@ -142,160 +171,607 @@ const makeFieldsetList = (listOfFieldsets, intl) => {
142
171
  return result;
143
172
  };
144
173
 
145
- /**
146
- * schemaField used for modal form, when editing a field
147
- * - based on the factory a set of fields is presented
148
- * - fields can be moved to another fieldset
149
- * @param {string} factory - the kind of field
150
- * @param {Object} intl
151
- * @param {*} fieldsets
152
- * @return {Object} - schema
153
- */
154
- const schemaField = (factory, intl, fieldsets) => ({
155
- fieldsets: [
156
- {
157
- id: 'default',
158
- title: 'default',
159
- fields: [
160
- ...['title', 'description', 'parentFieldSet'],
161
- ...((factory) => {
162
- switch (factory) {
163
- case 'Rich Text':
164
- return ['maxLength'];
165
- case 'URL':
166
- case 'Password':
167
- case 'label_password_field':
168
- case 'Email':
169
- case 'label_email':
170
- return ['minLength', 'maxLength'];
171
- case 'Integer':
172
- case 'label_integer_field':
173
- return ['minimum', 'maximum'];
174
- case 'Floating-point number':
175
- case 'label_float_field':
176
- case 'Date/Time':
177
- case 'label_datetime_field':
178
- case 'Date':
179
- case 'label_date_field':
180
- case 'File':
181
- case 'File Upload':
182
- case 'Image':
183
- case 'Yes/No':
184
- case 'label_boolean_field':
185
- case 'JSONField':
186
- case 'Relation Choice':
187
- case 'Relation List':
188
- return [];
189
- case 'Multiple Choice':
190
- case 'label_multi_choice_field':
191
- case 'Choice':
192
- case 'label_choice_field':
193
- return ['values'];
194
- default:
195
- return ['minLength', 'maxLength'];
196
- }
197
- })(factory),
198
- ...['required'],
199
- ],
174
+ // Register field factory properties utilities
175
+
176
+ config.registerUtility({
177
+ name: 'Rich Text',
178
+ type: 'fieldFactoryProperties',
179
+ method: (intl) => ({
180
+ maxLength: {
181
+ type: 'integer',
182
+ title: intl.formatMessage(messages.maxLength),
200
183
  },
201
- ],
202
- properties: {
203
- title: {
184
+ default: {
185
+ title: intl.formatMessage(messages.defaultValue),
186
+ widget: 'richtext',
204
187
  type: 'string',
205
- title: intl.formatMessage(messages.title),
206
188
  },
207
- description: {
189
+ }),
190
+ });
191
+
192
+ ['URL', 'Password', 'label_password_field', 'Email', 'label_email'].forEach(
193
+ (factory) => {
194
+ config.registerUtility({
195
+ name: factory,
196
+ type: 'fieldFactoryProperties',
197
+ method: (intl) => ({
198
+ minLength: {
199
+ type: 'integer',
200
+ title: intl.formatMessage(messages.minLength),
201
+ },
202
+ maxLength: {
203
+ type: 'integer',
204
+ title: intl.formatMessage(messages.maxLength),
205
+ },
206
+ default: {
207
+ type: 'string',
208
+ title: intl.formatMessage(messages.defaultValue),
209
+ },
210
+ }),
211
+ });
212
+ },
213
+ );
214
+
215
+ ['Integer', 'label_integer_field'].forEach((factory) => {
216
+ config.registerUtility({
217
+ name: factory,
218
+ type: 'fieldFactoryProperties',
219
+ method: (intl) => ({
220
+ minimum: {
221
+ type: 'integer',
222
+ title: intl.formatMessage(messages.minimum),
223
+ },
224
+ maximum: {
225
+ type: 'integer',
226
+ title: intl.formatMessage(messages.maximum),
227
+ },
228
+ default: {
229
+ type: 'integer',
230
+ title: intl.formatMessage(messages.default),
231
+ },
232
+ }),
233
+ });
234
+ });
235
+
236
+ [
237
+ 'Floating-point number',
238
+ 'label_float_field',
239
+ 'JSONField',
240
+ 'Relation Choice',
241
+ 'Relation List',
242
+ ].forEach((factory) => {
243
+ config.registerUtility({
244
+ name: factory,
245
+ type: 'fieldFactoryProperties',
246
+ method: (intl) => ({}),
247
+ });
248
+ });
249
+
250
+ ['Yes/No', 'label_boolean_field'].forEach((factory) => {
251
+ config.registerUtility({
252
+ name: factory,
253
+ type: 'fieldFactoryProperties',
254
+ method: (intl) => ({
255
+ default: {
256
+ type: 'string',
257
+ title: intl.formatMessage(messages.defaultValue),
258
+ },
259
+ }),
260
+ });
261
+ });
262
+
263
+ ['Date/Time', 'label_datetime_field'].forEach((factory) => {
264
+ config.registerUtility({
265
+ name: factory,
266
+ type: 'fieldFactoryProperties',
267
+ method: (intl) => ({
268
+ default: {
269
+ type: 'string',
270
+ widget: 'datetime',
271
+ title: intl.formatMessage(messages.defaultValue),
272
+ },
273
+ }),
274
+ });
275
+ });
276
+
277
+ ['Date', 'label_date_field'].forEach((factory) => {
278
+ config.registerUtility({
279
+ name: factory,
280
+ type: 'fieldFactoryProperties',
281
+ method: (intl) => ({
282
+ default: {
283
+ type: 'string',
284
+ widget: 'date',
285
+ title: intl.formatMessage(messages.defaultValue),
286
+ },
287
+ }),
288
+ });
289
+ });
290
+
291
+ ['time'].forEach((factory) => {
292
+ config.registerUtility({
293
+ name: factory,
294
+ type: 'fieldFactoryProperties',
295
+ method: (intl) => ({
296
+ default: {
297
+ type: 'string',
298
+ widget: 'time',
299
+ title: intl.formatMessage(messages.defaultValue),
300
+ },
301
+ }),
302
+ });
303
+ });
304
+
305
+ ['File', 'File Upload', 'Image'].forEach((factory) => {
306
+ config.registerUtility({
307
+ name: factory,
308
+ type: 'fieldFactoryProperties',
309
+ method: (intl) => ({
310
+ size: {
311
+ type: 'integer',
312
+ title: intl.formatMessage(messages.size),
313
+ },
314
+ accept: {
315
+ type: 'string',
316
+ title: intl.formatMessage(messages.accept),
317
+ },
318
+ }),
319
+ });
320
+ });
321
+
322
+ ['Multiple Choice', 'label_multi_choice_field', 'checkbox_group'].forEach(
323
+ (factory) => {
324
+ config.registerUtility({
325
+ name: factory,
326
+ type: 'fieldFactoryProperties',
327
+ method: (intl) => ({
328
+ values: {
329
+ type: 'string',
330
+ title: intl.formatMessage(messages.choices),
331
+ widget: 'textarea',
332
+ },
333
+ default: {
334
+ type: 'string',
335
+ widget: 'textarea',
336
+ title: intl.formatMessage(messages.defaultValue),
337
+ },
338
+ }),
339
+ });
340
+ },
341
+ );
342
+
343
+ ['Choice', 'label_choice_field', 'radio_group'].forEach((factory) => {
344
+ config.registerUtility({
345
+ name: factory,
346
+ type: 'fieldFactoryProperties',
347
+ method: (intl) => ({
348
+ values: {
349
+ type: 'string',
350
+ title: intl.formatMessage(messages.choices),
351
+ widget: 'textarea',
352
+ },
353
+ default: {
354
+ type: 'string',
355
+ title: intl.formatMessage(messages.defaultValue),
356
+ },
357
+ }),
358
+ });
359
+ });
360
+
361
+ config.registerUtility({
362
+ name: 'static_text',
363
+ type: 'fieldFactoryProperties',
364
+ method: (intl) => ({
365
+ default: {
366
+ title: intl.formatMessage(messages.text),
367
+ widget: 'richtext',
368
+ type: 'string',
369
+ },
370
+ }),
371
+ });
372
+
373
+ config.registerUtility({
374
+ name: 'number',
375
+ type: 'fieldFactoryProperties',
376
+ method: (intl) => ({
377
+ default: {
378
+ type: 'number',
379
+ title: intl.formatMessage(messages.defaultValue),
380
+ },
381
+ }),
382
+ });
383
+
384
+ config.registerUtility({
385
+ name: 'hidden',
386
+ type: 'fieldFactoryProperties',
387
+ method: (intl) => ({
388
+ default: {
389
+ type: 'string',
390
+ title: intl.formatMessage(messages.defaultValue),
391
+ },
392
+ }),
393
+ });
394
+
395
+ config.registerUtility({
396
+ name: 'textarea',
397
+ type: 'fieldFactoryProperties',
398
+ method: (intl) => ({
399
+ minLength: {
400
+ type: 'integer',
401
+ title: intl.formatMessage(messages.minLength),
402
+ },
403
+ maxLength: {
404
+ type: 'integer',
405
+ title: intl.formatMessage(messages.maxLength),
406
+ },
407
+ default: {
208
408
  type: 'string',
209
409
  widget: 'textarea',
210
- title: intl.formatMessage(messages.description),
410
+ title: intl.formatMessage(messages.defaultValue),
211
411
  },
212
- parentFieldSet: {
412
+ placeholder: {
213
413
  type: 'string',
214
- title: intl.formatMessage(messages.parentFieldSet),
215
- choices: makeFieldsetList(fieldsets),
414
+ title: intl.formatMessage(messages.placeholder),
216
415
  },
217
- required: {
416
+ }),
417
+ });
418
+
419
+ // Register field factory initial data utilities
420
+
421
+ ['Date/Time', 'label_datetime_field'].forEach((factory) => {
422
+ config.registerUtility({
423
+ name: factory,
424
+ type: 'fieldFactoryInitialData',
425
+ method: (intl) => ({
426
+ type: 'string',
427
+ widget: 'datetime',
428
+ factory,
429
+ }),
430
+ });
431
+ });
432
+
433
+ ['Date', 'label_date_field'].forEach((factory) => {
434
+ config.registerUtility({
435
+ name: factory,
436
+ type: 'fieldFactoryInitialData',
437
+ method: (intl) => ({
438
+ type: 'string',
439
+ widget: 'date',
440
+ factory,
441
+ }),
442
+ });
443
+ });
444
+
445
+ config.registerUtility({
446
+ name: 'time',
447
+ type: 'fieldFactoryInitialData',
448
+ method: (intl) => ({
449
+ type: 'string',
450
+ widget: 'time',
451
+ factory: 'time',
452
+ }),
453
+ });
454
+
455
+ ['Email', 'label_email'].forEach((factory) => {
456
+ config.registerUtility({
457
+ name: factory,
458
+ type: 'fieldFactoryInitialData',
459
+ method: (intl) => ({
460
+ type: 'string',
461
+ widget: 'email',
462
+ id: 'email',
463
+ factory,
464
+ }),
465
+ });
466
+ });
467
+
468
+ ['File', 'File Upload'].forEach((factory) => {
469
+ config.registerUtility({
470
+ name: factory,
471
+ type: 'fieldFactoryInitialData',
472
+ method: (intl) => ({
473
+ type: 'object',
474
+ factory,
475
+ }),
476
+ });
477
+ });
478
+
479
+ ['Floating-point number', 'label_float_field'].forEach((factory) => {
480
+ config.registerUtility({
481
+ name: factory,
482
+ type: 'fieldFactoryInitialData',
483
+ method: (intl) => ({
484
+ type: 'number',
485
+ factory,
486
+ }),
487
+ });
488
+ });
489
+
490
+ ['Integer', 'label_integer_field'].forEach((factory) => {
491
+ config.registerUtility({
492
+ name: factory,
493
+ type: 'fieldFactoryInitialData',
494
+ method: (intl) => ({
495
+ type: 'integer',
496
+ factory,
497
+ }),
498
+ });
499
+ });
500
+
501
+ config.registerUtility({
502
+ name: 'Image',
503
+ type: 'fieldFactoryInitialData',
504
+ method: (intl) => ({
505
+ type: 'object',
506
+ factory: 'Image',
507
+ }),
508
+ });
509
+
510
+ config.registerUtility({
511
+ name: 'JSONField',
512
+ type: 'fieldFactoryInitialData',
513
+ method: (intl) => ({
514
+ type: 'dict',
515
+ widget: 'json',
516
+ factory: 'JSONField',
517
+ }),
518
+ });
519
+
520
+ ['Multiple Choice', 'label_multi_choice_field'].forEach((factory) => {
521
+ config.registerUtility({
522
+ name: factory,
523
+ type: 'fieldFactoryInitialData',
524
+ method: (intl) => ({
525
+ type: 'array',
526
+ factory,
527
+ }),
528
+ });
529
+ });
530
+
531
+ config.registerUtility({
532
+ name: 'Relation List',
533
+ type: 'fieldFactoryInitialData',
534
+ method: (intl) => ({
535
+ type: 'array',
536
+ factory: 'Relation List',
537
+ }),
538
+ });
539
+
540
+ ['Choice', 'label_choice_field'].forEach((factory) => {
541
+ config.registerUtility({
542
+ name: factory,
543
+ type: 'fieldFactoryInitialData',
544
+ method: (intl) => ({
545
+ type: 'string',
546
+ choices: [],
547
+ factory,
548
+ }),
549
+ });
550
+ });
551
+
552
+ config.registerUtility({
553
+ name: 'Relation Choice',
554
+ type: 'fieldFactoryInitialData',
555
+ method: (intl) => ({
556
+ type: 'string',
557
+ factory: 'Relation Choice',
558
+ }),
559
+ });
560
+
561
+ ['Password', 'label_password_field'].forEach((factory) => {
562
+ config.registerUtility({
563
+ name: factory,
564
+ type: 'fieldFactoryInitialData',
565
+ method: (intl) => ({
566
+ type: 'string',
567
+ widget: 'password',
568
+ factory,
569
+ }),
570
+ });
571
+ });
572
+
573
+ config.registerUtility({
574
+ name: 'Rich Text',
575
+ type: 'fieldFactoryInitialData',
576
+ method: (intl) => ({
577
+ type: 'string',
578
+ widget: 'richtext',
579
+ factory: 'Rich Text',
580
+ }),
581
+ });
582
+
583
+ config.registerUtility({
584
+ name: 'URL',
585
+ type: 'fieldFactoryInitialData',
586
+ method: (intl) => ({
587
+ type: 'string',
588
+ widget: 'url',
589
+ factory: 'URL',
590
+ }),
591
+ });
592
+
593
+ ['Yes/No', 'label_boolean_field'].forEach((factory) => {
594
+ config.registerUtility({
595
+ name: factory,
596
+ type: 'fieldFactoryInitialData',
597
+ method: (intl) => ({
218
598
  type: 'boolean',
219
- title: intl.formatMessage(messages.required),
220
- },
221
- ...((factory) => {
222
- switch (factory) {
223
- case 'Rich Text':
224
- return {
225
- maxLength: {
226
- type: 'integer',
227
- title: intl.formatMessage(messages.maxLength),
228
- },
229
- };
230
- case 'URL':
231
- case 'Password':
232
- case 'label_password_field':
233
- case 'Email':
234
- case 'label_email':
235
- return {
236
- minLength: {
237
- type: 'integer',
238
- title: intl.formatMessage(messages.minLength),
239
- },
240
- maxLength: {
241
- type: 'integer',
242
- title: intl.formatMessage(messages.maxLength),
243
- },
244
- };
245
- case 'Integer':
246
- case 'label_integer_field':
247
- return {
248
- minimum: {
249
- type: 'integer',
250
- title: intl.formatMessage(messages.minimum),
251
- },
252
- maximum: {
253
- type: 'integer',
254
- title: intl.formatMessage(messages.maximum),
255
- },
256
- };
257
- case 'Floating-point number':
258
- case 'label_float_field':
259
- case 'Date/Time':
260
- case 'label_datetime_field':
261
- case 'Date':
262
- case 'label_date_field':
263
- case 'File':
264
- case 'File Upload':
265
- case 'Image':
266
- case 'Yes/No':
267
- case 'label_boolean_field':
268
- case 'JSONField':
269
- case 'Relation Choice':
270
- case 'Relation List':
271
- return {};
272
- case 'Multiple Choice':
273
- case 'label_multi_choice_field':
274
- case 'Choice':
275
- case 'label_choice_field':
276
- return {
277
- values: {
599
+ factory,
600
+ }),
601
+ });
602
+ });
603
+
604
+ config.registerUtility({
605
+ name: 'static_text',
606
+ type: 'fieldFactoryInitialData',
607
+ method: (intl) => ({
608
+ type: 'object',
609
+ widget: 'static_text',
610
+ factory: 'static_text',
611
+ }),
612
+ });
613
+
614
+ config.registerUtility({
615
+ name: 'hidden',
616
+ type: 'fieldFactoryInitialData',
617
+ method: (intl) => ({
618
+ type: 'string',
619
+ widget: 'hidden',
620
+ factory: 'hidden',
621
+ }),
622
+ });
623
+
624
+ config.registerUtility({
625
+ name: 'number',
626
+ type: 'fieldFactoryInitialData',
627
+ method: (intl) => ({
628
+ type: 'number',
629
+ factory: 'number',
630
+ }),
631
+ });
632
+
633
+ config.registerUtility({
634
+ name: 'radio_group',
635
+ type: 'fieldFactoryInitialData',
636
+ method: (intl) => ({
637
+ type: 'string',
638
+ choices: [],
639
+ widget: 'radio_group',
640
+ factory: 'radio_group',
641
+ }),
642
+ });
643
+
644
+ config.registerUtility({
645
+ name: 'checkbox_group',
646
+ type: 'fieldFactoryInitialData',
647
+ method: (intl) => ({
648
+ type: 'array',
649
+ widget: 'checkbox_group',
650
+ factory: 'checkbox_group',
651
+ }),
652
+ });
653
+
654
+ config.registerUtility({
655
+ name: 'textarea',
656
+ type: 'fieldFactoryInitialData',
657
+ method: (intl) => ({
658
+ type: 'string',
659
+ widget: 'textarea',
660
+ factory: 'textarea',
661
+ }),
662
+ });
663
+
664
+ /**
665
+ * schemaField used for modal form, when editing a field
666
+ * - based on the factory a set of fields is presented
667
+ * - fields can be moved to another fieldset
668
+ * @param {string} factory - the kind of field
669
+ * @param {Object} intl
670
+ * @param {*} fieldsets
671
+ * @param {Boolean} allowEditId
672
+ * @param {Boolean} allowEditQueryParameter
673
+ * @param {Boolean} allowEditPlaceholder
674
+ * @param {Object} extraFields
675
+ * @return {Object} - schema
676
+ */
677
+ const schemaField = (
678
+ factory,
679
+ intl,
680
+ fieldsets,
681
+ allowEditId,
682
+ allowEditQueryParameter,
683
+ allowEditPlaceholder,
684
+ extraFields = {},
685
+ ) => {
686
+ const utility = config.getUtility({
687
+ name: factory,
688
+ type: 'fieldFactoryProperties',
689
+ });
690
+
691
+ const properties = utility.method
692
+ ? utility.method(intl)
693
+ : {
694
+ minLength: {
695
+ type: 'integer',
696
+ title: intl.formatMessage(messages.minLength),
697
+ },
698
+ maxLength: {
699
+ type: 'integer',
700
+ title: intl.formatMessage(messages.maxLength),
701
+ },
702
+ default: {
703
+ type: 'string',
704
+ title: intl.formatMessage(messages.defaultValue),
705
+ },
706
+ ...(allowEditPlaceholder
707
+ ? {
708
+ placeholder: {
709
+ type: 'string',
710
+ title: intl.formatMessage(messages.placeholder),
711
+ },
712
+ }
713
+ : {}),
714
+ };
715
+
716
+ return {
717
+ fieldsets: [
718
+ {
719
+ id: 'default',
720
+ title: 'default',
721
+ fields: [
722
+ ...keys(extraFields),
723
+ ...(allowEditId ? ['id'] : []),
724
+ ...['title', 'description', 'parentFieldSet'],
725
+ ...(allowEditQueryParameter ? ['queryParameterName'] : []),
726
+ ...keys(properties),
727
+ ...['required'],
728
+ ],
729
+ },
730
+ ],
731
+ properties: {
732
+ ...extraFields,
733
+ ...(allowEditId
734
+ ? {
735
+ id: {
278
736
  type: 'string',
279
- title: intl.formatMessage(messages.choices),
280
- widget: 'textarea',
737
+ title: intl.formatMessage(messages.idTitle),
281
738
  },
282
- };
283
- default:
284
- return {
285
- minLength: {
286
- type: 'integer',
287
- title: intl.formatMessage(messages.minLength),
288
- },
289
- maxLength: {
290
- type: 'integer',
291
- title: intl.formatMessage(messages.maxLength),
739
+ }
740
+ : {}),
741
+ title: {
742
+ type: 'string',
743
+ title: intl.formatMessage(messages.title),
744
+ },
745
+ description: {
746
+ type: 'string',
747
+ widget: 'textarea',
748
+ title: intl.formatMessage(messages.description),
749
+ },
750
+ parentFieldSet: {
751
+ type: 'string',
752
+ title: intl.formatMessage(messages.parentFieldSet),
753
+ choices: makeFieldsetList(fieldsets),
754
+ },
755
+ ...(allowEditQueryParameter
756
+ ? {
757
+ queryParameterName: {
758
+ type: 'string',
759
+ title: intl.formatMessage(messages.queryParameterName),
760
+ description: intl.formatMessage(
761
+ messages.queryParameterNameDescription,
762
+ ),
292
763
  },
293
- };
294
- }
295
- })(factory),
296
- },
297
- required: ['type', 'title'],
298
- });
764
+ }
765
+ : {}),
766
+ required: {
767
+ type: 'boolean',
768
+ title: intl.formatMessage(messages.required),
769
+ },
770
+ ...properties,
771
+ },
772
+ required: ['type', 'title'],
773
+ };
774
+ };
299
775
 
300
776
  /**
301
777
  * schema for adding a new field
@@ -427,13 +903,34 @@ class SchemaWidget extends Component {
427
903
  * List of error messages
428
904
  */
429
905
  error: PropTypes.arrayOf(PropTypes.string),
906
+ /**
907
+ * Filter for factory choices
908
+ */
909
+ filterFactory: PropTypes.arrayOf(PropTypes.string),
910
+ /**
911
+ * Additional factories
912
+ */
913
+ additionalFactory: PropTypes.arrayOf(PropTypes.object),
914
+ /**
915
+ * Allow editing of the id
916
+ */
917
+ allowEditId: PropTypes.bool,
918
+ /**
919
+ * Allow editing of the query parameter
920
+ */
921
+ allowEditQueryParameter: PropTypes.bool,
922
+ /**
923
+ * Allow editing of the placeholder
924
+ */
925
+ allowEditPlaceholder: PropTypes.bool,
430
926
  /**
431
927
  * On change handler
432
928
  */
433
929
  onChange: PropTypes.func.isRequired,
434
930
  /**
435
- * Intl object
931
+ * Get vocabulary action
436
932
  */
933
+ getVocabulary: PropTypes.func.isRequired,
437
934
  };
438
935
 
439
936
  /**
@@ -445,6 +942,11 @@ class SchemaWidget extends Component {
445
942
  required: false,
446
943
  value: {},
447
944
  error: [],
945
+ filterFactory: null,
946
+ additionalFactory: null,
947
+ allowEditId: false,
948
+ allowEditQueryParameter: false,
949
+ allowEditPlaceholder: false,
448
950
  };
449
951
 
450
952
  /**
@@ -485,6 +987,19 @@ class SchemaWidget extends Component {
485
987
  };
486
988
  }
487
989
 
990
+ /**
991
+ * Component did mount
992
+ * @method componentDidMount
993
+ * @returns {undefined}
994
+ */
995
+ componentDidMount() {
996
+ this.props.getVocabulary({
997
+ vocabNameOrURL: 'Fields',
998
+ size: -1,
999
+ subrequest: 'schemawidget',
1000
+ });
1001
+ }
1002
+
488
1003
  /**
489
1004
  * Add field handler
490
1005
  * @method onAddField
@@ -492,7 +1007,10 @@ class SchemaWidget extends Component {
492
1007
  * @returns {undefined}
493
1008
  */
494
1009
  onAddField(values) {
495
- const fieldId = slugify(values.title);
1010
+ const fieldId = slugify(
1011
+ values.id || values.title,
1012
+ keys(this.props.value.properties),
1013
+ );
496
1014
  const currentFieldsetFields =
497
1015
  this.props.value.fieldsets[this.state.currentFieldset].fields;
498
1016
  const hasChangeNote = currentFieldsetFields.indexOf('changeNote') > -1;
@@ -504,6 +1022,22 @@ class SchemaWidget extends Component {
504
1022
  ]
505
1023
  : [...currentFieldsetFields, fieldId];
506
1024
 
1025
+ const utility = config.getUtility({
1026
+ name: values.factory,
1027
+ type: 'fieldFactoryInitialData',
1028
+ });
1029
+
1030
+ const multiple =
1031
+ values.factory === 'Multiple Choice' ||
1032
+ values.factory === 'label_multi_choice_field';
1033
+
1034
+ const initialData = utility.method
1035
+ ? omit(utility.method(this.props.intl), ['id'])
1036
+ : {
1037
+ type: 'string',
1038
+ factory: values.factory,
1039
+ };
1040
+
507
1041
  this.onChange({
508
1042
  ...this.props.value,
509
1043
  fieldsets: [
@@ -517,121 +1051,17 @@ class SchemaWidget extends Component {
517
1051
  properties: {
518
1052
  ...this.props.value.properties,
519
1053
  [fieldId]: {
520
- title: values.title,
521
- description: values.description,
522
1054
  id: fieldId,
523
- ...((factory) => {
524
- switch (factory) {
525
- case 'Date/Time':
526
- case 'label_datetime_field':
527
- return {
528
- type: 'string',
529
- widget: 'datetime',
530
- factory,
531
- };
532
- case 'Date':
533
- case 'label_date_field':
534
- return {
535
- type: 'string',
536
- widget: 'date',
537
- factory,
538
- };
539
- case 'Email':
540
- case 'label_email':
541
- return {
542
- type: 'string',
543
- widget: 'email',
544
- factory,
545
- };
546
- case 'File':
547
- case 'File Upload':
548
- return {
549
- type: 'object',
550
- factory,
551
- };
552
- case 'Floating-point number':
553
- case 'label_float_field':
554
- return {
555
- type: 'number',
556
- factory,
557
- };
558
- case 'Integer':
559
- case 'label_integer_field':
560
- return {
561
- type: 'integer',
562
- factory,
563
- };
564
- case 'Image':
565
- return {
566
- type: 'object',
567
- factory,
568
- };
569
- case 'JSONField':
570
- return {
571
- type: 'dict',
572
- widget: 'json',
573
- factory,
574
- };
575
- case 'Multiple Choice':
576
- case 'label_multi_choice_field':
577
- return {
578
- type: 'array',
579
- factory,
580
- };
581
- case 'Relation List':
582
- return {
583
- type: 'array',
584
- factory,
585
- };
586
- case 'Choice':
587
- case 'label_choice_field':
588
- return {
589
- type: 'string',
590
- choices: [],
591
- factory,
592
- };
593
- case 'Relation Choice':
594
- return {
595
- type: 'string',
596
- factory,
597
- };
598
- case 'Password':
599
- case 'label_password_field':
600
- return {
601
- type: 'string',
602
- widget: 'password',
603
- factory,
604
- };
605
- case 'Rich Text':
606
- return {
607
- type: 'string',
608
- widget: 'richtext',
609
- factory,
610
- };
611
- case 'URL':
612
- return {
613
- type: 'string',
614
- widget: 'url',
615
- factory,
616
- };
617
- case 'Yes/No':
618
- case 'label_boolean_field':
619
- return {
620
- type: 'boolean',
621
- factory,
622
- };
623
- default:
624
- return {
625
- type: 'string',
626
- factory,
627
- };
628
- }
629
- })(values.factory),
1055
+ ...omit(initialData, ['required']),
1056
+ ...omit(values, ['factory', 'required', 'id', 'parentFieldset']),
1057
+ ...formatTextareaToArray(values.values),
1058
+ ...formatTextareaToChoices(values.values, multiple),
630
1059
  },
631
1060
  },
632
- required: values.required
633
- ? [...this.props.value.required, fieldId]
634
- : this.props.value.required,
1061
+ required: [
1062
+ ...this.props.value.required,
1063
+ ...(values.required || initialData.required ? [fieldId] : []),
1064
+ ],
635
1065
  });
636
1066
  this.onCancel();
637
1067
  }
@@ -748,7 +1178,7 @@ class SchemaWidget extends Component {
748
1178
  ...slice(fieldsets, 0, currentFieldset),
749
1179
  {
750
1180
  ...fieldsets[currentFieldset],
751
- fields: map(fieldsets[currentFieldset].fields, (field) =>
1181
+ fields: fieldsets[currentFieldset].fields.map((field) =>
752
1182
  field === oldfieldId ? newfieldId : field,
753
1183
  ),
754
1184
  },
@@ -777,7 +1207,7 @@ class SchemaWidget extends Component {
777
1207
  listOfProp.forEach((prop) => {
778
1208
  formattedValues = {
779
1209
  ...formattedValues,
780
- ...{ [prop]: values[prop] ? parseFloat(values[prop]) : null },
1210
+ ...{ [prop]: values[prop] ? parseFloat(values[prop]) : undefined },
781
1211
  };
782
1212
  });
783
1213
 
@@ -786,22 +1216,42 @@ class SchemaWidget extends Component {
786
1216
  'Multiple Choice' ||
787
1217
  this.props.value.properties[this.state.editField.id]?.factory ===
788
1218
  'label_multi_choice_field';
1219
+
1220
+ let fieldsets = this.props.value.fieldsets;
1221
+
1222
+ if (this.state.editField.id !== formattedValues.id) {
1223
+ this.props.value.fieldsets[this.state.currentFieldset].fields =
1224
+ this.props.value.fieldsets[this.state.currentFieldset].fields.map(
1225
+ (field) =>
1226
+ field === this.state.editField.id ? formattedValues.id : field,
1227
+ );
1228
+ const index = isArray(this.props.value.required)
1229
+ ? this.props.value.required.indexOf(formattedValues.id)
1230
+ : -1;
1231
+
1232
+ if (index > -1) {
1233
+ this.props.value.required[index] = formattedValues.id;
1234
+ }
1235
+ }
1236
+
1237
+ if (formattedValues.parentFieldSet) {
1238
+ fieldsets = this.editFieldset(
1239
+ this.props.value.fieldsets,
1240
+ formattedValues.parentFieldSet,
1241
+ this.state.currentFieldset,
1242
+ this.state.editField.id,
1243
+ formattedValues.id,
1244
+ );
1245
+ }
1246
+
789
1247
  const result = {
790
1248
  ...this.props.value,
791
- fieldsets: formattedValues.parentFieldSet
792
- ? this.editFieldset(
793
- this.props.value.fieldsets,
794
- formattedValues.parentFieldSet,
795
- this.state.currentFieldset,
796
- this.state.editField.id,
797
- formattedValues.id,
798
- )
799
- : this.props.value.fieldsets,
1249
+ fieldsets,
800
1250
  properties: {
801
1251
  ...omit(this.props.value.properties, [this.state.editField.id]),
802
1252
  [formattedValues.id]: {
803
1253
  ...this.props.value.properties[this.state.editField.id],
804
- ...omit(formattedValues, ['id', 'parentFieldSet']),
1254
+ ...omit(formattedValues, ['parentFieldSet']),
805
1255
  ...formatTextareaToArray(formattedValues.values),
806
1256
  ...formatTextareaToChoices(formattedValues.values, multiple),
807
1257
  },
@@ -863,6 +1313,10 @@ class SchemaWidget extends Component {
863
1313
  ...slice(this.props.value.fieldsets, this.state.currentFieldset + 1),
864
1314
  ],
865
1315
  properties: omit(this.props.value.properties, [this.state.deleteField]),
1316
+ required: without(
1317
+ this.props.value.required || [],
1318
+ this.state.deleteField,
1319
+ ),
866
1320
  });
867
1321
  this.onCancel();
868
1322
  }
@@ -926,7 +1380,7 @@ class SchemaWidget extends Component {
926
1380
  */
927
1381
  onShowAddField(event) {
928
1382
  this.setState({
929
- addField: true,
1383
+ addField: '',
930
1384
  });
931
1385
  event.preventDefault();
932
1386
  }
@@ -1080,11 +1534,34 @@ class SchemaWidget extends Component {
1080
1534
  * @returns {string} Markup for the component.
1081
1535
  */
1082
1536
  render() {
1083
- const { error, reactBeautifulDnd } = this.props;
1537
+ const { additionalFactory, error, reactBeautifulDnd, filterFactory } =
1538
+ this.props;
1084
1539
  const { Draggable, DragDropContext, Droppable } = reactBeautifulDnd;
1085
1540
  if (!this.props.value) {
1086
1541
  return '';
1087
1542
  }
1543
+ const choices = [
1544
+ ...this.props.fields,
1545
+ ...(this.props.additionalFactory || []),
1546
+ ];
1547
+ let editFieldType = '';
1548
+ if (this.state.editField) {
1549
+ let factory =
1550
+ this.props.value.properties[this.state.editField.id].factory;
1551
+
1552
+ if (factory.value) {
1553
+ factory = factory.value;
1554
+ }
1555
+ const fieldType = find(choices, {
1556
+ value: factory !== '' ? factory : 'label_text_field',
1557
+ });
1558
+ editFieldType = fieldType
1559
+ ? this.props.intl.formatMessage({
1560
+ id: fieldType.value,
1561
+ defaultMessage: fieldType.label,
1562
+ })
1563
+ : '';
1564
+ }
1088
1565
  const nonUserCreatedFields = this.props.value.fieldsets[
1089
1566
  this.state.currentFieldset
1090
1567
  ].fields.filter(
@@ -1102,12 +1579,9 @@ class SchemaWidget extends Component {
1102
1579
  : this.props.value.fieldsets[this.state.currentFieldset].fields.length;
1103
1580
  // fields that were not created by the user, but are part of a behavior
1104
1581
  const makeNonUserFields = () =>
1105
- map(
1106
- this.props.value.fieldsets[this.state.currentFieldset].fields.slice(
1107
- 0,
1108
- userCreatedFieldsStartingIndex,
1109
- ),
1110
- (field, index) => (
1582
+ this.props.value.fieldsets[this.state.currentFieldset].fields
1583
+ .slice(0, userCreatedFieldsStartingIndex)
1584
+ .map((field, index) => (
1111
1585
  <div
1112
1586
  style={{ background: '#c7d5d859' }}
1113
1587
  key={`${field}-${this.state.currentFieldset}-${index}`}
@@ -1116,6 +1590,7 @@ class SchemaWidget extends Component {
1116
1590
  {...this.props.value.properties[field]}
1117
1591
  id={field}
1118
1592
  required={this.props.value.required.indexOf(field) !== -1}
1593
+ widgets={this.props.widgets}
1119
1594
  onEdit={this.onShowEditField}
1120
1595
  draggable={false}
1121
1596
  isDisabled={true}
@@ -1125,16 +1600,12 @@ class SchemaWidget extends Component {
1125
1600
  value={this.props.value.properties[field].default}
1126
1601
  />
1127
1602
  </div>
1128
- ),
1129
- );
1603
+ ));
1130
1604
  // fields created by the user
1131
1605
  const makeUserFields = () =>
1132
- map(
1133
- this.props.value.fieldsets[this.state.currentFieldset].fields.slice(
1134
- userCreatedFieldsStartingIndex,
1135
- lastUserCreatedFieldsIndex,
1136
- ),
1137
- (field, index) => (
1606
+ this.props.value.fieldsets[this.state.currentFieldset].fields
1607
+ .slice(userCreatedFieldsStartingIndex, lastUserCreatedFieldsIndex)
1608
+ .map((field, index) => (
1138
1609
  <Draggable
1139
1610
  draggableId={field}
1140
1611
  index={userCreatedFieldsStartingIndex + index}
@@ -1153,7 +1624,11 @@ class SchemaWidget extends Component {
1153
1624
  <Field
1154
1625
  {...this.props.value.properties[field]}
1155
1626
  id={field}
1156
- required={this.props.value.required.indexOf(field) !== -1}
1627
+ required={
1628
+ this.props.value.required &&
1629
+ this.props.value.required.indexOf(field) !== -1
1630
+ }
1631
+ widgets={this.props.widgets}
1157
1632
  onEdit={this.onShowEditField}
1158
1633
  draggable={true}
1159
1634
  isDisabled={false}
@@ -1166,8 +1641,7 @@ class SchemaWidget extends Component {
1166
1641
  </div>
1167
1642
  )}
1168
1643
  </Draggable>
1169
- ),
1170
- );
1644
+ ));
1171
1645
 
1172
1646
  const canAddFields =
1173
1647
  this.state.currentFieldset === 0 ||
@@ -1176,6 +1650,13 @@ class SchemaWidget extends Component {
1176
1650
  'generated',
1177
1651
  );
1178
1652
 
1653
+ const utility = config.getUtility({
1654
+ name: this.state.addField,
1655
+ type: 'fieldFactoryInitialData',
1656
+ });
1657
+
1658
+ const id = utility?.method ? utility.method(this.props.intl).id : undefined;
1659
+
1179
1660
  return (
1180
1661
  <div>
1181
1662
  <Segment.Group
@@ -1184,7 +1665,7 @@ class SchemaWidget extends Component {
1184
1665
  }}
1185
1666
  >
1186
1667
  {error.length > 0 &&
1187
- map(error, (err, index) => (
1668
+ error.map((err, index) => (
1188
1669
  <Message
1189
1670
  icon="warning"
1190
1671
  key={`${err}-${index}`}
@@ -1204,7 +1685,7 @@ class SchemaWidget extends Component {
1204
1685
  {...provided.draggableProps}
1205
1686
  style={getTabStyle(snapshot.isDraggingOver)}
1206
1687
  >
1207
- {map(this.props.value.fieldsets, (fieldset, index) => (
1688
+ {this.props.value.fieldsets.map((fieldset, index) => (
1208
1689
  <SchemaWidgetFieldset
1209
1690
  key={`${fieldset.id}-${this.state.currentFieldset}-${index}`}
1210
1691
  title={fieldset.title}
@@ -1283,7 +1764,7 @@ class SchemaWidget extends Component {
1283
1764
  ) : null}
1284
1765
 
1285
1766
  {canAddFields && (
1286
- <Form.Field inline>
1767
+ <Form.Field inline className="addfield">
1287
1768
  <Grid>
1288
1769
  <Grid.Row stretched>
1289
1770
  <Grid.Column width="12">
@@ -1312,21 +1793,31 @@ class SchemaWidget extends Component {
1312
1793
  <ModalForm
1313
1794
  onSubmit={this.onAddField}
1314
1795
  onCancel={this.onCancel}
1796
+ className={`field-${slugify(isString(this.state.addField) && this.state.addField !== '' ? this.state.addField : 'label_text_field')}`}
1797
+ onChangeFormData={(data) => {
1798
+ this.setState({
1799
+ addField: data.factory,
1800
+ });
1801
+ }}
1315
1802
  title={this.props.intl.formatMessage(messages.addField)}
1316
1803
  formData={{
1317
- type: '',
1318
- id: '',
1319
- title: '',
1804
+ factory:
1805
+ find(choices, { value: 'label_text_field' }) || undefined,
1806
+ id,
1320
1807
  }}
1321
- schema={{
1322
- fieldsets: [
1323
- {
1324
- id: 'default',
1325
- title: this.props.intl.formatMessage(messages.default),
1326
- fields: ['factory', 'title', 'description', 'required'],
1327
- },
1328
- ],
1329
- properties: {
1808
+ schema={schemaField(
1809
+ this.state.addField,
1810
+ this.props.intl,
1811
+ this.props.value.fieldsets.filter(
1812
+ (fieldset) =>
1813
+ !fieldset.behavior ||
1814
+ fieldset.id === 'default' ||
1815
+ fieldset.behavior.includes('generated'),
1816
+ ),
1817
+ this.props.allowEditId,
1818
+ this.props.allowEditQueryParameter,
1819
+ this.props.allowEditPlaceholder,
1820
+ {
1330
1821
  factory: {
1331
1822
  type: 'string',
1332
1823
  factory: 'Choice',
@@ -1334,30 +1825,20 @@ class SchemaWidget extends Component {
1334
1825
  vocabulary: {
1335
1826
  '@id': `Fields`,
1336
1827
  },
1337
- },
1338
- title: {
1339
- type: 'string',
1340
- title: this.props.intl.formatMessage(messages.title),
1341
- },
1342
- description: {
1343
- type: 'string',
1344
- widget: 'textarea',
1345
- title: this.props.intl.formatMessage(messages.description),
1346
- },
1347
- required: {
1348
- type: 'boolean',
1349
- title: this.props.intl.formatMessage(messages.required),
1828
+ filterChoices: filterFactory,
1829
+ additionalChoices: additionalFactory,
1830
+ sort: true,
1350
1831
  },
1351
1832
  },
1352
- required: ['type', 'title'],
1353
- }}
1833
+ )}
1354
1834
  />
1355
1835
  )}
1356
1836
  {this.state.editField !== null && (
1357
1837
  <ModalForm
1358
1838
  onSubmit={this.onEditField}
1359
1839
  onCancel={this.onCancel}
1360
- title={this.props.intl.formatMessage(messages.editField)}
1840
+ title={`${this.props.intl.formatMessage(messages.editField)}: ${editFieldType}`}
1841
+ className={`factory-${slugify(editFieldType)}`}
1361
1842
  formData={{
1362
1843
  ...this.props.value.properties[this.state.editField.id],
1363
1844
  id: this.state.editField.id,
@@ -1379,6 +1860,9 @@ class SchemaWidget extends Component {
1379
1860
  fieldset.id === 'default' ||
1380
1861
  fieldset.behavior.includes('generated'),
1381
1862
  ),
1863
+ this.props.allowEditId,
1864
+ this.props.allowEditQueryParameter,
1865
+ this.props.allowEditPlaceholder,
1382
1866
  )}
1383
1867
  />
1384
1868
  )}
@@ -1433,7 +1917,9 @@ export default compose(
1433
1917
  connect(
1434
1918
  (state, props) => ({
1435
1919
  value: isString(props.value) ? JSON.parse(props.value) : props.value,
1920
+ fields:
1921
+ state.vocabularies?.Fields?.subrequests?.schemawidget?.items || [],
1436
1922
  }),
1437
- {},
1923
+ { getVocabulary },
1438
1924
  ),
1439
1925
  )(SchemaWidget);