@plone/volto 18.32.1 → 18.32.3

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 (167) hide show
  1. package/.eslintignore +1 -0
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +0 -4
  4. package/locales/af/LC_MESSAGES/volto.po +20 -0
  5. package/locales/af.json +1 -1
  6. package/locales/ar/LC_MESSAGES/volto.po +20 -0
  7. package/locales/ar.json +1 -1
  8. package/locales/bg/LC_MESSAGES/volto.po +20 -0
  9. package/locales/bg.json +1 -1
  10. package/locales/bn/LC_MESSAGES/volto.po +20 -0
  11. package/locales/bn.json +1 -1
  12. package/locales/ca/LC_MESSAGES/volto.po +20 -0
  13. package/locales/ca.json +1 -1
  14. package/locales/cs/LC_MESSAGES/volto.po +20 -0
  15. package/locales/cs.json +1 -1
  16. package/locales/cy/LC_MESSAGES/volto.po +20 -0
  17. package/locales/cy.json +1 -1
  18. package/locales/da/LC_MESSAGES/volto.po +20 -0
  19. package/locales/da.json +1 -1
  20. package/locales/de/LC_MESSAGES/volto.po +20 -0
  21. package/locales/de.json +1 -1
  22. package/locales/el/LC_MESSAGES/volto.po +20 -0
  23. package/locales/el.json +1 -1
  24. package/locales/en/LC_MESSAGES/volto.po +20 -0
  25. package/locales/en.json +1 -1
  26. package/locales/en_AU/LC_MESSAGES/volto.po +20 -0
  27. package/locales/en_AU.json +1 -1
  28. package/locales/en_GB/LC_MESSAGES/volto.po +20 -0
  29. package/locales/en_GB.json +1 -1
  30. package/locales/eo/LC_MESSAGES/volto.po +20 -0
  31. package/locales/eo.json +1 -1
  32. package/locales/es/LC_MESSAGES/volto.po +20 -0
  33. package/locales/es.json +1 -1
  34. package/locales/et/LC_MESSAGES/volto.po +20 -0
  35. package/locales/et.json +1 -1
  36. package/locales/eu/LC_MESSAGES/volto.po +20 -0
  37. package/locales/eu.json +1 -1
  38. package/locales/fa/LC_MESSAGES/volto.po +20 -0
  39. package/locales/fa.json +1 -1
  40. package/locales/fi/LC_MESSAGES/volto.po +20 -0
  41. package/locales/fi.json +1 -1
  42. package/locales/fr/LC_MESSAGES/volto.po +20 -0
  43. package/locales/fr.json +1 -1
  44. package/locales/fu/LC_MESSAGES/volto.po +20 -0
  45. package/locales/fu.json +1 -1
  46. package/locales/gl/LC_MESSAGES/volto.po +20 -0
  47. package/locales/gl.json +1 -1
  48. package/locales/he/LC_MESSAGES/volto.po +20 -0
  49. package/locales/he.json +1 -1
  50. package/locales/hi/LC_MESSAGES/volto.po +20 -0
  51. package/locales/hi.json +1 -1
  52. package/locales/hr/LC_MESSAGES/volto.po +20 -0
  53. package/locales/hr.json +1 -1
  54. package/locales/hu/LC_MESSAGES/volto.po +20 -0
  55. package/locales/hu.json +1 -1
  56. package/locales/hy/LC_MESSAGES/volto.po +20 -0
  57. package/locales/hy.json +1 -1
  58. package/locales/id/LC_MESSAGES/volto.po +20 -0
  59. package/locales/id.json +1 -1
  60. package/locales/it/LC_MESSAGES/volto.po +31 -11
  61. package/locales/it.json +1 -1
  62. package/locales/ja/LC_MESSAGES/volto.po +20 -0
  63. package/locales/ja.json +1 -1
  64. package/locales/ka/LC_MESSAGES/volto.po +20 -0
  65. package/locales/ka.json +1 -1
  66. package/locales/kn/LC_MESSAGES/volto.po +20 -0
  67. package/locales/kn.json +1 -1
  68. package/locales/ko/LC_MESSAGES/volto.po +20 -0
  69. package/locales/ko.json +1 -1
  70. package/locales/lt/LC_MESSAGES/volto.po +20 -0
  71. package/locales/lt.json +1 -1
  72. package/locales/lv/LC_MESSAGES/volto.po +20 -0
  73. package/locales/lv.json +1 -1
  74. package/locales/mi/LC_MESSAGES/volto.po +20 -0
  75. package/locales/mi.json +1 -1
  76. package/locales/mk/LC_MESSAGES/volto.po +20 -0
  77. package/locales/mk.json +1 -1
  78. package/locales/my/LC_MESSAGES/volto.po +20 -0
  79. package/locales/my.json +1 -1
  80. package/locales/nb_NO/LC_MESSAGES/volto.po +20 -0
  81. package/locales/nb_NO.json +1 -1
  82. package/locales/nl/LC_MESSAGES/volto.po +20 -0
  83. package/locales/nl.json +1 -1
  84. package/locales/nn/LC_MESSAGES/volto.po +20 -0
  85. package/locales/nn.json +1 -1
  86. package/locales/pl/LC_MESSAGES/volto.po +20 -0
  87. package/locales/pl.json +1 -1
  88. package/locales/pt/LC_MESSAGES/volto.po +20 -0
  89. package/locales/pt.json +1 -1
  90. package/locales/pt_BR/LC_MESSAGES/volto.po +20 -0
  91. package/locales/pt_BR.json +1 -1
  92. package/locales/rm/LC_MESSAGES/volto.po +20 -0
  93. package/locales/rm.json +1 -1
  94. package/locales/ro/LC_MESSAGES/volto.po +20 -0
  95. package/locales/ro.json +1 -1
  96. package/locales/ru/LC_MESSAGES/volto.po +20 -0
  97. package/locales/ru.json +1 -1
  98. package/locales/sk/LC_MESSAGES/volto.po +20 -0
  99. package/locales/sk.json +1 -1
  100. package/locales/sl/LC_MESSAGES/volto.po +20 -0
  101. package/locales/sl.json +1 -1
  102. package/locales/sm/LC_MESSAGES/volto.po +20 -0
  103. package/locales/sm.json +1 -1
  104. package/locales/sq/LC_MESSAGES/volto.po +20 -0
  105. package/locales/sq.json +1 -1
  106. package/locales/sr/LC_MESSAGES/volto.po +20 -0
  107. package/locales/sr.json +1 -1
  108. package/locales/sr@cyrl/LC_MESSAGES/volto.po +20 -0
  109. package/locales/sr@cyrl.json +1 -1
  110. package/locales/sr@latn/LC_MESSAGES/volto.po +20 -0
  111. package/locales/sr@latn.json +1 -1
  112. package/locales/sv/LC_MESSAGES/volto.po +20 -0
  113. package/locales/sv.json +1 -1
  114. package/locales/ta/LC_MESSAGES/volto.po +20 -0
  115. package/locales/ta.json +1 -1
  116. package/locales/te/LC_MESSAGES/volto.po +20 -0
  117. package/locales/te.json +1 -1
  118. package/locales/th/LC_MESSAGES/volto.po +20 -0
  119. package/locales/th.json +1 -1
  120. package/locales/to/LC_MESSAGES/volto.po +20 -0
  121. package/locales/to.json +1 -1
  122. package/locales/tr/LC_MESSAGES/volto.po +20 -0
  123. package/locales/tr.json +1 -1
  124. package/locales/uk/LC_MESSAGES/volto.po +20 -0
  125. package/locales/uk.json +1 -1
  126. package/locales/vi/LC_MESSAGES/volto.po +20 -0
  127. package/locales/vi.json +1 -1
  128. package/locales/volto.pot +21 -1
  129. package/locales/zh_CN/LC_MESSAGES/volto.po +20 -0
  130. package/locales/zh_CN.json +1 -1
  131. package/locales/zh_Hant/LC_MESSAGES/volto.po +20 -0
  132. package/locales/zh_Hant.json +1 -1
  133. package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +20 -0
  134. package/locales/zh_Hant_HK.json +1 -1
  135. package/package.json +6 -5
  136. package/src/components/manage/Blocks/Block/BlocksForm.jsx +10 -7
  137. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +2 -9
  138. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +10 -1
  139. package/src/components/manage/Blocks/Block/Order/Item.jsx +9 -3
  140. package/src/components/manage/Blocks/Block/Order/Order.jsx +116 -67
  141. package/src/components/manage/Blocks/Block/Order/utilities.js +28 -11
  142. package/src/components/manage/Blocks/Listing/Edit.jsx +1 -0
  143. package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -1
  144. package/src/components/manage/Sharing/Sharing.jsx +10 -12
  145. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +5 -1
  146. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +16 -0
  147. package/src/components/manage/UniversalLink/UniversalLink.tsx +1 -0
  148. package/src/components/theme/App/App.jsx +3 -1
  149. package/src/components/theme/ConnectionRefused/ConnectionRefused.jsx +3 -2
  150. package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
  151. package/src/components/theme/View/RenderBlocks.jsx +8 -10
  152. package/src/components/theme/View/RenderBlocks.test.jsx +14 -4
  153. package/src/config/index.js +1 -1
  154. package/src/config/validation.ts +8 -0
  155. package/src/helpers/Blocks/Blocks.js +109 -24
  156. package/src/helpers/Blocks/Blocks.test.js +100 -0
  157. package/src/helpers/FormValidation/FormValidation.test.js +47 -0
  158. package/src/helpers/FormValidation/validators.ts +37 -4
  159. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  160. package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
  161. package/types/components/theme/ConnectionRefused/ConnectionRefused.d.ts +2 -2
  162. package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
  163. package/types/config/Views.d.ts +1 -1
  164. package/types/helpers/Blocks/Blocks.d.ts +4 -0
  165. package/types/helpers/FormValidation/validators.d.ts +18 -1
  166. package/types/helpers/MessageLabels/MessageLabels.d.ts +100 -94
  167. package/types/routes.d.ts +7 -5
@@ -161,19 +161,12 @@ test('Removes invalid blocks on saving', () => {
161
161
  </Provider>,
162
162
  );
163
163
 
164
+ expect(onChangeFormData).toHaveBeenCalledTimes(1);
164
165
  expect(onChangeFormData).toHaveBeenCalledWith({
165
166
  blocks: {
166
167
  a: { '@type': 'custom', text: 'a' },
167
168
  b: { '@type': 'custom', text: 'b' },
168
169
  },
169
- blocks_layout: { items: ['a', 'b', 'MISSING-YOU-1'] },
170
- });
171
-
172
- expect(onChangeFormData).toHaveBeenCalledWith({
173
- blocks: {
174
- a: { '@type': 'custom', text: 'a' },
175
- b: { '@type': 'custom', text: 'b' },
176
- },
177
- blocks_layout: { items: ['a', 'b', 'MISSING-YOU-2'] },
170
+ blocks_layout: { items: ['a', 'b'] },
178
171
  });
179
172
  });
@@ -25,6 +25,14 @@ const messages = defineMessages({
25
25
  id: 'delete',
26
26
  defaultMessage: 'delete',
27
27
  },
28
+ delete_block: {
29
+ id: 'delete_block',
30
+ defaultMessage: 'delete {type} block',
31
+ },
32
+ drag_block: {
33
+ id: 'drag_block',
34
+ defaultMessage: 'drag {type} block',
35
+ },
28
36
  });
29
37
 
30
38
  const EditBlockWrapper = (props) => {
@@ -99,6 +107,7 @@ const EditBlockWrapper = (props) => {
99
107
  }}
100
108
  {...draginfo.dragHandleProps}
101
109
  className="drag handle wrapper"
110
+ aria-label={intl.formatMessage(messages.drag_block, { type })}
102
111
  >
103
112
  <Icon name={dragSVG} size="18px" />
104
113
  </div>
@@ -111,7 +120,7 @@ const EditBlockWrapper = (props) => {
111
120
  basic
112
121
  onClick={() => onDeleteBlock(block, true)}
113
122
  className="delete-button"
114
- aria-label={intl.formatMessage(messages.delete)}
123
+ aria-label={intl.formatMessage(messages.delete_block, { type })}
115
124
  >
116
125
  <Icon name={trashSVG} size="18px" />
117
126
  </Button>
@@ -25,6 +25,7 @@ export const Item = forwardRef(
25
25
  onRemove,
26
26
  onSelectBlock,
27
27
  parentId,
28
+ parentType,
28
29
  style,
29
30
  value,
30
31
  wrapperRef,
@@ -39,6 +40,10 @@ export const Item = forwardRef(
39
40
  const gridSelected = useSelector((state) => state.form.ui.gridSelected);
40
41
  const dispatch = useDispatch();
41
42
 
43
+ const icon =
44
+ config.blocks.blocksConfig[data?.['@type']]?.icon ||
45
+ config.blocks.blocksConfig.title?.icon;
46
+
42
47
  return (
43
48
  <li
44
49
  className={classNames(
@@ -102,15 +107,16 @@ export const Item = forwardRef(
102
107
  errored: errors && Object.keys(errors).length > 0,
103
108
  })}
104
109
  >
105
- {config.blocks.blocksConfig[data?.['@type']]?.icon && (
110
+ {icon && (
106
111
  <Icon
107
- name={config.blocks.blocksConfig[data?.['@type']]?.icon}
112
+ name={icon}
108
113
  size="20px"
109
114
  style={{ verticalAlign: 'middle' }}
110
115
  />
111
116
  )}{' '}
112
117
  {data?.plaintext ||
113
- config.blocks.blocksConfig[data?.['@type']]?.title}
118
+ config.blocks.blocksConfig[data?.['@type']]?.title ||
119
+ data?.title}
114
120
  </span>
115
121
  {!clone && onRemove && (
116
122
  <button
@@ -1,13 +1,23 @@
1
1
  import React, { useEffect, useMemo, useRef, useState } from 'react';
2
+ import { defineMessages, useIntl } from 'react-intl';
2
3
  import { createPortal } from 'react-dom';
4
+ import { toast } from 'react-toastify';
5
+ import Toast from '@plone/volto/components/manage/Toast/Toast';
3
6
  import find from 'lodash/find';
4
- import min from 'lodash/min';
7
+ import { messages as defaultMessages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
5
8
 
6
9
  import { flattenTree, getProjection, removeChildrenOf } from './utilities';
7
10
  import SortableItem from './SortableItem';
8
11
 
9
12
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
10
13
 
14
+ const messages = defineMessages({
15
+ invalidBlockType: {
16
+ id: 'You can not move this type of block to the new location',
17
+ defaultMessage: 'You can not move this type of block to the new location',
18
+ },
19
+ });
20
+
11
21
  export function Order({
12
22
  items = [],
13
23
  onMoveBlock,
@@ -24,6 +34,7 @@ export function Order({
24
34
  const [overId, setOverId] = useState(null);
25
35
  const [offsetLeft, setOffsetLeft] = useState(0);
26
36
  const [currentPosition, setCurrentPosition] = useState(null);
37
+ const intl = useIntl();
27
38
 
28
39
  const {
29
40
  DndContext,
@@ -72,6 +83,7 @@ export function Order({
72
83
  () => removeChildrenOf(flattenTree(items), activeId ? [activeId] : []),
73
84
  [activeId, items],
74
85
  );
86
+
75
87
  const projected =
76
88
  activeId && overId
77
89
  ? getProjection(
@@ -135,16 +147,14 @@ export function Order({
135
147
  onDragCancel={handleDragCancel}
136
148
  >
137
149
  <SortableContext items={sortedIds} strategy={verticalListSortingStrategy}>
138
- {flattenedItems.map(({ id, parentId, depth, data }) => (
150
+ {flattenedItems.map(({ id, parentId, parentType, depth, data }) => (
139
151
  <SortableItem
140
152
  key={id}
141
153
  id={id}
142
154
  parentId={parentId}
155
+ parentType={parentType}
143
156
  data={data}
144
- depth={min([
145
- id === activeId && projected ? projected.depth : depth,
146
- 1,
147
- ])}
157
+ depth={id === activeId && projected ? projected.depth : depth}
148
158
  indentationWidth={indentationWidth}
149
159
  onRemove={removable ? () => handleRemove(id) : undefined}
150
160
  onSelectBlock={onSelectBlock}
@@ -178,6 +188,7 @@ export function Order({
178
188
  if (activeItem) {
179
189
  setCurrentPosition({
180
190
  parentId: activeItem.parentId,
191
+ parentType: activeItem.parentType,
181
192
  overId: activeId,
182
193
  });
183
194
  }
@@ -195,18 +206,24 @@ export function Order({
195
206
 
196
207
  function handleDragEnd({ active, over }) {
197
208
  if (projected && over) {
198
- const { depth, parentId } = projected;
209
+ const { depth, parentId, parentType } = projected;
199
210
  const clonedItems = JSON.parse(JSON.stringify(flattenedItems));
200
211
  const overIndex = clonedItems.findIndex(({ id }) => id === over.id);
201
212
  const activeIndex = clonedItems.findIndex(({ id }) => id === active.id);
202
213
  const activeTreeItem = clonedItems[activeIndex];
203
214
  const oldParentId = activeTreeItem.parentId;
215
+ const oldParentType = activeTreeItem.parentType;
204
216
 
205
- clonedItems[activeIndex] = { ...activeTreeItem, depth, parentId };
217
+ clonedItems[activeIndex] = {
218
+ ...activeTreeItem,
219
+ depth,
220
+ parentId,
221
+ parentType,
222
+ };
206
223
 
207
224
  // Translate position depending on parent
208
225
  if (parentId === oldParentId) {
209
- // Move from and to toplevel or move within the same grid block
226
+ // Move from and to toplevel or move within the same sub block
210
227
 
211
228
  let destIndex = clonedItems[overIndex].index;
212
229
  if (clonedItems[overIndex].depth > clonedItems[activeIndex].depth) {
@@ -226,66 +243,97 @@ export function Order({
226
243
  },
227
244
  });
228
245
  } else if (parentId && oldParentId) {
229
- // Move from one gridblock to another
230
-
231
- onMoveBlock({
232
- source: {
233
- position: clonedItems[activeIndex].index,
234
- parent: oldParentId,
235
- id: active.id,
236
- },
237
- destination: {
238
- position:
239
- overIndex < activeIndex
240
- ? clonedItems[overIndex - 1].parentId
241
- ? clonedItems[overIndex - 1].index + 1
242
- : clonedItems[overIndex].index
243
- : overIndex + 1 < clonedItems.length
244
- ? clonedItems[overIndex + 1].index
245
- : clonedItems[overIndex].index + 1,
246
- parent: parentId,
247
- },
248
- });
246
+ // Move from one subblock to another
247
+
248
+ if (parentType === oldParentType) {
249
+ // Moving within the same type of subblock
250
+ onMoveBlock({
251
+ source: {
252
+ position: clonedItems[activeIndex].index,
253
+ parent: oldParentId,
254
+ id: active.id,
255
+ },
256
+ destination: {
257
+ position:
258
+ overIndex < activeIndex
259
+ ? clonedItems[overIndex - 1].parentId
260
+ ? clonedItems[overIndex - 1].index + 1
261
+ : clonedItems[overIndex].index
262
+ : overIndex + 1 < clonedItems.length
263
+ ? clonedItems[overIndex + 1].index
264
+ : clonedItems[overIndex].index + 1,
265
+ parent: parentId,
266
+ },
267
+ });
268
+ } else {
269
+ toast.error(
270
+ <Toast
271
+ error
272
+ title={intl.formatMessage(defaultMessages.error)}
273
+ content={intl.formatMessage(messages.invalidBlockType)}
274
+ />,
275
+ );
276
+ }
249
277
  } else if (oldParentId) {
250
- // Moving to the main container from a gridblock
251
-
252
- onMoveBlock({
253
- source: {
254
- position: clonedItems[activeIndex].index,
255
- parent: oldParentId,
256
- id: active.id,
257
- },
258
- destination: {
259
- position:
260
- overIndex > activeIndex
261
- ? overIndex + 1 < clonedItems.length
262
- ? clonedItems[overIndex + 1].index
263
- : clonedItems[overIndex].index + 1
264
- : clonedItems[overIndex].index,
265
- parent: parentId,
266
- },
267
- });
278
+ // Moving to the main container from a subblock
279
+
280
+ if (oldParentType === 'gridBlock') {
281
+ onMoveBlock({
282
+ source: {
283
+ position: clonedItems[activeIndex].index,
284
+ parent: oldParentId,
285
+ id: active.id,
286
+ },
287
+ destination: {
288
+ position:
289
+ overIndex > activeIndex
290
+ ? overIndex + 1 < clonedItems.length
291
+ ? clonedItems[overIndex + 1].index
292
+ : clonedItems[overIndex].index + 1
293
+ : clonedItems[overIndex].index,
294
+ parent: parentId,
295
+ },
296
+ });
297
+ } else {
298
+ toast.error(
299
+ <Toast
300
+ error
301
+ title={intl.formatMessage(defaultMessages.error)}
302
+ content={intl.formatMessage(messages.invalidBlockType)}
303
+ />,
304
+ );
305
+ }
268
306
  } else {
269
- // Moving from the main container to a gridblock
270
-
271
- onMoveBlock({
272
- source: {
273
- position: clonedItems[activeIndex].index,
274
- parent: oldParentId,
275
- id: active.id,
276
- },
277
- destination: {
278
- position:
279
- overIndex < activeIndex
280
- ? clonedItems[overIndex - 1].parentId
281
- ? clonedItems[overIndex - 1].index + 1
282
- : clonedItems[overIndex].index
283
- : overIndex + 1 < clonedItems.length
284
- ? clonedItems[overIndex + 1].index
285
- : clonedItems[overIndex].index + 1,
286
- parent: parentId,
287
- },
288
- });
307
+ // Moving from the main container to a subblock
308
+
309
+ if (parentType === 'gridBlock') {
310
+ onMoveBlock({
311
+ source: {
312
+ position: clonedItems[activeIndex].index,
313
+ parent: oldParentId,
314
+ id: active.id,
315
+ },
316
+ destination: {
317
+ position:
318
+ overIndex < activeIndex
319
+ ? clonedItems[overIndex - 1].parentId
320
+ ? clonedItems[overIndex - 1].index + 1
321
+ : clonedItems[overIndex].index
322
+ : overIndex + 1 < clonedItems.length
323
+ ? clonedItems[overIndex + 1].index
324
+ : clonedItems[overIndex].index + 1,
325
+ parent: parentId,
326
+ },
327
+ });
328
+ } else {
329
+ toast.error(
330
+ <Toast
331
+ error
332
+ title={intl.formatMessage(defaultMessages.error)}
333
+ content={intl.formatMessage(messages.invalidBlockType)}
334
+ />,
335
+ );
336
+ }
289
337
  }
290
338
  }
291
339
 
@@ -321,6 +369,7 @@ export function Order({
321
369
  } else {
322
370
  setCurrentPosition({
323
371
  parentId: projected.parentId,
372
+ parentType: projected.parentType,
324
373
  overId,
325
374
  });
326
375
  }
@@ -34,27 +34,44 @@ export function getProjection(
34
34
  depth = minDepth;
35
35
  }
36
36
 
37
- return { depth, maxDepth, minDepth, parentId: getParentId() };
37
+ return { depth, maxDepth, minDepth, ...getParent() };
38
38
 
39
- function getParentId() {
39
+ function getParent() {
40
40
  if (depth === 0 || !previousItem) {
41
- return null;
41
+ return {
42
+ parentId: null,
43
+ parentType: null,
44
+ };
42
45
  }
43
46
 
44
47
  if (depth <= previousItem.depth) {
45
- return previousItem.parentId;
48
+ return {
49
+ parentId: previousItem.parentId,
50
+ parentType: previousItem.parentType,
51
+ };
46
52
  }
47
53
 
48
54
  if (depth > previousItem.depth) {
49
- return previousItem.id;
55
+ return {
56
+ parentId: previousItem.id,
57
+ parentType: previousItem.data?.['@type'] || null,
58
+ };
50
59
  }
51
60
 
52
61
  const newParent = newItems
53
62
  .slice(0, overItemIndex)
54
63
  .reverse()
55
- .find((item) => item.depth === depth)?.parentId;
56
-
57
- return newParent ?? null;
64
+ .find((item) => item.depth === depth);
65
+
66
+ return newParent
67
+ ? {
68
+ parentId: newParent.parentId,
69
+ parentType: newParent.parentType,
70
+ }
71
+ : {
72
+ parentId: null,
73
+ parentType: null,
74
+ };
58
75
  }
59
76
  }
60
77
 
@@ -79,12 +96,12 @@ function getMinDepth({ nextItem }) {
79
96
  return 0;
80
97
  }
81
98
 
82
- function flatten(items = [], parentId = null, depth = 0) {
99
+ function flatten(items = [], parentId = null, parentType = null, depth = 0) {
83
100
  return items.reduce((acc, item, index) => {
84
101
  return [
85
102
  ...acc,
86
- { ...item, parentId, depth, index },
87
- ...flatten(item.children, item.id, depth + 1),
103
+ { ...item, parentId, parentType, depth, index },
104
+ ...flatten(item.children, item.id, item.data?.['@type'], depth + 1),
88
105
  ];
89
106
  }, []);
90
107
  }
@@ -50,6 +50,7 @@ const Edit = React.memo(
50
50
  function areEquals(prevProps, nextProps) {
51
51
  return !(
52
52
  nextProps.selected !== prevProps.selected ||
53
+ nextProps.index !== prevProps.index ||
53
54
  !isEqual(prevProps.data, nextProps.data)
54
55
  );
55
56
  },
@@ -169,7 +169,7 @@ class ContentTypeSchema extends Component {
169
169
  error
170
170
  title={this.props.intl.formatMessage(messages.error)}
171
171
  content={JSON.stringify(
172
- nextProps.schemaRequest.put.error.response.body ||
172
+ nextProps.schemaRequest.put.error.response.body?.message ||
173
173
  nextProps.schemaRequest.put.error.response.text,
174
174
  )}
175
175
  />,
@@ -485,11 +485,19 @@ class SharingComponent extends Component {
485
485
  />
486
486
  </p>
487
487
  </Segment>
488
- <Segment className="actions" attached clearing>
488
+ <Segment className="right aligned actions" attached clearing>
489
+ <Button
490
+ basic
491
+ secondary
492
+ aria-label={this.props.intl.formatMessage(messages.cancel)}
493
+ title={this.props.intl.formatMessage(messages.cancel)}
494
+ onClick={this.onCancel}
495
+ >
496
+ <Icon className="circled" name={clearSVG} size="30px" />
497
+ </Button>
489
498
  <Button
490
499
  basic
491
500
  primary
492
- floated="right"
493
501
  type="submit"
494
502
  aria-label={this.props.intl.formatMessage(messages.save)}
495
503
  title={this.props.intl.formatMessage(messages.save)}
@@ -498,16 +506,6 @@ class SharingComponent extends Component {
498
506
  >
499
507
  <Icon className="circled" name={aheadSVG} size="30px" />
500
508
  </Button>
501
- <Button
502
- basic
503
- secondary
504
- aria-label={this.props.intl.formatMessage(messages.cancel)}
505
- title={this.props.intl.formatMessage(messages.cancel)}
506
- floated="right"
507
- onClick={this.onCancel}
508
- >
509
- <Icon className="circled" name={clearSVG} size="30px" />
510
- </Button>
511
509
  </Segment>
512
510
  </Form>
513
511
  </Plug>
@@ -144,10 +144,14 @@ class ObjectBrowserBody extends Component {
144
144
  showSearchInput: false,
145
145
  // In image mode, the searchable types default to the image types which
146
146
  // can be overridden with the property if specified.
147
+ // If selectableTypes are passed, the searchableTypes are the selectableTypes
147
148
  searchableTypes:
148
149
  this.props.mode === 'image'
149
150
  ? this.props.searchableTypes || config.settings.imageObjects
150
- : this.props.searchableTypes,
151
+ : [
152
+ ...(this.props.searchableTypes ?? []),
153
+ ...(this.props.selectableTypes ?? []),
154
+ ],
151
155
  view: this.props.mode === 'image' ? 'icons' : 'list',
152
156
  };
153
157
  this.searchInputRef = React.createRef();
@@ -89,6 +89,22 @@ describe('UniversalLink', () => {
89
89
  );
90
90
  });
91
91
 
92
+ it('check UniversalLink append http when user has not entered the protocol', () => {
93
+ const { getByTitle } = render(
94
+ <Provider store={store}>
95
+ <MemoryRouter>
96
+ <UniversalLink href="www.github.com" title="Volto GitHub repository">
97
+ <h1>Title</h1>
98
+ </UniversalLink>
99
+ </MemoryRouter>
100
+ </Provider>,
101
+ );
102
+
103
+ expect(getByTitle('Volto GitHub repository').getAttribute('href')).toBe(
104
+ 'http://www.github.com',
105
+ );
106
+ });
107
+
92
108
  it('check UniversalLink set target attribute for ext links', () => {
93
109
  const { getByTitle } = render(
94
110
  <Provider store={store}>
@@ -122,6 +122,7 @@ const UniversalLink = React.memo(
122
122
  onClick,
123
123
  onKeyDown,
124
124
  item,
125
+ href,
125
126
  ...rest
126
127
  } = props;
127
128
  __test.renderCounter();
@@ -174,7 +174,9 @@ export class App extends Component {
174
174
  <main ref={this.mainRef}>
175
175
  <OutdatedBrowser />
176
176
  {this.props.connectionRefused ? (
177
- <ConnectionRefusedView />
177
+ <ConnectionRefusedView
178
+ staticContext={this.props.staticContext}
179
+ />
178
180
  ) : this.state.hasError ? (
179
181
  <Error
180
182
  message={this.state.error.message}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Home container.
2
+ * Connection refused error page.
3
3
  * @module components/theme/ConnectionRefused/ConnectionRefused
4
4
  */
5
5
 
@@ -7,6 +7,7 @@ import React from 'react';
7
7
  import { FormattedMessage } from 'react-intl';
8
8
  import { Container } from 'semantic-ui-react';
9
9
  import config from '@plone/volto/registry';
10
+ import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
10
11
 
11
12
  const ConnectionRefused = () => (
12
13
  <Container
@@ -71,4 +72,4 @@ const ConnectionRefused = () => (
71
72
  </Container>
72
73
  );
73
74
 
74
- export default ConnectionRefused;
75
+ export default withServerErrorCode(503)(ConnectionRefused);