@plone/volto 18.0.0-alpha.41 → 18.0.0-alpha.43

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 (187) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/finalreleasechangelog.py +48 -0
  3. package/locales/ca/LC_MESSAGES/volto.po +39 -13
  4. package/locales/ca.json +1 -1
  5. package/locales/de/LC_MESSAGES/volto.po +40 -14
  6. package/locales/de.json +1 -1
  7. package/locales/en/LC_MESSAGES/volto.po +39 -13
  8. package/locales/en.json +1 -1
  9. package/locales/es/LC_MESSAGES/volto.po +40 -14
  10. package/locales/es.json +1 -1
  11. package/locales/eu/LC_MESSAGES/volto.po +40 -14
  12. package/locales/eu.json +1 -1
  13. package/locales/fi/LC_MESSAGES/volto.po +40 -14
  14. package/locales/fi.json +1 -1
  15. package/locales/fr/LC_MESSAGES/volto.po +40 -14
  16. package/locales/fr.json +1 -1
  17. package/locales/hi/LC_MESSAGES/volto.po +40 -14
  18. package/locales/hi.json +1 -1
  19. package/locales/it/LC_MESSAGES/volto.po +40 -14
  20. package/locales/it.json +1 -1
  21. package/locales/ja/LC_MESSAGES/volto.po +39 -13
  22. package/locales/ja.json +1 -1
  23. package/locales/nl/LC_MESSAGES/volto.po +39 -13
  24. package/locales/nl.json +1 -1
  25. package/locales/pt/LC_MESSAGES/volto.po +39 -13
  26. package/locales/pt.json +1 -1
  27. package/locales/pt_BR/LC_MESSAGES/volto.po +40 -14
  28. package/locales/pt_BR.json +1 -1
  29. package/locales/ro/LC_MESSAGES/volto.po +39 -13
  30. package/locales/ro.json +1 -1
  31. package/locales/volto.pot +40 -14
  32. package/locales/zh_CN/LC_MESSAGES/volto.po +40 -14
  33. package/locales/zh_CN.json +1 -1
  34. package/package.json +5 -6
  35. package/razzle.config.js +3 -3
  36. package/src/components/index.js +0 -1
  37. package/src/components/manage/Actions/Actions.stories.jsx +138 -0
  38. package/src/components/manage/Add/Add.jsx +7 -4
  39. package/src/components/manage/BlockChooser/BlockChooser.jsx +9 -1
  40. package/src/components/manage/Blocks/Block/BlocksForm.jsx +5 -0
  41. package/src/components/manage/Blocks/Block/Edit.jsx +24 -8
  42. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +17 -1
  43. package/src/components/manage/Blocks/Block/Order/Item.jsx +8 -2
  44. package/src/components/manage/Blocks/Block/Order/Order.jsx +2 -0
  45. package/src/components/manage/Blocks/Container/Data.jsx +10 -2
  46. package/src/components/manage/Blocks/Grid/View.jsx +3 -0
  47. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +10 -2
  48. package/src/components/manage/Blocks/LeadImage/Edit.jsx +74 -126
  49. package/src/components/manage/Blocks/Listing/ListingData.jsx +10 -2
  50. package/src/components/manage/Blocks/Maps/MapsSidebar.jsx +3 -1
  51. package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +2 -0
  52. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +18 -2
  53. package/src/components/manage/Blocks/Search/components/SortOn.jsx +82 -55
  54. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +1 -1
  55. package/src/components/manage/Blocks/Search/widgets/SelectMetadataField.jsx +107 -176
  56. package/src/components/manage/Blocks/Teaser/Data.jsx +10 -2
  57. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +15 -8
  58. package/src/components/manage/Blocks/ToC/Edit.jsx +36 -28
  59. package/src/components/manage/Blocks/Video/Edit.jsx +105 -172
  60. package/src/components/manage/Blocks/Video/Edit.stories.jsx +57 -0
  61. package/src/components/manage/Blocks/Video/VideoSidebar.jsx +3 -1
  62. package/src/components/manage/Contents/Contents.jsx +4 -1
  63. package/src/components/manage/Contents/ContentsBreadcrumbs.stories.jsx +46 -0
  64. package/src/components/manage/Contents/ContentsPropertiesModal.jsx +85 -52
  65. package/src/components/manage/Contents/ContentsUploadModal.jsx +230 -323
  66. package/src/components/manage/Contents/ContentsUploadModal.stories.jsx +56 -0
  67. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +323 -441
  68. package/src/components/manage/Controlpanels/Aliases.jsx +452 -580
  69. package/src/components/manage/Controlpanels/Aliases.stories.jsx +74 -0
  70. package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -0
  71. package/src/components/manage/Controlpanels/Controlpanel.jsx +41 -2
  72. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +55 -24
  73. package/src/components/manage/Controlpanels/DatabaseInformation.jsx +162 -229
  74. package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +74 -122
  75. package/src/components/manage/Controlpanels/UndoControlpanel.jsx +3 -3
  76. package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +28 -12
  77. package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +12 -4
  78. package/src/components/manage/Display/Display.jsx +92 -148
  79. package/src/components/manage/Display/Display.stories.jsx +46 -0
  80. package/src/components/manage/Edit/Edit.jsx +2 -4
  81. package/src/components/manage/Form/Form.jsx +85 -20
  82. package/src/components/manage/Form/InlineForm.jsx +2 -4
  83. package/src/components/manage/Form/ModalForm.jsx +1 -1
  84. package/src/components/manage/History/History.jsx +1 -1
  85. package/src/components/manage/Pluggable/Pluggable.test.js +1 -1
  86. package/src/components/manage/Preferences/ChangePassword.jsx +94 -172
  87. package/src/components/manage/Preferences/ChangePassword.stories.jsx +41 -0
  88. package/src/components/manage/Preferences/PersonalInformation.jsx +50 -115
  89. package/src/components/manage/Preferences/PersonalPreferences.jsx +46 -100
  90. package/src/components/manage/Preferences/PersonalPreferences.stories.jsx +48 -0
  91. package/src/components/manage/Toolbar/More.jsx +308 -399
  92. package/src/components/manage/Toolbar/Toolbar.jsx +1 -1
  93. package/src/components/manage/Widgets/ArrayWidget.jsx +2 -2
  94. package/src/components/manage/Widgets/DatetimeWidget.jsx +121 -175
  95. package/src/components/manage/Widgets/ImageWidget.jsx +6 -5
  96. package/src/components/manage/Widgets/RecurrenceWidget/EndField.jsx +7 -1
  97. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +80 -31
  98. package/src/components/manage/Widgets/ReferenceWidget.jsx +134 -210
  99. package/src/components/theme/Register/Register.jsx +70 -142
  100. package/src/components/theme/Register/Register.stories.jsx +49 -0
  101. package/src/components/theme/Search/Search.jsx +13 -5
  102. package/src/components/theme/Tags/Tags.jsx +19 -10
  103. package/src/components/theme/Tags/Tags.test.jsx +9 -11
  104. package/src/components/theme/View/AlbumView.jsx +122 -167
  105. package/src/components/theme/View/LinkView.jsx +4 -0
  106. package/src/components/theme/View/LinkView.test.jsx +2 -0
  107. package/src/components/theme/View/View.jsx +0 -13
  108. package/src/components/theme/View/View.test.jsx +0 -3
  109. package/src/config/ControlPanels.js +49 -43
  110. package/src/config/Widgets.jsx +1 -1
  111. package/src/config/config.test.js +1 -0
  112. package/src/config/index.js +23 -2
  113. package/src/config/slots.js +12 -0
  114. package/src/config/validation.ts +155 -0
  115. package/src/helpers/Blocks/Blocks.js +12 -7
  116. package/src/helpers/Blocks/Blocks.test.js +15 -0
  117. package/src/helpers/Blocks/cloneBlocks.ts +1 -1
  118. package/src/helpers/Extensions/withBlockExtensions.jsx +1 -1
  119. package/src/helpers/FormValidation/FormValidation.jsx +128 -172
  120. package/src/helpers/FormValidation/FormValidation.test.js +836 -8
  121. package/src/helpers/FormValidation/validators.ts +203 -0
  122. package/src/helpers/MessageLabels/MessageLabels.js +28 -0
  123. package/src/helpers/Url/Url.test.js +19 -6
  124. package/src/helpers/Url/urlRegex.js +1 -1
  125. package/src/helpers/User/User.js +1 -1
  126. package/src/helpers/index.js +2 -0
  127. package/src/hooks/client/useClient.js +1 -1
  128. package/src/middleware/api.js +4 -2
  129. package/src/middleware/index.js +1 -0
  130. package/src/middleware/userSessionReset.js +46 -0
  131. package/src/store.js +2 -0
  132. package/test-setup-config.jsx +10 -0
  133. package/theme/themes/default/modules/embed.variables +1 -1
  134. package/theme/themes/pastanaga/collections/form.overrides +34 -0
  135. package/theme/themes/pastanaga/extras/blocks.less +6 -0
  136. package/theme/themes/pastanaga/extras/sidebar.less +4 -0
  137. package/theme/themes/pastanaga/extras/toolbar.less +10 -3
  138. package/tsconfig.declarations.json +3 -2
  139. package/types/components/index.d.ts +0 -1
  140. package/types/components/manage/Actions/Actions.stories.d.ts +8 -0
  141. package/types/components/manage/Blocks/Block/Order/Order.d.ts +2 -1
  142. package/types/components/manage/Blocks/LeadImage/Edit.d.ts +14 -5
  143. package/types/components/manage/Blocks/Search/widgets/SelectMetadataField.d.ts +0 -5
  144. package/types/components/manage/Blocks/ToC/Edit.d.ts +1 -6
  145. package/types/components/manage/Blocks/Video/Edit.d.ts +1 -1
  146. package/types/components/manage/Blocks/Video/Edit.stories.d.ts +8 -0
  147. package/types/components/manage/Contents/ContentsBreadcrumbs.stories.d.ts +8 -0
  148. package/types/components/manage/Contents/ContentsUploadModal.d.ts +14 -2
  149. package/types/components/manage/Contents/ContentsUploadModal.stories.d.ts +8 -0
  150. package/types/components/manage/Contents/index.d.ts +1 -1
  151. package/types/components/manage/Controlpanels/AddonsControlpanel.d.ts +2 -2
  152. package/types/components/manage/Controlpanels/Aliases.d.ts +2 -2
  153. package/types/components/manage/Controlpanels/Aliases.stories.d.ts +8 -0
  154. package/types/components/manage/Controlpanels/DatabaseInformation.d.ts +2 -2
  155. package/types/components/manage/Controlpanels/Groups/RenderGroups.d.ts +10 -5
  156. package/types/components/manage/Controlpanels/index.d.ts +4 -4
  157. package/types/components/manage/Display/Display.stories.d.ts +8 -0
  158. package/types/components/manage/Preferences/ChangePassword.d.ts +2 -2
  159. package/types/components/manage/Preferences/ChangePassword.stories.d.ts +8 -0
  160. package/types/components/manage/Preferences/PersonalInformation.d.ts +7 -2
  161. package/types/components/manage/Preferences/PersonalPreferences.d.ts +5 -1
  162. package/types/components/manage/Preferences/PersonalPreferences.stories.d.ts +8 -0
  163. package/types/components/manage/Toolbar/More.d.ts +8 -5
  164. package/types/components/manage/Widgets/DatetimeWidget.d.ts +0 -85
  165. package/types/components/manage/Widgets/DatetimeWidget.stories.d.ts +0 -1
  166. package/types/components/manage/Widgets/ReferenceWidget.d.ts +27 -2
  167. package/types/components/manage/Widgets/index.d.ts +1 -1
  168. package/types/components/theme/Register/Register.d.ts +2 -2
  169. package/types/components/theme/Register/Register.stories.d.ts +9 -0
  170. package/types/components/theme/Tags/Tags.d.ts +15 -7
  171. package/types/components/theme/View/AlbumView.d.ts +3 -17
  172. package/types/config/ControlPanels.d.ts +8 -0
  173. package/types/config/RichTextEditor/ToHTML.d.ts +1 -1
  174. package/types/config/Widgets.d.ts +3 -3
  175. package/types/config/slots.d.ts +21 -0
  176. package/types/config/validation.d.ts +3 -0
  177. package/types/helpers/Blocks/Blocks.d.ts +6 -0
  178. package/types/helpers/Extensions/withBlockExtensions.d.ts +1 -1
  179. package/types/helpers/FormValidation/FormValidation.d.ts +2 -0
  180. package/types/helpers/FormValidation/validators.d.ts +29 -0
  181. package/types/helpers/MessageLabels/MessageLabels.d.ts +36 -0
  182. package/types/helpers/User/User.d.ts +1 -1
  183. package/types/helpers/index.d.ts +2 -2
  184. package/types/middleware/index.d.ts +1 -0
  185. package/types/middleware/userSessionReset.d.ts +5 -0
  186. package/src/components/theme/SocialSharing/SocialSharing.jsx +0 -48
  187. package/src/components/theme/SocialSharing/SocialSharing.test.jsx +0 -14
@@ -0,0 +1,203 @@
1
+ import { validationMessage } from '@plone/volto/helpers/FormValidation/FormValidation';
2
+ import { messages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
3
+
4
+ type MinMaxValidator = {
5
+ value: string | number;
6
+ fieldSpec: string | number;
7
+ criterion: string;
8
+ formatMessage: Function;
9
+ };
10
+
11
+ type Validator = {
12
+ value: string;
13
+ field: Record<string, any>;
14
+ formData: any;
15
+ formatMessage: Function;
16
+ };
17
+
18
+ export const isMaxPropertyValid = ({
19
+ value,
20
+ fieldSpec,
21
+ criterion,
22
+ formatMessage,
23
+ }: MinMaxValidator) => {
24
+ const isValid = fieldSpec !== undefined ? value <= fieldSpec : true;
25
+ return validationMessage(isValid, criterion, fieldSpec, formatMessage);
26
+ };
27
+
28
+ export const isMinPropertyValid = ({
29
+ value,
30
+ fieldSpec,
31
+ criterion,
32
+ formatMessage,
33
+ }: MinMaxValidator) => {
34
+ const isValid = fieldSpec !== undefined ? value >= fieldSpec : true;
35
+ return validationMessage(isValid, criterion, fieldSpec, formatMessage);
36
+ };
37
+
38
+ export const minLengthValidator = ({
39
+ value,
40
+ field,
41
+ formatMessage,
42
+ }: Validator) =>
43
+ isMinPropertyValid({
44
+ value: value.length,
45
+ fieldSpec: field.minLength,
46
+ criterion: 'minLength',
47
+ formatMessage,
48
+ });
49
+
50
+ export const maxLengthValidator = ({
51
+ value,
52
+ field,
53
+ formatMessage,
54
+ }: Validator) =>
55
+ isMaxPropertyValid({
56
+ value: value.length,
57
+ fieldSpec: field.maxLength,
58
+ criterion: 'maxLength',
59
+ formatMessage,
60
+ });
61
+
62
+ export const urlValidator = ({ value, formatMessage }: Validator) => {
63
+ const urlRegex = new RegExp(
64
+ '^(https?:\\/\\/)?' + // validate protocol
65
+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name
66
+ '((\\d{1,3}\\.){3}\\d{1,3}))|' + // validate OR ip (v4) address
67
+ '(localhost)' + // validate OR localhost address
68
+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path
69
+ '(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
70
+ '(\\#[-a-z\\d_]*)?$', // validate fragment locator
71
+ 'i',
72
+ );
73
+ const isValid = urlRegex.test(value);
74
+ return !isValid ? formatMessage(messages.isValidURL) : null;
75
+ };
76
+
77
+ export const emailValidator = ({ value, formatMessage }: Validator): string => {
78
+ // Email Regex taken from from WHATWG living standard:
79
+ // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type=email)
80
+ const emailRegex =
81
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
82
+ const isValid = emailRegex.test(value);
83
+ return !isValid ? formatMessage(messages.isValidEmail) : null;
84
+ };
85
+
86
+ export const isNumberValidator = ({ value, formatMessage }: Validator) => {
87
+ const isNumeric = (string: string | number) => Number.isFinite(+string);
88
+ const floatRegex = /^[+-]?\d+(\.\d+)?$/;
89
+ const isValid = isNumeric(value) && floatRegex.test(value);
90
+ // const isValid =
91
+ // typeof value === 'string' && !isNaN(+value) && floatRegex.test(value);
92
+ return !isValid ? formatMessage(messages.isNumber) : null;
93
+ };
94
+
95
+ export const minimumValidator = ({ value, field, formatMessage }: Validator) =>
96
+ isMinPropertyValid({
97
+ value,
98
+ fieldSpec: field.minimum,
99
+ criterion: 'minimum',
100
+ formatMessage,
101
+ });
102
+
103
+ export const maximumValidator = ({ value, field, formatMessage }: Validator) =>
104
+ isMaxPropertyValid({
105
+ value,
106
+ fieldSpec: field.maximum,
107
+ criterion: 'maximum',
108
+ formatMessage,
109
+ });
110
+
111
+ export const isIntegerValidator = ({ value, formatMessage }: Validator) => {
112
+ const isNumeric = (string: string | number) => Number.isFinite(+string);
113
+ const intRegex = /^-?[0-9]+$/;
114
+ const isValid = isNumeric(value) && intRegex.test(value);
115
+ return !isValid ? formatMessage(messages.isInteger) : null;
116
+ };
117
+
118
+ export const hasUniqueItemsValidator = ({
119
+ value,
120
+ field,
121
+ formatMessage,
122
+ }: Validator) => {
123
+ if (!field.uniqueItems) {
124
+ return null;
125
+ }
126
+ const isValid =
127
+ field.uniqueItems &&
128
+ value &&
129
+ // unique items
130
+ [...new Set(value)].length === value.length;
131
+ return !isValid ? formatMessage(messages.uniqueItems) : null;
132
+ };
133
+
134
+ export const startEventDateRangeValidator = ({
135
+ value,
136
+ field,
137
+ formData,
138
+ formatMessage,
139
+ }: Validator) => {
140
+ const isValid =
141
+ value && formData.end && new Date(value) < new Date(formData.end);
142
+ return !isValid
143
+ ? formatMessage(messages.startEventRange, {
144
+ endDateValueOrEndFieldName: formData.end || 'end',
145
+ })
146
+ : null;
147
+ };
148
+
149
+ export const endEventDateRangeValidator = ({
150
+ value,
151
+ field,
152
+ formData,
153
+ formatMessage,
154
+ }: Validator) => {
155
+ const isValid =
156
+ value && formData.start && new Date(value) > new Date(formData.start);
157
+ return !isValid
158
+ ? formatMessage(messages.endEventRange, {
159
+ startDateValueOrStartFieldName: formData.start || 'start',
160
+ })
161
+ : null;
162
+ };
163
+
164
+ export const patternValidator = ({
165
+ value,
166
+ field,
167
+ formatMessage,
168
+ }: Validator) => {
169
+ if (!field.pattern) {
170
+ return null;
171
+ }
172
+ const regex = new RegExp(field.pattern);
173
+ const isValid = regex.test(value);
174
+ return !isValid ? formatMessage(messages.pattern) : null;
175
+ };
176
+
177
+ export const maxItemsValidator = ({
178
+ value,
179
+ field,
180
+ formatMessage,
181
+ }: Validator) => {
182
+ if (!field.maxItems) {
183
+ return null;
184
+ }
185
+ const isValid = Array.isArray(value) && value.length <= field.maxItems;
186
+ return !isValid
187
+ ? formatMessage(messages.maxItems, { maxItems: field.maxItems })
188
+ : null;
189
+ };
190
+
191
+ export const minItemsValidator = ({
192
+ value,
193
+ field,
194
+ formatMessage,
195
+ }: Validator) => {
196
+ if (!field.minItems) {
197
+ return null;
198
+ }
199
+ const isValid = Array.isArray(value) && value.length >= field.minItems;
200
+ return !isValid
201
+ ? formatMessage(messages.minItems, { minItems: field.minItems })
202
+ : null;
203
+ };
@@ -375,4 +375,32 @@ export const messages = defineMessages({
375
375
  id: 'fileTooLarge',
376
376
  defaultMessage: 'This website does not accept files larger than {limit}',
377
377
  },
378
+ blocksFieldsErrorTitle: {
379
+ id: 'blocksFieldsErrorTitle',
380
+ defaultMessage: 'Error in the block field {errorField}.',
381
+ },
382
+ startEventRange: {
383
+ id: 'Event start date must be on or before {endDateValueOrEndFieldName}',
384
+ defaultMessage:
385
+ 'Event start date must be on or before {endDateValueOrEndFieldName}',
386
+ },
387
+ endEventRange: {
388
+ id: 'Event end date must be on or after {startDateValueOrStartFieldName}',
389
+ defaultMessage:
390
+ 'Event end date must be on or after {startDateValueOrStartFieldName}',
391
+ },
392
+ pattern: {
393
+ id: 'The value does not match the pattern {pattern}',
394
+ defaultMessage: 'The value does not match the pattern {pattern}',
395
+ },
396
+ maxItems: {
397
+ id: 'The number of items must be less than or equal to {maxItems}',
398
+ defaultMessage:
399
+ 'The number of items must be less than or equal to {maxItems}',
400
+ },
401
+ minItems: {
402
+ id: 'The number of items must be greater than or equal to {minItems}',
403
+ defaultMessage:
404
+ 'The number of items must be greater than or equal to {minItems}',
405
+ },
378
406
  });
@@ -66,7 +66,7 @@ describe('Url', () => {
66
66
  it('return empty string if no url is empty string', () => {
67
67
  expect(getBaseUrl('')).toBe('');
68
68
  });
69
- it('return a null/undefined mailto adress ', () => {
69
+ it('return a null/undefined mailto address ', () => {
70
70
  expect(normaliseMail(null)).toBe('mailto:null');
71
71
  expect(normaliseMail(undefined)).toBe('mailto:undefined');
72
72
  });
@@ -163,14 +163,14 @@ describe('Url', () => {
163
163
  });
164
164
 
165
165
  describe('flattenHTMLToAppURL', () => {
166
- it('flattens all occurences of the api URL from an html snippet', () => {
166
+ it('flattens all occurrences of the api URL from an html snippet', () => {
167
167
  const html = `<a href="${settings.apiPath}/foo/bar">An internal link</a><a href="${settings.apiPath}/foo/baz">second link</a>`;
168
168
  expect(flattenHTMLToAppURL(html)).toBe(
169
169
  '<a href="/foo/bar">An internal link</a><a href="/foo/baz">second link</a>',
170
170
  );
171
171
  });
172
172
 
173
- it('flattens all occurences of the api URL from an html snippet, with settings.internalApiPath', () => {
173
+ it('flattens all occurrences of the api URL from an html snippet, with settings.internalApiPath', () => {
174
174
  const html = `<a href="http://plone:8080/Plone/foo/bar">An internal link</a><a href="http://plone:8080/Plone/foo/baz">second link</a>`;
175
175
  const saved = settings.internalApiPath;
176
176
  settings.internalApiPath = 'http://plone:8080/Plone';
@@ -228,7 +228,7 @@ describe('Url', () => {
228
228
  const href = undefined;
229
229
  expect(isInternalURL(href)).toBe(undefined);
230
230
  });
231
- it('tells if an URL is external if settings.externalroutes is persent.', () => {
231
+ it('tells if an URL is external if settings.externalroutes is present.', () => {
232
232
  const url = `https://localhost:3000/fb/my-page/contents`;
233
233
  const blacklistedurl = '/blacklisted';
234
234
  settings.externalRoutes = [
@@ -255,11 +255,24 @@ describe('Url', () => {
255
255
  });
256
256
  it('isUrl test 4', () => {
257
257
  const href = `https://www`;
258
- expect(isUrl(href)).toBe(false);
258
+ expect(isUrl(href)).toBe(true);
259
259
  });
260
260
  it('isUrl test 5', () => {
261
+ const href = `https://www/foo/bar`;
262
+ expect(isUrl(href)).toBe(true);
263
+ });
264
+ it('isUrl test 6', () => {
265
+ // at the end of the day, this is a strange, but valid, URL
261
266
  const href = `www.e`;
262
- expect(isUrl(href)).toBe(false);
267
+ expect(isUrl(href)).toBe(true);
268
+ });
269
+ it('isUrl test 7', () => {
270
+ const href = `file://server/folder/file.txt`;
271
+ expect(isUrl(href)).toBe(true);
272
+ });
273
+ it('isUrl test 8', () => {
274
+ const href = `file://server.dir.internal/folder/file.txt`;
275
+ expect(isUrl(href)).toBe(true);
263
276
  });
264
277
  });
265
278
  describe('getFieldURL', () => {
@@ -52,7 +52,7 @@ export const urlRegex = (_opts) => {
52
52
  })\\.?`;
53
53
  const port = '(?::\\d{2,5})?';
54
54
  const path = '(?:[/?#][^\\s"]*)?';
55
- const regex = `(?:${protocol}|www\\.)${auth}(?:localhost|${ip}|${host}${domain}${tld})${port}${path}`;
55
+ const regex = `(?:${protocol}|www\\.)${auth}(?:localhost|${ip}|${host}${domain}${tld}|${host})${port}${path}`;
56
56
 
57
57
  return opts.exact
58
58
  ? new RegExp(`(?:^${regex}$)`, 'i')
@@ -23,7 +23,7 @@ export function isManager(user) {
23
23
  }
24
24
 
25
25
  /**
26
- * Checks if the user can assing group.
26
+ * Checks if the user can assign group.
27
27
  * @method canAssignGroup
28
28
  * @returns {boolean}
29
29
  */
@@ -40,6 +40,7 @@ export {
40
40
  getLanguageIndependentFields,
41
41
  } from '@plone/volto/helpers/Content/Content';
42
42
  export {
43
+ applyBlockInitialValue,
43
44
  addBlock,
44
45
  insertBlock,
45
46
  blockHasValue,
@@ -85,6 +86,7 @@ export { default as Helmet } from './Helmet/Helmet';
85
86
  export { default as FormValidation } from './FormValidation/FormValidation';
86
87
  export { validateFileUploadSize } from './FormValidation/FormValidation';
87
88
  export { tryParseJSON } from './FormValidation/FormValidation';
89
+ export { extractInvariantErrors } from './FormValidation/FormValidation';
88
90
  export {
89
91
  difference,
90
92
  getColor,
@@ -1,4 +1,4 @@
1
- //useClient hook to replace repetitive delcaration in the components
1
+ //useClient hook to replace repetitive declaration in the components
2
2
  import { useEffect, useState } from 'react';
3
3
 
4
4
  export function useClient() {
@@ -222,7 +222,8 @@ const apiMiddlewareFactory =
222
222
  }
223
223
 
224
224
  const { settings } = config;
225
- if (getState().apierror.connectionRefused) {
225
+ const state = getState();
226
+ if (state.apierror.connectionRefused) {
226
227
  next({
227
228
  ...rest,
228
229
  type: RESET_APIERROR,
@@ -232,7 +233,7 @@ const apiMiddlewareFactory =
232
233
  const lang = result?.language?.token;
233
234
  if (
234
235
  lang &&
235
- getState().intl.locale !== toReactIntlLang(lang) &&
236
+ state.intl.locale !== toReactIntlLang(lang) &&
236
237
  !subrequest &&
237
238
  config.settings.supportedLanguages.includes(lang)
238
239
  ) {
@@ -244,6 +245,7 @@ const apiMiddlewareFactory =
244
245
  });
245
246
  }
246
247
  }
248
+
247
249
  if (type === LOGIN && settings.websockets) {
248
250
  const cookies = new Cookies();
249
251
  cookies.set(
@@ -11,3 +11,4 @@ export {
11
11
  protectLoadEnd,
12
12
  loadProtector,
13
13
  } from '@plone/volto/middleware/storeProtectLoadUtils';
14
+ export { default as userSessionReset } from './userSessionReset';
@@ -0,0 +1,46 @@
1
+ import Cookies from 'universal-cookie';
2
+
3
+ const LOCATION_CHANGE = '@@router/LOCATION_CHANGE';
4
+
5
+ const userSessionReset =
6
+ ({ dispatch, getState }) =>
7
+ (next) =>
8
+ (action) => {
9
+ if (typeof action === 'function') {
10
+ return next(action);
11
+ }
12
+
13
+ switch (action.type) {
14
+ case LOCATION_CHANGE:
15
+ if (action.request?.subrequest || __SERVER__) {
16
+ return next(action);
17
+ }
18
+
19
+ const cookies = new Cookies();
20
+ const token = cookies.get('auth_token');
21
+ const state = getState();
22
+
23
+ if (token && !state.userSession?.token) {
24
+ const loginAction = {
25
+ type: 'LOGIN_SUCCESS',
26
+ result: {
27
+ token,
28
+ },
29
+ };
30
+ dispatch(loginAction);
31
+ } else if (!token && state.userSession?.token) {
32
+ const logoutAction = {
33
+ type: 'LOGOUT_SUCCESS',
34
+ result: {
35
+ token,
36
+ },
37
+ };
38
+ dispatch(logoutAction);
39
+ }
40
+ return next(action);
41
+ default:
42
+ return next(action);
43
+ }
44
+ };
45
+
46
+ export default userSessionReset;
package/src/store.js CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  protectLoadStart,
14
14
  protectLoadEnd,
15
15
  loadProtector,
16
+ userSessionReset,
16
17
  } from '@plone/volto/middleware';
17
18
 
18
19
  const configureStore = (initialState, history, apiHelper) => {
@@ -22,6 +23,7 @@ const configureStore = (initialState, history, apiHelper) => {
22
23
  routerMiddleware(history),
23
24
  thunk,
24
25
  ...(apiHelper ? [api(apiHelper)] : []),
26
+ userSessionReset,
25
27
  protectLoadEnd,
26
28
  ...(__CLIENT__
27
29
  ? [save({ states: config.settings.persistentReducers, debounce: 500 })]
@@ -20,9 +20,11 @@ import {
20
20
  controlPanelsIcons,
21
21
  filterControlPanels,
22
22
  filterControlPanelsSchema,
23
+ unwantedControlPanelsFields,
23
24
  } from '@plone/volto/config/ControlPanels';
24
25
 
25
26
  import ListingBlockSchema from '@plone/volto/components/manage/Blocks/Listing/schema';
27
+ import { registerValidators } from '@plone/volto/config/validation';
26
28
 
27
29
  config.set('settings', {
28
30
  apiPath: 'http://localhost:8080/Plone',
@@ -30,6 +32,7 @@ config.set('settings', {
30
32
  defaultLanguage: 'en',
31
33
  supportedLanguages: ['en'],
32
34
  defaultPageSize: 25,
35
+ showTags: true,
33
36
  isMultilingual: false,
34
37
  nonContentRoutes,
35
38
  contentIcons: contentIcons,
@@ -48,6 +51,7 @@ config.set('settings', {
48
51
  controlPanelsIcons,
49
52
  filterControlPanels,
50
53
  filterControlPanelsSchema,
54
+ unwantedControlPanelsFields,
51
55
  apiExpanders: [],
52
56
  downloadableObjects: ['File'],
53
57
  viewableInBrowserObjects: [],
@@ -153,9 +157,15 @@ config.set('components', {
153
157
  component: (props) => <img alt="Image component mock" {...props} />,
154
158
  },
155
159
  });
160
+
161
+ config.set('utilities', {});
162
+
156
163
  config.set('experimental', {
157
164
  addBlockButton: {
158
165
  enabled: false,
159
166
  },
160
167
  });
168
+
161
169
  config.set('slots', {});
170
+
171
+ registerValidators(config);
@@ -14,7 +14,7 @@
14
14
  /* Placeholder */
15
15
  @placeholderUnderlay: @background;
16
16
 
17
- /* Placeholder Overlayed Background */
17
+ /* Placeholder Overlaid Background */
18
18
  @placeholderBackground: radial-gradient(transparent 45%, rgba(0, 0, 0, 0.3));
19
19
  @placeholderBackgroundOpacity: 0.5;
20
20
  @placeholderBackgroundTransition: opacity @transitionDuration @transitionEasing;
@@ -123,16 +123,50 @@
123
123
  z-index: 1;
124
124
  top: 0;
125
125
  right: 0;
126
+ left: auto;
126
127
  display: flex;
127
128
  height: 60px;
128
129
  align-items: center;
129
130
  margin-right: 1rem;
131
+ background: transparent;
132
+ box-shadow: none;
133
+ transform: none;
130
134
 
131
135
  .item {
132
136
  cursor: pointer;
133
137
  }
134
138
  }
135
139
 
140
+ .block.form {
141
+ [data-rbd-draggable-context-id] {
142
+ margin-bottom: 0;
143
+ }
144
+
145
+ .ui.menu .item > i.icon {
146
+ margin-left: -2px;
147
+ }
148
+
149
+ .square.icon {
150
+ margin-top: -2px;
151
+ }
152
+
153
+ .ui.segments > div {
154
+ background: white !important;
155
+ }
156
+
157
+ .drag.handle {
158
+ cursor: grab;
159
+ }
160
+
161
+ .tabular.menu > .item {
162
+ height: 66px;
163
+
164
+ button {
165
+ border-bottom-width: 5px;
166
+ }
167
+ }
168
+ }
169
+
136
170
  .ui.form .field .ui.basic.button.delete-button {
137
171
  padding: 0;
138
172
  border: none;
@@ -1120,6 +1120,12 @@ div.image-upload-widget-image {
1120
1120
  flex-direction: row;
1121
1121
  align-items: center;
1122
1122
  margin-right: 0.5em;
1123
+
1124
+ .sorted-label-value {
1125
+ margin-right: 0.5em;
1126
+ margin-left: 0.7em;
1127
+ color: @lightGrey;
1128
+ }
1123
1129
  }
1124
1130
 
1125
1131
  .sort-label {
@@ -518,6 +518,10 @@
518
518
  padding-left: 0.5rem;
519
519
  text-overflow: ellipsis;
520
520
  white-space: nowrap;
521
+
522
+ &.errored {
523
+ color: @red;
524
+ }
521
525
  }
522
526
 
523
527
  &.disable-interaction {
@@ -129,7 +129,7 @@ body:not(.has-sidebar):not(.has-sidebar-collapsed) {
129
129
  }
130
130
 
131
131
  .toolbar-handler {
132
- button {
132
+ .toolbar-handler-button {
133
133
  opacity: 0.3;
134
134
  }
135
135
 
@@ -243,7 +243,7 @@ body:not(.has-sidebar):not(.has-sidebar-collapsed) {
243
243
  width: 100%;
244
244
  justify-content: center;
245
245
 
246
- button {
246
+ .toolbar-handler-button {
247
247
  width: @toolbarWidth;
248
248
  height: 20px;
249
249
  padding: 0;
@@ -428,7 +428,7 @@ body:not(.has-sidebar):not(.has-sidebar-collapsed) {
428
428
  flex-direction: column;
429
429
  justify-content: center;
430
430
 
431
- button {
431
+ .toolbar-handler-button {
432
432
  width: @toolbarWidthMin;
433
433
  height: @toolbarWidth;
434
434
 
@@ -752,3 +752,10 @@ body:not(.has-sidebar):not(.has-sidebar-collapsed) {
752
752
  }
753
753
  }
754
754
  // End Orphaned CSS
755
+
756
+ // Toolbar handler color in homepage
757
+ .contenttype-plone-site {
758
+ #toolbar .toolbar-handler .toolbar-handler-button:before {
759
+ background: @teal-blue;
760
+ }
761
+ }
@@ -9,9 +9,10 @@
9
9
  "esModuleInterop": true,
10
10
  "jsx": "react-jsx",
11
11
  "preserveSymlinks": true,
12
+ "downlevelIteration": true,
12
13
  "paths": {
13
- "@plone/volto/*": ["./src/*"],
14
+ "@plone/volto/*": ["./src/*"]
14
15
  }
15
16
  },
16
- "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.tsx"],
17
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.tsx"]
17
18
  }
@@ -33,7 +33,6 @@ export { default as Logout } from "@plone/volto/components/theme/Logout/Logout";
33
33
  export { default as Sitemap } from "@plone/volto/components/theme/Sitemap/Sitemap";
34
34
  export { default as Search } from "@plone/volto/components/theme/Search/Search";
35
35
  export { default as Comments } from "@plone/volto/components/theme/Comments/Comments";
36
- export { default as SocialSharing } from "@plone/volto/components/theme/SocialSharing/SocialSharing";
37
36
  export { default as Register } from "@plone/volto/components/theme/Register/Register";
38
37
  export { default as PasswordReset } from "@plone/volto/components/theme/PasswordReset/PasswordReset";
39
38
  export { default as RequestPasswordReset } from "@plone/volto/components/theme/PasswordReset/RequestPasswordReset";
@@ -0,0 +1,8 @@
1
+ export const Actions: any;
2
+ declare namespace _default {
3
+ export let title: string;
4
+ export { Actions as component };
5
+ export let decorators: ((Story: any) => import("react/jsx-runtime").JSX.Element)[];
6
+ export let argTypes: {};
7
+ }
8
+ export default _default;
@@ -1,4 +1,4 @@
1
- export function Order({ items, onMoveBlock, onDeleteBlock, onSelectBlock, indentationWidth, removable, dndKitCore, dndKitSortable, dndKitUtilities, }: {
1
+ export function Order({ items, onMoveBlock, onDeleteBlock, onSelectBlock, indentationWidth, removable, dndKitCore, dndKitSortable, dndKitUtilities, errors, }: {
2
2
  items?: any[];
3
3
  onMoveBlock: any;
4
4
  onDeleteBlock: any;
@@ -8,6 +8,7 @@ export function Order({ items, onMoveBlock, onDeleteBlock, onSelectBlock, indent
8
8
  dndKitCore: any;
9
9
  dndKitSortable: any;
10
10
  dndKitUtilities: any;
11
+ errors: any;
11
12
  }): import("react/jsx-runtime").JSX.Element;
12
13
  declare const _default: any;
13
14
  export default _default;
@@ -1,5 +1,14 @@
1
- declare const _default: React.FC<import("react-intl").WithIntlProps<any>> & {
2
- WrappedComponent: React.ComponentType<any>;
3
- };
4
- export default _default;
5
- import React from 'react';
1
+ export default Edit;
2
+ declare function Edit(props: any): import("react/jsx-runtime").JSX.Element;
3
+ declare namespace Edit {
4
+ namespace propTypes {
5
+ let properties: any;
6
+ let selected: any;
7
+ let block: any;
8
+ let index: any;
9
+ let data: any;
10
+ let pathname: any;
11
+ let onChangeBlock: any;
12
+ let openObjectBrowser: any;
13
+ }
14
+ }