@plone/volto 19.0.0-alpha.2 → 19.0.0-alpha.20

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 (366) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +37 -3
  3. package/CHANGELOG.md +338 -1
  4. package/README.md +20 -16
  5. package/babel.js +1 -3
  6. package/cypress/docker/prefixed-rules.yml +26 -0
  7. package/cypress/docker/prefixed.yml +24 -0
  8. package/cypress/support/commands.js +12 -6
  9. package/cypress/support/guillotina.js +1 -0
  10. package/cypress.config.js +1 -0
  11. package/global-test-setup.js +1 -2
  12. package/locales/af.json +1 -0
  13. package/locales/ar.json +1 -0
  14. package/locales/bg.json +1 -0
  15. package/locales/bn.json +1 -0
  16. package/locales/ca/LC_MESSAGES/volto.po +124 -17
  17. package/locales/ca.json +1 -1
  18. package/locales/cs.json +1 -0
  19. package/locales/cy.json +1 -0
  20. package/locales/da.json +1 -0
  21. package/locales/de/LC_MESSAGES/volto.po +135 -28
  22. package/locales/de.json +1 -1
  23. package/locales/el.json +1 -0
  24. package/locales/en/LC_MESSAGES/volto.po +125 -18
  25. package/locales/en.json +1 -1
  26. package/locales/en_AU.json +1 -0
  27. package/locales/en_GB.json +1 -0
  28. package/locales/eo.json +1 -0
  29. package/locales/es/LC_MESSAGES/volto.po +125 -18
  30. package/locales/es.json +1 -1
  31. package/locales/et.json +1 -0
  32. package/locales/eu/LC_MESSAGES/volto.po +124 -17
  33. package/locales/eu.json +1 -1
  34. package/locales/fa.json +1 -0
  35. package/locales/fi/LC_MESSAGES/volto.po +124 -17
  36. package/locales/fi.json +1 -1
  37. package/locales/fr/LC_MESSAGES/volto.po +125 -18
  38. package/locales/fr.json +1 -1
  39. package/locales/fu.json +1 -0
  40. package/locales/gl.json +1 -0
  41. package/locales/he.json +1 -0
  42. package/locales/hi/LC_MESSAGES/volto.po +128 -21
  43. package/locales/hi.json +1 -1
  44. package/locales/hr.json +1 -0
  45. package/locales/hu.json +1 -0
  46. package/locales/hy.json +1 -0
  47. package/locales/id.json +1 -0
  48. package/locales/it/LC_MESSAGES/volto.po +129 -22
  49. package/locales/it.json +1 -1
  50. package/locales/ja/LC_MESSAGES/volto.po +124 -17
  51. package/locales/ja.json +1 -1
  52. package/locales/ka.json +1 -0
  53. package/locales/kn.json +1 -0
  54. package/locales/ko.json +1 -0
  55. package/locales/lt.json +1 -0
  56. package/locales/lv.json +1 -0
  57. package/locales/mi.json +1 -0
  58. package/locales/mk.json +1 -0
  59. package/locales/my.json +1 -0
  60. package/locales/nb_NO.json +1 -0
  61. package/locales/nl/LC_MESSAGES/volto.po +128 -21
  62. package/locales/nl.json +1 -1
  63. package/locales/nn.json +1 -0
  64. package/locales/pl.json +1 -0
  65. package/locales/pt/LC_MESSAGES/volto.po +124 -17
  66. package/locales/pt.json +1 -1
  67. package/locales/pt_BR/LC_MESSAGES/volto.po +147 -40
  68. package/locales/pt_BR.json +1 -1
  69. package/locales/rm.json +1 -0
  70. package/locales/ro/LC_MESSAGES/volto.po +128 -21
  71. package/locales/ro.json +1 -1
  72. package/locales/ru/LC_MESSAGES/volto.po +128 -21
  73. package/locales/ru.json +1 -1
  74. package/locales/sk.json +1 -0
  75. package/locales/sl.json +1 -0
  76. package/locales/sm.json +1 -0
  77. package/locales/sq.json +1 -0
  78. package/locales/sr.json +1 -0
  79. package/locales/sr@cyrl.json +1 -0
  80. package/locales/sr@latn.json +1 -0
  81. package/locales/sv.json +1 -1
  82. package/locales/ta.json +1 -0
  83. package/locales/te.json +1 -0
  84. package/locales/th.json +1 -0
  85. package/locales/to.json +1 -0
  86. package/locales/tr.json +1 -0
  87. package/locales/uk.json +1 -0
  88. package/locales/vi.json +1 -0
  89. package/locales/volto.pot +125 -18
  90. package/locales/zh_CN/LC_MESSAGES/volto.po +124 -17
  91. package/locales/zh_CN.json +1 -1
  92. package/locales/zh_Hant.json +1 -0
  93. package/locales/zh_Hant_HK.json +1 -0
  94. package/package.json +43 -100
  95. package/razzle.config.js +21 -21
  96. package/src/actions/content/content.js +0 -1
  97. package/src/actions/controlpanels/controlpanels.js +13 -7
  98. package/src/actions/controlpanels/controlpanels.test.js +11 -5
  99. package/src/actions/users/users.js +2 -2
  100. package/src/components/manage/Actions/Actions.test.jsx +1 -5
  101. package/src/components/manage/Add/Add.jsx +5 -6
  102. package/src/components/manage/BlockChooser/BlockChooser.jsx +1 -0
  103. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +1 -5
  104. package/src/components/manage/Blocks/Block/Edit.jsx +1 -0
  105. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +9 -4
  106. package/src/components/manage/Blocks/Block/Settings.test.jsx +1 -5
  107. package/src/components/manage/Blocks/HTML/Edit.test.jsx +1 -5
  108. package/src/components/manage/Blocks/Image/Edit.jsx +5 -1
  109. package/src/components/manage/Blocks/Image/ImageSidebar.test.jsx +1 -5
  110. package/src/components/manage/Blocks/LeadImage/Edit.jsx +2 -2
  111. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +1 -1
  112. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +1 -5
  113. package/src/components/manage/Blocks/Listing/ImageGallery.jsx +6 -4
  114. package/src/components/manage/Blocks/Maps/Edit.jsx +2 -1
  115. package/src/components/manage/Blocks/Maps/MapsSidebar.test.jsx +1 -5
  116. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +21 -4
  117. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +1 -6
  118. package/src/components/manage/Blocks/Search/components/SelectFacet.test.jsx +1 -6
  119. package/src/components/manage/Blocks/Teaser/Data.jsx +21 -7
  120. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +1 -1
  121. package/src/components/manage/Blocks/Teaser/schema.js +8 -3
  122. package/src/components/manage/Blocks/Video/Edit.jsx +2 -1
  123. package/src/components/manage/Blocks/Video/VideoSidebar.test.jsx +1 -5
  124. package/src/components/manage/Contents/Contents.jsx +689 -654
  125. package/src/components/manage/Contents/Contents.test.jsx +8 -5
  126. package/src/components/manage/Contents/ContentsBreadcrumbs.Multilingual.test.jsx +18 -5
  127. package/src/components/manage/Contents/ContentsBreadcrumbs.jsx +20 -26
  128. package/src/components/manage/Contents/ContentsBreadcrumbs.test.jsx +14 -0
  129. package/src/components/manage/Contents/ContentsDeleteModal.jsx +258 -206
  130. package/src/components/manage/Contents/ContentsDeleteModal.stories.jsx +26 -8
  131. package/src/components/manage/Contents/ContentsItem.jsx +10 -2
  132. package/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +1 -5
  133. package/src/components/manage/Contents/ContentsRenameModal.test.jsx +1 -5
  134. package/src/components/manage/Contents/ContentsTagsModal.test.jsx +1 -5
  135. package/src/components/manage/Contents/ContentsUploadModal.test.jsx +13 -22
  136. package/src/components/manage/Contents/ContentsWorkflowModal.test.jsx +1 -5
  137. package/src/components/manage/Contents/DropZoneContent.jsx +323 -0
  138. package/src/components/manage/Contents/__mocks__/index.tsx +2 -18
  139. package/src/components/manage/Controlpanels/Aliases.test.jsx +1 -5
  140. package/src/components/manage/Controlpanels/ContentType.jsx +1 -1
  141. package/src/components/manage/Controlpanels/ContentType.test.jsx +1 -5
  142. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +3 -2
  143. package/src/components/manage/Controlpanels/Relations/Relations.jsx +1 -1
  144. package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +1 -5
  145. package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +1 -5
  146. package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +1 -5
  147. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +156 -175
  148. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +575 -630
  149. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +4 -3
  150. package/src/components/manage/Diff/Diff.test.jsx +1 -6
  151. package/src/components/manage/Diff/DiffField.test.jsx +1 -6
  152. package/src/components/manage/Display/Display.test.jsx +2 -11
  153. package/src/components/manage/Edit/Edit.jsx +2 -3
  154. package/src/components/manage/Edit/Edit.test.jsx +1 -5
  155. package/src/components/manage/Form/BlockDataForm.test.jsx +1 -5
  156. package/src/components/manage/Form/Form.test.jsx +1 -5
  157. package/src/components/manage/Form/InlineForm.jsx +2 -2
  158. package/src/components/manage/Form/InlineForm.test.jsx +1 -5
  159. package/src/components/manage/Form/ModalForm.jsx +12 -10
  160. package/src/components/manage/Form/ModalForm.test.jsx +27 -5
  161. package/src/components/manage/Form/__mocks__/index.tsx +9 -27
  162. package/src/components/manage/Multilingual/CompareLanguages.jsx +2 -5
  163. package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -8
  164. package/src/components/manage/Multilingual/ManageTranslations.jsx +4 -2
  165. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +5 -1
  166. package/src/components/manage/Multilingual/TranslationObject.jsx +1 -1
  167. package/src/components/manage/Preferences/ChangePassword.test.jsx +1 -5
  168. package/src/components/manage/Preferences/PersonalPreferences.test.jsx +1 -17
  169. package/src/components/manage/Sidebar/ObjectBrowser.jsx +3 -0
  170. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +13 -1
  171. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
  172. package/src/components/manage/Sidebar/SidebarPortal.test.tsx +42 -0
  173. package/src/components/manage/Sidebar/SidebarPortal.tsx +48 -0
  174. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +2 -1
  175. package/src/components/manage/Toolbar/More.jsx +4 -1
  176. package/src/components/manage/Toolbar/More.test.jsx +3 -0
  177. package/src/components/manage/Toolbar/PersonalTools.jsx +2 -1
  178. package/src/components/manage/Toolbar/Toolbar.jsx +3 -4
  179. package/src/components/manage/Toolbar/Types.jsx +7 -7
  180. package/src/components/manage/UniversalLink/UniversalLink.tsx +1 -0
  181. package/src/components/manage/Widgets/AlignWidget.stories.jsx +9 -0
  182. package/src/components/manage/Widgets/AlignWidget.test.tsx +95 -0
  183. package/src/components/manage/Widgets/{AlignWidget.jsx → AlignWidget.tsx} +23 -7
  184. package/src/components/manage/Widgets/ArrayWidget.test.jsx +1 -6
  185. package/src/components/manage/Widgets/BlockAlignment.stories.tsx +104 -0
  186. package/src/components/manage/Widgets/BlockAlignment.test.tsx +104 -0
  187. package/src/components/manage/Widgets/BlockAlignment.tsx +88 -0
  188. package/src/components/manage/Widgets/BlockWidth.stories.tsx +69 -0
  189. package/src/components/manage/Widgets/BlockWidth.test.tsx +62 -0
  190. package/src/components/manage/Widgets/BlockWidth.tsx +101 -0
  191. package/src/components/manage/Widgets/ButtonsWidget.stories.jsx +61 -0
  192. package/src/components/manage/Widgets/ButtonsWidget.test.tsx +138 -0
  193. package/src/components/manage/Widgets/ButtonsWidget.tsx +176 -0
  194. package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +1 -6
  195. package/src/components/manage/Widgets/DatetimeWidget.jsx +16 -1
  196. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +1 -6
  197. package/src/components/manage/Widgets/FileWidget.jsx +14 -8
  198. package/src/components/manage/Widgets/FormFieldWrapper.jsx +146 -168
  199. package/src/components/manage/Widgets/ImageWidget.jsx +171 -38
  200. package/src/components/manage/Widgets/InternalUrlWidget.jsx +2 -0
  201. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +8 -0
  202. package/src/components/manage/Widgets/ObjectListWidget.test.jsx +2 -11
  203. package/src/components/manage/Widgets/ObjectWidget.test.jsx +1 -5
  204. package/src/components/manage/Widgets/QueryWidget.jsx +137 -9
  205. package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +1 -6
  206. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.test.jsx +1 -6
  207. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +3 -2
  208. package/src/components/manage/Widgets/SchemaWidget.test.jsx +1 -6
  209. package/src/components/manage/Widgets/SchemaWidgetFieldset.test.jsx +1 -6
  210. package/src/components/manage/Widgets/SelectAutoComplete.jsx +29 -12
  211. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +1 -6
  212. package/src/components/manage/Widgets/SelectWidget.test.jsx +1 -6
  213. package/src/components/manage/Widgets/Size.stories.tsx +69 -0
  214. package/src/components/manage/Widgets/Size.test.tsx +59 -0
  215. package/src/components/manage/Widgets/Size.tsx +78 -0
  216. package/src/components/manage/Widgets/TimeWidget.test.jsx +1 -6
  217. package/src/components/manage/Widgets/TokenWidget.test.jsx +1 -6
  218. package/src/components/manage/Widgets/UrlWidget.jsx +2 -0
  219. package/src/components/manage/Widgets/VocabularyTermsWidget.test.jsx +2 -11
  220. package/src/components/manage/Widgets/__mocks__/index.tsx +33 -51
  221. package/src/components/manage/Widgets/index.tsx +21 -0
  222. package/src/components/manage/Workflow/Workflow.test.jsx +2 -11
  223. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +1 -3
  224. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +0 -4
  225. package/src/components/theme/App/App.jsx +5 -1
  226. package/src/components/theme/App/App.test.jsx +1 -0
  227. package/src/components/theme/Avatar/Avatar.jsx +2 -1
  228. package/src/components/theme/Comments/CommentEditModal.test.jsx +1 -5
  229. package/src/components/theme/Comments/Comments.test.jsx +2 -11
  230. package/src/components/theme/ContactForm/ContactForm.test.jsx +1 -5
  231. package/src/components/theme/FormattedDate/FormattedDate.stories.jsx +20 -2
  232. package/src/components/theme/Image/Image.jsx +11 -8
  233. package/src/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.tsx +7 -0
  234. package/src/components/theme/LanguageSelector/{LanguageSelector.test.jsx → LanguageSelector.test.tsx} +6 -6
  235. package/src/components/theme/LanguageSelector/LanguageSelector.tsx +89 -0
  236. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +0 -5
  237. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +10 -14
  238. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.test.jsx +3 -5
  239. package/src/components/theme/Navigation/NavItem.jsx +1 -5
  240. package/src/components/theme/Navigation/Navigation.Multilingual.test.jsx +0 -5
  241. package/src/components/theme/NotFound/NotFound.jsx +5 -2
  242. package/src/components/theme/NotFound/NotFound.test.jsx +3 -0
  243. package/src/components/theme/PasswordReset/RequestPasswordReset.test.jsx +1 -5
  244. package/src/components/theme/PreviewImage/PreviewImage.jsx +1 -1
  245. package/src/components/theme/Register/Register.test.jsx +1 -5
  246. package/src/components/theme/RequestTimeout/RequestTimeout.jsx +1 -1
  247. package/src/components/theme/Sitemap/Sitemap.jsx +6 -5
  248. package/src/components/theme/Sitemap/Sitemap.test.jsx +0 -1
  249. package/src/components/theme/Unauthorized/Unauthorized.jsx +5 -2
  250. package/src/components/theme/View/EventDatesInfo.test.jsx +1 -6
  251. package/src/components/theme/View/EventView.test.jsx +1 -6
  252. package/src/components/theme/View/FileView.jsx +9 -1
  253. package/src/components/theme/View/View.jsx +8 -1
  254. package/src/components/theme/Widgets/ImageWidget.jsx +2 -1
  255. package/src/config/ControlPanels.js +1 -0
  256. package/src/config/Widgets.jsx +7 -0
  257. package/src/config/index.js +18 -25
  258. package/src/config/server.js +0 -2
  259. package/src/config/slots.js +19 -0
  260. package/src/express-middleware/devproxy.js +20 -5
  261. package/src/helpers/Api/APIResourceWithAuth.js +8 -3
  262. package/src/helpers/Api/Api.js +7 -4
  263. package/src/helpers/AsyncConnect/ssr.js +4 -1
  264. package/src/helpers/Content/Content.js +23 -0
  265. package/src/helpers/Content/Content.test.js +39 -0
  266. package/src/helpers/Content/withClientSideContent.jsx +35 -0
  267. package/src/helpers/Extensions/withBlockSchemaEnhancer.jsx +4 -1
  268. package/src/helpers/Html/Html.jsx +13 -7
  269. package/src/helpers/LanguageMap/LanguageMap.js +115 -8
  270. package/src/helpers/Loadable/__mocks__/Loadable.jsx +7 -22
  271. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  272. package/src/helpers/Sitemap/Sitemap.js +4 -4
  273. package/src/helpers/Url/Url.js +33 -2
  274. package/src/helpers/Url/Url.test.js +62 -0
  275. package/src/hooks/user/useUser.js +1 -1
  276. package/src/internalChecks.test.ts +11 -0
  277. package/src/middleware/Api.test.js +4 -0
  278. package/src/middleware/api.js +82 -28
  279. package/src/middleware/storeProtectLoadUtils.test.js +3 -3
  280. package/src/reducers/content/content.js +3 -18
  281. package/src/reducers/diff/diff.js +5 -1
  282. package/src/reducers/diff/diff.test.js +60 -4
  283. package/src/reducers/querystring/querystring.js +8 -1
  284. package/src/routes.js +4 -2
  285. package/src/server.jsx +45 -14
  286. package/src/start-client.jsx +9 -6
  287. package/src/start-server.js +9 -3
  288. package/test-addons-loader.js +3 -0
  289. package/test-setup-config.jsx +0 -2
  290. package/test-setup-globals.js +30 -2
  291. package/theme/themes/pastanaga/extras/blocks.less +26 -0
  292. package/theme/themes/pastanaga/extras/contents.less +80 -5
  293. package/theme/themes/pastanaga/extras/main.less +17 -2
  294. package/theme/themes/pastanaga/extras/widgets.less +79 -0
  295. package/tsconfig.declarations.json +1 -1
  296. package/tsconfig.json +4 -5
  297. package/types/components/manage/Blocks/Teaser/schema.d.ts +1 -0
  298. package/types/components/manage/Contents/DropZoneContent.d.ts +2 -0
  299. package/types/components/manage/Contents/__mocks__/index.d.ts +2 -2
  300. package/types/components/manage/Controlpanels/Relations/RelationsMatrix.d.ts +1 -1
  301. package/types/components/manage/Controlpanels/Users/RenderUsers.d.ts +18 -2
  302. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +6 -2
  303. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  304. package/types/components/manage/Form/__mocks__/index.d.ts +8 -8
  305. package/types/components/manage/Multilingual/ManageTranslations.d.ts +1 -1
  306. package/types/components/manage/Sidebar/ObjectBrowser.d.ts +1 -1
  307. package/types/components/manage/Sidebar/SidebarPortal.d.ts +7 -15
  308. package/types/components/manage/Widgets/AlignWidget.d.ts +8 -10
  309. package/types/components/manage/Widgets/AlignWidget.stories.d.ts +1 -0
  310. package/types/components/manage/Widgets/BlockAlignment.d.ts +7 -0
  311. package/types/components/manage/Widgets/BlockAlignment.stories.d.ts +8 -0
  312. package/types/components/manage/Widgets/BlockWidth.d.ts +7 -0
  313. package/types/components/manage/Widgets/BlockWidth.stories.d.ts +6 -0
  314. package/types/components/manage/Widgets/ButtonsWidget.d.ts +48 -1
  315. package/types/components/manage/Widgets/ButtonsWidget.stories.d.ts +3 -0
  316. package/types/components/manage/Widgets/FormFieldWrapper.d.ts +28 -5
  317. package/types/components/manage/Widgets/ImageWidget.d.ts +41 -1
  318. package/types/components/manage/Widgets/InternalUrlWidget.d.ts +1 -1
  319. package/types/components/manage/Widgets/ObjectBrowserWidget.d.ts +2 -0
  320. package/types/components/manage/Widgets/QueryWidget.d.ts +5 -2
  321. package/types/components/manage/Widgets/RecurrenceWidget/Utils.d.ts +12 -18
  322. package/types/components/manage/Widgets/Size.d.ts +7 -0
  323. package/types/components/manage/Widgets/Size.stories.d.ts +6 -0
  324. package/types/components/manage/Widgets/UrlWidget.d.ts +1 -1
  325. package/types/components/manage/Widgets/__mocks__/index.d.ts +33 -33
  326. package/types/components/manage/Widgets/index.d.ts +11 -6
  327. package/types/components/theme/FormattedDate/FormattedDate.stories.d.ts +1 -1
  328. package/types/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.d.ts +3 -0
  329. package/types/components/theme/LanguageSelector/LanguageSelector.d.ts +3 -10
  330. package/types/components/theme/Unauthorized/Unauthorized.d.ts +2 -2
  331. package/types/config/Widgets.d.ts +6 -0
  332. package/types/config/slots.d.ts +7 -0
  333. package/types/helpers/Content/Content.d.ts +7 -0
  334. package/types/helpers/Content/withClientSideContent.d.ts +1 -0
  335. package/types/helpers/Extensions/withBlockSchemaEnhancer.d.ts +4 -5
  336. package/types/helpers/Helmet/Helmet.d.ts +1 -1
  337. package/types/helpers/LanguageMap/LanguageMap.d.ts +428 -4
  338. package/types/helpers/Loadable/__mocks__/Loadable.d.ts +2 -2
  339. package/types/helpers/MessageLabels/MessageLabels.d.ts +68 -62
  340. package/types/helpers/Url/Url.d.ts +14 -0
  341. package/types/helpers/Url/bulkFlattenToAppURL.d.ts +5 -0
  342. package/types/middleware/api.d.ts +6 -9
  343. package/types/reducers/index.d.ts +1 -0
  344. package/types/start-client.d.ts +0 -1
  345. package/vitest.config.mjs +4 -4
  346. package/webpack-plugins/webpack-scss-plugin.js +172 -0
  347. package/jest-addons-loader.js +0 -3
  348. package/jest-extender-plugin.js +0 -39
  349. package/jest-setup-afterenv.js +0 -2
  350. package/jest-svgsystem-transform.js +0 -10
  351. package/package-why.json +0 -34
  352. package/patches/patchit.sh +0 -2
  353. package/patches/razzle-jest.patch +0 -10
  354. package/src/actions/content/content.multilingual.test.js +0 -17
  355. package/src/components/manage/Contents/__mocks__/index.vitest.tsx +0 -5
  356. package/src/components/manage/Form/__mocks__/index.vitest.tsx +0 -73
  357. package/src/components/manage/Sidebar/SidebarPortal.jsx +0 -47
  358. package/src/components/manage/Sidebar/SidebarPortal.test.jsx +0 -26
  359. package/src/components/manage/Widgets/AlignWidget.test.jsx +0 -59
  360. package/src/components/manage/Widgets/ButtonsWidget.jsx +0 -41
  361. package/src/components/manage/Widgets/ButtonsWidget.test.jsx +0 -70
  362. package/src/components/manage/Widgets/__mocks__/index.vitest.tsx +0 -41
  363. package/src/components/theme/LanguageSelector/LanguageSelector.jsx +0 -77
  364. package/src/helpers/Loadable/__mocks__/Loadable.vitest.jsx +0 -39
  365. package/test-setup-globals-vitest.js +0 -46
  366. package/theme/themes/pastanaga/extras/utils.less +0 -63
@@ -5,6 +5,7 @@
5
5
  import React from 'react';
6
6
  import PropTypes from 'prop-types';
7
7
  import { getInitials } from '@plone/volto/helpers/Utils/Utils';
8
+ import Image from '@plone/volto/components/theme/Image/Image';
8
9
 
9
10
  const defaultSize = 30;
10
11
  const defaultColor = 'Teal';
@@ -15,7 +16,7 @@ const Avatar = ({ src, title, text, size, color, className }) => {
15
16
  return (
16
17
  <div className={className} title={title}>
17
18
  {src ? (
18
- <img src={src} alt={title}></img>
19
+ <Image src={src} alt={title} />
19
20
  ) : (
20
21
  <svg width={size} height={size}>
21
22
  <circle cx={radius} cy={radius} r={radius} fill={color} />
@@ -7,11 +7,7 @@ import CommentEditModal from './CommentEditModal';
7
7
 
8
8
  const mockStore = configureStore();
9
9
 
10
- vi.mock('@plone/volto/components/manage/Form', async () => {
11
- return await import(
12
- '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
13
- );
14
- });
10
+ vi.mock('@plone/volto/components/manage/Form');
15
11
 
16
12
  describe('CommentEditModal', () => {
17
13
  it('renders a comment edit modal component', () => {
@@ -19,17 +19,8 @@ vi.mock('moment', () => ({
19
19
  })),
20
20
  }));
21
21
 
22
- vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
23
- return await import(
24
- '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
25
- );
26
- });
27
- vi.mock('@plone/volto/components/manage/Form', async () => {
28
- return await import(
29
- '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
30
- );
31
- });
32
-
22
+ vi.mock('@plone/volto/helpers/Loadable/Loadable');
23
+ vi.mock('@plone/volto/components/manage/Form');
33
24
  beforeAll(async () => {
34
25
  const { __setLoadables } = await import(
35
26
  '@plone/volto/helpers/Loadable/Loadable'
@@ -9,11 +9,7 @@ vi.mock('../../manage/Toolbar/Toolbar', () => ({
9
9
  default: vi.fn(() => <div id="Portal" />),
10
10
  }));
11
11
 
12
- vi.mock('@plone/volto/components/manage/Form', async () => {
13
- return await import(
14
- '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
15
- );
16
- });
12
+ vi.mock('@plone/volto/components/manage/Form');
17
13
 
18
14
  const mockStore = configureStore();
19
15
  describe('Contact form', () => {
@@ -82,9 +82,27 @@ export default {
82
82
  ],
83
83
  argTypes: {
84
84
  locale: {
85
+ options: [
86
+ 'ca',
87
+ 'de',
88
+ 'en',
89
+ 'es',
90
+ 'eu',
91
+ 'fi',
92
+ 'fr',
93
+ 'hi',
94
+ 'it',
95
+ 'ja',
96
+ 'nl',
97
+ 'pt',
98
+ 'pt-BR',
99
+ 'ro',
100
+ 'ru',
101
+ 'sv',
102
+ 'zh-CN',
103
+ ],
85
104
  control: {
86
- type: 'select',
87
- options: ['en', 'de', 'us'],
105
+ type: 'radio',
88
106
  },
89
107
  },
90
108
  },
@@ -1,6 +1,10 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import cx from 'classnames';
3
- import { flattenToAppURL, flattenScales } from '@plone/volto/helpers/Url/Url';
3
+ import {
4
+ flattenToAppURL,
5
+ flattenScales,
6
+ addSubpathPrefix,
7
+ } from '@plone/volto/helpers/Url/Url';
4
8
 
5
9
  /**
6
10
  * Image component
@@ -30,7 +34,7 @@ export default function Image({
30
34
  attrs.className = cx(className, { responsive }) || undefined;
31
35
 
32
36
  if (!item && src) {
33
- attrs.src = src;
37
+ attrs.src = addSubpathPrefix(src);
34
38
  } else {
35
39
  const isFromRealObject = !item.image_scales;
36
40
  const imageFieldWithDefault = imageField || item.image_field || 'image';
@@ -46,9 +50,11 @@ export default function Image({
46
50
 
47
51
  const isSvg = image['content-type'] === 'image/svg+xml';
48
52
  // In case `base_path` is present (`preview_image_link`) use it as base path
49
- const basePath = image.base_path || item['@id'];
53
+ const basePath = addSubpathPrefix(
54
+ flattenToAppURL(image.base_path || item['@id']),
55
+ );
56
+ attrs.src = `${basePath}/${image.download}`;
50
57
 
51
- attrs.src = `${flattenToAppURL(basePath)}/${image.download}`;
52
58
  attrs.width = image.width;
53
59
  attrs.height = image.height;
54
60
 
@@ -67,10 +73,7 @@ export default function Image({
67
73
  });
68
74
 
69
75
  attrs.srcSet = sortedScales
70
- .map(
71
- (scale) =>
72
- `${flattenToAppURL(basePath)}/${scale.download} ${scale.width}w`,
73
- )
76
+ .map((scale) => `${basePath}/${scale.download} ${scale.width}w`)
74
77
  .join(', ');
75
78
  }
76
79
  }
@@ -0,0 +1,7 @@
1
+ import '@plone/components/dist/basic.css';
2
+
3
+ const InjectPloneComponentsCSS = () => {
4
+ return null;
5
+ };
6
+
7
+ export default InjectPloneComponentsCSS;
@@ -3,15 +3,9 @@ import renderer from 'react-test-renderer';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
- import config from '@plone/volto/registry';
7
6
 
8
7
  import LanguageSelector from './LanguageSelector';
9
8
 
10
- beforeAll(() => {
11
- config.settings.isMultilingual = true;
12
- config.settings.supportedLanguages = ['de', 'es'];
13
- });
14
-
15
9
  const mockStore = configureStore();
16
10
 
17
11
  describe('LanguageSelector', () => {
@@ -30,6 +24,12 @@ describe('LanguageSelector', () => {
30
24
  },
31
25
  },
32
26
  },
27
+ site: {
28
+ data: {
29
+ features: { multilingual: true },
30
+ 'plone.available_languages': ['es'],
31
+ },
32
+ },
33
33
  });
34
34
  const component = renderer.create(
35
35
  <Provider store={store}>
@@ -0,0 +1,89 @@
1
+ import { Link } from 'react-router-dom';
2
+
3
+ import { useSelector } from 'react-redux';
4
+ import cx from 'classnames';
5
+
6
+ import Helmet from '@plone/volto/helpers/Helmet/Helmet';
7
+ import langmap from '@plone/volto/helpers/LanguageMap/LanguageMap';
8
+ import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
9
+ import { toReactIntlLang } from '@plone/volto/helpers/Utils/Utils';
10
+
11
+ import { defineMessages, useIntl, type IntlShape } from 'react-intl';
12
+ import type {
13
+ Content,
14
+ GetSiteResponse,
15
+ GetTranslationResponse,
16
+ } from '@plone/types';
17
+
18
+ const messages = defineMessages({
19
+ switchLanguageTo: {
20
+ id: 'Switch to',
21
+ defaultMessage: 'Switch to',
22
+ },
23
+ });
24
+
25
+ type FormState = {
26
+ content: {
27
+ data: Content;
28
+ };
29
+ intl: IntlShape;
30
+ site: {
31
+ data: GetSiteResponse;
32
+ };
33
+ };
34
+
35
+ const LanguageSelector = ({
36
+ onClickAction = () => {},
37
+ }: {
38
+ onClickAction?: () => void;
39
+ }) => {
40
+ const intl = useIntl();
41
+ const currentLang = useSelector<FormState, IntlShape['locale']>(
42
+ (state) => state.intl.locale,
43
+ );
44
+ const translations = useSelector<
45
+ FormState,
46
+ GetTranslationResponse['items'] | undefined
47
+ >((state) => state.content.data?.['@components']?.translations?.items);
48
+ const isMultilingual = useSelector<
49
+ FormState,
50
+ GetSiteResponse['features']['multilingual']
51
+ >((state) => state.site.data.features?.multilingual);
52
+ const availableLanguages = useSelector<
53
+ FormState,
54
+ GetSiteResponse['plone.available_languages']
55
+ >((state) => state.site.data?.['plone.available_languages']);
56
+
57
+ return isMultilingual ? (
58
+ <div className="language-selector">
59
+ {availableLanguages?.map((lang) => {
60
+ const langKey = lang as keyof typeof langmap;
61
+ const translation = translations?.find(
62
+ (t: { language: string }) => t.language === lang,
63
+ );
64
+ return (
65
+ <Link
66
+ aria-label={`${intl.formatMessage(
67
+ messages.switchLanguageTo,
68
+ )} ${langmap[langKey].nativeName.toLowerCase()}`}
69
+ className={cx({ selected: toReactIntlLang(lang) === currentLang })}
70
+ to={translation ? flattenToAppURL(translation['@id']) : `/${lang}`}
71
+ title={langmap[langKey].nativeName}
72
+ onClick={() => {
73
+ onClickAction();
74
+ }}
75
+ key={`language-selector-${lang}`}
76
+ >
77
+ {langmap[langKey].nativeName}
78
+ </Link>
79
+ );
80
+ })}
81
+ </div>
82
+ ) : (
83
+ <Helmet>
84
+ <html lang={toReactIntlLang(currentLang)} />
85
+ </Helmet>
86
+ );
87
+ };
88
+
89
+ export default LanguageSelector;
@@ -3,14 +3,9 @@ import renderer from 'react-test-renderer';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
- import config from '@plone/volto/registry';
7
6
 
8
7
  import Logo from './Logo';
9
8
 
10
- beforeAll(() => {
11
- config.settings.isMultilingual = true;
12
- });
13
-
14
9
  const mockStore = configureStore();
15
10
 
16
11
  describe('Multilingual Logo', () => {
@@ -1,28 +1,24 @@
1
1
  import React from 'react';
2
2
  import { Redirect } from 'react-router-dom';
3
- import { useDispatch } from 'react-redux';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
4
  import { useCookies } from 'react-cookie';
5
- import config from '@plone/volto/registry';
6
5
  import { changeLanguage } from '@plone/volto/actions/language/language';
7
- import { toGettextLang } from '@plone/volto/helpers/Utils/Utils';
6
+ import { toGettextLang, toBackendLang } from '@plone/volto/helpers/Utils/Utils';
8
7
 
9
8
  const MultilingualRedirector = (props) => {
10
- const { settings } = config;
11
9
  const { pathname, children } = props;
12
10
  const [cookies] = useCookies();
13
- const currentLanguage = cookies['I18N_LANGUAGE'] || settings.defaultLanguage;
14
- const redirectToLanguage = settings.supportedLanguages.includes(
15
- currentLanguage,
16
- )
17
- ? currentLanguage
18
- : settings.defaultLanguage;
11
+ const site = useSelector((state) => state.site.data);
12
+ const isMultilingual = site.features?.multilingual;
13
+ const redirectToLanguage =
14
+ cookies['I18N_LANGUAGE'] || site['plone.default_language'];
19
15
  const dispatch = useDispatch();
20
16
 
21
17
  React.useEffect(() => {
22
18
  // ToDo: Add means to support language negotiation (with config)
23
19
  // const detectedLang = (navigator.language || navigator.userLanguage).substring(0, 2);
24
20
  let mounted = true;
25
- if (settings.isMultilingual && pathname === '/') {
21
+ if (isMultilingual && pathname === '/') {
26
22
  const langFileName = toGettextLang(redirectToLanguage);
27
23
  import(
28
24
  /* @vite-ignore */ '@root/../locales/' + langFileName + '.json'
@@ -35,10 +31,10 @@ const MultilingualRedirector = (props) => {
35
31
  return () => {
36
32
  mounted = false;
37
33
  };
38
- }, [pathname, dispatch, redirectToLanguage, settings.isMultilingual]);
34
+ }, [pathname, dispatch, redirectToLanguage, isMultilingual]);
39
35
 
40
- return pathname === '/' && settings.isMultilingual ? (
41
- <Redirect to={`/${redirectToLanguage}`} />
36
+ return pathname === '/' && isMultilingual ? (
37
+ <Redirect to={`/${toBackendLang(redirectToLanguage)}`} />
42
38
  ) : (
43
39
  <>{children}</>
44
40
  );
@@ -3,19 +3,17 @@ import renderer from 'react-test-renderer';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
- import config from '@plone/volto/registry';
7
6
 
8
7
  import MultilingualRedirector from './MultilingualRedirector';
9
8
 
10
- beforeAll(() => {
11
- config.settings.isMultilingual = true;
12
- });
13
-
14
9
  const mockStore = configureStore();
15
10
 
16
11
  describe('MultilingualRedirector', () => {
17
12
  it('renders a MultilingualRedirector component', () => {
18
13
  const store = mockStore({
14
+ site: {
15
+ data: {},
16
+ },
19
17
  intl: {
20
18
  locale: 'en',
21
19
  messages: {},
@@ -15,11 +15,7 @@ const NavItem = ({ item, lang }) => {
15
15
  key={item.url}
16
16
  className="item"
17
17
  activeClassName="active"
18
- exact={
19
- settings.isMultilingual
20
- ? item.url === `/${toBackendLang(lang)}`
21
- : item.url === ''
22
- }
18
+ exact={item.url === '' || item.url === `/${toBackendLang(lang)}`}
23
19
  >
24
20
  {item.title}
25
21
  </NavLink>
@@ -3,14 +3,9 @@ import renderer from 'react-test-renderer';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
- import config from '@plone/volto/registry';
7
6
 
8
7
  import Navigation from './Navigation';
9
8
 
10
- beforeAll(() => {
11
- config.settings.isMultilingual = true;
12
- });
13
-
14
9
  const mockStore = configureStore();
15
10
 
16
11
  describe('Navigation Multilingual', () => {
@@ -19,15 +19,18 @@ import config from '@plone/volto/registry';
19
19
  const NotFound = () => {
20
20
  const dispatch = useDispatch();
21
21
  const lang = useSelector((state) => state.intl.locale);
22
+ const isMultilingual = useSelector(
23
+ (state) => state.site.data.features?.multilingual,
24
+ );
22
25
 
23
26
  useEffect(() => {
24
27
  dispatch(
25
28
  getNavigation(
26
- config.settings.isMultilingual ? `/${toBackendLang(lang)}` : '/',
29
+ isMultilingual ? `/${toBackendLang(lang)}` : '/',
27
30
  config.settings.navDepth,
28
31
  ),
29
32
  );
30
- }, [dispatch, lang]);
33
+ }, [dispatch, lang, isMultilingual]);
31
34
 
32
35
  return (
33
36
  <Container className="view-wrapper">
@@ -13,6 +13,9 @@ const mockStore = configureStore();
13
13
  describe('NotFound', () => {
14
14
  it('renders a not found component', () => {
15
15
  const store = mockStore({
16
+ site: {
17
+ data: {},
18
+ },
16
19
  intl: {
17
20
  locale: 'en',
18
21
  messages: {},
@@ -6,11 +6,7 @@ import { MemoryRouter } from 'react-router-dom';
6
6
 
7
7
  import RequestPasswordReset from './RequestPasswordReset';
8
8
 
9
- vi.mock('@plone/volto/components/manage/Form', async () => {
10
- return await import(
11
- '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
12
- );
13
- });
9
+ vi.mock('@plone/volto/components/manage/Form');
14
10
 
15
11
  const mockStore = configureStore();
16
12
 
@@ -25,7 +25,7 @@ function PreviewImage({ item, alt, image_field, showDefault = true, ...rest }) {
25
25
  return image;
26
26
  } else {
27
27
  return (
28
- <img
28
+ <Image
29
29
  src={
30
30
  config.getComponent({
31
31
  name: 'DefaultImage',
@@ -6,11 +6,7 @@ import { MemoryRouter } from 'react-router-dom';
6
6
 
7
7
  import Register from './Register';
8
8
 
9
- vi.mock('@plone/volto/components/manage/Form', async () => {
10
- return await import(
11
- '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
12
- );
13
- });
9
+ vi.mock('@plone/volto/components/manage/Form');
14
10
 
15
11
  const mockStore = configureStore();
16
12
 
@@ -29,7 +29,7 @@ const RequestTimeout = () => (
29
29
  <h1 style={{ textAlign: 'center', lineHeight: '40px' }}>
30
30
  <FormattedMessage
31
31
  id="No connection to the server"
32
- defaultMessage="There is no connection to the server, due to a timeout o no network connection."
32
+ defaultMessage="There is no connection to the server, due to a timeout or no network connection."
33
33
  />
34
34
  <br />
35
35
  <a href={config.settings.apiPath}>{config.settings.apiPath}</a>
@@ -36,14 +36,14 @@ function Sitemap(props) {
36
36
  location: { pathname },
37
37
  lang,
38
38
  getNavigation,
39
+ isMultilingual,
39
40
  } = props;
40
41
 
41
42
  useEffect(() => {
42
- const { settings } = config;
43
- const language = settings.isMultilingual ? `${toBackendLang(lang)}` : null;
43
+ const language = isMultilingual ? `${toBackendLang(lang)}` : null;
44
44
  const path = getSitemapPath(pathname, language);
45
45
  getNavigation(path, 4);
46
- }, [pathname, lang, getNavigation]);
46
+ }, [pathname, lang, getNavigation, isMultilingual]);
47
47
 
48
48
  const renderItems = (items) => {
49
49
  return (
@@ -100,6 +100,7 @@ export default compose(
100
100
  (state) => ({
101
101
  items: state.navigation.items,
102
102
  lang: state.intl.locale,
103
+ isMultilingual: state.site.data.features?.multilingual,
103
104
  }),
104
105
  { getNavigation },
105
106
  ),
@@ -108,10 +109,10 @@ export default compose(
108
109
  key: 'navigation',
109
110
  promise: ({ location, store: { dispatch, getState } }) => {
110
111
  if (!__SERVER__) return;
111
- const { settings } = config;
112
+ const state = getState();
112
113
  const path = getSitemapPath(
113
114
  location.pathname,
114
- settings.isMultilingual
115
+ state.site.data.features?.multilingual
115
116
  ? toBackendLang(getState().intl.locale)
116
117
  : null,
117
118
  );
@@ -58,7 +58,6 @@ describe('Sitemap', () => {
58
58
 
59
59
  describe('Sitemap in a multilingual site', () => {
60
60
  beforeEach(() => {
61
- config.settings.isMultilingual = true;
62
61
  config.settings.supportedLanguages = ['en', 'es'];
63
62
  });
64
63
  it('renders a sitemap component', () => {
@@ -5,6 +5,7 @@ import { useSelector } from 'react-redux';
5
5
  import { useLocation } from 'react-router-dom';
6
6
  import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
7
7
  import { getBaseUrl } from '@plone/volto/helpers/Url/Url';
8
+ import BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
8
9
 
9
10
  const Unauthorized = () => {
10
11
  const error_message = useSelector((state) => state.apierror?.message);
@@ -12,6 +13,7 @@ const Unauthorized = () => {
12
13
 
13
14
  return (
14
15
  <Container className="view-wrapper">
16
+ <BodyClass className="view-unauthorized" />
15
17
  <h1>
16
18
  <FormattedMessage id="Unauthorized" defaultMessage="Unauthorized" />
17
19
  </h1>
@@ -62,5 +64,6 @@ const Unauthorized = () => {
62
64
  </Container>
63
65
  );
64
66
  };
65
-
66
- export default withServerErrorCode(401)(Unauthorized);
67
+ const UnauthorizedWithCode = withServerErrorCode(401)(Unauthorized);
68
+ UnauthorizedWithCode.displayName = 'unauthorized';
69
+ export default UnauthorizedWithCode;
@@ -5,12 +5,7 @@ import { When } from './EventDatesInfo';
5
5
  import configureStore from 'redux-mock-store';
6
6
  const mockStore = configureStore();
7
7
 
8
- vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
9
- return await import(
10
- '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
11
- );
12
- });
13
-
8
+ vi.mock('@plone/volto/helpers/Loadable/Loadable');
14
9
  beforeAll(async () => {
15
10
  const { __setLoadables } = await import(
16
11
  '@plone/volto/helpers/Loadable/Loadable'
@@ -14,12 +14,7 @@ const store = mockStore({
14
14
  },
15
15
  });
16
16
 
17
- vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
18
- return await import(
19
- '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
20
- );
21
- });
22
-
17
+ vi.mock('@plone/volto/helpers/Loadable/Loadable');
23
18
  beforeAll(async () => {
24
19
  const { __setLoadables } = await import(
25
20
  '@plone/volto/helpers/Loadable/Loadable'
@@ -7,6 +7,7 @@ import React from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { Container as SemanticContainer } from 'semantic-ui-react';
9
9
  import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
10
+ import { FormattedMessage } from 'react-intl';
10
11
  import config from '@plone/volto/registry';
11
12
 
12
13
  /**
@@ -30,7 +31,14 @@ const FileView = ({ content }) => {
30
31
  )}
31
32
  {content.file?.download && (
32
33
  <a href={flattenToAppURL(content.file.download)}>
33
- {content.file.filename}
34
+ {content.file.filename ? (
35
+ content.file.filename
36
+ ) : (
37
+ <FormattedMessage
38
+ id="Download file"
39
+ defaultMessage="Download file"
40
+ />
41
+ )}
34
42
  </a>
35
43
  )}
36
44
  </Container>
@@ -222,6 +222,13 @@ class View extends Component {
222
222
  }
223
223
  return (
224
224
  <div id="view">
225
+ <BodyClass
226
+ className={
227
+ FoundView.displayName
228
+ ? `view-${this.cleanViewName(FoundView.displayName)}`
229
+ : null
230
+ }
231
+ />
225
232
  <FoundView {...this.props} />
226
233
  </div>
227
234
  );
@@ -246,7 +253,7 @@ class View extends Component {
246
253
  />
247
254
  <SlotRenderer name="aboveContent" content={this.props.content} />
248
255
  <RenderedView
249
- key={this.props.content['@id']}
256
+ key={flattenToAppURL(this.props.content['@id'])}
250
257
  content={this.props.content}
251
258
  location={this.props.location}
252
259
  token={this.props.token}
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import cx from 'classnames';
3
3
  import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
4
+ import Image from '@plone/volto/components/theme/Image/Image';
4
5
 
5
6
  const niceBytes = (bytes) => {
6
7
  bytes = Number(bytes);
@@ -18,7 +19,7 @@ const niceBytes = (bytes) => {
18
19
  const ImageWidget = ({ value, className }) =>
19
20
  value ? (
20
21
  <span className={cx(className, 'image', 'widget')}>
21
- <img
22
+ <Image
22
23
  src={
23
24
  value.data
24
25
  ? `data:${value['content-type']};base64,${value.data}`
@@ -77,6 +77,7 @@ export const unwantedControlPanelsFields = {
77
77
  'exposeDCMetaTags',
78
78
  'enable_sitemap',
79
79
  'webstats_js',
80
+ 'webstats_head_js',
80
81
  ],
81
82
  editing: ['available_editors', 'default_editor', 'ext_editor'],
82
83
  imaging: [