@plone/volto 19.0.0-alpha.1 → 19.0.0-alpha.10

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 (238) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +37 -2
  3. package/CHANGELOG.md +228 -0
  4. package/README.md +3 -6
  5. package/cypress/docker/prefixed-rules.yml +26 -0
  6. package/cypress/docker/prefixed.yml +24 -0
  7. package/cypress/support/commands.js +12 -6
  8. package/cypress/support/guillotina.js +1 -0
  9. package/cypress.config.js +1 -0
  10. package/locales/af.json +1 -0
  11. package/locales/ar.json +1 -0
  12. package/locales/bg.json +1 -0
  13. package/locales/bn.json +1 -0
  14. package/locales/ca/LC_MESSAGES/volto.po +96 -17
  15. package/locales/ca.json +1 -1
  16. package/locales/cs.json +1 -0
  17. package/locales/cy.json +1 -0
  18. package/locales/da.json +1 -0
  19. package/locales/de/LC_MESSAGES/volto.po +104 -25
  20. package/locales/de.json +1 -1
  21. package/locales/el.json +1 -0
  22. package/locales/en/LC_MESSAGES/volto.po +97 -18
  23. package/locales/en.json +1 -1
  24. package/locales/en_AU.json +1 -0
  25. package/locales/en_GB.json +1 -0
  26. package/locales/eo.json +1 -0
  27. package/locales/es/LC_MESSAGES/volto.po +97 -18
  28. package/locales/es.json +1 -1
  29. package/locales/et.json +1 -0
  30. package/locales/eu/LC_MESSAGES/volto.po +96 -17
  31. package/locales/eu.json +1 -1
  32. package/locales/fa.json +1 -0
  33. package/locales/fi/LC_MESSAGES/volto.po +96 -17
  34. package/locales/fi.json +1 -1
  35. package/locales/fr/LC_MESSAGES/volto.po +97 -18
  36. package/locales/fr.json +1 -1
  37. package/locales/fu.json +1 -0
  38. package/locales/gl.json +1 -0
  39. package/locales/he.json +1 -0
  40. package/locales/hi/LC_MESSAGES/volto.po +100 -21
  41. package/locales/hi.json +1 -1
  42. package/locales/hr.json +1 -0
  43. package/locales/hu.json +1 -0
  44. package/locales/hy.json +1 -0
  45. package/locales/id.json +1 -0
  46. package/locales/it/LC_MESSAGES/volto.po +101 -22
  47. package/locales/it.json +1 -1
  48. package/locales/ja/LC_MESSAGES/volto.po +96 -17
  49. package/locales/ja.json +1 -1
  50. package/locales/ka.json +1 -0
  51. package/locales/kn.json +1 -0
  52. package/locales/ko.json +1 -0
  53. package/locales/lt.json +1 -0
  54. package/locales/lv.json +1 -0
  55. package/locales/mi.json +1 -0
  56. package/locales/mk.json +1 -0
  57. package/locales/my.json +1 -0
  58. package/locales/nb_NO.json +1 -0
  59. package/locales/nl/LC_MESSAGES/volto.po +100 -21
  60. package/locales/nl.json +1 -1
  61. package/locales/nn.json +1 -0
  62. package/locales/pl.json +1 -0
  63. package/locales/pt/LC_MESSAGES/volto.po +96 -17
  64. package/locales/pt.json +1 -1
  65. package/locales/pt_BR/LC_MESSAGES/volto.po +116 -37
  66. package/locales/pt_BR.json +1 -1
  67. package/locales/rm.json +1 -0
  68. package/locales/ro/LC_MESSAGES/volto.po +100 -21
  69. package/locales/ro.json +1 -1
  70. package/locales/ru/LC_MESSAGES/volto.po +100 -21
  71. package/locales/ru.json +1 -1
  72. package/locales/sk.json +1 -0
  73. package/locales/sl.json +1 -0
  74. package/locales/sm.json +1 -0
  75. package/locales/sq.json +1 -0
  76. package/locales/sr.json +1 -0
  77. package/locales/sr@cyrl.json +1 -0
  78. package/locales/sr@latn.json +1 -0
  79. package/locales/sv.json +1 -1
  80. package/locales/ta.json +1 -0
  81. package/locales/te.json +1 -0
  82. package/locales/th.json +1 -0
  83. package/locales/to.json +1 -0
  84. package/locales/tr.json +1 -0
  85. package/locales/uk.json +1 -0
  86. package/locales/vi.json +1 -0
  87. package/locales/volto.pot +97 -18
  88. package/locales/zh_CN/LC_MESSAGES/volto.po +96 -17
  89. package/locales/zh_CN.json +1 -1
  90. package/locales/zh_Hant.json +1 -0
  91. package/locales/zh_Hant_HK.json +1 -0
  92. package/package.json +28 -26
  93. package/razzle.config.js +16 -0
  94. package/src/actions/content/content.js +0 -1
  95. package/src/actions/controlpanels/controlpanels.js +13 -7
  96. package/src/actions/controlpanels/controlpanels.test.js +11 -5
  97. package/src/actions/users/users.js +2 -2
  98. package/src/components/manage/Add/Add.jsx +5 -6
  99. package/src/components/manage/Blocks/Block/Edit.jsx +1 -0
  100. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +9 -4
  101. package/src/components/manage/Blocks/Image/Edit.jsx +5 -1
  102. package/src/components/manage/Blocks/LeadImage/Edit.jsx +2 -2
  103. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +1 -1
  104. package/src/components/manage/Blocks/Listing/ImageGallery.jsx +6 -4
  105. package/src/components/manage/Blocks/Maps/Edit.jsx +2 -1
  106. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +21 -4
  107. package/src/components/manage/Blocks/Teaser/Data.jsx +21 -7
  108. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +1 -1
  109. package/src/components/manage/Blocks/Teaser/schema.js +8 -3
  110. package/src/components/manage/Blocks/Title/Edit.jsx +8 -2
  111. package/src/components/manage/Blocks/Video/Edit.jsx +2 -1
  112. package/src/components/manage/Contents/Contents.jsx +23 -2
  113. package/src/components/manage/Contents/Contents.test.jsx +7 -0
  114. package/src/components/manage/Contents/ContentsBreadcrumbs.Multilingual.test.jsx +18 -5
  115. package/src/components/manage/Contents/ContentsBreadcrumbs.jsx +20 -26
  116. package/src/components/manage/Contents/ContentsBreadcrumbs.test.jsx +14 -0
  117. package/src/components/manage/Contents/ContentsDeleteModal.jsx +258 -206
  118. package/src/components/manage/Contents/ContentsDeleteModal.stories.jsx +26 -8
  119. package/src/components/manage/Contents/ContentsItem.jsx +10 -2
  120. package/src/components/manage/Contents/ContentsUploadModal.test.jsx +13 -22
  121. package/src/components/manage/Controlpanels/ContentType.jsx +1 -1
  122. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +3 -2
  123. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +156 -175
  124. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +575 -630
  125. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +4 -3
  126. package/src/components/manage/Edit/Edit.jsx +2 -3
  127. package/src/components/manage/Form/Form.jsx +32 -0
  128. package/src/components/manage/Form/Form.test.jsx +22 -18
  129. package/src/components/manage/Form/InlineForm.jsx +2 -2
  130. package/src/components/manage/Multilingual/CompareLanguages.jsx +2 -5
  131. package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -8
  132. package/src/components/manage/Multilingual/ManageTranslations.jsx +4 -2
  133. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +5 -1
  134. package/src/components/manage/Multilingual/TranslationObject.jsx +1 -1
  135. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
  136. package/src/components/manage/Sidebar/SidebarPortal.test.tsx +42 -0
  137. package/src/components/manage/Sidebar/SidebarPortal.tsx +48 -0
  138. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +2 -1
  139. package/src/components/manage/Toolbar/More.jsx +4 -1
  140. package/src/components/manage/Toolbar/More.test.jsx +3 -0
  141. package/src/components/manage/Toolbar/PersonalTools.jsx +2 -1
  142. package/src/components/manage/Toolbar/Toolbar.jsx +3 -4
  143. package/src/components/manage/Toolbar/Types.jsx +7 -7
  144. package/src/components/manage/UniversalLink/UniversalLink.tsx +1 -0
  145. package/src/components/manage/Widgets/DatetimeWidget.jsx +5 -0
  146. package/src/components/manage/Widgets/FileWidget.jsx +14 -8
  147. package/src/components/manage/Widgets/ImageWidget.jsx +171 -38
  148. package/src/components/manage/Widgets/InternalUrlWidget.jsx +2 -0
  149. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +3 -0
  150. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +3 -2
  151. package/src/components/manage/Widgets/SelectAutoComplete.jsx +29 -12
  152. package/src/components/manage/Widgets/SelectWidget.jsx +3 -1
  153. package/src/components/manage/Widgets/UrlWidget.jsx +2 -0
  154. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +1 -3
  155. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +0 -4
  156. package/src/components/theme/App/App.jsx +3 -1
  157. package/src/components/theme/App/App.test.jsx +1 -0
  158. package/src/components/theme/Avatar/Avatar.jsx +2 -1
  159. package/src/components/theme/FormattedDate/FormattedDate.stories.jsx +20 -2
  160. package/src/components/theme/Image/Image.jsx +11 -8
  161. package/src/components/theme/LanguageSelector/{LanguageSelector.test.jsx → LanguageSelector.test.tsx} +6 -6
  162. package/src/components/theme/LanguageSelector/LanguageSelector.tsx +89 -0
  163. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +0 -5
  164. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +8 -12
  165. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.test.jsx +3 -5
  166. package/src/components/theme/Navigation/NavItem.jsx +1 -5
  167. package/src/components/theme/Navigation/Navigation.Multilingual.test.jsx +0 -5
  168. package/src/components/theme/NotFound/NotFound.jsx +5 -2
  169. package/src/components/theme/NotFound/NotFound.test.jsx +3 -0
  170. package/src/components/theme/PreviewImage/PreviewImage.jsx +1 -1
  171. package/src/components/theme/RequestTimeout/RequestTimeout.jsx +1 -1
  172. package/src/components/theme/Sitemap/Sitemap.jsx +6 -5
  173. package/src/components/theme/Sitemap/Sitemap.test.jsx +0 -1
  174. package/src/components/theme/View/FileView.jsx +9 -1
  175. package/src/components/theme/View/View.jsx +1 -1
  176. package/src/components/theme/Widgets/ImageWidget.jsx +2 -1
  177. package/src/config/ControlPanels.js +1 -0
  178. package/src/config/index.js +18 -25
  179. package/src/config/server.js +0 -2
  180. package/src/express-middleware/devproxy.js +20 -5
  181. package/src/helpers/Api/APIResourceWithAuth.js +8 -3
  182. package/src/helpers/Api/Api.js +7 -4
  183. package/src/helpers/AsyncConnect/ssr.js +4 -1
  184. package/src/helpers/Content/Content.js +23 -0
  185. package/src/helpers/Content/Content.test.js +39 -0
  186. package/src/helpers/Content/withClientSideContent.jsx +35 -0
  187. package/src/helpers/Extensions/withBlockSchemaEnhancer.jsx +4 -1
  188. package/src/helpers/Html/Html.jsx +13 -7
  189. package/src/helpers/LanguageMap/LanguageMap.js +115 -8
  190. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  191. package/src/helpers/Sitemap/Sitemap.js +4 -4
  192. package/src/helpers/Url/Url.js +32 -2
  193. package/src/helpers/Url/Url.test.js +62 -0
  194. package/src/helpers/Utils/withSaveAsDraft.jsx +241 -0
  195. package/src/hooks/user/useUser.js +1 -1
  196. package/src/middleware/Api.test.js +4 -0
  197. package/src/middleware/api.js +77 -28
  198. package/src/middleware/storeProtectLoadUtils.test.js +3 -3
  199. package/src/reducers/content/content.js +3 -18
  200. package/src/reducers/diff/diff.js +5 -1
  201. package/src/reducers/diff/diff.test.js +60 -4
  202. package/src/routes.js +4 -2
  203. package/src/server.jsx +45 -14
  204. package/src/start-client.jsx +9 -6
  205. package/src/start-server.js +9 -3
  206. package/test-setup-config.jsx +0 -2
  207. package/theme/themes/pastanaga/collections/table.overrides +9 -0
  208. package/theme/themes/pastanaga/extras/blocks.less +26 -0
  209. package/theme/themes/pastanaga/extras/contents.less +17 -5
  210. package/theme/themes/pastanaga/extras/main.less +32 -2
  211. package/tsconfig.json +3 -4
  212. package/types/components/manage/Blocks/Teaser/schema.d.ts +1 -0
  213. package/types/components/manage/Controlpanels/Users/RenderUsers.d.ts +18 -2
  214. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +6 -2
  215. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  216. package/types/components/manage/Sidebar/SidebarPortal.d.ts +7 -15
  217. package/types/components/manage/Widgets/ImageWidget.d.ts +41 -1
  218. package/types/components/manage/Widgets/RecurrenceWidget/Utils.d.ts +12 -18
  219. package/types/components/theme/FormattedDate/FormattedDate.stories.d.ts +1 -1
  220. package/types/components/theme/LanguageSelector/LanguageSelector.d.ts +3 -10
  221. package/types/helpers/Content/Content.d.ts +7 -0
  222. package/types/helpers/Content/withClientSideContent.d.ts +1 -0
  223. package/types/helpers/Extensions/withBlockSchemaEnhancer.d.ts +4 -5
  224. package/types/helpers/Helmet/Helmet.d.ts +1 -1
  225. package/types/helpers/LanguageMap/LanguageMap.d.ts +428 -4
  226. package/types/helpers/MessageLabels/MessageLabels.d.ts +68 -62
  227. package/types/helpers/Url/Url.d.ts +14 -0
  228. package/types/helpers/Url/bulkFlattenToAppURL.d.ts +5 -0
  229. package/types/helpers/Utils/withSaveAsDraft.d.ts +1 -0
  230. package/types/middleware/api.d.ts +6 -9
  231. package/types/reducers/index.d.ts +1 -0
  232. package/types/start-client.d.ts +0 -1
  233. package/package-why.json +0 -34
  234. package/src/actions/content/content.multilingual.test.js +0 -17
  235. package/src/components/manage/Sidebar/SidebarPortal.jsx +0 -47
  236. package/src/components/manage/Sidebar/SidebarPortal.test.jsx +0 -26
  237. package/src/components/theme/LanguageSelector/LanguageSelector.jsx +0 -77
  238. package/theme/themes/pastanaga/extras/utils.less +0 -63
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  }
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "19.0.0-alpha.1",
12
+ "version": "19.0.0-alpha.10",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git@github.com:plone/volto.git"
@@ -144,21 +144,25 @@
144
144
  "not dead"
145
145
  ],
146
146
  "engines": {
147
- "node": "^20 || ^22"
147
+ "node": "^22 || ^24"
148
148
  },
149
149
  "dependencies": {
150
+ "@dnd-kit/core": "6.0.8",
151
+ "@dnd-kit/sortable": "7.0.2",
152
+ "@dnd-kit/utilities": "3.2.2",
150
153
  "@loadable/component": "5.14.1",
151
154
  "@loadable/server": "5.14.0",
152
155
  "@redux-devtools/extension": "^3.3.0",
153
156
  "classnames": "2.5.1",
154
157
  "connected-react-router": "6.8.0",
155
- "debug": "4.3.2",
158
+ "debug": "4.3.4",
156
159
  "decorate-component-with-props": "1.2.1",
157
160
  "dependency-graph": "0.10.0",
158
161
  "detect-browser": "5.1.0",
159
162
  "diff": "3.5.0",
160
163
  "express": "4.19.2",
161
164
  "filesize": "6",
165
+ "full-icu": "1.4.0",
162
166
  "github-slugger": "1.4.0",
163
167
  "history": "4.10.1",
164
168
  "hoist-non-react-statics": "3.3.2",
@@ -181,7 +185,7 @@
181
185
  "process": "^0.11.10",
182
186
  "promise-file-reader": "1.0.2",
183
187
  "prop-types": "15.7.2",
184
- "query-string": "7.1.0",
188
+ "query-string": "^9.0.0",
185
189
  "rc-time-picker": "3.7.3",
186
190
  "react": "18.2.0",
187
191
  "react-anchor-link-smooth-scroll": "1.0.12",
@@ -225,9 +229,9 @@
225
229
  "semantic-ui-less": "2.4.1",
226
230
  "semantic-ui-react": "2.1.5",
227
231
  "serialize-javascript": "3.1.0",
228
- "slate": "0.100.0",
229
- "slate-hyperscript": "0.100.0",
230
- "slate-react": "0.98.4",
232
+ "slate": "0.118.1",
233
+ "slate-hyperscript": "0.115.0",
234
+ "slate-react": "0.117.4",
231
235
  "superagent": "3.8.2",
232
236
  "tlds": "1.203.1",
233
237
  "undoo": "0.5.0",
@@ -236,9 +240,9 @@
236
240
  "url": "^0.11.3",
237
241
  "use-deep-compare-effect": "1.8.1",
238
242
  "uuid": "^8.3.2",
239
- "@plone/registry": "3.0.0-alpha.3",
240
- "@plone/volto-slate": "19.0.0-alpha.1",
241
- "@plone/scripts": "4.0.0-alpha.1"
243
+ "@plone/scripts": "4.0.0-alpha.3",
244
+ "@plone/registry": "3.0.0-alpha.7",
245
+ "@plone/volto-slate": "19.0.0-alpha.6"
242
246
  },
243
247
  "devDependencies": {
244
248
  "@babel/core": "^7.0.0",
@@ -251,9 +255,6 @@
251
255
  "@babel/plugin-syntax-export-namespace-from": "7.8.3",
252
256
  "@babel/runtime": "7.20.6",
253
257
  "@babel/types": "7.20.5",
254
- "@dnd-kit/core": "6.0.8",
255
- "@dnd-kit/sortable": "7.0.2",
256
- "@dnd-kit/utilities": "3.2.2",
257
258
  "@fiverr/afterbuild-webpack-plugin": "^1.0.0",
258
259
  "@jest/globals": "^29.7.0",
259
260
  "@loadable/babel-plugin": "5.13.2",
@@ -268,19 +269,21 @@
268
269
  "@storybook/react": "^8.0.4",
269
270
  "@storybook/react-webpack5": "^8.0.4",
270
271
  "@storybook/theming": "^8.0.4",
271
- "@testing-library/cypress": "10.0.1",
272
+ "@testing-library/cypress": "10.1.0",
272
273
  "@testing-library/jest-dom": "6.4.2",
273
- "@testing-library/react": "14.2.0",
274
+ "@testing-library/react": "14.3.1",
274
275
  "@testing-library/react-hooks": "8.0.1",
275
276
  "@types/history": "^4.7.11",
276
277
  "@types/jest": "^29.5.8",
277
278
  "@types/loadable__component": "^5.13.9",
278
279
  "@types/lodash": "^4.14.201",
279
- "@types/node": "^22.13.0",
280
+ "@types/node": "^24",
280
281
  "@types/react": "^18",
281
282
  "@types/react-dom": "^18",
283
+ "@types/react-intl-redux": "^0.1.19",
282
284
  "@types/react-router-dom": "^5.3.3",
283
285
  "@types/react-test-renderer": "18.0.7",
286
+ "@types/redux-mock-store": "^1.5.0",
284
287
  "@types/uuid": "^9.0.2",
285
288
  "@typescript-eslint/eslint-plugin": "^7.7.0",
286
289
  "@typescript-eslint/parser": "^7.7.0",
@@ -297,22 +300,22 @@
297
300
  "bundlewatch": "0.3.3",
298
301
  "circular-dependency-plugin": "5.2.2",
299
302
  "css-loader": "5.2.7",
300
- "cypress": "13.13.2",
301
- "cypress-axe": "1.5.0",
303
+ "cypress": "15.5.0",
304
+ "cypress-axe": "1.7.0",
302
305
  "cypress-file-upload": "5.0.8",
303
306
  "deep-freeze": "0.0.1",
304
307
  "eslint": "^8.57.0",
305
- "eslint-config-prettier": "^9.1.0",
308
+ "eslint-config-prettier": "^9.1.2",
306
309
  "eslint-config-react-app": "^7.0.1",
307
310
  "eslint-import-resolver-alias": "^1.1.2",
308
311
  "eslint-import-resolver-babel-plugin-root-import": "^1.1.1",
309
312
  "eslint-import-resolver-typescript": "^3.6.1",
310
313
  "eslint-plugin-import": "^2.29.1",
311
314
  "eslint-plugin-jsx-a11y": "^6.7.1",
315
+ "eslint-plugin-no-only-tests": "^3.3.0",
312
316
  "eslint-plugin-prettier": "^5.1.3",
313
317
  "eslint-plugin-react": "^7.34.1",
314
318
  "eslint-plugin-react-hooks": "^4.6.0",
315
- "full-icu": "1.4.0",
316
319
  "html-webpack-plugin": "5.5.0",
317
320
  "identity-obj-proxy": "3.0.0",
318
321
  "jest": "26.6.3",
@@ -340,7 +343,7 @@
340
343
  "react-docgen-typescript-plugin": "^1.0.5",
341
344
  "react-error-overlay": "6.0.9",
342
345
  "react-is": "^18.2.0",
343
- "release-it": "^17.1.1",
346
+ "release-it": "^19.0.4",
344
347
  "semver": "^7.5.4",
345
348
  "start-server-and-test": "1.14.0",
346
349
  "storybook": "^8.0.4",
@@ -363,8 +366,7 @@
363
366
  "webpack-bundle-analyzer": "4.10.1",
364
367
  "webpack-dev-server": "4.11.1",
365
368
  "webpack-node-externals": "3.0.0",
366
- "why": "0.6.2",
367
- "@plone/types": "2.0.0-alpha.3",
369
+ "@plone/types": "2.0.0-alpha.8",
368
370
  "@plone/volto-coresandbox": "1.0.0"
369
371
  },
370
372
  "volta": {
@@ -378,7 +380,7 @@
378
380
  "build:types": "tsc --project tsconfig.declarations.json",
379
381
  "vitest": "vitest",
380
382
  "coverage": "vitest run --coverage",
381
- "test": "razzle test --maxWorkers=50%",
383
+ "test": "razzle test --maxWorkers=${MAX_WORKERS:-50%}",
382
384
  "test:ci": "CI=true NODE_ICU_DATA=node_modules/full-icu razzle test",
383
385
  "test:husky": "CI=true yarn test --bail --findRelatedTests",
384
386
  "start:prod": "NODE_ENV=production node build/server.js",
@@ -388,8 +390,8 @@
388
390
  "stylelint": "stylelint 'theme/**/*.{css,less}' 'src/**/*.{css,less}'",
389
391
  "stylelint:overrides": "stylelint 'theme/**/*.overrides' 'src/**/*.overrides'",
390
392
  "stylelint:fix": "yarn stylelint --fix && yarn stylelint:overrides --fix",
391
- "lint": "eslint --max-warnings=0 'src/**/*.{js,jsx,ts,tsx,json}'",
392
- "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx,json}'",
393
+ "lint": "eslint --max-warnings=0 '{src,cypress}/**/*.{js,jsx,ts,tsx,json}'",
394
+ "lint:fix": "eslint --fix '{src,cypress}/**/*.{js,jsx,ts,tsx,json}'",
393
395
  "lint:husky": "eslint --max-warnings=0 --fix",
394
396
  "i18n": "rm -rf build/messages && NODE_ENV=production i18n",
395
397
  "i18n:ci": "pnpm i18n && git diff -G'^[^\"POT]' --exit-code",
package/razzle.config.js CHANGED
@@ -414,6 +414,22 @@ const defaultModify = ({
414
414
  ]
415
415
  : [];
416
416
 
417
+ // If Volto is served under a subpath,
418
+ // we have to adjust where Webpack assets are served too.
419
+ const subpathPrefix = process.env.RAZZLE_SUBPATH_PREFIX || '';
420
+ if (subpathPrefix) {
421
+ if (target === 'web' && dev) {
422
+ if (config.devServer.devMiddleware) {
423
+ config.devServer.devMiddleware.publicPath = subpathPrefix;
424
+ } else {
425
+ config.devServer.publicPath += `${subpathPrefix.slice(1)}/`;
426
+ }
427
+ }
428
+ const publicPath = config.output.publicPath;
429
+ if (publicPath.indexOf(subpathPrefix) === -1) {
430
+ config.output.publicPath = `${publicPath}${subpathPrefix.slice(1)}/`;
431
+ }
432
+ }
417
433
  return config;
418
434
  };
419
435
 
@@ -164,7 +164,6 @@ export function getContent(
164
164
  b_size: settings.defaultPageSize,
165
165
  }
166
166
  : {},
167
- settings.isMultilingual ? { expand: 'translations' } : {},
168
167
  );
169
168
 
170
169
  let qs = Object.keys(query)
@@ -12,6 +12,8 @@ import {
12
12
  SYSTEM_INFORMATION,
13
13
  DATABASE_INFORMATION,
14
14
  } from '@plone/volto/constants/ActionTypes';
15
+ import { getSite } from '@plone/volto/actions/site/site';
16
+
15
17
  /**
16
18
  * Get controlpanel function.
17
19
  * @function getControlpanel
@@ -86,13 +88,17 @@ export function listControlpanels() {
86
88
  * @returns {Object} Update controlpanel action.
87
89
  */
88
90
  export function updateControlpanel(url, data) {
89
- return {
90
- type: UPDATE_CONTROLPANEL,
91
- request: {
92
- op: 'patch',
93
- path: url,
94
- data,
95
- },
91
+ return (dispatch) => {
92
+ dispatch({
93
+ type: UPDATE_CONTROLPANEL,
94
+ request: {
95
+ op: 'patch',
96
+ path: url,
97
+ data,
98
+ },
99
+ }).then(() => {
100
+ dispatch(getSite());
101
+ });
96
102
  };
97
103
  }
98
104
 
@@ -35,12 +35,18 @@ describe('Controlpanels action', () => {
35
35
  it('should create an action to update a controlpanel', () => {
36
36
  const url = 'http://localhost';
37
37
  const data = 'Hello World!';
38
- const action = updateControlpanel(url, data);
39
38
 
40
- expect(action.type).toEqual(UPDATE_CONTROLPANEL);
41
- expect(action.request.op).toEqual('patch');
42
- expect(action.request.path).toEqual(url);
43
- expect(action.request.data).toEqual(data);
39
+ const dispatch = vi.fn().mockResolvedValue();
40
+ updateControlpanel(url, data)(dispatch);
41
+
42
+ expect(dispatch).toHaveBeenCalledWith({
43
+ type: UPDATE_CONTROLPANEL,
44
+ request: {
45
+ op: 'patch',
46
+ path: url,
47
+ data,
48
+ },
49
+ });
44
50
  });
45
51
  });
46
52
  });
@@ -3,7 +3,7 @@
3
3
  * @module actions/users/users
4
4
  */
5
5
 
6
- import { stringify } from 'query-string';
6
+ import qs from 'query-string';
7
7
 
8
8
  import {
9
9
  CREATE_USER,
@@ -92,7 +92,7 @@ export function listUsers(options = {}) {
92
92
 
93
93
  let filterarg =
94
94
  groups_filter.length > 0
95
- ? stringify(
95
+ ? qs.stringify(
96
96
  { 'groups-filter': groups_filter },
97
97
  { arrayFormat: 'colon-list-separator' },
98
98
  )
@@ -223,11 +223,10 @@ class Add extends Component {
223
223
  ? keys(this.props.schema.definitions)
224
224
  : null,
225
225
  '@type': this.props.type,
226
- ...(config.settings.isMultilingual &&
227
- this.props.location?.state?.translationOf && {
228
- translation_of: this.props.location.state.translationOf,
229
- language: this.props.location.state.language,
230
- }),
226
+ ...(this.props.location?.state?.translationOf && {
227
+ translation_of: this.props.location.state.translationOf,
228
+ language: this.props.location.state.language,
229
+ }),
231
230
  });
232
231
  }
233
232
 
@@ -348,7 +347,7 @@ class Add extends Component {
348
347
  <div id="page-add">
349
348
  <Helmet
350
349
  title={this.props.intl.formatMessage(messages.add, {
351
- type: this.props.type,
350
+ type: this.props?.schema?.title || this.props.type,
352
351
  })}
353
352
  />
354
353
  <Form
@@ -187,6 +187,7 @@ export class Edit extends Component {
187
187
  selected: this.props.selected || this.props.multiSelected,
188
188
  multiSelected: this.props.multiSelected,
189
189
  hovered: this.props.hovered === this.props.id,
190
+ error: !!this.props.blocksErrors?.[this.props.id],
190
191
  })}
191
192
  style={{ outline: 'none' }}
192
193
  ref={this.blockNode}
@@ -21,9 +21,13 @@ import BlockChooserButton from '@plone/volto/components/manage/BlockChooser/Bloc
21
21
  import trashSVG from '@plone/volto/icons/delete.svg';
22
22
 
23
23
  const messages = defineMessages({
24
- delete: {
25
- id: 'delete',
26
- defaultMessage: 'delete',
24
+ delete_block: {
25
+ id: 'delete_block',
26
+ defaultMessage: 'delete {type} block',
27
+ },
28
+ drag_block: {
29
+ id: 'drag_block',
30
+ defaultMessage: 'drag {type} block',
27
31
  },
28
32
  });
29
33
 
@@ -99,6 +103,7 @@ const EditBlockWrapper = (props) => {
99
103
  }}
100
104
  {...draginfo.dragHandleProps}
101
105
  className="drag handle wrapper"
106
+ aria-label={intl.formatMessage(messages.drag_block, { type })}
102
107
  >
103
108
  <Icon name={dragSVG} size="18px" />
104
109
  </div>
@@ -111,7 +116,7 @@ const EditBlockWrapper = (props) => {
111
116
  basic
112
117
  onClick={() => onDeleteBlock(block, true)}
113
118
  className="delete-button"
114
- aria-label={intl.formatMessage(messages.delete)}
119
+ aria-label={intl.formatMessage(messages.delete_block, { type })}
115
120
  >
116
121
  <Icon name={trashSVG} size="18px" />
117
122
  </Button>
@@ -20,7 +20,11 @@ function Edit(props) {
20
20
 
21
21
  const handleChange = React.useCallback(
22
22
  async (id, image, { title, image_field, image_scales } = {}) => {
23
- const url = image ? image['@id'] || image : '';
23
+ const url = Array.isArray(image)
24
+ ? image?.[0]?.['@id']
25
+ : image
26
+ ? image['@id'] || image
27
+ : '';
24
28
 
25
29
  props.onChangeBlock(props.block, {
26
30
  ...props.data,
@@ -43,13 +43,13 @@ const Edit = (props) => {
43
43
  {!hasImage && (
44
44
  <Message>
45
45
  <center>
46
- <img src={imageBlockSVG} alt="" />
46
+ <Image src={imageBlockSVG} alt="" />
47
47
  <div className="message-text">{placeholder}</div>
48
48
  </center>
49
49
  </Message>
50
50
  )}
51
51
  {hasImage && hasImageData && (
52
- <img
52
+ <Image
53
53
  className={className}
54
54
  src={`data:${properties.image['content-type']};base64,${properties.image.data}`}
55
55
  width={properties.image.width}
@@ -96,7 +96,7 @@ const LeadImageSidebar = ({
96
96
  <Segment className="sidebar-metadata-container" secondary>
97
97
  {properties.image.filename}
98
98
  {properties.image.data && (
99
- <img
99
+ <Image
100
100
  // TODO understand when this actually happens
101
101
  src={`data:${properties.image['content-type']};base64,${properties.image.data}`}
102
102
  width={properties.image.width}
@@ -1,10 +1,12 @@
1
- import React from 'react';
2
1
  import PropTypes from 'prop-types';
3
2
  import loadable from '@loadable/component';
4
3
  import 'react-image-gallery/styles/css/image-gallery.css';
5
4
  import { Button } from 'semantic-ui-react';
6
5
  import Icon from '@plone/volto/components/theme/Icon/Icon';
7
- import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
6
+ import {
7
+ addSubpathPrefix,
8
+ flattenToAppURL,
9
+ } from '@plone/volto/helpers/Url/Url';
8
10
  import config from '@plone/volto/registry';
9
11
 
10
12
  import galleryLeftSVG from '@plone/volto/icons/left-key.svg';
@@ -81,10 +83,10 @@ const ImageGalleryTemplate = ({ items }) => {
81
83
  );
82
84
  const imagesInfo = renderItems.map((item) => {
83
85
  return {
84
- original: `${flattenToAppURL(item['@id'])}/@@images/${
86
+ original: `${addSubpathPrefix(flattenToAppURL(item['@id']))}/@@images/${
85
87
  item.image_field
86
88
  }/large`,
87
- thumbnail: `${flattenToAppURL(item['@id'])}/@@images/${
89
+ thumbnail: `${addSubpathPrefix(flattenToAppURL(item['@id']))}/@@images/${
88
90
  item.image_field
89
91
  }/thumb`,
90
92
  };
@@ -11,6 +11,7 @@ import MapsSidebar from '@plone/volto/components/manage/Blocks/Maps/MapsSidebar'
11
11
  import clearSVG from '@plone/volto/icons/clear.svg';
12
12
  import aheadSVG from '@plone/volto/icons/ahead.svg';
13
13
  import mapsBlockSVG from '@plone/volto/components/manage/Blocks/Maps/block-maps.svg';
14
+ import Image from '@plone/volto/components/theme/Image/Image';
14
15
 
15
16
  const messages = defineMessages({
16
17
  MapsBlockInputPlaceholder: {
@@ -121,7 +122,7 @@ const Edit = React.memo((props) => {
121
122
  ) : (
122
123
  <Message>
123
124
  <center>
124
- <img src={mapsBlockSVG} alt="" />
125
+ <Image src={mapsBlockSVG} alt="" />
125
126
  <div className="toolbar-inner">
126
127
  <Input
127
128
  onKeyDown={onKeyDownVariantMenuForm}
@@ -42,7 +42,7 @@ const blockPropsAreChanged = (prevProps, nextProps) => {
42
42
  return isEqual(prev, next);
43
43
  };
44
44
 
45
- const applyDefaults = (data, root) => {
45
+ const applyDefaults = (data, root, blockQuery) => {
46
46
  const defaultQuery = [
47
47
  {
48
48
  i: 'path',
@@ -51,7 +51,8 @@ const applyDefaults = (data, root) => {
51
51
  },
52
52
  ];
53
53
 
54
- const searchBySearchableText = data.query.filter(
54
+ const dataQuery = data?.query?.length ? data.query : [];
55
+ const searchBySearchableText = dataQuery.filter(
55
56
  (item) => item['i'] === 'SearchableText',
56
57
  ).length;
57
58
 
@@ -66,11 +67,27 @@ const applyDefaults = (data, root) => {
66
67
  ? { sort_order: 'descending' }
67
68
  : {};
68
69
 
70
+ // We start with the base query from the block.
71
+ // We enhance it with the query from the facets (filters).
72
+ // We fall back to the default query.
73
+ let query = blockQuery?.length ? blockQuery : [];
74
+ if (!query.length) {
75
+ query = dataQuery.length ? dataQuery : defaultQuery;
76
+ } else if (dataQuery.length) {
77
+ // We have both a base query and a filter. Combine them.
78
+ // Items in the filter win over items in the base query.
79
+ const filterKeys = new Set(dataQuery.map((obj) => obj.i));
80
+ query = [
81
+ ...dataQuery,
82
+ ...blockQuery.filter((item) => !filterKeys.has(item.i)),
83
+ ];
84
+ }
85
+
69
86
  return {
70
87
  ...data,
71
88
  ...sort_on,
72
89
  ...sort_order,
73
- query: data?.query?.length ? data.query : defaultQuery,
90
+ query,
74
91
  };
75
92
  };
76
93
 
@@ -93,7 +110,7 @@ const SearchBlockView = (props) => {
93
110
  }, [dataListingBodyVariation, mode]);
94
111
 
95
112
  const root = useSelector((state) => state.breadcrumbs.root);
96
- const listingBodyData = applyDefaults(searchData, root);
113
+ const listingBodyData = applyDefaults(searchData, root, data.query?.query);
97
114
 
98
115
  const { variations } = config.blocks.blocksConfig.listing;
99
116
  const listingBodyVariation = variations.find(({ id }) => id === selectedView);
@@ -21,7 +21,7 @@ const messages = defineMessages({
21
21
  },
22
22
  refreshTeaser: {
23
23
  id: 'Refresh source content',
24
- defaultMessage: 'Refresh source content',
24
+ defaultMessage: 'Reset to target',
25
25
  },
26
26
  invalidTeaser: {
27
27
  id: 'Invalid teaser source',
@@ -29,6 +29,16 @@ const messages = defineMessages({
29
29
  },
30
30
  });
31
31
 
32
+ function getImageField(resp) {
33
+ if (!resp) return null;
34
+
35
+ if (resp.preview_image_link) return 'preview_image_link';
36
+ if (resp.preview_image) return 'preview_image';
37
+ if (resp.image) return 'image';
38
+
39
+ return null;
40
+ }
41
+
32
42
  const TeaserData = (props) => {
33
43
  const {
34
44
  block,
@@ -58,16 +68,20 @@ const TeaserData = (props) => {
58
68
  '@type': resp?.['@type'],
59
69
  Description: resp?.description,
60
70
  Title: resp.title,
61
- hasPreviewImage: resp?.preview_image ? true : false,
71
+ hasPreviewImage: getImageField(resp) ? true : false,
62
72
  head_title: resp.head_title ?? null,
63
- image_field: resp?.preview_image
64
- ? 'preview_image'
65
- : resp?.image
66
- ? 'image'
67
- : null,
73
+ image_field: getImageField(resp),
68
74
  image_scales: {
69
75
  preview_image: [resp?.preview_image],
70
76
  image: [resp?.image],
77
+ preview_image_link: resp?.preview_image_link
78
+ ? [
79
+ {
80
+ ...resp?.preview_image_link?.['image_scales']?.image?.[0],
81
+ base_path: resp?.preview_image_link?.['@id'],
82
+ },
83
+ ]
84
+ : [],
71
85
  },
72
86
  title: resp.title,
73
87
  };
@@ -33,7 +33,7 @@ const TeaserDefaultTemplate = (props) => {
33
33
  {!href && isEditMode && (
34
34
  <Message>
35
35
  <div className="teaser-item placeholder">
36
- <img src={imageBlockSVG} alt="" />
36
+ <Image src={imageBlockSVG} alt="" />
37
37
  <p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
38
38
  </div>
39
39
  </Message>
@@ -22,9 +22,13 @@ const messages = defineMessages({
22
22
  id: 'Description',
23
23
  defaultMessage: 'Description',
24
24
  },
25
- head_title: {
25
+ kicker: {
26
26
  id: 'head_title',
27
- defaultMessage: 'Head title',
27
+ defaultMessage: 'Kicker',
28
+ },
29
+ kicker_description: {
30
+ id: 'The kicker is a line of text shown above the title.',
31
+ defaultMessage: 'The kicker is a line of text shown above the title.',
28
32
  },
29
33
  teaser: {
30
34
  id: 'Teaser',
@@ -88,7 +92,8 @@ export const TeaserSchema = ({ data, intl }) => {
88
92
  title: intl.formatMessage(messages.title),
89
93
  },
90
94
  head_title: {
91
- title: intl.formatMessage(messages.head_title),
95
+ title: intl.formatMessage(messages.kicker),
96
+ description: intl.formatMessage(messages.kicker_description),
92
97
  },
93
98
  description: {
94
99
  title: intl.formatMessage(messages.description),
@@ -77,8 +77,14 @@ export const TitleBlockEdit = (props) => {
77
77
  ReactEditor.focus(editor);
78
78
  } else {
79
79
  // nothing is selected, move focus to end
80
- ReactEditor.focus(editor);
81
- Transforms.select(editor, Editor.end(editor, []));
80
+ // make sure that the editor is focused
81
+ setTimeout(() => {
82
+ const focused = ReactEditor.focus(editor);
83
+ if (!focused) {
84
+ ReactEditor.focus(editor);
85
+ Transforms.select(editor, Editor.end(editor, []));
86
+ }
87
+ }, 0);
82
88
  }
83
89
  }
84
90
  }, [prevSelected, selected, editor]);
@@ -12,6 +12,7 @@ import aheadSVG from '@plone/volto/icons/ahead.svg';
12
12
  import videoBlockSVG from '@plone/volto/components/manage/Blocks/Video/block-video.svg';
13
13
  import Body from '@plone/volto/components/manage/Blocks/Video/Body';
14
14
  import { withBlockExtensions } from '@plone/volto/helpers/Extensions';
15
+ import Image from '@plone/volto/components/theme/Image/Image';
15
16
 
16
17
  const messages = defineMessages({
17
18
  VideoFormDescription: {
@@ -82,7 +83,7 @@ const Edit = (props) => {
82
83
  ) : (
83
84
  <Message>
84
85
  <center>
85
- <img src={videoBlockSVG} alt="" />
86
+ <Image src={videoBlockSVG} alt="" />
86
87
  <div className="toolbar-inner">
87
88
  <Input
88
89
  onKeyDown={onKeyDownVariantMenuForm}