@plone/volto 19.0.0-alpha.9 → 19.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +26 -15
  3. package/AGENTS.md +47 -0
  4. package/CHANGELOG.md +525 -12
  5. package/README.md +22 -19
  6. package/babel.js +1 -9
  7. package/cypress/support/guillotina.js +1 -0
  8. package/cypress.config.js +1 -0
  9. package/global-test-setup.js +1 -2
  10. package/locales/af/LC_MESSAGES/volto.po +5516 -0
  11. package/locales/af.json +1 -1
  12. package/locales/ar/LC_MESSAGES/volto.po +5516 -0
  13. package/locales/ar.json +1 -1
  14. package/locales/bg/LC_MESSAGES/volto.po +5516 -0
  15. package/locales/bg.json +1 -1
  16. package/locales/bn/LC_MESSAGES/volto.po +5516 -0
  17. package/locales/bn.json +1 -1
  18. package/locales/ca/LC_MESSAGES/volto.po +546 -354
  19. package/locales/ca.json +1 -1
  20. package/locales/cs/LC_MESSAGES/volto.po +5516 -0
  21. package/locales/cs.json +1 -1
  22. package/locales/cy/LC_MESSAGES/volto.po +5516 -0
  23. package/locales/cy.json +1 -1
  24. package/locales/da/LC_MESSAGES/volto.po +5516 -0
  25. package/locales/da.json +1 -1
  26. package/locales/de/LC_MESSAGES/volto.po +217 -24
  27. package/locales/de.json +1 -1
  28. package/locales/el/LC_MESSAGES/volto.po +5516 -0
  29. package/locales/el.json +1 -1
  30. package/locales/en/LC_MESSAGES/volto.po +206 -10
  31. package/locales/en.json +1 -1
  32. package/locales/en_AU/LC_MESSAGES/volto.po +5516 -0
  33. package/locales/en_AU.json +1 -1
  34. package/locales/en_GB/LC_MESSAGES/volto.po +5516 -0
  35. package/locales/en_GB.json +1 -1
  36. package/locales/eo/LC_MESSAGES/volto.po +5516 -0
  37. package/locales/eo.json +1 -1
  38. package/locales/es/LC_MESSAGES/volto.po +331 -140
  39. package/locales/es.json +1 -1
  40. package/locales/et/LC_MESSAGES/volto.po +5516 -0
  41. package/locales/et.json +1 -1
  42. package/locales/eu/LC_MESSAGES/volto.po +408 -217
  43. package/locales/eu.json +1 -1
  44. package/locales/fa/LC_MESSAGES/volto.po +5516 -0
  45. package/locales/fa.json +1 -1
  46. package/locales/fi/LC_MESSAGES/volto.po +207 -15
  47. package/locales/fi.json +1 -1
  48. package/locales/fr/LC_MESSAGES/volto.po +364 -173
  49. package/locales/fr.json +1 -1
  50. package/locales/fu/LC_MESSAGES/volto.po +5516 -0
  51. package/locales/fu.json +1 -1
  52. package/locales/gl/LC_MESSAGES/volto.po +5516 -0
  53. package/locales/gl.json +1 -1
  54. package/locales/he/LC_MESSAGES/volto.po +5516 -0
  55. package/locales/he.json +1 -1
  56. package/locales/hi/LC_MESSAGES/volto.po +215 -18
  57. package/locales/hi.json +1 -1
  58. package/locales/hr/LC_MESSAGES/volto.po +5516 -0
  59. package/locales/hr.json +1 -1
  60. package/locales/hu/LC_MESSAGES/volto.po +5516 -0
  61. package/locales/hu.json +1 -1
  62. package/locales/hy/LC_MESSAGES/volto.po +5516 -0
  63. package/locales/hy.json +1 -1
  64. package/locales/id/LC_MESSAGES/volto.po +5516 -0
  65. package/locales/id.json +1 -1
  66. package/locales/it/LC_MESSAGES/volto.po +231 -34
  67. package/locales/it.json +1 -1
  68. package/locales/ja/LC_MESSAGES/volto.po +249 -56
  69. package/locales/ja.json +1 -1
  70. package/locales/ka/LC_MESSAGES/volto.po +5516 -0
  71. package/locales/ka.json +1 -1
  72. package/locales/kn/LC_MESSAGES/volto.po +5516 -0
  73. package/locales/kn.json +1 -1
  74. package/locales/ko/LC_MESSAGES/volto.po +5516 -0
  75. package/locales/ko.json +1 -1
  76. package/locales/lt/LC_MESSAGES/volto.po +5516 -0
  77. package/locales/lt.json +1 -1
  78. package/locales/lv/LC_MESSAGES/volto.po +5516 -0
  79. package/locales/lv.json +1 -1
  80. package/locales/mi/LC_MESSAGES/volto.po +5516 -0
  81. package/locales/mi.json +1 -1
  82. package/locales/mk/LC_MESSAGES/volto.po +5516 -0
  83. package/locales/mk.json +1 -1
  84. package/locales/my/LC_MESSAGES/volto.po +5516 -0
  85. package/locales/my.json +1 -1
  86. package/locales/nb_NO/LC_MESSAGES/volto.po +5516 -0
  87. package/locales/nb_NO.json +1 -1
  88. package/locales/nl/LC_MESSAGES/volto.po +259 -66
  89. package/locales/nl.json +1 -1
  90. package/locales/nn/LC_MESSAGES/volto.po +5516 -0
  91. package/locales/nn.json +1 -1
  92. package/locales/pl/LC_MESSAGES/volto.po +5516 -0
  93. package/locales/pl.json +1 -1
  94. package/locales/pt/LC_MESSAGES/volto.po +858 -666
  95. package/locales/pt.json +1 -1
  96. package/locales/pt_BR/LC_MESSAGES/volto.po +211 -20
  97. package/locales/pt_BR.json +1 -1
  98. package/locales/rm/LC_MESSAGES/volto.po +5516 -0
  99. package/locales/rm.json +1 -1
  100. package/locales/ro/LC_MESSAGES/volto.po +243 -52
  101. package/locales/ro.json +1 -1
  102. package/locales/ru/LC_MESSAGES/volto.po +206 -14
  103. package/locales/ru.json +1 -1
  104. package/locales/sk/LC_MESSAGES/volto.po +5516 -0
  105. package/locales/sk.json +1 -1
  106. package/locales/sl/LC_MESSAGES/volto.po +5516 -0
  107. package/locales/sl.json +1 -1
  108. package/locales/sm/LC_MESSAGES/volto.po +5516 -0
  109. package/locales/sm.json +1 -1
  110. package/locales/sq/LC_MESSAGES/volto.po +5516 -0
  111. package/locales/sq.json +1 -1
  112. package/locales/sr/LC_MESSAGES/volto.po +5516 -0
  113. package/locales/sr.json +1 -1
  114. package/locales/sr@cyrl/LC_MESSAGES/volto.po +5516 -0
  115. package/locales/sr@cyrl.json +1 -1
  116. package/locales/sr@latn/LC_MESSAGES/volto.po +5516 -0
  117. package/locales/sr@latn.json +1 -1
  118. package/locales/sv/LC_MESSAGES/volto.po +5516 -0
  119. package/locales/sv.json +1 -1
  120. package/locales/ta/LC_MESSAGES/volto.po +5516 -0
  121. package/locales/ta.json +1 -1
  122. package/locales/te/LC_MESSAGES/volto.po +5516 -0
  123. package/locales/te.json +1 -1
  124. package/locales/th/LC_MESSAGES/volto.po +5516 -0
  125. package/locales/th.json +1 -1
  126. package/locales/to/LC_MESSAGES/volto.po +5516 -0
  127. package/locales/to.json +1 -1
  128. package/locales/tr/LC_MESSAGES/volto.po +5516 -0
  129. package/locales/tr.json +1 -1
  130. package/locales/uk/LC_MESSAGES/volto.po +5516 -0
  131. package/locales/uk.json +1 -1
  132. package/locales/vi/LC_MESSAGES/volto.po +5516 -0
  133. package/locales/vi.json +1 -1
  134. package/locales/volto.pot +200 -9
  135. package/locales/zh_CN/LC_MESSAGES/volto.po +206 -14
  136. package/locales/zh_CN.json +1 -1
  137. package/locales/zh_Hant/LC_MESSAGES/volto.po +5516 -0
  138. package/locales/zh_Hant.json +1 -1
  139. package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +5516 -0
  140. package/locales/zh_Hant_HK.json +1 -1
  141. package/package.json +69 -146
  142. package/razzle.config.js +16 -25
  143. package/src/actions/blockTypes/blockTypes.ts +24 -0
  144. package/src/actions/controlpanels/controlpanels.js +7 -12
  145. package/src/actions/controlpanels/controlpanels.test.js +2 -3
  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/Add/Add.test.jsx +10 -3
  149. package/src/components/manage/Aliases/Aliases.test.jsx +5 -2
  150. package/src/components/manage/BlockChooser/BlockChooser.jsx +8 -10
  151. package/src/components/manage/Blocks/Block/BlocksForm.jsx +10 -7
  152. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +3 -14
  153. package/src/components/manage/Blocks/Block/Edit.jsx +19 -10
  154. package/src/components/manage/Blocks/Block/Order/Item.jsx +33 -14
  155. package/src/components/manage/Blocks/Block/Order/Item.test.jsx +90 -0
  156. package/src/components/manage/Blocks/Block/Order/Order.jsx +116 -67
  157. package/src/components/manage/Blocks/Block/Order/utilities.js +28 -11
  158. package/src/components/manage/Blocks/Block/Settings.test.jsx +1 -5
  159. package/src/components/manage/Blocks/Grid/View.jsx +14 -11
  160. package/src/components/manage/Blocks/Grid/context.js +3 -0
  161. package/src/components/manage/Blocks/HTML/Edit.test.jsx +1 -5
  162. package/src/components/manage/Blocks/Image/ImageSidebar.test.jsx +2 -5
  163. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +2 -5
  164. package/src/components/manage/Blocks/Listing/Edit.jsx +1 -0
  165. package/src/components/manage/Blocks/Listing/ListingBody.jsx +4 -0
  166. package/src/components/manage/Blocks/Maps/MapsSidebar.test.jsx +1 -5
  167. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +1 -6
  168. package/src/components/manage/Blocks/Search/components/SelectFacet.jsx +22 -1
  169. package/src/components/manage/Blocks/Search/components/SelectFacet.test.jsx +1 -6
  170. package/src/components/manage/Blocks/Search/components/SortOn.jsx +8 -2
  171. package/src/components/manage/Blocks/Search/components/ToggleFacet.jsx +14 -0
  172. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +10 -2
  173. package/src/components/manage/Blocks/Teaser/View.jsx +0 -1
  174. package/src/components/manage/Blocks/Teaser/utils.js +13 -0
  175. package/src/components/manage/Blocks/Teaser/utils.test.js +34 -0
  176. package/src/components/manage/Blocks/Title/Edit.jsx +5 -0
  177. package/src/components/manage/Blocks/Video/Body.jsx +69 -43
  178. package/src/components/manage/Blocks/Video/Body.test.jsx +122 -5
  179. package/src/components/manage/Blocks/Video/Edit.jsx +20 -2
  180. package/src/components/manage/Blocks/Video/Edit.test.jsx +6 -0
  181. package/src/components/manage/Blocks/Video/VideoSidebar.test.jsx +1 -5
  182. package/src/components/manage/Blocks/Video/View.jsx +1 -0
  183. package/src/components/manage/Blocks/Video/View.test.jsx +29 -15
  184. package/src/components/manage/Blocks/Video/schema.js +14 -1
  185. package/src/components/manage/Contents/Contents.jsx +854 -747
  186. package/src/components/manage/Contents/Contents.test.jsx +9 -10
  187. package/src/components/manage/Contents/ContentsBreadcrumbs.jsx +4 -3
  188. package/src/components/manage/Contents/ContentsIndexHeader.jsx +47 -81
  189. package/src/components/manage/Contents/ContentsIndexHeader.test.jsx +10 -3
  190. package/src/components/manage/Contents/ContentsItem.jsx +226 -278
  191. package/src/components/manage/Contents/ContentsItem.test.jsx +10 -6
  192. package/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +1 -5
  193. package/src/components/manage/Contents/ContentsRenameModal.test.jsx +1 -5
  194. package/src/components/manage/Contents/ContentsTagsModal.test.jsx +1 -5
  195. package/src/components/manage/Contents/ContentsWorkflowModal.test.jsx +1 -5
  196. package/src/components/manage/Contents/DropZoneContent.jsx +339 -0
  197. package/src/components/manage/Contents/__mocks__/index.tsx +2 -18
  198. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +7 -0
  199. package/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx +7 -4
  200. package/src/components/manage/Controlpanels/Aliases.test.jsx +8 -9
  201. package/src/components/manage/Controlpanels/BlockType.tsx +165 -0
  202. package/src/components/manage/Controlpanels/BlockTypes.tsx +145 -0
  203. package/src/components/manage/Controlpanels/ContentType.jsx +131 -222
  204. package/src/components/manage/Controlpanels/ContentType.test.jsx +13 -14
  205. package/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx +12 -9
  206. package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -1
  207. package/src/components/manage/Controlpanels/ContentTypes.jsx +9 -2
  208. package/src/components/manage/Controlpanels/ContentTypes.test.jsx +7 -4
  209. package/src/components/manage/Controlpanels/Controlpanel.jsx +122 -218
  210. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +8 -33
  211. package/src/components/manage/Controlpanels/Controlpanels.jsx +28 -5
  212. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +23 -8
  213. package/src/components/manage/Controlpanels/DatabaseInformation.jsx +9 -0
  214. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +7 -4
  215. package/src/components/manage/Controlpanels/ModerateComments.jsx +8 -0
  216. package/src/components/manage/Controlpanels/ModerateComments.test.jsx +7 -4
  217. package/src/components/manage/Controlpanels/Relations/Relations.jsx +1 -1
  218. package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +8 -9
  219. package/src/components/manage/Controlpanels/Rules/ConfigureRule.test.jsx +9 -6
  220. package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +8 -9
  221. package/src/components/manage/Controlpanels/Rules/Rules.test.jsx +7 -4
  222. package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +8 -9
  223. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +10 -4
  224. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +628 -631
  225. package/src/components/manage/Controlpanels/Users/UsersControlpanel.ssr.test.jsx +624 -0
  226. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +70 -10
  227. package/src/components/manage/Delete/Delete.test.jsx +13 -8
  228. package/src/components/manage/Diff/Diff.jsx +201 -298
  229. package/src/components/manage/Diff/Diff.test.jsx +8 -10
  230. package/src/components/manage/Diff/DiffField.test.jsx +1 -6
  231. package/src/components/manage/Display/Display.test.jsx +2 -11
  232. package/src/components/manage/Edit/Edit.test.jsx +12 -11
  233. package/src/components/manage/Form/BlockDataForm.test.jsx +1 -5
  234. package/src/components/manage/Form/Field.jsx +1 -69
  235. package/src/components/manage/Form/Form.jsx +17 -4
  236. package/src/components/manage/Form/Form.test.jsx +130 -5
  237. package/src/components/manage/Form/InlineForm.test.jsx +1 -5
  238. package/src/components/manage/Form/ModalForm.jsx +175 -97
  239. package/src/components/manage/Form/ModalForm.test.jsx +27 -5
  240. package/src/components/manage/Form/__mocks__/index.tsx +9 -27
  241. package/src/components/manage/History/History.test.jsx +15 -8
  242. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +7 -4
  243. package/src/components/manage/Multilingual/CompareLanguages.jsx +6 -6
  244. package/src/components/manage/Multilingual/CreateTranslation.jsx +16 -13
  245. package/src/components/manage/Multilingual/ManageTranslations.jsx +5 -5
  246. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +15 -12
  247. package/src/components/manage/Multilingual/TranslationObject.jsx +11 -8
  248. package/src/components/manage/Preferences/ChangePassword.test.jsx +8 -9
  249. package/src/components/manage/Preferences/PersonalPreferences.jsx +8 -5
  250. package/src/components/manage/Preferences/PersonalPreferences.test.jsx +10 -23
  251. package/src/components/manage/Rules/Rules.test.jsx +5 -2
  252. package/src/components/manage/Sharing/Sharing.jsx +21 -15
  253. package/src/components/manage/Sharing/Sharing.test.jsx +9 -6
  254. package/src/components/manage/Sidebar/ObjectBrowser.jsx +10 -0
  255. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +25 -5
  256. package/src/components/manage/Sidebar/ObjectBrowserBody.test.jsx +52 -0
  257. package/src/components/manage/Sidebar/Sidebar.jsx +2 -0
  258. package/src/components/manage/Sidebar/Sidebar.test.jsx +4 -1
  259. package/src/components/manage/Sidebar/SidebarPortal.test.tsx +42 -0
  260. package/src/components/manage/Sidebar/SidebarPortal.tsx +48 -0
  261. package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +1 -0
  262. package/src/components/manage/Toast/Toast.jsx +32 -0
  263. package/src/components/manage/Toast/Toast.test.jsx +9 -5
  264. package/src/components/manage/Toolbar/PersonalTools.test.jsx +15 -0
  265. package/src/components/manage/Toolbar/Toolbar.jsx +103 -11
  266. package/src/components/manage/Toolbar/Toolbar.test.jsx +15 -10
  267. package/src/components/manage/Toolbar/Types.crash.test.jsx +48 -0
  268. package/src/components/manage/Toolbar/Types.jsx +6 -4
  269. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +16 -0
  270. package/src/components/manage/UniversalLink/UniversalLink.tsx +1 -0
  271. package/src/components/manage/Widgets/AlignWidget.stories.jsx +9 -0
  272. package/src/components/manage/Widgets/AlignWidget.test.tsx +95 -0
  273. package/src/components/manage/Widgets/{AlignWidget.jsx → AlignWidget.tsx} +23 -7
  274. package/src/components/manage/Widgets/ArrayWidget.jsx +111 -88
  275. package/src/components/manage/Widgets/ArrayWidget.test.jsx +1 -12
  276. package/src/components/manage/Widgets/BlockAlignment.stories.tsx +104 -0
  277. package/src/components/manage/Widgets/BlockAlignment.test.tsx +104 -0
  278. package/src/components/manage/Widgets/BlockAlignment.tsx +88 -0
  279. package/src/components/manage/Widgets/BlockWidth.stories.tsx +69 -0
  280. package/src/components/manage/Widgets/BlockWidth.test.tsx +62 -0
  281. package/src/components/manage/Widgets/BlockWidth.tsx +101 -0
  282. package/src/components/manage/Widgets/ButtonsWidget.stories.jsx +61 -0
  283. package/src/components/manage/Widgets/ButtonsWidget.test.tsx +138 -0
  284. package/src/components/manage/Widgets/ButtonsWidget.tsx +195 -0
  285. package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +1 -6
  286. package/src/components/manage/Widgets/DatetimeWidget.jsx +98 -54
  287. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +56 -6
  288. package/src/components/manage/Widgets/FileWidget.jsx +7 -0
  289. package/src/components/manage/Widgets/FormFieldWrapper.jsx +143 -163
  290. package/src/components/manage/Widgets/ImageWidget.jsx +18 -5
  291. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +6 -0
  292. package/src/components/manage/Widgets/ObjectListWidget.test.jsx +2 -11
  293. package/src/components/manage/Widgets/ObjectWidget.test.jsx +1 -5
  294. package/src/components/manage/Widgets/QueryWidget.jsx +137 -9
  295. package/src/components/manage/Widgets/QuerystringWidget.test.jsx +3 -1
  296. package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +1 -6
  297. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.test.jsx +1 -6
  298. package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.jsx +56 -50
  299. package/src/components/manage/Widgets/RegistryImageWidget.jsx +1 -1
  300. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +1 -0
  301. package/src/components/manage/Widgets/SchemaWidget.test.jsx +1 -6
  302. package/src/components/manage/Widgets/SchemaWidgetFieldset.test.jsx +1 -6
  303. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +1 -6
  304. package/src/components/manage/Widgets/SelectStyling.jsx +52 -20
  305. package/src/components/manage/Widgets/SelectWidget.test.jsx +1 -6
  306. package/src/components/manage/Widgets/Size.stories.tsx +69 -0
  307. package/src/components/manage/Widgets/Size.test.tsx +59 -0
  308. package/src/components/manage/Widgets/Size.tsx +78 -0
  309. package/src/components/manage/Widgets/TextWidget.jsx +4 -0
  310. package/src/components/manage/Widgets/TimeWidget.test.jsx +1 -6
  311. package/src/components/manage/Widgets/TokenWidget.jsx +142 -186
  312. package/src/components/manage/Widgets/TokenWidget.test.jsx +1 -6
  313. package/src/components/manage/Widgets/UrlWidget.jsx +47 -18
  314. package/src/components/manage/Widgets/VocabularyTermsWidget.test.jsx +2 -11
  315. package/src/components/manage/Widgets/__mocks__/index.tsx +33 -51
  316. package/src/components/manage/Widgets/index.tsx +21 -0
  317. package/src/components/manage/Workflow/Workflow.test.jsx +2 -11
  318. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +1 -0
  319. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +30 -0
  320. package/src/components/theme/App/App.jsx +5 -1
  321. package/src/components/theme/App/App.test.jsx +13 -10
  322. package/src/components/theme/Comments/CommentEditModal.test.jsx +1 -5
  323. package/src/components/theme/Comments/Comments.test.jsx +2 -11
  324. package/src/components/theme/ConnectionRefused/ConnectionRefused.jsx +3 -2
  325. package/src/components/theme/ContactForm/ContactForm.test.jsx +14 -13
  326. package/src/components/theme/Image/Image.jsx +14 -5
  327. package/src/components/theme/Image/Image.test.jsx +247 -146
  328. package/src/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.tsx +7 -0
  329. package/src/components/theme/LanguageSelector/LanguageSelector.tsx +3 -3
  330. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +42 -12
  331. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.test.jsx +6 -3
  332. package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
  333. package/src/components/theme/PasswordReset/RequestPasswordReset.test.jsx +1 -5
  334. package/src/components/theme/Register/Register.test.jsx +1 -5
  335. package/src/components/theme/Search/Search.jsx +230 -327
  336. package/src/components/theme/Search/Search.test.jsx +14 -14
  337. package/src/components/theme/Sitemap/Sitemap.jsx +22 -30
  338. package/src/components/theme/Sitemap/Sitemap.stories.jsx +82 -0
  339. package/src/components/theme/Sitemap/Sitemap.test.jsx +18 -0
  340. package/src/components/theme/SlotRenderer/SlotRenderer.tsx +12 -6
  341. package/src/components/theme/Unauthorized/Unauthorized.jsx +27 -24
  342. package/src/components/theme/Unauthorized/Unauthorized.test.jsx +31 -2
  343. package/src/components/theme/VideoEmbed/VideoEmbed.jsx +100 -0
  344. package/src/components/theme/View/EventDatesInfo.test.jsx +1 -6
  345. package/src/components/theme/View/EventView.stories.jsx +89 -0
  346. package/src/components/theme/View/EventView.test.jsx +1 -6
  347. package/src/components/theme/View/FileView.stories.jsx +50 -0
  348. package/src/components/theme/View/ImageView.jsx +2 -1
  349. package/src/components/theme/View/ImageView.test.jsx +3 -0
  350. package/src/components/theme/View/LinkView.stories.jsx +57 -0
  351. package/src/components/theme/View/ListingView.stories.jsx +70 -0
  352. package/src/components/theme/View/NewsItemView.stories.jsx +58 -0
  353. package/src/components/theme/View/RenderBlocks.jsx +8 -10
  354. package/src/components/theme/View/RenderBlocks.stories.jsx +112 -0
  355. package/src/components/theme/View/RenderBlocks.test.jsx +14 -4
  356. package/src/components/theme/View/SummaryView.stories.jsx +71 -0
  357. package/src/components/theme/View/TabularView.stories.jsx +66 -0
  358. package/src/components/theme/View/View.jsx +8 -1
  359. package/src/components/theme/View/View.test.jsx +37 -24
  360. package/src/components/theme/Widgets/DateWidget.jsx +4 -5
  361. package/src/components/theme/Widgets/DatetimeWidget.jsx +4 -5
  362. package/src/components/theme/Widgets/ImageWidget.test.jsx +31 -11
  363. package/src/components/theme/Widgets/RichTextWidget.jsx +1 -1
  364. package/src/config/Blocks.jsx +3 -0
  365. package/src/config/ControlPanels.js +2 -0
  366. package/src/config/Loadables.jsx +1 -5
  367. package/src/config/Widgets.jsx +7 -0
  368. package/src/config/index.js +10 -1
  369. package/src/config/slots.js +19 -0
  370. package/src/config/validation.ts +8 -0
  371. package/src/constants/ActionTypes.js +1 -0
  372. package/src/express-middleware/devproxy.js +3 -1
  373. package/src/express-middleware/files.js +1 -0
  374. package/src/express-middleware/files.test.js +59 -0
  375. package/src/express-middleware/images.js +1 -0
  376. package/src/express-middleware/images.test.js +50 -0
  377. package/src/helpers/Api/Api.js +2 -2
  378. package/src/helpers/AuthToken/AuthToken.js +1 -6
  379. package/src/helpers/Blocks/Blocks.js +113 -28
  380. package/src/helpers/Blocks/Blocks.test.js +100 -0
  381. package/src/helpers/Content/Content.js +23 -0
  382. package/src/helpers/Content/Content.test.js +39 -0
  383. package/src/helpers/Extensions/withBlockSchemaEnhancer.jsx +4 -1
  384. package/src/helpers/FormValidation/FormValidation.test.js +31 -0
  385. package/src/helpers/FormValidation/validators.ts +52 -6
  386. package/src/helpers/I18n/I18n.test.ts +44 -0
  387. package/src/helpers/I18n/I18n.ts +31 -0
  388. package/src/helpers/Loadable/__mocks__/Loadable.jsx +7 -22
  389. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  390. package/src/helpers/Robots/Robots.js +1 -1
  391. package/src/helpers/Robots/Robots.test.js +34 -0
  392. package/src/helpers/Url/Url.js +1 -0
  393. package/src/helpers/Utils/Date.js +26 -1
  394. package/src/helpers/Utils/Date.test.js +237 -0
  395. package/src/helpers/Utils/Utils.jsx +17 -0
  396. package/src/helpers/Utils/Utils.test.jsx +39 -0
  397. package/src/helpers/Utils/withSaveAsDraft.jsx +33 -9
  398. package/src/helpers/index.js +1 -0
  399. package/src/hooks/user/useUser.js +1 -1
  400. package/src/internalChecks.test.ts +11 -0
  401. package/src/middleware/api.js +14 -5
  402. package/src/reducers/blockTypes/blockTypes.js +38 -0
  403. package/src/reducers/content/content.js +3 -18
  404. package/src/reducers/diff/diff.js +5 -1
  405. package/src/reducers/diff/diff.test.js +60 -4
  406. package/src/reducers/index.js +2 -0
  407. package/src/reducers/querystring/querystring.js +8 -1
  408. package/src/reducers/users/users.js +1 -1
  409. package/src/routes.js +10 -0
  410. package/src/server.jsx +14 -6
  411. package/src/start-client.jsx +21 -3
  412. package/test-addons-loader.js +3 -0
  413. package/test-setup-globals.js +56 -2
  414. package/theme/themes/default/elements/segment.variables +9 -16
  415. package/theme/themes/default/globals/site.variables +3 -3
  416. package/theme/themes/pastanaga/collections/form.overrides +22 -1
  417. package/theme/themes/pastanaga/elements/button.overrides +30 -3
  418. package/theme/themes/pastanaga/elements/segment.variables +1 -4
  419. package/theme/themes/pastanaga/extras/block-types.less +17 -0
  420. package/theme/themes/pastanaga/extras/contents.less +63 -4
  421. package/theme/themes/pastanaga/extras/main.less +16 -4
  422. package/theme/themes/pastanaga/extras/toolbar.less +10 -5
  423. package/theme/themes/pastanaga/extras/videoembed.less +22 -0
  424. package/theme/themes/pastanaga/extras/widgets.less +79 -0
  425. package/theme/themes/pastanaga/globals/site.variables +0 -3
  426. package/tsconfig.declarations.json +1 -1
  427. package/tsconfig.json +1 -1
  428. package/types/actions/blockTypes/blockTypes.d.ts +7 -0
  429. package/types/components/index.d.ts +1 -1
  430. package/types/components/manage/Blocks/Block/Order/Item.test.d.ts +1 -0
  431. package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
  432. package/types/components/manage/Blocks/Grid/context.d.ts +1 -0
  433. package/types/components/manage/Blocks/Teaser/utils.d.ts +5 -0
  434. package/types/components/manage/Blocks/Video/Body.d.ts +4 -2
  435. package/types/components/manage/Blocks/Video/schema.d.ts +4 -0
  436. package/types/components/manage/Contents/Contents.d.ts +1 -1
  437. package/types/components/manage/Contents/ContentsIndexHeader.d.ts +6 -11
  438. package/types/components/manage/Contents/ContentsItem.d.ts +3 -10
  439. package/types/components/manage/Contents/DropZoneContent.d.ts +2 -0
  440. package/types/components/manage/Contents/__mocks__/index.d.ts +2 -2
  441. package/types/components/manage/Controlpanels/BlockType.d.ts +7 -0
  442. package/types/components/manage/Controlpanels/BlockTypes.d.ts +7 -0
  443. package/types/components/manage/Controlpanels/ContentType.d.ts +2 -2
  444. package/types/components/manage/Controlpanels/Controlpanel.d.ts +2 -5
  445. package/types/components/manage/Controlpanels/Relations/RelationsMatrix.d.ts +1 -1
  446. package/types/components/manage/Controlpanels/Users/UsersControlpanel.ssr.test.d.ts +1 -0
  447. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  448. package/types/components/manage/Diff/Diff.d.ts +7 -2
  449. package/types/components/manage/Form/__mocks__/index.d.ts +8 -8
  450. package/types/components/manage/Multilingual/ManageTranslations.d.ts +1 -1
  451. package/types/components/manage/Sidebar/ObjectBrowser.d.ts +1 -1
  452. package/types/components/manage/Sidebar/ObjectBrowserBody.test.d.ts +1 -0
  453. package/types/components/manage/Sidebar/SidebarPortal.d.ts +7 -15
  454. package/types/components/manage/Toolbar/Types.crash.test.d.ts +1 -0
  455. package/types/components/manage/Widgets/AlignWidget.d.ts +8 -10
  456. package/types/components/manage/Widgets/AlignWidget.stories.d.ts +1 -0
  457. package/types/components/manage/Widgets/BlockAlignment.d.ts +7 -0
  458. package/types/components/manage/Widgets/BlockAlignment.stories.d.ts +8 -0
  459. package/types/components/manage/Widgets/BlockWidth.d.ts +7 -0
  460. package/types/components/manage/Widgets/BlockWidth.stories.d.ts +6 -0
  461. package/types/components/manage/Widgets/ButtonsWidget.d.ts +48 -1
  462. package/types/components/manage/Widgets/ButtonsWidget.stories.d.ts +3 -0
  463. package/types/components/manage/Widgets/FormFieldWrapper.d.ts +28 -5
  464. package/types/components/manage/Widgets/ImageWidget.d.ts +1 -1
  465. package/types/components/manage/Widgets/InternalUrlWidget.d.ts +1 -1
  466. package/types/components/manage/Widgets/ObjectBrowserWidget.d.ts +2 -0
  467. package/types/components/manage/Widgets/QueryWidget.d.ts +5 -2
  468. package/types/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.d.ts +22 -5
  469. package/types/components/manage/Widgets/SelectStyling.d.ts +1 -0
  470. package/types/components/manage/Widgets/Size.d.ts +7 -0
  471. package/types/components/manage/Widgets/Size.stories.d.ts +6 -0
  472. package/types/components/manage/Widgets/UrlWidget.d.ts +1 -1
  473. package/types/components/manage/Widgets/__mocks__/index.d.ts +33 -33
  474. package/types/components/manage/Widgets/index.d.ts +11 -6
  475. package/types/components/theme/ConnectionRefused/ConnectionRefused.d.ts +2 -2
  476. package/types/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.d.ts +3 -0
  477. package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
  478. package/types/components/theme/Search/Search.d.ts +1 -1
  479. package/types/components/theme/Sitemap/Sitemap.stories.d.ts +13 -0
  480. package/types/components/theme/SlotRenderer/SlotRenderer.d.ts +4 -5
  481. package/types/components/theme/Unauthorized/Unauthorized.d.ts +2 -2
  482. package/types/components/theme/VideoEmbed/VideoEmbed.d.ts +2 -0
  483. package/types/components/theme/View/EventView.stories.d.ts +19 -0
  484. package/types/components/theme/View/FileView.stories.d.ts +18 -0
  485. package/types/components/theme/View/LinkView.stories.d.ts +18 -0
  486. package/types/components/theme/View/ListingView.stories.d.ts +24 -0
  487. package/types/components/theme/View/NewsItemView.stories.d.ts +23 -0
  488. package/types/components/theme/View/RenderBlocks.stories.d.ts +23 -0
  489. package/types/components/theme/View/SummaryView.stories.d.ts +23 -0
  490. package/types/components/theme/View/TabularView.stories.d.ts +23 -0
  491. package/types/config/ControlPanels.d.ts +1 -0
  492. package/types/config/Views.d.ts +1 -1
  493. package/types/config/Widgets.d.ts +6 -0
  494. package/types/config/slots.d.ts +7 -0
  495. package/types/constants/ActionTypes.d.ts +1 -0
  496. package/types/helpers/Blocks/Blocks.d.ts +4 -0
  497. package/types/helpers/Content/Content.d.ts +7 -0
  498. package/types/helpers/Extensions/withBlockSchemaEnhancer.d.ts +4 -5
  499. package/types/helpers/FormValidation/validators.d.ts +18 -1
  500. package/types/helpers/I18n/I18n.d.ts +20 -0
  501. package/types/helpers/Loadable/__mocks__/Loadable.d.ts +2 -2
  502. package/types/helpers/MessageLabels/MessageLabels.d.ts +100 -94
  503. package/types/helpers/Utils/Utils.d.ts +1 -0
  504. package/types/helpers/index.d.ts +1 -0
  505. package/types/reducers/blockTypes/blockTypes.d.ts +16 -0
  506. package/types/reducers/index.d.ts +2 -0
  507. package/types/routes.d.ts +7 -5
  508. package/vitest.config.mjs +84 -42
  509. package/webpack-plugins/webpack-less-plugin.js +1 -1
  510. package/webpack-plugins/webpack-scss-plugin.js +172 -0
  511. package/jest-addons-loader.js +0 -3
  512. package/jest-extender-plugin.js +0 -39
  513. package/jest-setup-afterenv.js +0 -2
  514. package/jest-svgsystem-transform.js +0 -10
  515. package/patches/patchit.sh +0 -2
  516. package/patches/razzle-jest.patch +0 -10
  517. package/src/components/manage/Contents/__mocks__/index.vitest.tsx +0 -5
  518. package/src/components/manage/Form/__mocks__/index.vitest.tsx +0 -73
  519. package/src/components/manage/Sidebar/SidebarPortal.jsx +0 -47
  520. package/src/components/manage/Sidebar/SidebarPortal.test.jsx +0 -26
  521. package/src/components/manage/Widgets/AlignWidget.test.jsx +0 -59
  522. package/src/components/manage/Widgets/ButtonsWidget.jsx +0 -41
  523. package/src/components/manage/Widgets/ButtonsWidget.test.jsx +0 -70
  524. package/src/components/manage/Widgets/__mocks__/index.vitest.tsx +0 -41
  525. package/src/helpers/Loadable/__mocks__/Loadable.vitest.jsx +0 -39
  526. package/test-setup-globals-vitest.js +0 -46
  527. package/theme/themes/pastanaga/extras/utils.less +0 -63
@@ -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.',
@@ -24,7 +24,7 @@ export const generateRobots = (req) =>
24
24
  request.set('Authorization', `Bearer ${authToken}`);
25
25
  }
26
26
  request.use(addHeadersFactory(req));
27
- request.end((error, { text, body }) => {
27
+ request.end((error, { text, body } = {}) => {
28
28
  if (error) {
29
29
  resolve(text || error);
30
30
  } else {
@@ -0,0 +1,34 @@
1
+ import { generateRobots } from './Robots';
2
+
3
+ const request = {
4
+ set: vi.fn(() => request),
5
+ use: vi.fn(() => request),
6
+ end: vi.fn(),
7
+ };
8
+
9
+ vi.mock('superagent', () => ({
10
+ default: {
11
+ get: vi.fn(() => request),
12
+ },
13
+ }));
14
+
15
+ vi.mock('@plone/volto/helpers/Proxy/Proxy', () => ({
16
+ addHeadersFactory: vi.fn(() => vi.fn()),
17
+ }));
18
+
19
+ describe('generateRobots', () => {
20
+ beforeEach(() => {
21
+ vi.clearAllMocks();
22
+ });
23
+
24
+ it('resolves the original error when superagent does not provide a response', async () => {
25
+ const error = new Error('network error');
26
+ request.end.mockImplementationOnce((callback) => callback(error));
27
+
28
+ await expect(
29
+ generateRobots({
30
+ universalCookies: { get: vi.fn(() => null) },
31
+ }),
32
+ ).resolves.toBe(error);
33
+ });
34
+ });
@@ -411,6 +411,7 @@ export function flattenScales(path, image) {
411
411
  const basePath = image.base_path || path;
412
412
  const imageInfo = {
413
413
  ...image,
414
+ scales: image.scales || {},
414
415
  download: flattenToAppURL(removeObjectIdFromURL(basePath, image.download)),
415
416
  };
416
417
 
@@ -5,6 +5,21 @@ const DAY = HOUR * 24;
5
5
  const MONTH = DAY * 30;
6
6
  const YEAR = DAY * 365; // ? is this safe or should it be more accurate
7
7
 
8
+ // moment-style format tokens → Intl.DateTimeFormat options (for backward compat)
9
+ const MOMENT_FORMAT_MAP = {
10
+ ll: { year: 'numeric', month: 'short', day: 'numeric' },
11
+ lll: {
12
+ year: 'numeric',
13
+ month: 'short',
14
+ day: 'numeric',
15
+ hour: 'numeric',
16
+ minute: 'numeric',
17
+ },
18
+ LLLL: { dateStyle: 'full', timeStyle: 'short' },
19
+ L: { year: 'numeric', month: '2-digit', day: '2-digit' },
20
+ LT: { timeStyle: 'short' },
21
+ };
22
+
8
23
  export const short_date_format = {
9
24
  // 12/9/2021
10
25
  year: 'numeric',
@@ -32,13 +47,23 @@ export const toDate = (d) =>
32
47
  */
33
48
  export function formatDate({
34
49
  date, // Date() or '2022-01-03T19:26:08.999Z'
35
- format, // format object, see https://tc39.es/ecma402/#datetimeformat-objects
50
+ format, // format object (Intl.DateTimeFormat options) or moment-style token string (e.g. 'll', 'lll', 'LLLL', 'L', 'LT')
36
51
  locale = 'en',
37
52
  long, // true if format should be in long readable form.
38
53
  includeTime, // true if short date format should include time
39
54
  formatToParts = false,
40
55
  }) {
41
56
  date = toDate(date);
57
+ // Resolve moment-style token strings to Intl format options
58
+ if (typeof format === 'string') {
59
+ if (process.env.NODE_ENV !== 'production' && !MOMENT_FORMAT_MAP[format]) {
60
+ // eslint-disable-next-line no-console
61
+ console.warn(
62
+ `[formatDate] Unknown format token "${format}". Supported tokens: ${Object.keys(MOMENT_FORMAT_MAP).join(', ')}. Falling back to short_date_format.`,
63
+ );
64
+ }
65
+ format = MOMENT_FORMAT_MAP[format] || short_date_format;
66
+ }
42
67
  format = format
43
68
  ? format
44
69
  : long && !includeTime
@@ -79,6 +79,243 @@ describe('formatDate helper', () => {
79
79
  }),
80
80
  ).toBe('J 03, 2022');
81
81
  });
82
+
83
+ describe('moment-style format tokens', () => {
84
+ it('formats with "ll" token (short date)', () => {
85
+ expect(formatDate({ date, format: 'll' })).toBe('Jan 3, 2022');
86
+ });
87
+
88
+ it('formats with "lll" token (short date + time)', () => {
89
+ expect(formatDate({ date, format: 'lll' })).toBe('Jan 3, 2022, 7:26 PM');
90
+ });
91
+
92
+ it('formats with "LLLL" token (full date + time)', () => {
93
+ expect(formatDate({ date, format: 'LLLL' })).toBe(
94
+ 'Monday, January 3, 2022 at 7:26 PM',
95
+ );
96
+ });
97
+
98
+ it('formats with "L" token (numeric short date)', () => {
99
+ expect(formatDate({ date, format: 'L' })).toBe('01/03/2022');
100
+ });
101
+
102
+ it('formats with "LT" token (time only)', () => {
103
+ expect(formatDate({ date, format: 'LT' })).toBe('7:26 PM');
104
+ });
105
+
106
+ it('moment token works with other locales', () => {
107
+ expect(formatDate({ date, format: 'll', locale: 'de' })).toBe(
108
+ '3. Jan. 2022',
109
+ );
110
+ });
111
+
112
+ it('unknown string format falls back to short_date_format', () => {
113
+ expect(formatDate({ date, format: 'unknown' })).toBe('1/3/2022');
114
+ });
115
+ });
116
+
117
+ describe('Italian locale (it)', () => {
118
+ it('formats a basic date', () => {
119
+ expect(formatDate({ date, locale: 'it' })).toBe('03/01/2022');
120
+ });
121
+
122
+ it('formats a date with time', () => {
123
+ expect(formatDate({ date, locale: 'it', includeTime: true })).toBe(
124
+ '03/01/22, 19:26',
125
+ );
126
+ });
127
+
128
+ it('formats a date as long', () => {
129
+ expect(formatDate({ date, locale: 'it', long: true })).toBe(
130
+ 'lunedì 3 gennaio 2022 alle ore 19:26',
131
+ );
132
+ });
133
+
134
+ it('formats with "ll" token', () => {
135
+ expect(formatDate({ date, format: 'll', locale: 'it' })).toBe(
136
+ '3 gen 2022',
137
+ );
138
+ });
139
+
140
+ it('formats with "lll" token', () => {
141
+ expect(formatDate({ date, format: 'lll', locale: 'it' })).toBe(
142
+ '3 gen 2022, 19:26',
143
+ );
144
+ });
145
+
146
+ it('formats with "LLLL" token', () => {
147
+ expect(formatDate({ date, format: 'LLLL', locale: 'it' })).toBe(
148
+ 'lunedì 3 gennaio 2022 alle ore 19:26',
149
+ );
150
+ });
151
+
152
+ it('formats with "L" token', () => {
153
+ expect(formatDate({ date, format: 'L', locale: 'it' })).toBe(
154
+ '03/01/2022',
155
+ );
156
+ });
157
+
158
+ it('formats with "LT" token', () => {
159
+ expect(formatDate({ date, format: 'LT', locale: 'it' })).toBe('19:26');
160
+ });
161
+ });
162
+
163
+ describe('German locale (de)', () => {
164
+ it('formats a basic date', () => {
165
+ expect(formatDate({ date, locale: 'de' })).toBe('3.1.2022');
166
+ });
167
+
168
+ it('formats a date with time', () => {
169
+ expect(formatDate({ date, locale: 'de', includeTime: true })).toBe(
170
+ '03.01.22, 19:26',
171
+ );
172
+ });
173
+
174
+ it('formats a date as long', () => {
175
+ expect(formatDate({ date, locale: 'de', long: true })).toBe(
176
+ 'Montag, 3. Januar 2022 um 19:26',
177
+ );
178
+ });
179
+
180
+ it('formats with "ll" token', () => {
181
+ expect(formatDate({ date, format: 'll', locale: 'de' })).toBe(
182
+ '3. Jan. 2022',
183
+ );
184
+ });
185
+
186
+ it('formats with "lll" token', () => {
187
+ expect(formatDate({ date, format: 'lll', locale: 'de' })).toBe(
188
+ '3. Jan. 2022, 19:26',
189
+ );
190
+ });
191
+
192
+ it('formats with "LLLL" token', () => {
193
+ expect(formatDate({ date, format: 'LLLL', locale: 'de' })).toBe(
194
+ 'Montag, 3. Januar 2022 um 19:26',
195
+ );
196
+ });
197
+
198
+ it('formats with "L" token', () => {
199
+ expect(formatDate({ date, format: 'L', locale: 'de' })).toBe(
200
+ '03.01.2022',
201
+ );
202
+ });
203
+
204
+ it('formats with "LT" token', () => {
205
+ expect(formatDate({ date, format: 'LT', locale: 'de' })).toBe('19:26');
206
+ });
207
+ });
208
+
209
+ describe('Brazilian Portuguese locale (pt-BR)', () => {
210
+ it('formats a basic date', () => {
211
+ expect(formatDate({ date, locale: 'pt-BR' })).toBe('03/01/2022');
212
+ });
213
+
214
+ it('formats a date with time', () => {
215
+ expect(formatDate({ date, locale: 'pt-BR', includeTime: true })).toBe(
216
+ '03/01/2022, 19:26',
217
+ );
218
+ });
219
+
220
+ it('formats a date as long', () => {
221
+ expect(formatDate({ date, locale: 'pt-BR', long: true })).toBe(
222
+ 'segunda-feira, 3 de janeiro de 2022 às 19:26',
223
+ );
224
+ });
225
+
226
+ it('formats with "ll" token', () => {
227
+ expect(formatDate({ date, format: 'll', locale: 'pt-BR' })).toBe(
228
+ '3 de jan. de 2022',
229
+ );
230
+ });
231
+
232
+ it('formats with "lll" token', () => {
233
+ expect(formatDate({ date, format: 'lll', locale: 'pt-BR' })).toBe(
234
+ '3 de jan. de 2022, 19:26',
235
+ );
236
+ });
237
+
238
+ it('formats with "LLLL" token', () => {
239
+ expect(formatDate({ date, format: 'LLLL', locale: 'pt-BR' })).toBe(
240
+ 'segunda-feira, 3 de janeiro de 2022 às 19:26',
241
+ );
242
+ });
243
+
244
+ it('formats with "L" token', () => {
245
+ expect(formatDate({ date, format: 'L', locale: 'pt-BR' })).toBe(
246
+ '03/01/2022',
247
+ );
248
+ });
249
+
250
+ it('formats with "LT" token', () => {
251
+ expect(formatDate({ date, format: 'LT', locale: 'pt-BR' })).toBe('19:26');
252
+ });
253
+ });
254
+
255
+ describe('Romanian locale (ro)', () => {
256
+ it('formats a basic date', () => {
257
+ expect(formatDate({ date, locale: 'ro' })).toBe('03.01.2022');
258
+ });
259
+
260
+ it('formats a date with time', () => {
261
+ expect(formatDate({ date, locale: 'ro', includeTime: true })).toBe(
262
+ '03.01.2022, 19:26',
263
+ );
264
+ });
265
+
266
+ it('formats a date as long', () => {
267
+ expect(formatDate({ date, locale: 'ro', long: true })).toBe(
268
+ 'luni, 3 ianuarie 2022 la 19:26',
269
+ );
270
+ });
271
+
272
+ it('formats with "ll" token', () => {
273
+ expect(formatDate({ date, format: 'll', locale: 'ro' })).toBe(
274
+ '3 ian. 2022',
275
+ );
276
+ });
277
+
278
+ it('formats with "lll" token', () => {
279
+ expect(formatDate({ date, format: 'lll', locale: 'ro' })).toBe(
280
+ '3 ian. 2022, 19:26',
281
+ );
282
+ });
283
+
284
+ it('formats with "LLLL" token', () => {
285
+ expect(formatDate({ date, format: 'LLLL', locale: 'ro' })).toBe(
286
+ 'luni, 3 ianuarie 2022 la 19:26',
287
+ );
288
+ });
289
+
290
+ it('formats with "L" token', () => {
291
+ expect(formatDate({ date, format: 'L', locale: 'ro' })).toBe(
292
+ '03.01.2022',
293
+ );
294
+ });
295
+
296
+ it('formats with "LT" token', () => {
297
+ expect(formatDate({ date, format: 'LT', locale: 'ro' })).toBe('19:26');
298
+ });
299
+ });
300
+
301
+ // moment vs Intl comparison
302
+ // This section documents known differences between the former moment.js output
303
+ // and our Intl-based formatDate implementation. Reference values are hardcoded
304
+ // from moment@2.29.4 to avoid a runtime dependency on the library we are removing.
305
+ //
306
+ // Tokens that match moment exactly: ll, L, LT (most locales), LLLL (pt-BR only)
307
+ //
308
+ // Known differences from moment@2.29.4:
309
+ // - lll (all locales): Intl inserts a comma between date and time;
310
+ // moment did not (e.g. "Jan 3, 2022, 7:26 PM" vs "Jan 3, 2022 7:26 PM")
311
+ // - LLLL (en, it, de, ro): Intl inserts a locale-specific preposition before
312
+ // the time; moment did not
313
+ // en: "...at 7:26 PM" vs "...7:26 PM"
314
+ // it: "...alle ore 19:26" vs "...19:26"
315
+ // de: "...um 19:26" vs "...19:26"
316
+ // ro: "...la 19:26" vs "...19:26"
317
+ // - ll/lll (pt-BR): Intl adds a period after abbreviated month ("jan.");
318
+ // moment did not ("jan")
82
319
  });
83
320
 
84
321
  describe('formatRelativeDate helper', () => {
@@ -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(
@@ -9,6 +9,7 @@ import checkSVG from '@plone/volto/icons/check.svg';
9
9
  import clearSVG from '@plone/volto/icons/clear.svg';
10
10
  import { useIntl, defineMessages } from 'react-intl';
11
11
  import { useLocation } from 'react-router-dom';
12
+ import config from '@plone/volto/registry';
12
13
 
13
14
  const messages = defineMessages({
14
15
  autoSaveFound: {
@@ -227,15 +228,38 @@ export default function withSaveAsDraft(options) {
227
228
  WrappedComponent,
228
229
  )})`;
229
230
 
230
- if (forwardRef) {
231
- return hoistNonReactStatics(
232
- React.forwardRef((props, ref) => (
233
- <WithSaveAsDraft {...props} forwardedRef={ref} />
234
- )),
235
- WrappedComponent,
236
- );
237
- }
231
+ const DraftWrappedComponent = forwardRef
232
+ ? hoistNonReactStatics(
233
+ React.forwardRef((props, ref) => (
234
+ <WithSaveAsDraft {...props} forwardedRef={ref} />
235
+ )),
236
+ WrappedComponent,
237
+ )
238
+ : hoistNonReactStatics(WithSaveAsDraft, WrappedComponent);
239
+
240
+ const WithExperimentalSaveAsDraft = forwardRef
241
+ ? hoistNonReactStatics(
242
+ React.forwardRef((props, ref) => {
243
+ const ComponentToRender = config.experimental?.saveAsDraft?.enabled
244
+ ? DraftWrappedComponent
245
+ : WrappedComponent;
246
+
247
+ return <ComponentToRender {...props} ref={ref} />;
248
+ }),
249
+ WrappedComponent,
250
+ )
251
+ : hoistNonReactStatics((props) => {
252
+ const ComponentToRender = config.experimental?.saveAsDraft?.enabled
253
+ ? DraftWrappedComponent
254
+ : WrappedComponent;
255
+
256
+ return <ComponentToRender {...props} />;
257
+ }, WrappedComponent);
258
+
259
+ WithExperimentalSaveAsDraft.displayName = `WithExperimentalSaveAsDraft(${getDisplayName(
260
+ WrappedComponent,
261
+ )})`;
238
262
 
239
- return hoistNonReactStatics(WithSaveAsDraft, WrappedComponent);
263
+ return WithExperimentalSaveAsDraft;
240
264
  };
241
265
  }
@@ -112,6 +112,7 @@ export {
112
112
  normalizeString,
113
113
  } from '@plone/volto/helpers/Utils/Utils';
114
114
  export { messages } from './MessageLabels/MessageLabels';
115
+ export { formatMessageWithFallback } from './I18n/I18n';
115
116
  export {
116
117
  withBlockSchemaEnhancer,
117
118
  withVariationSchemaEnhancer,
@@ -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,8 +345,13 @@ 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
  }
@@ -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
  };