@plone/volto 19.0.0-alpha.3 → 19.0.0-alpha.30

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 (502) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +37 -6
  3. package/CHANGELOG.md +534 -2
  4. package/README.md +23 -21
  5. package/babel.js +1 -9
  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/LC_MESSAGES/volto.po +5500 -0
  13. package/locales/af.json +1 -1
  14. package/locales/ar/LC_MESSAGES/volto.po +5500 -0
  15. package/locales/ar.json +1 -1
  16. package/locales/bg/LC_MESSAGES/volto.po +5500 -0
  17. package/locales/bg.json +1 -1
  18. package/locales/bn/LC_MESSAGES/volto.po +5500 -0
  19. package/locales/bn.json +1 -1
  20. package/locales/ca/LC_MESSAGES/volto.po +559 -349
  21. package/locales/ca.json +1 -1
  22. package/locales/cs/LC_MESSAGES/volto.po +5500 -0
  23. package/locales/cs.json +1 -1
  24. package/locales/cy/LC_MESSAGES/volto.po +5500 -0
  25. package/locales/cy.json +1 -1
  26. package/locales/da/LC_MESSAGES/volto.po +5500 -0
  27. package/locales/da.json +1 -1
  28. package/locales/de/LC_MESSAGES/volto.po +232 -21
  29. package/locales/de.json +1 -1
  30. package/locales/el/LC_MESSAGES/volto.po +5500 -0
  31. package/locales/el.json +1 -1
  32. package/locales/en/LC_MESSAGES/volto.po +226 -11
  33. package/locales/en.json +1 -1
  34. package/locales/en_AU/LC_MESSAGES/volto.po +5500 -0
  35. package/locales/en_AU.json +1 -1
  36. package/locales/en_GB/LC_MESSAGES/volto.po +5500 -0
  37. package/locales/en_GB.json +1 -1
  38. package/locales/eo/LC_MESSAGES/volto.po +5500 -0
  39. package/locales/eo.json +1 -1
  40. package/locales/es/LC_MESSAGES/volto.po +321 -111
  41. package/locales/es.json +1 -1
  42. package/locales/et/LC_MESSAGES/volto.po +5500 -0
  43. package/locales/et.json +1 -1
  44. package/locales/eu/LC_MESSAGES/volto.po +404 -194
  45. package/locales/eu.json +1 -1
  46. package/locales/fa/LC_MESSAGES/volto.po +5500 -0
  47. package/locales/fa.json +1 -1
  48. package/locales/fi/LC_MESSAGES/volto.po +221 -11
  49. package/locales/fi.json +1 -1
  50. package/locales/fr/LC_MESSAGES/volto.po +220 -10
  51. package/locales/fr.json +1 -1
  52. package/locales/fu/LC_MESSAGES/volto.po +5500 -0
  53. package/locales/fu.json +1 -1
  54. package/locales/gl/LC_MESSAGES/volto.po +5501 -0
  55. package/locales/gl.json +1 -1
  56. package/locales/he/LC_MESSAGES/volto.po +5500 -0
  57. package/locales/he.json +1 -1
  58. package/locales/hi/LC_MESSAGES/volto.po +225 -10
  59. package/locales/hi.json +1 -1
  60. package/locales/hr/LC_MESSAGES/volto.po +5500 -0
  61. package/locales/hr.json +1 -1
  62. package/locales/hu/LC_MESSAGES/volto.po +5500 -0
  63. package/locales/hu.json +1 -1
  64. package/locales/hy/LC_MESSAGES/volto.po +5500 -0
  65. package/locales/hy.json +1 -1
  66. package/locales/id/LC_MESSAGES/volto.po +5500 -0
  67. package/locales/id.json +1 -1
  68. package/locales/it/LC_MESSAGES/volto.po +239 -24
  69. package/locales/it.json +1 -1
  70. package/locales/ja/LC_MESSAGES/volto.po +264 -53
  71. package/locales/ja.json +1 -1
  72. package/locales/ka/LC_MESSAGES/volto.po +5500 -0
  73. package/locales/ka.json +1 -1
  74. package/locales/kn/LC_MESSAGES/volto.po +5500 -0
  75. package/locales/kn.json +1 -1
  76. package/locales/ko/LC_MESSAGES/volto.po +5500 -0
  77. package/locales/ko.json +1 -1
  78. package/locales/lt/LC_MESSAGES/volto.po +5500 -0
  79. package/locales/lt.json +1 -1
  80. package/locales/lv/LC_MESSAGES/volto.po +5500 -0
  81. package/locales/lv.json +1 -1
  82. package/locales/mi/LC_MESSAGES/volto.po +5500 -0
  83. package/locales/mi.json +1 -1
  84. package/locales/mk/LC_MESSAGES/volto.po +5500 -0
  85. package/locales/mk.json +1 -1
  86. package/locales/my/LC_MESSAGES/volto.po +5500 -0
  87. package/locales/my.json +1 -1
  88. package/locales/nb_NO/LC_MESSAGES/volto.po +5500 -0
  89. package/locales/nb_NO.json +1 -1
  90. package/locales/nl/LC_MESSAGES/volto.po +243 -32
  91. package/locales/nl.json +1 -1
  92. package/locales/nn/LC_MESSAGES/volto.po +5500 -0
  93. package/locales/nn.json +1 -1
  94. package/locales/pl/LC_MESSAGES/volto.po +5500 -0
  95. package/locales/pl.json +1 -1
  96. package/locales/pt/LC_MESSAGES/volto.po +869 -659
  97. package/locales/pt.json +1 -1
  98. package/locales/pt_BR/LC_MESSAGES/volto.po +229 -19
  99. package/locales/pt_BR.json +1 -1
  100. package/locales/rm/LC_MESSAGES/volto.po +5500 -0
  101. package/locales/rm.json +1 -1
  102. package/locales/ro/LC_MESSAGES/volto.po +252 -42
  103. package/locales/ro.json +1 -1
  104. package/locales/ru/LC_MESSAGES/volto.po +220 -10
  105. package/locales/ru.json +1 -1
  106. package/locales/sk/LC_MESSAGES/volto.po +5500 -0
  107. package/locales/sk.json +1 -1
  108. package/locales/sl/LC_MESSAGES/volto.po +5500 -0
  109. package/locales/sl.json +1 -1
  110. package/locales/sm/LC_MESSAGES/volto.po +5500 -0
  111. package/locales/sm.json +1 -1
  112. package/locales/sq/LC_MESSAGES/volto.po +5500 -0
  113. package/locales/sq.json +1 -1
  114. package/locales/sr/LC_MESSAGES/volto.po +5500 -0
  115. package/locales/sr.json +1 -1
  116. package/locales/sr@cyrl/LC_MESSAGES/volto.po +5500 -0
  117. package/locales/sr@cyrl.json +1 -1
  118. package/locales/sr@latn/LC_MESSAGES/volto.po +5500 -0
  119. package/locales/sr@latn.json +1 -1
  120. package/locales/sv/LC_MESSAGES/volto.po +5500 -0
  121. package/locales/sv.json +1 -1
  122. package/locales/ta/LC_MESSAGES/volto.po +5501 -0
  123. package/locales/ta.json +1 -1
  124. package/locales/te/LC_MESSAGES/volto.po +5500 -0
  125. package/locales/te.json +1 -1
  126. package/locales/th/LC_MESSAGES/volto.po +5500 -0
  127. package/locales/th.json +1 -1
  128. package/locales/to/LC_MESSAGES/volto.po +5500 -0
  129. package/locales/to.json +1 -1
  130. package/locales/tr/LC_MESSAGES/volto.po +5501 -0
  131. package/locales/tr.json +1 -1
  132. package/locales/uk/LC_MESSAGES/volto.po +5500 -0
  133. package/locales/uk.json +1 -1
  134. package/locales/vi/LC_MESSAGES/volto.po +5500 -0
  135. package/locales/vi.json +1 -1
  136. package/locales/volto.pot +220 -10
  137. package/locales/zh_CN/LC_MESSAGES/volto.po +221 -10
  138. package/locales/zh_CN.json +1 -1
  139. package/locales/zh_Hant/LC_MESSAGES/volto.po +5500 -0
  140. package/locales/zh_Hant.json +1 -1
  141. package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +5500 -0
  142. package/locales/zh_Hant_HK.json +1 -1
  143. package/package.json +72 -146
  144. package/razzle.config.js +32 -25
  145. package/src/actions/blockTypes/blockTypes.ts +24 -0
  146. package/src/components/manage/Actions/Actions.test.jsx +1 -5
  147. package/src/components/manage/Add/Add.jsx +15 -10
  148. package/src/components/manage/BlockChooser/BlockChooser.jsx +1 -0
  149. package/src/components/manage/Blocks/Block/BlocksForm.jsx +10 -7
  150. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +3 -14
  151. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +9 -4
  152. package/src/components/manage/Blocks/Block/Order/Item.jsx +27 -13
  153. package/src/components/manage/Blocks/Block/Order/Item.test.jsx +90 -0
  154. package/src/components/manage/Blocks/Block/Order/Order.jsx +116 -67
  155. package/src/components/manage/Blocks/Block/Order/utilities.js +28 -11
  156. package/src/components/manage/Blocks/Block/Settings.test.jsx +1 -5
  157. package/src/components/manage/Blocks/Grid/View.jsx +14 -11
  158. package/src/components/manage/Blocks/Grid/context.js +3 -0
  159. package/src/components/manage/Blocks/HTML/Edit.test.jsx +1 -5
  160. package/src/components/manage/Blocks/Image/Edit.jsx +5 -1
  161. package/src/components/manage/Blocks/Image/ImageSidebar.test.jsx +2 -5
  162. package/src/components/manage/Blocks/LeadImage/Edit.jsx +2 -2
  163. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +1 -1
  164. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +2 -5
  165. package/src/components/manage/Blocks/Listing/Edit.jsx +1 -0
  166. package/src/components/manage/Blocks/Listing/ImageGallery.jsx +6 -4
  167. package/src/components/manage/Blocks/Listing/ListingBody.jsx +4 -0
  168. package/src/components/manage/Blocks/Maps/Edit.jsx +2 -1
  169. package/src/components/manage/Blocks/Maps/MapsSidebar.test.jsx +1 -5
  170. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +21 -4
  171. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +1 -6
  172. package/src/components/manage/Blocks/Search/components/SelectFacet.jsx +22 -1
  173. package/src/components/manage/Blocks/Search/components/SelectFacet.test.jsx +1 -6
  174. package/src/components/manage/Blocks/Search/components/SortOn.jsx +8 -2
  175. package/src/components/manage/Blocks/Search/components/ToggleFacet.jsx +14 -0
  176. package/src/components/manage/Blocks/Teaser/Data.jsx +21 -7
  177. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +11 -3
  178. package/src/components/manage/Blocks/Teaser/View.jsx +0 -1
  179. package/src/components/manage/Blocks/Teaser/utils.js +13 -0
  180. package/src/components/manage/Blocks/Teaser/utils.test.js +34 -0
  181. package/src/components/manage/Blocks/Title/Edit.jsx +5 -0
  182. package/src/components/manage/Blocks/Video/Body.jsx +69 -43
  183. package/src/components/manage/Blocks/Video/Body.test.jsx +122 -5
  184. package/src/components/manage/Blocks/Video/Edit.jsx +22 -3
  185. package/src/components/manage/Blocks/Video/Edit.test.jsx +6 -0
  186. package/src/components/manage/Blocks/Video/VideoSidebar.test.jsx +1 -5
  187. package/src/components/manage/Blocks/Video/View.jsx +1 -0
  188. package/src/components/manage/Blocks/Video/View.test.jsx +29 -15
  189. package/src/components/manage/Blocks/Video/schema.js +14 -1
  190. package/src/components/manage/Contents/Contents.jsx +697 -659
  191. package/src/components/manage/Contents/Contents.test.jsx +1 -5
  192. package/src/components/manage/Contents/ContentsBreadcrumbs.jsx +6 -5
  193. package/src/components/manage/Contents/ContentsItem.jsx +1 -1
  194. package/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +1 -5
  195. package/src/components/manage/Contents/ContentsRenameModal.test.jsx +1 -5
  196. package/src/components/manage/Contents/ContentsTagsModal.test.jsx +1 -5
  197. package/src/components/manage/Contents/ContentsWorkflowModal.test.jsx +1 -5
  198. package/src/components/manage/Contents/DropZoneContent.jsx +338 -0
  199. package/src/components/manage/Contents/__mocks__/index.tsx +2 -18
  200. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +7 -0
  201. package/src/components/manage/Controlpanels/Aliases.test.jsx +1 -5
  202. package/src/components/manage/Controlpanels/BlockType.tsx +166 -0
  203. package/src/components/manage/Controlpanels/BlockTypes.tsx +145 -0
  204. package/src/components/manage/Controlpanels/ContentType.jsx +1 -1
  205. package/src/components/manage/Controlpanels/ContentType.test.jsx +1 -5
  206. package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -1
  207. package/src/components/manage/Controlpanels/Controlpanels.jsx +28 -5
  208. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +10 -0
  209. package/src/components/manage/Controlpanels/DatabaseInformation.jsx +9 -0
  210. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +3 -2
  211. package/src/components/manage/Controlpanels/ModerateComments.jsx +8 -0
  212. package/src/components/manage/Controlpanels/Relations/Relations.jsx +1 -1
  213. package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +1 -5
  214. package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +1 -5
  215. package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +1 -5
  216. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +156 -175
  217. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +3 -0
  218. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +575 -631
  219. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +58 -11
  220. package/src/components/manage/Diff/Diff.jsx +201 -298
  221. package/src/components/manage/Diff/Diff.test.jsx +1 -6
  222. package/src/components/manage/Diff/DiffField.test.jsx +1 -6
  223. package/src/components/manage/Display/Display.test.jsx +2 -11
  224. package/src/components/manage/Edit/Edit.test.jsx +1 -5
  225. package/src/components/manage/Form/BlockDataForm.test.jsx +1 -5
  226. package/src/components/manage/Form/Form.jsx +3 -3
  227. package/src/components/manage/Form/Form.test.jsx +1 -5
  228. package/src/components/manage/Form/InlineForm.jsx +2 -2
  229. package/src/components/manage/Form/InlineForm.test.jsx +1 -5
  230. package/src/components/manage/Form/ModalForm.jsx +12 -10
  231. package/src/components/manage/Form/ModalForm.test.jsx +27 -5
  232. package/src/components/manage/Form/__mocks__/index.tsx +9 -27
  233. package/src/components/manage/Multilingual/CompareLanguages.jsx +6 -6
  234. package/src/components/manage/Multilingual/CreateTranslation.jsx +16 -13
  235. package/src/components/manage/Multilingual/ManageTranslations.jsx +5 -5
  236. package/src/components/manage/Multilingual/TranslationObject.jsx +11 -8
  237. package/src/components/manage/Preferences/ChangePassword.test.jsx +1 -5
  238. package/src/components/manage/Preferences/PersonalPreferences.jsx +8 -5
  239. package/src/components/manage/Preferences/PersonalPreferences.test.jsx +1 -17
  240. package/src/components/manage/Sharing/Sharing.jsx +21 -15
  241. package/src/components/manage/Sidebar/ObjectBrowser.jsx +3 -0
  242. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +18 -2
  243. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
  244. package/src/components/manage/Sidebar/SidebarPortal.test.tsx +42 -0
  245. package/src/components/manage/Sidebar/SidebarPortal.tsx +48 -0
  246. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +2 -1
  247. package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +1 -0
  248. package/src/components/manage/Toast/Toast.jsx +32 -0
  249. package/src/components/manage/Toast/Toast.test.jsx +9 -5
  250. package/src/components/manage/Toolbar/PersonalTools.jsx +2 -1
  251. package/src/components/manage/Toolbar/PersonalTools.test.jsx +15 -0
  252. package/src/components/manage/Toolbar/Toolbar.jsx +14 -4
  253. package/src/components/manage/Toolbar/Types.crash.test.jsx +48 -0
  254. package/src/components/manage/Toolbar/Types.jsx +6 -4
  255. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +16 -0
  256. package/src/components/manage/UniversalLink/UniversalLink.tsx +2 -0
  257. package/src/components/manage/Widgets/AlignWidget.stories.jsx +9 -0
  258. package/src/components/manage/Widgets/AlignWidget.test.tsx +95 -0
  259. package/src/components/manage/Widgets/{AlignWidget.jsx → AlignWidget.tsx} +23 -7
  260. package/src/components/manage/Widgets/ArrayWidget.test.jsx +1 -6
  261. package/src/components/manage/Widgets/BlockAlignment.stories.tsx +104 -0
  262. package/src/components/manage/Widgets/BlockAlignment.test.tsx +104 -0
  263. package/src/components/manage/Widgets/BlockAlignment.tsx +88 -0
  264. package/src/components/manage/Widgets/BlockWidth.stories.tsx +69 -0
  265. package/src/components/manage/Widgets/BlockWidth.test.tsx +62 -0
  266. package/src/components/manage/Widgets/BlockWidth.tsx +101 -0
  267. package/src/components/manage/Widgets/ButtonsWidget.stories.jsx +61 -0
  268. package/src/components/manage/Widgets/ButtonsWidget.test.tsx +138 -0
  269. package/src/components/manage/Widgets/ButtonsWidget.tsx +195 -0
  270. package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +1 -6
  271. package/src/components/manage/Widgets/DatetimeWidget.jsx +102 -53
  272. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +56 -6
  273. package/src/components/manage/Widgets/FileWidget.jsx +21 -8
  274. package/src/components/manage/Widgets/FormFieldWrapper.jsx +146 -168
  275. package/src/components/manage/Widgets/ImageWidget.jsx +177 -38
  276. package/src/components/manage/Widgets/InternalUrlWidget.jsx +2 -0
  277. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +8 -0
  278. package/src/components/manage/Widgets/ObjectListWidget.test.jsx +2 -11
  279. package/src/components/manage/Widgets/ObjectWidget.test.jsx +1 -5
  280. package/src/components/manage/Widgets/QueryWidget.jsx +137 -9
  281. package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +1 -6
  282. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.test.jsx +1 -6
  283. package/src/components/manage/Widgets/RegistryImageWidget.jsx +1 -1
  284. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +4 -2
  285. package/src/components/manage/Widgets/SchemaWidget.test.jsx +1 -6
  286. package/src/components/manage/Widgets/SchemaWidgetFieldset.test.jsx +1 -6
  287. package/src/components/manage/Widgets/SelectAutoComplete.jsx +29 -12
  288. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +1 -6
  289. package/src/components/manage/Widgets/SelectWidget.test.jsx +1 -6
  290. package/src/components/manage/Widgets/Size.stories.tsx +69 -0
  291. package/src/components/manage/Widgets/Size.test.tsx +59 -0
  292. package/src/components/manage/Widgets/Size.tsx +78 -0
  293. package/src/components/manage/Widgets/TimeWidget.test.jsx +1 -6
  294. package/src/components/manage/Widgets/TokenWidget.test.jsx +1 -6
  295. package/src/components/manage/Widgets/UrlWidget.jsx +49 -18
  296. package/src/components/manage/Widgets/VocabularyTermsWidget.test.jsx +2 -11
  297. package/src/components/manage/Widgets/__mocks__/index.tsx +33 -51
  298. package/src/components/manage/Widgets/index.tsx +21 -0
  299. package/src/components/manage/Workflow/Workflow.test.jsx +2 -11
  300. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +1 -0
  301. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +30 -0
  302. package/src/components/theme/App/App.jsx +5 -1
  303. package/src/components/theme/Avatar/Avatar.jsx +2 -1
  304. package/src/components/theme/Comments/CommentEditModal.test.jsx +1 -5
  305. package/src/components/theme/Comments/Comments.test.jsx +2 -11
  306. package/src/components/theme/ConnectionRefused/ConnectionRefused.jsx +3 -2
  307. package/src/components/theme/ContactForm/ContactForm.test.jsx +1 -5
  308. package/src/components/theme/Image/Image.jsx +25 -13
  309. package/src/components/theme/Image/Image.test.jsx +247 -146
  310. package/src/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.tsx +7 -0
  311. package/src/components/theme/LanguageSelector/LanguageSelector.tsx +89 -0
  312. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +42 -12
  313. package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
  314. package/src/components/theme/PasswordReset/RequestPasswordReset.test.jsx +1 -5
  315. package/src/components/theme/PreviewImage/PreviewImage.jsx +1 -1
  316. package/src/components/theme/Register/Register.test.jsx +1 -5
  317. package/src/components/theme/RequestTimeout/RequestTimeout.jsx +1 -1
  318. package/src/components/theme/Sitemap/Sitemap.stories.jsx +82 -0
  319. package/src/components/theme/SlotRenderer/SlotRenderer.tsx +12 -6
  320. package/src/components/theme/Unauthorized/Unauthorized.jsx +35 -25
  321. package/src/components/theme/Unauthorized/Unauthorized.test.jsx +28 -1
  322. package/src/components/theme/VideoEmbed/VideoEmbed.jsx +100 -0
  323. package/src/components/theme/View/EventDatesInfo.test.jsx +1 -6
  324. package/src/components/theme/View/EventView.stories.jsx +89 -0
  325. package/src/components/theme/View/EventView.test.jsx +1 -6
  326. package/src/components/theme/View/FileView.stories.jsx +50 -0
  327. package/src/components/theme/View/ImageView.jsx +2 -1
  328. package/src/components/theme/View/ImageView.test.jsx +3 -0
  329. package/src/components/theme/View/LinkView.stories.jsx +57 -0
  330. package/src/components/theme/View/ListingView.stories.jsx +70 -0
  331. package/src/components/theme/View/NewsItemView.stories.jsx +58 -0
  332. package/src/components/theme/View/RenderBlocks.jsx +8 -10
  333. package/src/components/theme/View/RenderBlocks.stories.jsx +112 -0
  334. package/src/components/theme/View/RenderBlocks.test.jsx +14 -4
  335. package/src/components/theme/View/SummaryView.stories.jsx +71 -0
  336. package/src/components/theme/View/TabularView.stories.jsx +66 -0
  337. package/src/components/theme/View/View.jsx +8 -1
  338. package/src/components/theme/Widgets/ImageWidget.jsx +2 -1
  339. package/src/components/theme/Widgets/ImageWidget.test.jsx +31 -11
  340. package/src/config/Blocks.jsx +3 -0
  341. package/src/config/ControlPanels.js +3 -0
  342. package/src/config/Widgets.jsx +7 -0
  343. package/src/config/index.js +19 -12
  344. package/src/config/server.js +0 -2
  345. package/src/config/slots.js +19 -0
  346. package/src/config/validation.ts +8 -0
  347. package/src/constants/ActionTypes.js +1 -0
  348. package/src/express-middleware/devproxy.js +22 -5
  349. package/src/express-middleware/files.js +1 -0
  350. package/src/express-middleware/files.test.js +59 -0
  351. package/src/express-middleware/images.js +1 -0
  352. package/src/express-middleware/images.test.js +50 -0
  353. package/src/helpers/Api/APIResourceWithAuth.js +8 -3
  354. package/src/helpers/Api/Api.js +7 -4
  355. package/src/helpers/AsyncConnect/ssr.js +4 -1
  356. package/src/helpers/AuthToken/AuthToken.js +1 -6
  357. package/src/helpers/Blocks/Blocks.js +113 -28
  358. package/src/helpers/Blocks/Blocks.test.js +100 -0
  359. package/src/helpers/Content/Content.js +23 -0
  360. package/src/helpers/Content/Content.test.js +39 -0
  361. package/src/helpers/Content/withClientSideContent.jsx +35 -0
  362. package/src/helpers/Extensions/withBlockSchemaEnhancer.jsx +4 -1
  363. package/src/helpers/FormValidation/FormValidation.test.js +31 -0
  364. package/src/helpers/FormValidation/validators.ts +52 -6
  365. package/src/helpers/Html/Html.jsx +13 -4
  366. package/src/helpers/Loadable/__mocks__/Loadable.jsx +7 -22
  367. package/src/helpers/MessageLabels/MessageLabels.js +10 -0
  368. package/src/helpers/Sitemap/Sitemap.js +4 -4
  369. package/src/helpers/Url/Url.js +33 -2
  370. package/src/helpers/Url/Url.test.js +62 -0
  371. package/src/helpers/Utils/Utils.jsx +17 -0
  372. package/src/helpers/Utils/Utils.test.jsx +39 -0
  373. package/src/hooks/user/useUser.js +1 -1
  374. package/src/internalChecks.test.ts +11 -0
  375. package/src/middleware/api.js +17 -8
  376. package/src/middleware/storeProtectLoadUtils.test.js +3 -3
  377. package/src/reducers/blockTypes/blockTypes.js +38 -0
  378. package/src/reducers/content/content.js +3 -18
  379. package/src/reducers/diff/diff.js +5 -1
  380. package/src/reducers/diff/diff.test.js +60 -4
  381. package/src/reducers/index.js +2 -0
  382. package/src/reducers/querystring/querystring.js +8 -1
  383. package/src/reducers/users/users.js +1 -1
  384. package/src/routes.js +13 -1
  385. package/src/server.jsx +47 -13
  386. package/src/start-client.jsx +9 -2
  387. package/src/start-server.js +9 -3
  388. package/test-addons-loader.js +3 -0
  389. package/test-setup-globals.js +56 -2
  390. package/theme/themes/default/elements/segment.variables +9 -16
  391. package/theme/themes/pastanaga/collections/form.overrides +1 -1
  392. package/theme/themes/pastanaga/elements/segment.variables +1 -4
  393. package/theme/themes/pastanaga/extras/block-types.less +17 -0
  394. package/theme/themes/pastanaga/extras/blocks.less +19 -0
  395. package/theme/themes/pastanaga/extras/contents.less +75 -0
  396. package/theme/themes/pastanaga/extras/main.less +20 -4
  397. package/theme/themes/pastanaga/extras/toolbar.less +10 -5
  398. package/theme/themes/pastanaga/extras/videoembed.less +22 -0
  399. package/theme/themes/pastanaga/extras/widgets.less +79 -0
  400. package/tsconfig.declarations.json +1 -1
  401. package/tsconfig.json +4 -5
  402. package/types/actions/blockTypes/blockTypes.d.ts +7 -0
  403. package/types/components/index.d.ts +1 -1
  404. package/types/components/manage/Blocks/Block/Order/Item.test.d.ts +1 -0
  405. package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
  406. package/types/components/manage/Blocks/Grid/context.d.ts +1 -0
  407. package/types/components/manage/Blocks/Teaser/utils.d.ts +5 -0
  408. package/types/components/manage/Blocks/Video/Body.d.ts +4 -2
  409. package/types/components/manage/Blocks/Video/schema.d.ts +4 -0
  410. package/types/components/manage/Contents/DropZoneContent.d.ts +2 -0
  411. package/types/components/manage/Contents/__mocks__/index.d.ts +2 -2
  412. package/types/components/manage/Controlpanels/BlockType.d.ts +7 -0
  413. package/types/components/manage/Controlpanels/BlockTypes.d.ts +7 -0
  414. package/types/components/manage/Controlpanels/Relations/RelationsMatrix.d.ts +1 -1
  415. package/types/components/manage/Controlpanels/Users/RenderUsers.d.ts +18 -2
  416. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +6 -2
  417. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  418. package/types/components/manage/Diff/Diff.d.ts +7 -2
  419. package/types/components/manage/Form/__mocks__/index.d.ts +8 -8
  420. package/types/components/manage/Multilingual/ManageTranslations.d.ts +1 -1
  421. package/types/components/manage/Sidebar/ObjectBrowser.d.ts +1 -1
  422. package/types/components/manage/Sidebar/SidebarPortal.d.ts +7 -15
  423. package/types/components/manage/Toolbar/Types.crash.test.d.ts +1 -0
  424. package/types/components/manage/Widgets/AlignWidget.d.ts +8 -10
  425. package/types/components/manage/Widgets/AlignWidget.stories.d.ts +1 -0
  426. package/types/components/manage/Widgets/BlockAlignment.d.ts +7 -0
  427. package/types/components/manage/Widgets/BlockAlignment.stories.d.ts +8 -0
  428. package/types/components/manage/Widgets/BlockWidth.d.ts +7 -0
  429. package/types/components/manage/Widgets/BlockWidth.stories.d.ts +6 -0
  430. package/types/components/manage/Widgets/ButtonsWidget.d.ts +48 -1
  431. package/types/components/manage/Widgets/ButtonsWidget.stories.d.ts +3 -0
  432. package/types/components/manage/Widgets/FormFieldWrapper.d.ts +28 -5
  433. package/types/components/manage/Widgets/ImageWidget.d.ts +41 -1
  434. package/types/components/manage/Widgets/InternalUrlWidget.d.ts +1 -1
  435. package/types/components/manage/Widgets/ObjectBrowserWidget.d.ts +2 -0
  436. package/types/components/manage/Widgets/QueryWidget.d.ts +5 -2
  437. package/types/components/manage/Widgets/RecurrenceWidget/Utils.d.ts +12 -18
  438. package/types/components/manage/Widgets/Size.d.ts +7 -0
  439. package/types/components/manage/Widgets/Size.stories.d.ts +6 -0
  440. package/types/components/manage/Widgets/UrlWidget.d.ts +1 -1
  441. package/types/components/manage/Widgets/__mocks__/index.d.ts +33 -33
  442. package/types/components/manage/Widgets/index.d.ts +11 -6
  443. package/types/components/theme/ConnectionRefused/ConnectionRefused.d.ts +2 -2
  444. package/types/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.d.ts +3 -0
  445. package/types/components/theme/LanguageSelector/LanguageSelector.d.ts +3 -10
  446. package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
  447. package/types/components/theme/Sitemap/Sitemap.stories.d.ts +13 -0
  448. package/types/components/theme/SlotRenderer/SlotRenderer.d.ts +4 -5
  449. package/types/components/theme/Unauthorized/Unauthorized.d.ts +2 -2
  450. package/types/components/theme/VideoEmbed/VideoEmbed.d.ts +2 -0
  451. package/types/components/theme/View/EventView.stories.d.ts +19 -0
  452. package/types/components/theme/View/FileView.stories.d.ts +18 -0
  453. package/types/components/theme/View/LinkView.stories.d.ts +18 -0
  454. package/types/components/theme/View/ListingView.stories.d.ts +24 -0
  455. package/types/components/theme/View/NewsItemView.stories.d.ts +23 -0
  456. package/types/components/theme/View/RenderBlocks.stories.d.ts +23 -0
  457. package/types/components/theme/View/SummaryView.stories.d.ts +23 -0
  458. package/types/components/theme/View/TabularView.stories.d.ts +23 -0
  459. package/types/config/ControlPanels.d.ts +1 -0
  460. package/types/config/Views.d.ts +1 -1
  461. package/types/config/Widgets.d.ts +6 -0
  462. package/types/config/slots.d.ts +7 -0
  463. package/types/constants/ActionTypes.d.ts +1 -0
  464. package/types/helpers/Blocks/Blocks.d.ts +4 -0
  465. package/types/helpers/Content/Content.d.ts +7 -0
  466. package/types/helpers/Content/withClientSideContent.d.ts +1 -0
  467. package/types/helpers/Extensions/withBlockSchemaEnhancer.d.ts +4 -5
  468. package/types/helpers/FormValidation/validators.d.ts +18 -1
  469. package/types/helpers/Helmet/Helmet.d.ts +1 -1
  470. package/types/helpers/Loadable/__mocks__/Loadable.d.ts +2 -2
  471. package/types/helpers/MessageLabels/MessageLabels.d.ts +105 -93
  472. package/types/helpers/Url/Url.d.ts +14 -0
  473. package/types/helpers/Url/bulkFlattenToAppURL.d.ts +5 -0
  474. package/types/helpers/Utils/Utils.d.ts +1 -0
  475. package/types/reducers/blockTypes/blockTypes.d.ts +16 -0
  476. package/types/reducers/index.d.ts +3 -0
  477. package/types/routes.d.ts +7 -5
  478. package/types/start-client.d.ts +0 -1
  479. package/vitest.config.mjs +84 -42
  480. package/webpack-plugins/webpack-less-plugin.js +1 -1
  481. package/webpack-plugins/webpack-scss-plugin.js +172 -0
  482. package/cypress/downloads/downloads.html +0 -0
  483. package/jest-addons-loader.js +0 -3
  484. package/jest-extender-plugin.js +0 -39
  485. package/jest-setup-afterenv.js +0 -2
  486. package/jest-svgsystem-transform.js +0 -10
  487. package/package-why.json +0 -34
  488. package/patches/patchit.sh +0 -2
  489. package/patches/razzle-jest.patch +0 -10
  490. package/src/components/manage/Contents/__mocks__/index.vitest.tsx +0 -5
  491. package/src/components/manage/Form/__mocks__/index.vitest.tsx +0 -73
  492. package/src/components/manage/Sidebar/SidebarPortal.jsx +0 -47
  493. package/src/components/manage/Sidebar/SidebarPortal.test.jsx +0 -26
  494. package/src/components/manage/Widgets/AlignWidget.test.jsx +0 -59
  495. package/src/components/manage/Widgets/ButtonsWidget.jsx +0 -41
  496. package/src/components/manage/Widgets/ButtonsWidget.test.jsx +0 -70
  497. package/src/components/manage/Widgets/__mocks__/index.vitest.tsx +0 -41
  498. package/src/components/theme/LanguageSelector/LanguageSelector.jsx +0 -79
  499. package/src/helpers/Loadable/__mocks__/Loadable.vitest.jsx +0 -39
  500. package/test-setup-globals-vitest.js +0 -46
  501. package/theme/themes/pastanaga/extras/utils.less +0 -63
  502. /package/src/components/theme/LanguageSelector/{LanguageSelector.test.jsx → LanguageSelector.test.tsx} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { validationMessage } from '@plone/volto/helpers/FormValidation/FormValidation';
2
2
  import { messages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
3
+ import config from '@plone/volto/registry';
3
4
 
4
5
  type MinMaxValidator = {
5
6
  value: string | number;
@@ -15,6 +16,24 @@ type Validator = {
15
16
  formatMessage: Function;
16
17
  };
17
18
 
19
+ type Choice = {
20
+ token: string;
21
+ label: string;
22
+ };
23
+ type ChoiceValidator = {
24
+ value: string | Choice;
25
+ field: Record<string, any>;
26
+ formData: any;
27
+ formatMessage: Function;
28
+ };
29
+
30
+ type FileValidator = {
31
+ value: Record<string, any>;
32
+ field: Record<string, any>;
33
+ formData: any;
34
+ formatMessage: Function;
35
+ };
36
+
18
37
  export const isMaxPropertyValid = ({
19
38
  value,
20
39
  fieldSpec,
@@ -134,6 +153,15 @@ export const hasUniqueItemsValidator = ({
134
153
  return !isValid ? formatMessage(messages.uniqueItems) : null;
135
154
  };
136
155
 
156
+ const formatDateValue = (isoString: string) => {
157
+ const date = new Date(isoString);
158
+ if (isNaN(date.getTime())) return isoString;
159
+ return new Intl.DateTimeFormat(undefined, {
160
+ dateStyle: 'medium',
161
+ timeStyle: 'short',
162
+ }).format(date);
163
+ };
164
+
137
165
  export const startEventDateRangeValidator = ({
138
166
  value,
139
167
  field,
@@ -144,7 +172,9 @@ export const startEventDateRangeValidator = ({
144
172
  value && formData.end && new Date(value) < new Date(formData.end);
145
173
  return !isValid
146
174
  ? formatMessage(messages.startEventRange, {
147
- endDateValueOrEndFieldName: formData.end || 'end',
175
+ endDateValueOrEndFieldName: formData.end
176
+ ? formatDateValue(formData.end)
177
+ : 'end',
148
178
  })
149
179
  : null;
150
180
  };
@@ -159,7 +189,9 @@ export const endEventDateRangeValidator = ({
159
189
  value && formData.start && new Date(value) > new Date(formData.start);
160
190
  return !isValid
161
191
  ? formatMessage(messages.endEventRange, {
162
- startDateValueOrStartFieldName: formData.start || 'start',
192
+ startDateValueOrStartFieldName: formData.start
193
+ ? formatDateValue(formData.start)
194
+ : 'start',
163
195
  })
164
196
  : null;
165
197
  };
@@ -211,12 +243,26 @@ export const defaultLanguageControlPanelValidator = ({
211
243
  value,
212
244
  formData,
213
245
  formatMessage,
214
- }: Validator) => {
246
+ }: ChoiceValidator) => {
247
+ const token = typeof value === 'object' ? value.token : value;
215
248
  const isValid =
216
- value &&
249
+ token &&
217
250
  (formData.available_languages.find(
218
- (lang: { token: string }) => lang.token === value,
251
+ (lang: { token: string }) => lang.token === token,
219
252
  ) ||
220
- formData.available_languages.includes(value));
253
+ formData.available_languages.includes(token));
221
254
  return !isValid ? formatMessage(messages.defaultLanguage) : null;
222
255
  };
256
+
257
+ export const sizeValidator = ({
258
+ value,
259
+ field,
260
+ formatMessage,
261
+ }: FileValidator) => {
262
+ const maxSize = field.size
263
+ ? parseInt(field.size, 10)
264
+ : config.settings.maxFileUploadSize;
265
+ return maxSize && value.size > maxSize
266
+ ? formatMessage(messages.maxSize, { maxSize, size: value.size })
267
+ : null;
268
+ };
@@ -9,6 +9,7 @@ import Helmet from '@plone/volto/helpers/Helmet/Helmet';
9
9
  import serialize from 'serialize-javascript';
10
10
  import join from 'lodash/join';
11
11
  import BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
12
+ import { addSubpathPrefix } from '@plone/volto/helpers/Url/Url';
12
13
  import { runtimeConfig } from '@plone/volto/runtime_config';
13
14
  import config from '@plone/volto/registry';
14
15
 
@@ -126,14 +127,22 @@ class Html extends Component {
126
127
  }}
127
128
  />
128
129
 
129
- <link rel="icon" href="/favicon.ico" sizes="any" />
130
- <link rel="icon" href="/icon.svg" type="image/svg+xml" />
130
+ <link
131
+ rel="icon"
132
+ href={addSubpathPrefix('/favicon.ico')}
133
+ sizes="any"
134
+ />
135
+ <link
136
+ rel="icon"
137
+ href={addSubpathPrefix('/icon.svg')}
138
+ type="image/svg+xml"
139
+ />
131
140
  <link
132
141
  rel="apple-touch-icon"
133
142
  sizes="180x180"
134
- href="/apple-touch-icon.png"
143
+ href={addSubpathPrefix('/apple-touch-icon.png')}
135
144
  />
136
- <link rel="manifest" href="/site.webmanifest" />
145
+ <link rel="manifest" href={addSubpathPrefix('/site.webmanifest')} />
137
146
  <meta name="generator" content="Plone 6 - https://plone.org" />
138
147
  <meta name="viewport" content="width=device-width, initial-scale=1" />
139
148
  <meta name="mobile-web-app-capable" content="yes" />
@@ -1,19 +1,4 @@
1
- /* TODO: When the Volto Team removes Jest configuration support from Volto core, update this file with the Vitest version of the mock.
2
- Then, in the tests, we need to replace:
3
-
4
- vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
5
- return await import(
6
- '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
7
- );
8
- });
9
-
10
- with the following:
11
-
12
- vi.mock('@plone/volto/helpers/Loadable/Loadable');
13
-
14
- Finally, remove this comment.
15
- */
16
-
1
+ import React from 'react';
17
2
  import config from '@plone/volto/registry';
18
3
  const loadables = config.settings.loadables;
19
4
 
@@ -33,21 +18,21 @@ export const __setLoadables = async () => {
33
18
  };
34
19
 
35
20
  // TODO: filter mockAllLoadables
36
- export const injectLazyLibs = jest.fn().mockImplementation(function ([
21
+ export const injectLazyLibs = vi.fn().mockImplementation(function ([
37
22
  libraries,
38
23
  ]) {
39
- return jest.fn((WrappedComponent) =>
40
- jest.fn((props) => {
24
+ return vi.fn((WrappedComponent) =>
25
+ vi.fn((props) => {
41
26
  return <WrappedComponent {...props} {...mockAllLoadables} />;
42
27
  }),
43
28
  );
44
29
  });
45
30
 
46
- export const preloadLazyLibs = jest.fn().mockImplementation(function ([
31
+ export const preloadLazyLibs = vi.fn().mockImplementation(function ([
47
32
  libraries,
48
33
  ]) {
49
- return jest.fn((WrappedComponent) =>
50
- jest.fn((props) => {
34
+ return vi.fn((WrappedComponent) =>
35
+ vi.fn((props) => {
51
36
  return <WrappedComponent {...props} />;
52
37
  }),
53
38
  );
@@ -25,6 +25,11 @@ export const messages = defineMessages({
25
25
  id: 'Maximum value is {len}.',
26
26
  defaultMessage: 'Maximum value is {len}.',
27
27
  },
28
+ maxSize: {
29
+ id: 'Maximum file size is {maxSize} bytes, but the uploaded file is {size} bytes.',
30
+ defaultMessage:
31
+ 'Maximum file size is {maxSize} bytes, but the uploaded file is {size} bytes.',
32
+ },
28
33
  uniqueItems: {
29
34
  id: 'Items must be unique.',
30
35
  defaultMessage: 'Items must be unique.',
@@ -152,6 +157,11 @@ export const messages = defineMessages({
152
157
  id: 'Groupname',
153
158
  defaultMessage: 'Groupname',
154
159
  },
160
+ addGroupsFormGroupNameDescription: {
161
+ id: 'A unique identifier for the group. Cannot be changed after creation. No spaces allowed.',
162
+ defaultMessage:
163
+ 'A unique identifier for the group. Cannot be changed after creation. No spaces allowed.',
164
+ },
155
165
  addGroupsFormDescriptionTitle: {
156
166
  id: 'Description',
157
167
  defaultMessage: 'Description',
@@ -22,10 +22,10 @@ export const SITEMAP_BATCH_SIZE = 5000;
22
22
  export const generateSitemap = (_req, start = 0, size = undefined) =>
23
23
  new Promise((resolve) => {
24
24
  const { settings } = config;
25
- const APISUFIX = settings.legacyTraverse ? '' : '/++api++';
25
+ const apiSuffix = settings.legacyTraverse ? '' : '/++api++';
26
26
  const apiPath = settings.internalApiPath ?? settings.apiPath;
27
27
  const request = superagent.get(
28
- `${apiPath}${APISUFIX}/@search?metadata_fields=modified&b_start=${start}&b_size=${
28
+ `${apiPath}${apiSuffix}/@search?metadata_fields=modified&b_start=${start}&b_size=${
29
29
  size !== undefined ? size : 100000000
30
30
  }&use_site_search_settings=1`,
31
31
  );
@@ -64,10 +64,10 @@ export const generateSitemap = (_req, start = 0, size = undefined) =>
64
64
  export const generateSitemapIndex = (_req, gzip = false) =>
65
65
  new Promise((resolve) => {
66
66
  const { settings } = config;
67
- const APISUFIX = settings.legacyTraverse ? '' : '/++api++';
67
+ const apiSuffix = settings.legacyTraverse ? '' : '/++api++';
68
68
  const apiPath = settings.internalApiPath ?? settings.apiPath;
69
69
  const request = superagent.get(
70
- `${apiPath}${APISUFIX}/@search?metadata_fields=modified&b_size=0&use_site_search_settings=1`,
70
+ `${apiPath}${apiSuffix}/@search?metadata_fields=modified&b_size=0&use_site_search_settings=1`,
71
71
  );
72
72
  request.set('Accept', 'application/json');
73
73
  const authToken = _req.universalCookies.get('auth_token');
@@ -193,7 +193,7 @@ export function addAppURL(url) {
193
193
  */
194
194
  export function expandToBackendURL(path) {
195
195
  const { settings } = config;
196
- const APISUFIX = settings.legacyTraverse ? '' : '/++api++';
196
+ const apiSuffix = settings.legacyTraverse ? '' : '/++api++';
197
197
  let adjustedPath;
198
198
  if (path.startsWith('http://') || path.startsWith('https://')) {
199
199
  // flattenToAppURL first if we get a full URL
@@ -210,7 +210,7 @@ export function expandToBackendURL(path) {
210
210
  apiPath = settings.apiPath;
211
211
  }
212
212
 
213
- return `${apiPath}${APISUFIX}${adjustedPath}`;
213
+ return `${apiPath}${apiSuffix}${adjustedPath}`;
214
214
  }
215
215
 
216
216
  /**
@@ -258,6 +258,36 @@ export function isUrl(url) {
258
258
  return urlRegex().test(url);
259
259
  }
260
260
 
261
+ /**
262
+ * Add subpath path if set in settings
263
+ * @method addSubpathPrefix
264
+ * @param {string} src pathname
265
+ * @returns {string} prefixed subpath pathname
266
+ */
267
+ export function addSubpathPrefix(src) {
268
+ let url = src;
269
+ const { subpathPrefix } = config.settings;
270
+ if (isInternalURL(src) && subpathPrefix && !src.startsWith(subpathPrefix)) {
271
+ url = subpathPrefix + src; //add subpathPrefix to src if it's an internal url and not a static resource.
272
+ }
273
+ return url;
274
+ }
275
+
276
+ /**
277
+ * strip subpath path particulary from api calls
278
+ * @method stripSubpathPrefix
279
+ * @param {string} src pathname
280
+ * @returns {string} pathname
281
+ */
282
+ export function stripSubpathPrefix(src) {
283
+ let url = src;
284
+ const { subpathPrefix } = config.settings;
285
+ if (subpathPrefix && src.match(new RegExp(`^${subpathPrefix}(/|$)`))) {
286
+ url = src.slice(subpathPrefix.length);
287
+ }
288
+ return url;
289
+ }
290
+
261
291
  /**
262
292
  * Get field url
263
293
  * @method getFieldURL
@@ -381,6 +411,7 @@ export function flattenScales(path, image) {
381
411
  const basePath = image.base_path || path;
382
412
  const imageInfo = {
383
413
  ...image,
414
+ scales: image.scales || {},
384
415
  download: flattenToAppURL(removeObjectIdFromURL(basePath, image.download)),
385
416
  };
386
417
 
@@ -19,6 +19,8 @@ import {
19
19
  normaliseMail,
20
20
  normalizeTelephone,
21
21
  flattenScales,
22
+ addSubpathPrefix,
23
+ stripSubpathPrefix,
22
24
  } from './Url';
23
25
 
24
26
  beforeEach(() => {
@@ -533,4 +535,64 @@ describe('Url', () => {
533
535
  });
534
536
  });
535
537
  });
538
+
539
+ describe('Subpath tests', () => {
540
+ beforeEach(() => {
541
+ settings.subpathPrefix = '/site';
542
+ });
543
+ describe('addSubpathPrefix', () => {
544
+ it('adds subpath prefix to internal URLs', () => {
545
+ expect(addSubpathPrefix('/some-page')).toBe('/site/some-page');
546
+ expect(addSubpathPrefix('/news/article')).toBe('/site/news/article');
547
+ });
548
+
549
+ it('does not add subpath prefix to URLs that already have it', () => {
550
+ expect(addSubpathPrefix('/site/some-page')).toBe('/site/some-page');
551
+ });
552
+
553
+ it('does not add subpath prefix to external URLs', () => {
554
+ expect(addSubpathPrefix('https://example.com/page')).toBe(
555
+ 'https://example.com/page',
556
+ );
557
+ });
558
+
559
+ it('handles empty subpath prefix', () => {
560
+ settings.subpathPrefix = '';
561
+ expect(addSubpathPrefix('/some-page')).toBe('/some-page');
562
+ });
563
+
564
+ it('handles undefined subpath prefix', () => {
565
+ settings.subpathPrefix = undefined;
566
+ expect(addSubpathPrefix('/some-page')).toBe('/some-page');
567
+ });
568
+ });
569
+
570
+ describe('stripSubpathPrefix', () => {
571
+ beforeEach(() => {
572
+ settings.subpathPrefix = '/site';
573
+ });
574
+ it('removes subpath prefix from URLs that have it', () => {
575
+ expect(stripSubpathPrefix('/site/some-page')).toBe('/some-page');
576
+ expect(stripSubpathPrefix('/site/news/article')).toBe('/news/article');
577
+ });
578
+
579
+ it('leaves URLs unchanged if they do not have the prefix', () => {
580
+ expect(stripSubpathPrefix('/other/some-page')).toBe('/other/some-page');
581
+ });
582
+
583
+ it('handles the case where URL is exactly the subpath prefix', () => {
584
+ expect(stripSubpathPrefix('/site')).toBe('');
585
+ });
586
+
587
+ it('handles empty subpath prefix', () => {
588
+ settings.subpathPrefix = '';
589
+ expect(stripSubpathPrefix('/some-page')).toBe('/some-page');
590
+ });
591
+
592
+ it('handles undefined subpath prefix', () => {
593
+ settings.subpathPrefix = undefined;
594
+ expect(stripSubpathPrefix('/some-page')).toBe('/some-page');
595
+ });
596
+ });
597
+ });
536
598
  });
@@ -37,6 +37,23 @@ export const safeWrapper = (func) => (config) => {
37
37
  return res;
38
38
  };
39
39
 
40
+ /**
41
+ * Extract a readable error message from several possible error shapes
42
+ * @param {object} error
43
+ * @returns {string} message
44
+ */
45
+ export const getErrorMessage = (error) => {
46
+ const respBody = error?.response?.body;
47
+ if (respBody?.error?.message) return respBody.error.message;
48
+ if (respBody?.message) return respBody.message;
49
+ if (error?.message) return error.message;
50
+ try {
51
+ return JSON.stringify(error);
52
+ } catch (e) {
53
+ return String(error);
54
+ }
55
+ };
56
+
40
57
  /**
41
58
  * A helper to pipe a configuration object through configuration loaders
42
59
  *
@@ -3,6 +3,7 @@ import config from '@plone/volto/registry';
3
3
  import {
4
4
  applyConfig,
5
5
  difference,
6
+ getErrorMessage,
6
7
  getColor,
7
8
  getInitials,
8
9
  hasApiExpander,
@@ -246,6 +247,44 @@ describe('Utils tests', () => {
246
247
  });
247
248
  });
248
249
 
250
+ describe('getErrorMessage', () => {
251
+ it('returns nested backend error message', () => {
252
+ const error = {
253
+ response: {
254
+ body: {
255
+ error: {
256
+ message: 'Backend nested message',
257
+ },
258
+ },
259
+ },
260
+ };
261
+
262
+ expect(getErrorMessage(error)).toEqual('Backend nested message');
263
+ });
264
+
265
+ it('returns body message when present', () => {
266
+ const error = {
267
+ response: {
268
+ body: {
269
+ message: 'Backend body message',
270
+ },
271
+ },
272
+ };
273
+
274
+ expect(getErrorMessage(error)).toEqual('Backend body message');
275
+ });
276
+
277
+ it('returns generic error.message fallback', () => {
278
+ expect(getErrorMessage(new Error('Generic message'))).toEqual(
279
+ 'Generic message',
280
+ );
281
+ });
282
+
283
+ it('returns stringified object as final fallback', () => {
284
+ expect(getErrorMessage({ foo: 'bar' })).toEqual('{"foo":"bar"}');
285
+ });
286
+ });
287
+
249
288
  describe('safeWrapper', () => {
250
289
  it('calls the function with config', () => {
251
290
  expect(
@@ -12,7 +12,7 @@ const useUser = () => {
12
12
  const dispatch = useDispatch();
13
13
 
14
14
  useEffect(() => {
15
- if (!user?.id && users?.get.loading === false) {
15
+ if (userId && !user?.id && users?.get.loading === false) {
16
16
  dispatch(getUser(userId));
17
17
  }
18
18
  }, [dispatch, userId, user, users?.get.loading]);
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import packageJson from '../package.json';
3
+
4
+ describe('internal checks', () => {
5
+ it('keeps prettier listed as a runtime dependency', () => {
6
+ const dependencies = packageJson.dependencies ?? {};
7
+
8
+ expect(dependencies).toHaveProperty('prettier');
9
+ expect(typeof dependencies.prettier).toBe('string');
10
+ });
11
+ });
@@ -287,9 +287,13 @@ const apiMiddlewareFactory =
287
287
  const langFileName = toGettextLang(lang);
288
288
  import(
289
289
  /* @vite-ignore */ '@root/../locales/' + langFileName + '.json'
290
- ).then((locale) => {
291
- dispatch(changeLanguage(lang, locale.default));
292
- });
290
+ )
291
+ .then((locale) => {
292
+ dispatch(changeLanguage(lang, locale.default));
293
+ })
294
+ .catch(() => {
295
+ dispatch(changeLanguage(lang, {}));
296
+ });
293
297
  }
294
298
  }
295
299
 
@@ -341,14 +345,19 @@ const apiMiddlewareFactory =
341
345
  (error) => {
342
346
  // Make sure an error during hydration
343
347
  // (for example when serving an archived page)
344
- // doesn't hide the SSR content.
345
- if (isHydrating && !hasExistingError) {
348
+ // doesn't hide the SSR content. Only suppress GET_CONTENT failures;
349
+ // user-initiated actions (LOGIN, etc.) must always dispatch _FAIL so
350
+ // loaders stop and errors surface.
351
+ const shouldIgnoreHydrationError =
352
+ isHydrating && !hasExistingError && type === GET_CONTENT;
353
+
354
+ if (shouldIgnoreHydrationError) {
346
355
  isHydrating = false;
347
356
  return;
348
357
  }
349
358
 
350
359
  // Only SSR can set ECONNREFUSED
351
- if (error.code === 'ECONNREFUSED') {
360
+ if (error?.code === 'ECONNREFUSED') {
352
361
  next({
353
362
  ...rest,
354
363
  error,
@@ -359,7 +368,7 @@ const apiMiddlewareFactory =
359
368
  }
360
369
 
361
370
  // Response error is marked crossDomain if CORS error happen
362
- else if (error.crossDomain) {
371
+ else if (error?.crossDomain) {
363
372
  next({
364
373
  ...rest,
365
374
  error,
@@ -410,7 +419,7 @@ const apiMiddlewareFactory =
410
419
  ...rest,
411
420
  error,
412
421
  statusCode: error.response,
413
- message: error.response.body.message,
422
+ message: error.response?.body?.message,
414
423
  connectionRefused: false,
415
424
  type: SET_APIERROR,
416
425
  });
@@ -445,9 +445,9 @@ describe('storeProtectLoadUtils', () => {
445
445
  isCounting: false,
446
446
  });
447
447
  };
448
- test('pending', expectPass({ type: 'ANY_PENDING' }), 2);
449
- test('success', expectPass({ type: 'ANY_SUCCESS' }), 2);
450
- test('failure', expectPass({ type: 'ANY_FAIL' }), 2);
448
+ test('pending', expectPass({ type: 'ANY_PENDING' }, 2));
449
+ test('success', expectPass({ type: 'ANY_SUCCESS' }, 2));
450
+ test('failure', expectPass({ type: 'ANY_FAIL' }, 2));
451
451
  });
452
452
  describe('counting', () => {
453
453
  const expectCount = (action, from, to) => () => {
@@ -0,0 +1,38 @@
1
+ import { GET_BLOCKTYPES_INDEX } from '@plone/volto/constants/ActionTypes';
2
+
3
+ const initialState = {
4
+ error: null,
5
+ items: {},
6
+ loaded: false,
7
+ loading: false,
8
+ };
9
+
10
+ export default function blockTypes(state = initialState, action = {}) {
11
+ switch (action.type) {
12
+ case `${GET_BLOCKTYPES_INDEX}_PENDING`:
13
+ return {
14
+ ...state,
15
+ error: null,
16
+ loaded: false,
17
+ loading: true,
18
+ };
19
+ case `${GET_BLOCKTYPES_INDEX}_SUCCESS`:
20
+ return {
21
+ ...state,
22
+ error: null,
23
+ items: action.result,
24
+ loaded: true,
25
+ loading: false,
26
+ };
27
+ case `${GET_BLOCKTYPES_INDEX}_FAIL`:
28
+ return {
29
+ ...state,
30
+ error: action.error,
31
+ items: {},
32
+ loaded: false,
33
+ loading: false,
34
+ };
35
+ default:
36
+ return state;
37
+ }
38
+ }
@@ -3,11 +3,10 @@
3
3
  * @module reducers/content/content
4
4
  */
5
5
 
6
- import map from 'lodash/map';
7
- import mapKeys from 'lodash/mapKeys';
8
6
  import omit from 'lodash/omit';
9
7
 
10
8
  import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
9
+ import { flattenStaticBehaviors } from '@plone/volto/helpers/Content/Content';
11
10
 
12
11
  import {
13
12
  CREATE_CONTENT,
@@ -131,14 +130,7 @@ export default function content(state = initialState, action = {}) {
131
130
  },
132
131
  };
133
132
  case `${CREATE_CONTENT}_SUCCESS`:
134
- if (result['@static_behaviors']) {
135
- map(result['@static_behaviors'], (behavior) => {
136
- result = {
137
- ...omit(result, behavior),
138
- ...mapKeys(result[behavior], (value, key) => `${behavior}.${key}`),
139
- };
140
- });
141
- }
133
+ result = flattenStaticBehaviors(result);
142
134
  const data = action.subrequest
143
135
  ? Array.isArray(result)
144
136
  ? result.map((item) => ({
@@ -188,14 +180,7 @@ export default function content(state = initialState, action = {}) {
188
180
  },
189
181
  };
190
182
  case `${GET_CONTENT}_SUCCESS`:
191
- if (result['@static_behaviors']) {
192
- map(result['@static_behaviors'], (behavior) => {
193
- result = {
194
- ...omit(result, behavior),
195
- ...mapKeys(result[behavior], (value, key) => `${behavior}.${key}`),
196
- };
197
- });
198
- }
183
+ result = flattenStaticBehaviors(result);
199
184
 
200
185
  const transforms = config.getUtilities({
201
186
  type: 'transform',
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { GET_DIFF } from '@plone/volto/constants/ActionTypes';
7
+ import { flattenStaticBehaviors } from '@plone/volto/helpers/Content/Content';
7
8
 
8
9
  const initialState = {
9
10
  error: null,
@@ -29,10 +30,13 @@ export default function diff(state = initialState, action = {}) {
29
30
  loading: true,
30
31
  };
31
32
  case `${GET_DIFF}_SUCCESS`:
33
+ const first_result = flattenStaticBehaviors(action.result[0]);
34
+ const second_result = flattenStaticBehaviors(action.result[1]);
35
+
32
36
  return {
33
37
  ...state,
34
38
  error: null,
35
- data: action.result,
39
+ data: [first_result, second_result],
36
40
  loaded: true,
37
41
  loading: false,
38
42
  };