@plone/volto 19.0.0-alpha.26 → 19.0.0-alpha.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.eslintrc +0 -3
- package/CHANGELOG.md +69 -0
- package/README.md +0 -1
- package/babel.js +0 -6
- package/locales/af/LC_MESSAGES/volto.po +5455 -0
- package/locales/af.json +1 -1
- package/locales/ar/LC_MESSAGES/volto.po +5455 -0
- package/locales/ar.json +1 -1
- package/locales/bg/LC_MESSAGES/volto.po +5455 -0
- package/locales/bg.json +1 -1
- package/locales/bn/LC_MESSAGES/volto.po +5455 -0
- package/locales/bn.json +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +406 -345
- package/locales/ca.json +1 -1
- package/locales/cs/LC_MESSAGES/volto.po +5455 -0
- package/locales/cs.json +1 -1
- package/locales/cy/LC_MESSAGES/volto.po +5455 -0
- package/locales/cy.json +1 -1
- package/locales/da/LC_MESSAGES/volto.po +5455 -0
- package/locales/da.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +70 -8
- package/locales/de.json +1 -1
- package/locales/el/LC_MESSAGES/volto.po +5455 -0
- package/locales/el.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +66 -0
- package/locales/en.json +1 -1
- package/locales/en_AU/LC_MESSAGES/volto.po +5455 -0
- package/locales/en_AU.json +1 -1
- package/locales/en_GB/LC_MESSAGES/volto.po +5455 -0
- package/locales/en_GB.json +1 -1
- package/locales/eo/LC_MESSAGES/volto.po +5455 -0
- package/locales/eo.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +173 -112
- package/locales/es.json +1 -1
- package/locales/et/LC_MESSAGES/volto.po +5455 -0
- package/locales/et.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +256 -195
- package/locales/eu.json +1 -1
- package/locales/fa/LC_MESSAGES/volto.po +5455 -0
- package/locales/fa.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +62 -1
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +61 -0
- package/locales/fr.json +1 -1
- package/locales/fu/LC_MESSAGES/volto.po +5455 -0
- package/locales/fu.json +1 -1
- package/locales/gl/LC_MESSAGES/volto.po +5456 -0
- package/locales/gl.json +1 -1
- package/locales/he/LC_MESSAGES/volto.po +5455 -0
- package/locales/he.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +66 -0
- package/locales/hi.json +1 -1
- package/locales/hr/LC_MESSAGES/volto.po +5455 -0
- package/locales/hr.json +1 -1
- package/locales/hu/LC_MESSAGES/volto.po +5455 -0
- package/locales/hu.json +1 -1
- package/locales/hy/LC_MESSAGES/volto.po +5455 -0
- package/locales/hy.json +1 -1
- package/locales/id/LC_MESSAGES/volto.po +5455 -0
- package/locales/id.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +90 -24
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +105 -43
- package/locales/ja.json +1 -1
- package/locales/ka/LC_MESSAGES/volto.po +5455 -0
- package/locales/ka.json +1 -1
- package/locales/kn/LC_MESSAGES/volto.po +5455 -0
- package/locales/kn.json +1 -1
- package/locales/ko/LC_MESSAGES/volto.po +5455 -0
- package/locales/ko.json +1 -1
- package/locales/lt/LC_MESSAGES/volto.po +5455 -0
- package/locales/lt.json +1 -1
- package/locales/lv/LC_MESSAGES/volto.po +5455 -0
- package/locales/lv.json +1 -1
- package/locales/mi/LC_MESSAGES/volto.po +5455 -0
- package/locales/mi.json +1 -1
- package/locales/mk/LC_MESSAGES/volto.po +5455 -0
- package/locales/mk.json +1 -1
- package/locales/my/LC_MESSAGES/volto.po +5455 -0
- package/locales/my.json +1 -1
- package/locales/nb_NO/LC_MESSAGES/volto.po +5455 -0
- package/locales/nb_NO.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +93 -31
- package/locales/nl.json +1 -1
- package/locales/nn/LC_MESSAGES/volto.po +5455 -0
- package/locales/nn.json +1 -1
- package/locales/pl/LC_MESSAGES/volto.po +5455 -0
- package/locales/pl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +723 -662
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +61 -0
- package/locales/pt_BR.json +1 -1
- package/locales/rm/LC_MESSAGES/volto.po +5455 -0
- package/locales/rm.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +61 -0
- package/locales/ro.json +1 -1
- package/locales/ru/LC_MESSAGES/volto.po +61 -0
- package/locales/ru.json +1 -1
- package/locales/sk/LC_MESSAGES/volto.po +5455 -0
- package/locales/sk.json +1 -1
- package/locales/sl/LC_MESSAGES/volto.po +5455 -0
- package/locales/sl.json +1 -1
- package/locales/sm/LC_MESSAGES/volto.po +5455 -0
- package/locales/sm.json +1 -1
- package/locales/sq/LC_MESSAGES/volto.po +5455 -0
- package/locales/sq.json +1 -1
- package/locales/sr/LC_MESSAGES/volto.po +5455 -0
- package/locales/sr.json +1 -1
- package/locales/sr@cyrl/LC_MESSAGES/volto.po +5455 -0
- package/locales/sr@cyrl.json +1 -1
- package/locales/sr@latn/LC_MESSAGES/volto.po +5455 -0
- package/locales/sr@latn.json +1 -1
- package/locales/sv/LC_MESSAGES/volto.po +5455 -0
- package/locales/sv.json +1 -1
- package/locales/ta/LC_MESSAGES/volto.po +5456 -0
- package/locales/ta.json +1 -1
- package/locales/te/LC_MESSAGES/volto.po +5455 -0
- package/locales/te.json +1 -1
- package/locales/th/LC_MESSAGES/volto.po +5455 -0
- package/locales/th.json +1 -1
- package/locales/to/LC_MESSAGES/volto.po +5455 -0
- package/locales/to.json +1 -1
- package/locales/tr/LC_MESSAGES/volto.po +5456 -0
- package/locales/tr.json +1 -1
- package/locales/uk/LC_MESSAGES/volto.po +5455 -0
- package/locales/uk.json +1 -1
- package/locales/vi/LC_MESSAGES/volto.po +5455 -0
- package/locales/vi.json +1 -1
- package/locales/volto.pot +62 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +62 -0
- package/locales/zh_CN.json +1 -1
- package/locales/zh_Hant/LC_MESSAGES/volto.po +5455 -0
- package/locales/zh_Hant.json +1 -1
- package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +5455 -0
- package/locales/zh_Hant_HK.json +1 -1
- package/package.json +19 -35
- package/razzle.config.js +12 -5
- package/src/actions/blockTypes/blockTypes.ts +24 -0
- package/src/components/manage/Add/Add.jsx +7 -6
- package/src/components/manage/Blocks/Block/Order/Item.jsx +9 -3
- package/src/components/manage/Blocks/Block/Order/Order.jsx +116 -67
- package/src/components/manage/Blocks/Block/Order/utilities.js +28 -11
- package/src/components/manage/Blocks/Listing/Edit.jsx +1 -0
- package/src/components/manage/Blocks/Title/Edit.jsx +5 -0
- package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +7 -0
- package/src/components/manage/Controlpanels/BlockType.tsx +166 -0
- package/src/components/manage/Controlpanels/BlockTypes.tsx +145 -0
- package/src/components/manage/Controlpanels/Controlpanels.jsx +28 -5
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +10 -0
- package/src/components/manage/Controlpanels/DatabaseInformation.jsx +9 -0
- package/src/components/manage/Controlpanels/ModerateComments.jsx +8 -0
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +4 -5
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +57 -11
- package/src/components/manage/Diff/Diff.jsx +201 -298
- package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -5
- package/src/components/manage/Multilingual/ManageTranslations.jsx +1 -1
- package/src/components/manage/Multilingual/TranslationObject.jsx +9 -6
- package/src/components/manage/Preferences/PersonalPreferences.jsx +8 -5
- package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +5 -1
- package/src/components/manage/Toolbar/Types.crash.test.jsx +48 -0
- package/src/components/manage/Widgets/FileWidget.jsx +7 -0
- package/src/components/manage/Widgets/RegistryImageWidget.jsx +1 -1
- package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
- package/src/config/ControlPanels.js +2 -0
- package/src/config/index.js +1 -1
- package/src/config/validation.ts +8 -0
- package/src/constants/ActionTypes.js +1 -0
- package/src/express-middleware/devproxy.js +3 -1
- package/src/helpers/Blocks/Blocks.js +81 -18
- package/src/helpers/FormValidation/FormValidation.test.js +31 -0
- package/src/helpers/FormValidation/validators.ts +21 -0
- package/src/helpers/MessageLabels/MessageLabels.js +5 -0
- package/src/helpers/Utils/Utils.jsx +17 -0
- package/src/helpers/Utils/Utils.test.jsx +39 -0
- package/src/middleware/api.js +7 -3
- package/src/reducers/blockTypes/blockTypes.js +38 -0
- package/src/reducers/index.js +2 -0
- package/src/reducers/users/users.js +1 -1
- package/src/routes.js +10 -0
- package/src/server.jsx +7 -5
- package/test-setup-globals.js +26 -0
- package/theme/themes/pastanaga/extras/block-types.less +17 -0
- package/theme/themes/pastanaga/extras/main.less +1 -2
- package/types/actions/blockTypes/blockTypes.d.ts +7 -0
- package/types/components/index.d.ts +1 -1
- package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
- package/types/components/manage/Controlpanels/BlockType.d.ts +7 -0
- package/types/components/manage/Controlpanels/BlockTypes.d.ts +7 -0
- package/types/components/manage/Diff/Diff.d.ts +7 -2
- package/types/components/manage/Toolbar/Types.crash.test.d.ts +1 -0
- package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
- package/types/config/ControlPanels.d.ts +1 -0
- package/types/constants/ActionTypes.d.ts +1 -0
- package/types/helpers/Blocks/Blocks.d.ts +3 -0
- package/types/helpers/FormValidation/validators.d.ts +7 -0
- package/types/helpers/MessageLabels/MessageLabels.d.ts +100 -94
- package/types/helpers/Utils/Utils.d.ts +1 -0
- package/types/reducers/blockTypes/blockTypes.d.ts +16 -0
- package/types/reducers/index.d.ts +2 -0
- package/types/routes.d.ts +7 -5
- package/vitest.config.mjs +84 -42
- package/webpack-plugins/webpack-less-plugin.js +1 -1
|
@@ -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
|
|
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={
|
|
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] = {
|
|
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
|
|
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
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
:
|
|
246
|
-
|
|
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
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
?
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
? clonedItems[overIndex - 1].
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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,
|
|
37
|
+
return { depth, maxDepth, minDepth, ...getParent() };
|
|
38
38
|
|
|
39
|
-
function
|
|
39
|
+
function getParent() {
|
|
40
40
|
if (depth === 0 || !previousItem) {
|
|
41
|
-
return
|
|
41
|
+
return {
|
|
42
|
+
parentId: null,
|
|
43
|
+
parentType: null,
|
|
44
|
+
};
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
if (depth <= previousItem.depth) {
|
|
45
|
-
return
|
|
48
|
+
return {
|
|
49
|
+
parentId: previousItem.parentId,
|
|
50
|
+
parentType: previousItem.parentType,
|
|
51
|
+
};
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
if (depth > previousItem.depth) {
|
|
49
|
-
return
|
|
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)
|
|
56
|
-
|
|
57
|
-
return newParent
|
|
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
|
}
|
|
@@ -17,6 +17,10 @@ const messages = defineMessages({
|
|
|
17
17
|
id: 'Type the title…',
|
|
18
18
|
defaultMessage: 'Type the title…',
|
|
19
19
|
},
|
|
20
|
+
editable_title: {
|
|
21
|
+
id: 'Content title',
|
|
22
|
+
defaultMessage: 'Content title',
|
|
23
|
+
},
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
function usePrevious(value) {
|
|
@@ -159,6 +163,7 @@ export const TitleBlockEdit = (props) => {
|
|
|
159
163
|
renderElement={renderElement}
|
|
160
164
|
onFocus={handleFocus}
|
|
161
165
|
aria-multiline="false"
|
|
166
|
+
aria-label={intl.formatMessage(messages.editable_title)}
|
|
162
167
|
></Editable>
|
|
163
168
|
</Slate>
|
|
164
169
|
);
|
|
@@ -27,6 +27,7 @@ import Helmet from '@plone/volto/helpers/Helmet/Helmet';
|
|
|
27
27
|
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
28
28
|
import Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
|
|
29
29
|
import Toast from '@plone/volto/components/manage/Toast/Toast';
|
|
30
|
+
import Error from '@plone/volto/components/theme/Error/Error';
|
|
30
31
|
import circleBottomSVG from '@plone/volto/icons/circle-bottom.svg';
|
|
31
32
|
import circleTopSVG from '@plone/volto/icons/circle-top.svg';
|
|
32
33
|
import backSVG from '@plone/volto/icons/back.svg';
|
|
@@ -148,6 +149,7 @@ const AddonsControlpanel = (props) => {
|
|
|
148
149
|
shallowEqual,
|
|
149
150
|
);
|
|
150
151
|
const loadingAddons = useSelector((state) => state.addons.loading);
|
|
152
|
+
const addonsError = useSelector((state) => state.addons.error);
|
|
151
153
|
|
|
152
154
|
useEffect(() => {
|
|
153
155
|
dispatch(listAddons());
|
|
@@ -245,6 +247,11 @@ const AddonsControlpanel = (props) => {
|
|
|
245
247
|
setactiveIndex(newIndex);
|
|
246
248
|
};
|
|
247
249
|
|
|
250
|
+
// Error handling for unauthorized access
|
|
251
|
+
if (addonsError) {
|
|
252
|
+
return <Error error={addonsError} />;
|
|
253
|
+
}
|
|
254
|
+
|
|
248
255
|
return (
|
|
249
256
|
<Container id="page-addons" className="controlpanel-addons">
|
|
250
257
|
<Helmet title={intl.formatMessage(messages.addOns)} />
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { getBlockTypes } from '@plone/volto/actions/blockTypes/blockTypes';
|
|
2
|
+
import Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
|
|
3
|
+
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
4
|
+
import { getParentUrl, flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
5
|
+
import { useClient } from '@plone/volto/hooks';
|
|
6
|
+
import config from '@plone/volto/registry';
|
|
7
|
+
import { useEffect } from 'react';
|
|
8
|
+
import { createPortal } from 'react-dom';
|
|
9
|
+
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
10
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
11
|
+
import { Link, useParams } from 'react-router-dom';
|
|
12
|
+
import Error from '@plone/volto/components/theme/Error/Error';
|
|
13
|
+
import { Table } from '@plone/components';
|
|
14
|
+
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
15
|
+
|
|
16
|
+
import backSVG from '@plone/volto/icons/back.svg';
|
|
17
|
+
import type { Location } from 'history';
|
|
18
|
+
import type { BlockTypeItem } from '@plone/types';
|
|
19
|
+
|
|
20
|
+
const messages = defineMessages({
|
|
21
|
+
back: {
|
|
22
|
+
id: 'Back',
|
|
23
|
+
defaultMessage: 'Back',
|
|
24
|
+
},
|
|
25
|
+
controlpanelTitle: {
|
|
26
|
+
id: 'controlpanel_block_type',
|
|
27
|
+
defaultMessage: 'Block: {title}',
|
|
28
|
+
},
|
|
29
|
+
item: {
|
|
30
|
+
id: 'Item',
|
|
31
|
+
defaultMessage: 'Item',
|
|
32
|
+
},
|
|
33
|
+
path: {
|
|
34
|
+
id: 'Path',
|
|
35
|
+
defaultMessage: 'Path',
|
|
36
|
+
},
|
|
37
|
+
occurrences: {
|
|
38
|
+
id: 'Occurrences',
|
|
39
|
+
defaultMessage: 'Occurrences',
|
|
40
|
+
},
|
|
41
|
+
loading: {
|
|
42
|
+
id: 'loading',
|
|
43
|
+
defaultMessage: 'Loading',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
type RouteProps = {
|
|
48
|
+
history: History;
|
|
49
|
+
location: Location;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type BlockTypesState = {
|
|
53
|
+
error: {
|
|
54
|
+
status?: number;
|
|
55
|
+
} | null;
|
|
56
|
+
items: BlockTypeItem[];
|
|
57
|
+
loaded: boolean;
|
|
58
|
+
loading: boolean;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type SelectorState = {
|
|
62
|
+
blockTypes: BlockTypesState;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const BlockTypeControlpanel = (props: RouteProps) => {
|
|
66
|
+
const { location } = props;
|
|
67
|
+
const params = useParams<{ id: string }>();
|
|
68
|
+
const id = params.id;
|
|
69
|
+
const intl = useIntl();
|
|
70
|
+
const blockTypes = useSelector((state: SelectorState) => state.blockTypes);
|
|
71
|
+
const isClient = useClient();
|
|
72
|
+
const dispatch = useDispatch();
|
|
73
|
+
const pathname = location.pathname;
|
|
74
|
+
const block =
|
|
75
|
+
config.blocks.blocksConfig[id as keyof typeof config.blocks.blocksConfig];
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
dispatch(getBlockTypes(id));
|
|
79
|
+
}, [dispatch, id]);
|
|
80
|
+
|
|
81
|
+
if (blockTypes.loading) {
|
|
82
|
+
return <div>{intl.formatMessage(messages.loading)}…</div>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (blockTypes?.error?.status) {
|
|
86
|
+
return <Error error={blockTypes.error} />;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const translatedTitle = block?.title
|
|
90
|
+
? intl.formatMessage({ id: block.title, defaultMessage: block.title })
|
|
91
|
+
: id;
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
blockTypes.loaded && (
|
|
95
|
+
<div
|
|
96
|
+
id="page-block_type"
|
|
97
|
+
className="ui container controlpanel-block-type"
|
|
98
|
+
>
|
|
99
|
+
<h1>
|
|
100
|
+
{intl.formatMessage(messages.controlpanelTitle, {
|
|
101
|
+
title: translatedTitle,
|
|
102
|
+
})}
|
|
103
|
+
</h1>
|
|
104
|
+
{blockTypes.items?.length > 0 ? (
|
|
105
|
+
<Table
|
|
106
|
+
className="react-aria-Table cmsui-table"
|
|
107
|
+
columns={[
|
|
108
|
+
{
|
|
109
|
+
id: 'title',
|
|
110
|
+
name: intl.formatMessage(messages.item),
|
|
111
|
+
isRowHeader: true,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'path',
|
|
115
|
+
name: intl.formatMessage(messages.path),
|
|
116
|
+
isRowHeader: true,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'occurrences',
|
|
120
|
+
name: intl.formatMessage(messages.occurrences),
|
|
121
|
+
isRowHeader: true,
|
|
122
|
+
},
|
|
123
|
+
]}
|
|
124
|
+
rows={blockTypes.items.map((item) => ({
|
|
125
|
+
id: item['@id'],
|
|
126
|
+
textValue: item.title,
|
|
127
|
+
title: (
|
|
128
|
+
<UniversalLink href={item['@id']}>{item.title}</UniversalLink>
|
|
129
|
+
),
|
|
130
|
+
path: flattenToAppURL(item['@id']) || '/',
|
|
131
|
+
occurrences: item.count,
|
|
132
|
+
}))}
|
|
133
|
+
/>
|
|
134
|
+
) : (
|
|
135
|
+
<FormattedMessage
|
|
136
|
+
id="no-blocks-found"
|
|
137
|
+
defaultMessage="No items found for type: {type}."
|
|
138
|
+
values={{
|
|
139
|
+
type: translatedTitle,
|
|
140
|
+
}}
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
{isClient &&
|
|
144
|
+
createPortal(
|
|
145
|
+
<Toolbar
|
|
146
|
+
pathname={pathname}
|
|
147
|
+
hideDefaultViewButtons
|
|
148
|
+
inner={
|
|
149
|
+
<Link to={getParentUrl(pathname)} className="item">
|
|
150
|
+
<Icon
|
|
151
|
+
name={backSVG}
|
|
152
|
+
className="contents circled"
|
|
153
|
+
size="30px"
|
|
154
|
+
title={intl.formatMessage(messages.back)}
|
|
155
|
+
/>
|
|
156
|
+
</Link>
|
|
157
|
+
}
|
|
158
|
+
/>,
|
|
159
|
+
document.getElementById('toolbar') as HTMLElement,
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
)
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export default BlockTypeControlpanel;
|