@plone/volto 18.32.3 → 18.33.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.
- package/CHANGELOG.md +48 -0
- package/locales/af/LC_MESSAGES/volto.po +10 -0
- package/locales/af.json +1 -1
- package/locales/ar/LC_MESSAGES/volto.po +10 -0
- package/locales/ar.json +1 -1
- package/locales/bg/LC_MESSAGES/volto.po +10 -0
- package/locales/bg.json +1 -1
- package/locales/bn/LC_MESSAGES/volto.po +10 -0
- package/locales/bn.json +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +10 -0
- package/locales/ca.json +1 -1
- package/locales/cs/LC_MESSAGES/volto.po +10 -0
- package/locales/cs.json +1 -1
- package/locales/cy/LC_MESSAGES/volto.po +10 -0
- package/locales/cy.json +1 -1
- package/locales/da/LC_MESSAGES/volto.po +10 -0
- package/locales/da.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +10 -0
- package/locales/de.json +1 -1
- package/locales/el/LC_MESSAGES/volto.po +10 -0
- package/locales/el.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +10 -0
- package/locales/en.json +1 -1
- package/locales/en_AU/LC_MESSAGES/volto.po +10 -0
- package/locales/en_AU.json +1 -1
- package/locales/en_GB/LC_MESSAGES/volto.po +10 -0
- package/locales/en_GB.json +1 -1
- package/locales/eo/LC_MESSAGES/volto.po +10 -0
- package/locales/eo.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +23 -13
- package/locales/es.json +1 -1
- package/locales/et/LC_MESSAGES/volto.po +10 -0
- package/locales/et.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +22 -12
- package/locales/eu.json +1 -1
- package/locales/fa/LC_MESSAGES/volto.po +10 -0
- package/locales/fa.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +10 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +10 -0
- package/locales/fr.json +1 -1
- package/locales/fu/LC_MESSAGES/volto.po +10 -0
- package/locales/fu.json +1 -1
- package/locales/gl/LC_MESSAGES/volto.po +1013 -1002
- package/locales/gl.json +1 -1
- package/locales/he/LC_MESSAGES/volto.po +10 -0
- package/locales/he.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +10 -0
- package/locales/hi.json +1 -1
- package/locales/hr/LC_MESSAGES/volto.po +10 -0
- package/locales/hr.json +1 -1
- package/locales/hu/LC_MESSAGES/volto.po +10 -0
- package/locales/hu.json +1 -1
- package/locales/hy/LC_MESSAGES/volto.po +10 -0
- package/locales/hy.json +1 -1
- package/locales/id/LC_MESSAGES/volto.po +10 -0
- package/locales/id.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +13 -3
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +10 -0
- package/locales/ja.json +1 -1
- package/locales/ka/LC_MESSAGES/volto.po +10 -0
- package/locales/ka.json +1 -1
- package/locales/kn/LC_MESSAGES/volto.po +10 -0
- package/locales/kn.json +1 -1
- package/locales/ko/LC_MESSAGES/volto.po +10 -0
- package/locales/ko.json +1 -1
- package/locales/lt/LC_MESSAGES/volto.po +10 -0
- package/locales/lt.json +1 -1
- package/locales/lv/LC_MESSAGES/volto.po +10 -0
- package/locales/lv.json +1 -1
- package/locales/mi/LC_MESSAGES/volto.po +10 -0
- package/locales/mi.json +1 -1
- package/locales/mk/LC_MESSAGES/volto.po +10 -0
- package/locales/mk.json +1 -1
- package/locales/my/LC_MESSAGES/volto.po +10 -0
- package/locales/my.json +1 -1
- package/locales/nb_NO/LC_MESSAGES/volto.po +10 -0
- package/locales/nb_NO.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +25 -15
- package/locales/nl.json +1 -1
- package/locales/nn/LC_MESSAGES/volto.po +10 -0
- package/locales/nn.json +1 -1
- package/locales/pl/LC_MESSAGES/volto.po +10 -0
- package/locales/pl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +10 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +10 -0
- package/locales/pt_BR.json +1 -1
- package/locales/rm/LC_MESSAGES/volto.po +10 -0
- package/locales/rm.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +10 -0
- package/locales/ro.json +1 -1
- package/locales/ru/LC_MESSAGES/volto.po +10 -0
- package/locales/ru.json +1 -1
- package/locales/sk/LC_MESSAGES/volto.po +10 -0
- package/locales/sk.json +1 -1
- package/locales/sl/LC_MESSAGES/volto.po +10 -0
- package/locales/sl.json +1 -1
- package/locales/sm/LC_MESSAGES/volto.po +10 -0
- package/locales/sm.json +1 -1
- package/locales/sq/LC_MESSAGES/volto.po +10 -0
- package/locales/sq.json +1 -1
- package/locales/sr/LC_MESSAGES/volto.po +10 -0
- package/locales/sr.json +1 -1
- package/locales/sr@cyrl/LC_MESSAGES/volto.po +10 -0
- package/locales/sr@cyrl.json +1 -1
- package/locales/sr@latn/LC_MESSAGES/volto.po +10 -0
- package/locales/sr@latn.json +1 -1
- package/locales/sv/LC_MESSAGES/volto.po +10 -0
- package/locales/sv.json +1 -1
- package/locales/ta/LC_MESSAGES/volto.po +10 -0
- package/locales/ta.json +1 -1
- package/locales/te/LC_MESSAGES/volto.po +10 -0
- package/locales/te.json +1 -1
- package/locales/th/LC_MESSAGES/volto.po +10 -0
- package/locales/th.json +1 -1
- package/locales/to/LC_MESSAGES/volto.po +10 -0
- package/locales/to.json +1 -1
- package/locales/tr/LC_MESSAGES/volto.po +35 -25
- package/locales/tr.json +1 -1
- package/locales/uk/LC_MESSAGES/volto.po +10 -0
- package/locales/uk.json +1 -1
- package/locales/vi/LC_MESSAGES/volto.po +10 -0
- package/locales/vi.json +1 -1
- package/locales/volto.pot +11 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +10 -0
- package/locales/zh_CN.json +1 -1
- package/locales/zh_Hant/LC_MESSAGES/volto.po +10 -0
- package/locales/zh_Hant.json +1 -1
- package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +10 -0
- package/locales/zh_Hant_HK.json +1 -1
- package/package.json +13 -27
- package/razzle.config.js +20 -5
- package/src/components/manage/Add/Add.jsx +9 -6
- package/src/components/manage/Blocks/Title/Edit.jsx +5 -0
- package/src/components/manage/Contents/Contents.jsx +8 -2
- 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/Multilingual/CompareLanguages.jsx +10 -10
- package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -5
- package/src/components/manage/Multilingual/ManageTranslations.jsx +9 -7
- package/src/components/manage/Multilingual/TranslationObject.jsx +11 -8
- package/src/components/manage/Preferences/PersonalPreferences.jsx +8 -5
- package/src/components/manage/Toolbar/Types.crash.test.jsx +46 -0
- package/src/components/manage/Toolbar/Types.jsx +9 -7
- package/src/components/manage/Widgets/FileWidget.jsx +7 -0
- package/src/components/manage/Widgets/FormFieldWrapper.jsx +168 -146
- package/src/components/theme/LanguageSelector/LanguageSelector.tsx +7 -5
- package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +12 -7
- package/src/express-middleware/devproxy.js +3 -1
- package/src/express-middleware/files.js +1 -0
- package/src/express-middleware/files.test.js +59 -0
- package/src/express-middleware/images.js +1 -0
- package/src/express-middleware/images.test.js +50 -0
- package/src/helpers/Blocks/Blocks.js +6 -6
- 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/users/users.js +1 -1
- package/src/server.jsx +14 -12
- package/test-setup-globals-vitest.js +25 -0
- package/theme/themes/pastanaga/extras/main.less +0 -2
- package/theme/themes/pastanaga/extras/widgets.less +17 -0
- package/types/components/manage/Toolbar/Types.crash.test.d.ts +1 -0
- package/types/components/manage/Widgets/FormFieldWrapper.d.ts +5 -28
- package/types/components/manage/Widgets/index.d.ts +1 -1
- package/types/helpers/Utils/Utils.d.ts +1 -0
- package/vitest.config.mjs +86 -40
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "18.
|
|
12
|
+
"version": "18.33.0",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git@github.com:plone/volto.git"
|
|
@@ -34,14 +34,6 @@
|
|
|
34
34
|
},
|
|
35
35
|
"main": "src/index.js",
|
|
36
36
|
"types": "types/index.d.ts",
|
|
37
|
-
"bundlewatch": {
|
|
38
|
-
"files": [
|
|
39
|
-
{
|
|
40
|
-
"path": "build/public/static/js/*.js",
|
|
41
|
-
"maxSize": "700kB"
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
},
|
|
45
37
|
"jest": {
|
|
46
38
|
"transform": {
|
|
47
39
|
"^.+\\.js(x)?$": "babel-jest",
|
|
@@ -166,16 +158,15 @@
|
|
|
166
158
|
"github-slugger": "1.4.0",
|
|
167
159
|
"history": "4.10.1",
|
|
168
160
|
"hoist-non-react-statics": "3.3.2",
|
|
169
|
-
"http-proxy-middleware": "2.0.
|
|
161
|
+
"http-proxy-middleware": "2.0.9",
|
|
170
162
|
"image-extensions": "1.1.0",
|
|
171
|
-
"immutable": "3",
|
|
172
163
|
"is-hotkey": "0.2.0",
|
|
173
164
|
"is-url": "1.2.4",
|
|
174
165
|
"jotai": "2.11.3",
|
|
175
166
|
"jwt-decode": "2.2.0",
|
|
176
167
|
"linkify-it": "3.0.2",
|
|
177
168
|
"locale": "0.1.0",
|
|
178
|
-
"lodash": "4.17.
|
|
169
|
+
"lodash": "4.17.23",
|
|
179
170
|
"lodash-move": "1.1.1",
|
|
180
171
|
"moment": "2.29.4",
|
|
181
172
|
"object-assign": "4.1.1",
|
|
@@ -193,7 +184,7 @@
|
|
|
193
184
|
"react-animate-height": "2.0.17",
|
|
194
185
|
"react-beautiful-dnd": "13.0.0",
|
|
195
186
|
"react-cookie": "4.1.1",
|
|
196
|
-
"react-dates": "21.
|
|
187
|
+
"react-dates": "21.8.0",
|
|
197
188
|
"react-detect-click-outside": "1.1.1",
|
|
198
189
|
"react-dnd": "5.0.0",
|
|
199
190
|
"react-dnd-html5-backend": "5.0.1",
|
|
@@ -229,7 +220,7 @@
|
|
|
229
220
|
"rrule": "2.7.1",
|
|
230
221
|
"semantic-ui-less": "2.4.1",
|
|
231
222
|
"semantic-ui-react": "2.1.5",
|
|
232
|
-
"serialize-javascript": "
|
|
223
|
+
"serialize-javascript": "7.0.4",
|
|
233
224
|
"slate": "0.100.0",
|
|
234
225
|
"slate-hyperscript": "0.100.0",
|
|
235
226
|
"slate-react": "0.98.4",
|
|
@@ -241,9 +232,9 @@
|
|
|
241
232
|
"url": "^0.11.3",
|
|
242
233
|
"use-deep-compare-effect": "1.8.1",
|
|
243
234
|
"uuid": "^8.3.2",
|
|
244
|
-
"@plone/
|
|
245
|
-
"@plone/
|
|
246
|
-
"@plone/scripts": "3.10.
|
|
235
|
+
"@plone/volto-slate": "18.9.0",
|
|
236
|
+
"@plone/registry": "2.7.1",
|
|
237
|
+
"@plone/scripts": "3.10.5"
|
|
247
238
|
},
|
|
248
239
|
"devDependencies": {
|
|
249
240
|
"@babel/core": "^7.0.0",
|
|
@@ -299,7 +290,6 @@
|
|
|
299
290
|
"babel-plugin-react-intl": "5.1.17",
|
|
300
291
|
"babel-plugin-root-import": "6.1.0",
|
|
301
292
|
"babel-preset-razzle": "4.2.18",
|
|
302
|
-
"bundlewatch": "0.3.3",
|
|
303
293
|
"circular-dependency-plugin": "5.2.2",
|
|
304
294
|
"css-loader": "5.2.7",
|
|
305
295
|
"cypress": "13.17.0",
|
|
@@ -326,7 +316,7 @@
|
|
|
326
316
|
"jiti": "^2.4.2",
|
|
327
317
|
"jsdom": "^16.7.0",
|
|
328
318
|
"jsonwebtoken": "9.0.0",
|
|
329
|
-
"less": "3.
|
|
319
|
+
"less": "3.13.1",
|
|
330
320
|
"less-loader": "11.1.0",
|
|
331
321
|
"lodash-webpack-plugin": "0.11.6",
|
|
332
322
|
"mini-css-extract-plugin": "2.7.2",
|
|
@@ -346,7 +336,7 @@
|
|
|
346
336
|
"react-is": "^18.2.0",
|
|
347
337
|
"release-it": "^19.0.5",
|
|
348
338
|
"semver": "^7.5.4",
|
|
349
|
-
"start-server-and-test": "1.
|
|
339
|
+
"start-server-and-test": "2.1.5",
|
|
350
340
|
"storybook": "^8.6.15",
|
|
351
341
|
"style-loader": "3.3.1",
|
|
352
342
|
"stylelint": "^16.3.1",
|
|
@@ -356,14 +346,13 @@
|
|
|
356
346
|
"svgo": "^3.0.0",
|
|
357
347
|
"svgo-loader": "3.0.3",
|
|
358
348
|
"terser-webpack-plugin": "5.3.6",
|
|
359
|
-
"tmp": "0.2.1",
|
|
360
349
|
"ts-jest": "^26.4.2",
|
|
361
350
|
"ts-loader": "9.4.4",
|
|
362
351
|
"typescript": "^5.7.3",
|
|
363
352
|
"use-trace-update": "1.3.2",
|
|
364
|
-
"vitest": "^3.
|
|
365
|
-
"wait-on": "
|
|
366
|
-
"webpack": "5.
|
|
353
|
+
"vitest": "^3.2.4",
|
|
354
|
+
"wait-on": "^9.0.4",
|
|
355
|
+
"webpack": "5.105.4",
|
|
367
356
|
"webpack-bundle-analyzer": "4.10.1",
|
|
368
357
|
"webpack-dev-server": "4.11.1",
|
|
369
358
|
"webpack-node-externals": "3.0.0",
|
|
@@ -371,9 +360,6 @@
|
|
|
371
360
|
"@plone/types": "1.6.1",
|
|
372
361
|
"@plone/volto-coresandbox": "1.0.0"
|
|
373
362
|
},
|
|
374
|
-
"volta": {
|
|
375
|
-
"node": "20.9.0"
|
|
376
|
-
},
|
|
377
363
|
"scripts": {
|
|
378
364
|
"analyze": "BUNDLE_ANALYZE=true razzle build",
|
|
379
365
|
"start": "make build-deps && razzle start",
|
package/razzle.config.js
CHANGED
|
@@ -420,11 +420,26 @@ const defaultModify = ({
|
|
|
420
420
|
const addonExtenders = registry.getAddonExtenders().map((m) => require(m));
|
|
421
421
|
|
|
422
422
|
const defaultPlugins = [
|
|
423
|
-
{
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
423
|
+
{
|
|
424
|
+
name: 'less',
|
|
425
|
+
object: require('./webpack-plugins/webpack-less-plugin')({ registry }),
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: 'svg',
|
|
429
|
+
object: require('./webpack-plugins/webpack-svg-plugin'),
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
name: 'bundle-analyze',
|
|
433
|
+
object: require('./webpack-plugins/webpack-bundle-analyze-plugin'),
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
name: 'jest-extender',
|
|
437
|
+
object: require('./jest-extender-plugin'),
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
name: 'scss',
|
|
441
|
+
object: require('razzle-plugin-scss'),
|
|
442
|
+
},
|
|
428
443
|
];
|
|
429
444
|
|
|
430
445
|
const plugins = addonExtenders.reduce(
|
|
@@ -241,11 +241,13 @@ class Add extends Component {
|
|
|
241
241
|
if (this.props.location?.state?.translationOf) {
|
|
242
242
|
const language = this.props.location.state.languageFrom;
|
|
243
243
|
const langFileName = toGettextLang(language);
|
|
244
|
-
import(
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
import(/* @vite-ignore */ '@root/../locales/' + langFileName + '.json')
|
|
245
|
+
.then((locale) => {
|
|
246
|
+
this.props.changeLanguage(language, locale.default);
|
|
247
|
+
})
|
|
248
|
+
.catch(() => {
|
|
249
|
+
this.props.changeLanguage(language, {});
|
|
250
|
+
});
|
|
249
251
|
this.props.history.push(this.props.location?.state?.translationOf);
|
|
250
252
|
} else {
|
|
251
253
|
this.props.history.push(getBaseUrl(this.props.pathname));
|
|
@@ -269,7 +271,8 @@ class Add extends Component {
|
|
|
269
271
|
const translationObject = this.props.location?.state?.translationObject;
|
|
270
272
|
|
|
271
273
|
const translateTo = translationObject
|
|
272
|
-
? langmap?.[this.props.location?.state?.language]?.nativeName
|
|
274
|
+
? langmap?.[this.props.location?.state?.language]?.nativeName ||
|
|
275
|
+
this.props.location?.state?.language
|
|
273
276
|
: null;
|
|
274
277
|
|
|
275
278
|
// Get initial blocks from local config, if any
|
|
@@ -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
|
);
|
|
@@ -504,11 +504,17 @@ class Contents extends Component {
|
|
|
504
504
|
}
|
|
505
505
|
|
|
506
506
|
if (this.props.deleteRequest.loading && nextProps.deleteRequest.error) {
|
|
507
|
+
const deleteErrorMessageTitle = this.props.intl.formatMessage(
|
|
508
|
+
messages.deleteError,
|
|
509
|
+
);
|
|
510
|
+
const deleteErrorMessageContent =
|
|
511
|
+
nextProps.deleteRequest.error?.response?.body?.message ||
|
|
512
|
+
deleteErrorMessageTitle;
|
|
507
513
|
this.props.toastify.toast.error(
|
|
508
514
|
<Toast
|
|
509
515
|
error
|
|
510
|
-
title={
|
|
511
|
-
content={
|
|
516
|
+
title={deleteErrorMessageTitle}
|
|
517
|
+
content={deleteErrorMessageContent}
|
|
512
518
|
/>,
|
|
513
519
|
);
|
|
514
520
|
}
|
|
@@ -25,6 +25,7 @@ import { Link } from 'react-router-dom';
|
|
|
25
25
|
import Helmet from '@plone/volto/helpers/Helmet/Helmet';
|
|
26
26
|
import { messages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
|
|
27
27
|
import { isManager, canAssignGroup } from '@plone/volto/helpers/User/User';
|
|
28
|
+
import { getErrorMessage } from '@plone/volto/helpers/Utils/Utils';
|
|
28
29
|
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
29
30
|
import addUserSvg from '@plone/volto/icons/add-user.svg';
|
|
30
31
|
import saveSVG from '@plone/volto/icons/save.svg';
|
|
@@ -351,9 +352,7 @@ const UsersControlpanel = () => {
|
|
|
351
352
|
})
|
|
352
353
|
.catch((error) => {
|
|
353
354
|
// Handle error
|
|
354
|
-
setAddUserError(
|
|
355
|
-
error.response?.body?.error?.message || 'Error creating user',
|
|
356
|
-
);
|
|
355
|
+
setAddUserError(getErrorMessage(error));
|
|
357
356
|
});
|
|
358
357
|
}
|
|
359
358
|
},
|
|
@@ -417,11 +416,11 @@ const UsersControlpanel = () => {
|
|
|
417
416
|
/**
|
|
418
417
|
* Handle Errors after createUser()
|
|
419
418
|
*
|
|
420
|
-
* @param {object} error object
|
|
419
|
+
* @param {object} error object
|
|
421
420
|
* @returns {undefined}
|
|
422
421
|
*/
|
|
423
422
|
const onAddUserError = useCallback((error) => {
|
|
424
|
-
setAddUserError(error
|
|
423
|
+
setAddUserError(getErrorMessage(error));
|
|
425
424
|
}, []);
|
|
426
425
|
|
|
427
426
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render,
|
|
2
|
+
import { render, waitFor } from '@testing-library/react';
|
|
3
3
|
import configureStore from 'redux-mock-store';
|
|
4
4
|
import { Provider } from 'react-intl-redux';
|
|
5
5
|
import { MemoryRouter } from 'react-router-dom';
|
|
@@ -39,17 +39,63 @@ describe('UsersControlpanel', () => {
|
|
|
39
39
|
messages: {},
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
|
-
const { container } =
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
});
|
|
42
|
+
const { container } = render(
|
|
43
|
+
<Provider store={store}>
|
|
44
|
+
<MemoryRouter initialEntries={['/controlpanel/users']}>
|
|
45
|
+
<UsersControlpanel />
|
|
46
|
+
<div id="toolbar"></div>
|
|
47
|
+
</MemoryRouter>
|
|
48
|
+
</Provider>,
|
|
49
|
+
);
|
|
50
|
+
await waitFor(() => {});
|
|
52
51
|
|
|
53
52
|
expect(container).toMatchSnapshot();
|
|
54
53
|
});
|
|
54
|
+
|
|
55
|
+
it('handles createRequest error when response body has only message', async () => {
|
|
56
|
+
const store = mockStore({
|
|
57
|
+
userSession: {
|
|
58
|
+
token: jwt.sign({ sub: 'john' }, 'secret'),
|
|
59
|
+
},
|
|
60
|
+
roles: { roles: [] },
|
|
61
|
+
users: {
|
|
62
|
+
users: [],
|
|
63
|
+
create: {
|
|
64
|
+
loading: false,
|
|
65
|
+
error: {
|
|
66
|
+
response: { body: { message: 'SMTP relay access denied' } },
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
user: {
|
|
70
|
+
roles: ['Manager'],
|
|
71
|
+
'@id': 'admin',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
groups: {
|
|
75
|
+
groups: [],
|
|
76
|
+
create: { loading: false },
|
|
77
|
+
},
|
|
78
|
+
authRole: {
|
|
79
|
+
authenticatedRole: [],
|
|
80
|
+
},
|
|
81
|
+
intl: {
|
|
82
|
+
locale: 'en',
|
|
83
|
+
messages: {},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
render(
|
|
88
|
+
<Provider store={store}>
|
|
89
|
+
<MemoryRouter initialEntries={['/controlpanel/users']}>
|
|
90
|
+
<UsersControlpanel />
|
|
91
|
+
<div id="toolbar"></div>
|
|
92
|
+
</MemoryRouter>
|
|
93
|
+
</Provider>,
|
|
94
|
+
);
|
|
95
|
+
await waitFor(() => {});
|
|
96
|
+
|
|
97
|
+
// If the component attempted to read a missing property it would throw.
|
|
98
|
+
// Reaching this line means the error shape was handled without exceptions.
|
|
99
|
+
expect(true).toBe(true);
|
|
100
|
+
});
|
|
55
101
|
});
|
|
@@ -57,33 +57,33 @@ const CompareLanguagesMenu = ({
|
|
|
57
57
|
{comparingLanguage === t.language ? (
|
|
58
58
|
<button
|
|
59
59
|
aria-label={`${intl.formatMessage(messages.stop_compare)} ${
|
|
60
|
-
langmap[t.language].
|
|
60
|
+
langmap[t.language]?.nativeName || t.language
|
|
61
61
|
}`}
|
|
62
62
|
title={`${intl.formatMessage(messages.stop_compare)} ${
|
|
63
|
-
langmap[t.language].
|
|
63
|
+
langmap[t.language]?.nativeName || t.language
|
|
64
64
|
}`}
|
|
65
65
|
onClick={() => {
|
|
66
66
|
setComparingLanguage(null);
|
|
67
67
|
closeMenu();
|
|
68
68
|
}}
|
|
69
69
|
>
|
|
70
|
-
{langmap[t.language].
|
|
70
|
+
{langmap[t.language]?.nativeName || t.language}
|
|
71
71
|
<Icon name={clearSVG} size="30px" />
|
|
72
72
|
</button>
|
|
73
73
|
) : (
|
|
74
74
|
<button
|
|
75
|
-
aria-label={`${intl.formatMessage(
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
title={`${intl.formatMessage(
|
|
79
|
-
|
|
80
|
-
)
|
|
75
|
+
aria-label={`${intl.formatMessage(messages.compare_to)} ${(
|
|
76
|
+
langmap[t.language]?.nativeName || t.language
|
|
77
|
+
).toLowerCase()}`}
|
|
78
|
+
title={`${intl.formatMessage(messages.compare_to)} ${(
|
|
79
|
+
langmap[t.language]?.nativeName || t.language
|
|
80
|
+
).toLowerCase()}`}
|
|
81
81
|
onClick={() => {
|
|
82
82
|
setComparingLanguage(t.language);
|
|
83
83
|
closeMenu();
|
|
84
84
|
}}
|
|
85
85
|
>
|
|
86
|
-
{langmap[t.language].
|
|
86
|
+
{langmap[t.language]?.nativeName || t.language}
|
|
87
87
|
</button>
|
|
88
88
|
)}
|
|
89
89
|
</li>
|
|
@@ -32,11 +32,14 @@ const CreateTranslation = (props) => {
|
|
|
32
32
|
// We change the interface language
|
|
33
33
|
if (config.settings.supportedLanguages.includes(language)) {
|
|
34
34
|
const langFileName = toGettextLang(language);
|
|
35
|
-
import(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
import(/* @vite-ignore */ '@root/../locales/' + langFileName + '.json')
|
|
36
|
+
.then((locale) => {
|
|
37
|
+
dispatch(changeLanguage(language, locale.default));
|
|
38
|
+
})
|
|
39
|
+
.catch(() => {
|
|
40
|
+
// If locale file doesn't exist, still switch language with empty locale
|
|
41
|
+
dispatch(changeLanguage(language, {}));
|
|
42
|
+
});
|
|
40
43
|
}
|
|
41
44
|
};
|
|
42
45
|
// On mount only
|
|
@@ -176,7 +176,7 @@ const ManageTranslations = (props) => {
|
|
|
176
176
|
<FormattedMessage
|
|
177
177
|
id="Manage translations for {title}"
|
|
178
178
|
defaultMessage="Manage translations for {title}"
|
|
179
|
-
values={{ title: <q>{content
|
|
179
|
+
values={{ title: <q>{content?.title || ''}</q> }}
|
|
180
180
|
/>
|
|
181
181
|
</Segment>
|
|
182
182
|
{content && (
|
|
@@ -193,9 +193,9 @@ const ManageTranslations = (props) => {
|
|
|
193
193
|
<Table.Row key={lang}>
|
|
194
194
|
<Table.Cell collapsing>
|
|
195
195
|
{lang === content.language.token ? (
|
|
196
|
-
<strong>{langmap[lang]
|
|
196
|
+
<strong>{langmap?.[lang]?.nativeName || lang}</strong>
|
|
197
197
|
) : (
|
|
198
|
-
langmap[lang]
|
|
198
|
+
langmap?.[lang]?.nativeName || lang
|
|
199
199
|
)}
|
|
200
200
|
</Table.Cell>
|
|
201
201
|
<Table.Cell>
|
|
@@ -233,7 +233,9 @@ const ManageTranslations = (props) => {
|
|
|
233
233
|
<Button
|
|
234
234
|
aria-label={`${intl.formatMessage(
|
|
235
235
|
messages.unlink,
|
|
236
|
-
)} ${
|
|
236
|
+
)} ${(
|
|
237
|
+
langmap?.[lang]?.nativeName || lang
|
|
238
|
+
).toLowerCase()}`}
|
|
237
239
|
basic
|
|
238
240
|
icon
|
|
239
241
|
disabled={lang === content.language.token}
|
|
@@ -252,9 +254,9 @@ const ManageTranslations = (props) => {
|
|
|
252
254
|
) : (
|
|
253
255
|
<Button.Group>
|
|
254
256
|
<Button
|
|
255
|
-
aria-label={`${intl.formatMessage(
|
|
256
|
-
|
|
257
|
-
)
|
|
257
|
+
aria-label={`${intl.formatMessage(messages.link)} ${(
|
|
258
|
+
langmap?.[lang]?.nativeName || lang
|
|
259
|
+
).toLowerCase()}`}
|
|
258
260
|
basic
|
|
259
261
|
icon
|
|
260
262
|
disabled={lang === content.language.token}
|
|
@@ -48,12 +48,15 @@ const TranslationObject = ({
|
|
|
48
48
|
let lang =
|
|
49
49
|
config.settings.supportedLanguages[Object.keys(locales).length];
|
|
50
50
|
const langFileName = toGettextLang(lang);
|
|
51
|
-
import(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
import(/* @vite-ignore */ '@root/../locales/' + langFileName + '.json')
|
|
52
|
+
.then((locale) => {
|
|
53
|
+
setLocales({ ...locales, [toReactIntlLang(lang)]: locale.default });
|
|
54
|
+
setLoadingLocale(false);
|
|
55
|
+
})
|
|
56
|
+
.catch(() => {
|
|
57
|
+
setLocales({ ...locales, [toReactIntlLang(lang)]: {} });
|
|
58
|
+
setLoadingLocale(false);
|
|
59
|
+
});
|
|
57
60
|
}
|
|
58
61
|
}, [loadingLocale, locales]);
|
|
59
62
|
|
|
@@ -83,7 +86,7 @@ const TranslationObject = ({
|
|
|
83
86
|
active={activeMenu === 'language'}
|
|
84
87
|
onClick={handleMenuClick}
|
|
85
88
|
>
|
|
86
|
-
{langmap[lang]
|
|
89
|
+
{langmap?.[lang]?.nativeName || lang}
|
|
87
90
|
</Menu.Item>
|
|
88
91
|
{visual && (
|
|
89
92
|
<Menu.Item
|
|
@@ -107,7 +110,7 @@ const TranslationObject = ({
|
|
|
107
110
|
hideActions
|
|
108
111
|
pathname={flattenToAppURL(translationObject['@id'])}
|
|
109
112
|
visual={visual}
|
|
110
|
-
title={langmap[lang]
|
|
113
|
+
title={langmap?.[lang]?.nativeName || lang}
|
|
111
114
|
loading={false}
|
|
112
115
|
isFormSelected={isFormSelected}
|
|
113
116
|
onSelectForm={onSelectForm}
|
|
@@ -53,11 +53,14 @@ const PersonalPreferences = (props) => {
|
|
|
53
53
|
let language = data.language || 'en';
|
|
54
54
|
if (config.settings.supportedLanguages.includes(language)) {
|
|
55
55
|
const langFileName = toGettextLang(language);
|
|
56
|
-
import(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
import(/* @vite-ignore */ '@root/../locales/' + langFileName + '.json')
|
|
57
|
+
.then((locale) => {
|
|
58
|
+
dispatch(changeLanguage(language, locale.default));
|
|
59
|
+
})
|
|
60
|
+
.catch(() => {
|
|
61
|
+
// If locale file doesn't exist, still switch language with empty locale
|
|
62
|
+
dispatch(changeLanguage(language, {}));
|
|
63
|
+
});
|
|
61
64
|
}
|
|
62
65
|
toast.success(<Toast success title={intl.formatMessage(messages.saved)} />);
|
|
63
66
|
closeMenu();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { Provider } from 'react-intl-redux';
|
|
4
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
5
|
+
import configureStore from 'redux-mock-store';
|
|
6
|
+
import config from '@plone/volto/registry';
|
|
7
|
+
import Types from './Types';
|
|
8
|
+
|
|
9
|
+
config.settings.isMultilingual = true;
|
|
10
|
+
config.settings.supportedLanguages = ['en', 'missing-lang'];
|
|
11
|
+
|
|
12
|
+
const mockStore = configureStore();
|
|
13
|
+
|
|
14
|
+
describe('Types', () => {
|
|
15
|
+
it('should not crash if a language is not in langmap', () => {
|
|
16
|
+
const store = mockStore({
|
|
17
|
+
intl: {
|
|
18
|
+
locale: 'en',
|
|
19
|
+
messages: {},
|
|
20
|
+
},
|
|
21
|
+
types: {
|
|
22
|
+
types: [],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const content = {
|
|
27
|
+
'@type': 'Folder',
|
|
28
|
+
'@id': '/folder',
|
|
29
|
+
'@components': {
|
|
30
|
+
translations: {
|
|
31
|
+
items: [],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const { getByText } = render(
|
|
37
|
+
<Provider store={store}>
|
|
38
|
+
<MemoryRouter>
|
|
39
|
+
<Types pathname="/folder" types={[]} content={content} />
|
|
40
|
+
</MemoryRouter>
|
|
41
|
+
</Provider>,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(getByText('Translate to missing-lang')).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -15,7 +15,7 @@ import config from '@plone/volto/registry';
|
|
|
15
15
|
const Types = ({ types, pathname, content, currentLanguage }) => {
|
|
16
16
|
const { settings } = config;
|
|
17
17
|
return types.length > 0 ||
|
|
18
|
-
(settings.isMultilingual && content['@components']
|
|
18
|
+
(settings.isMultilingual && content?.['@components']?.translations) ? (
|
|
19
19
|
<div className="menu-more pastanaga-menu">
|
|
20
20
|
{types.length > 0 && (
|
|
21
21
|
<>
|
|
@@ -54,14 +54,14 @@ const Types = ({ types, pathname, content, currentLanguage }) => {
|
|
|
54
54
|
</>
|
|
55
55
|
)}
|
|
56
56
|
{settings.isMultilingual &&
|
|
57
|
-
content['@components']
|
|
57
|
+
content?.['@components']?.translations &&
|
|
58
58
|
(() => {
|
|
59
59
|
const translationsLeft = filter(
|
|
60
60
|
settings.supportedLanguages,
|
|
61
61
|
(lang) =>
|
|
62
62
|
!Boolean(
|
|
63
|
-
content['@components']
|
|
64
|
-
find(content['@components']
|
|
63
|
+
content?.['@components']?.translations &&
|
|
64
|
+
find(content?.['@components']?.translations?.items, {
|
|
65
65
|
language: lang,
|
|
66
66
|
}),
|
|
67
67
|
) && toBackendLang(currentLanguage) !== lang,
|
|
@@ -84,8 +84,8 @@ const Types = ({ types, pathname, content, currentLanguage }) => {
|
|
|
84
84
|
to={{
|
|
85
85
|
pathname: `${pathname}/create-translation`,
|
|
86
86
|
state: {
|
|
87
|
-
type: content['@type'],
|
|
88
|
-
translationOf: flattenToAppURL(content['@id']),
|
|
87
|
+
type: content?.['@type'],
|
|
88
|
+
translationOf: flattenToAppURL(content?.['@id']),
|
|
89
89
|
language: lang,
|
|
90
90
|
},
|
|
91
91
|
}}
|
|
@@ -95,7 +95,9 @@ const Types = ({ types, pathname, content, currentLanguage }) => {
|
|
|
95
95
|
id="Translate to {lang}"
|
|
96
96
|
defaultMessage="Translate to {lang}"
|
|
97
97
|
values={{
|
|
98
|
-
lang:
|
|
98
|
+
lang: (
|
|
99
|
+
langmap?.[lang]?.nativeName || lang
|
|
100
|
+
).toLowerCase(),
|
|
99
101
|
}}
|
|
100
102
|
/>
|
|
101
103
|
</Link>
|
|
@@ -59,6 +59,10 @@ const messages = defineMessages({
|
|
|
59
59
|
id: 'File is not of the accepted type {accept}',
|
|
60
60
|
defaultMessage: 'File is not of the accepted type {accept}',
|
|
61
61
|
},
|
|
62
|
+
dragAndDropActionA11y: {
|
|
63
|
+
id: 'Press Enter to browse files from your computer.',
|
|
64
|
+
defaultMessage: 'Press Enter to browse files from your computer.',
|
|
65
|
+
},
|
|
62
66
|
});
|
|
63
67
|
|
|
64
68
|
/**
|
|
@@ -205,6 +209,9 @@ const FileWidget = (props) => {
|
|
|
205
209
|
{value
|
|
206
210
|
? intl.formatMessage(messages.replaceFile)
|
|
207
211
|
: intl.formatMessage(messages.addNewFile)}
|
|
212
|
+
<span className="visually-hidden">
|
|
213
|
+
{intl.formatMessage(messages.dragAndDropActionA11y)}
|
|
214
|
+
</span>
|
|
208
215
|
</label>
|
|
209
216
|
<input
|
|
210
217
|
{...getInputProps({
|