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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +530 -15
  3. package/CONTRIBUTING.md +1 -1
  4. package/README.md +11 -14
  5. package/addon-registry.js +34 -0
  6. package/create-theme-addons-loader.js +79 -0
  7. package/cypress/support/commands.js +56 -4
  8. package/cypress/support/volto-slate.js +4 -5
  9. package/docker-compose.yml +1 -1
  10. package/locales/ca/LC_MESSAGES/volto.po +272 -6
  11. package/locales/ca.json +1 -1
  12. package/locales/de/LC_MESSAGES/volto.po +291 -25
  13. package/locales/de.json +1 -1
  14. package/locales/en/LC_MESSAGES/volto.po +271 -5
  15. package/locales/en.json +1 -1
  16. package/locales/es/LC_MESSAGES/volto.po +281 -15
  17. package/locales/es.json +1 -1
  18. package/locales/eu/LC_MESSAGES/volto.po +272 -6
  19. package/locales/eu.json +1 -1
  20. package/locales/fi/LC_MESSAGES/volto.po +4882 -0
  21. package/locales/fi.json +1 -1
  22. package/locales/fr/LC_MESSAGES/volto.po +272 -6
  23. package/locales/fr.json +1 -1
  24. package/locales/it/LC_MESSAGES/volto.po +273 -7
  25. package/locales/it.json +1 -1
  26. package/locales/ja/LC_MESSAGES/volto.po +272 -6
  27. package/locales/ja.json +1 -1
  28. package/locales/nl/LC_MESSAGES/volto.po +927 -649
  29. package/locales/nl.json +1 -1
  30. package/locales/pt/LC_MESSAGES/volto.po +272 -6
  31. package/locales/pt.json +1 -1
  32. package/locales/pt_BR/LC_MESSAGES/volto.po +281 -15
  33. package/locales/pt_BR.json +1 -1
  34. package/locales/ro/LC_MESSAGES/volto.po +272 -6
  35. package/locales/ro.json +1 -1
  36. package/locales/volto.pot +272 -6
  37. package/locales/zh_CN/LC_MESSAGES/volto.po +272 -6
  38. package/locales/zh_CN.json +1 -1
  39. package/package.json +5 -3
  40. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
  41. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
  42. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
  43. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
  44. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
  45. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
  46. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
  47. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
  48. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
  49. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
  50. package/packages/volto-slate/package.json +1 -1
  51. package/packages/volto-slate/src/actions/index.js +1 -1
  52. package/packages/volto-slate/src/blocks/Table/TableBlockEdit.jsx +21 -212
  53. package/packages/volto-slate/src/blocks/Table/schema.js +122 -0
  54. package/packages/volto-slate/src/blocks/Text/DefaultTextBlockEditor.jsx +8 -3
  55. package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
  56. package/packages/volto-slate/src/blocks/Text/TextBlockView.jsx +20 -16
  57. package/packages/volto-slate/src/blocks/Text/extensions/withDeserializers.js +3 -1
  58. package/packages/volto-slate/src/blocks/Text/index.js +10 -2
  59. package/packages/volto-slate/src/editor/config.jsx +5 -4
  60. package/packages/volto-slate/src/editor/deserialize.js +0 -1
  61. package/packages/volto-slate/src/editor/index.js +4 -4
  62. package/packages/volto-slate/src/editor/less/slate.less +28 -0
  63. package/packages/volto-slate/src/editor/plugins/StyleMenu/StyleMenu.jsx +14 -4
  64. package/packages/volto-slate/src/editor/plugins/StyleMenu/utils.js +14 -5
  65. package/packages/volto-slate/src/editor/render.jsx +68 -8
  66. package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
  67. package/packages/volto-slate/src/editor/ui/index.js +15 -15
  68. package/packages/volto-slate/src/index.js +2 -2
  69. package/packages/volto-slate/src/utils/blocks.js +7 -0
  70. package/packages/volto-slate/src/widgets/RichTextWidget.jsx +15 -8
  71. package/razzle.config.js +28 -0
  72. package/src/actions/index.js +6 -0
  73. package/src/actions/language/language.js +9 -8
  74. package/src/actions/querystringsearch/querystringsearch.js +20 -14
  75. package/src/actions/relations/rebuild.js +25 -0
  76. package/src/actions/relations/relations.js +86 -0
  77. package/src/actions/relations/relations.test.js +15 -0
  78. package/src/components/index.js +2 -0
  79. package/src/components/manage/Add/Add.jsx +2 -2
  80. package/src/components/manage/AnchorPlugin/index.jsx +2 -2
  81. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
  82. package/src/components/manage/BlockChooser/BlockChooser.jsx +14 -5
  83. package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
  84. package/src/components/manage/Blocks/Block/BlocksForm.jsx +19 -2
  85. package/src/components/manage/Blocks/Block/Edit.jsx +1 -1
  86. package/src/components/manage/Blocks/Block/Style.jsx +2 -2
  87. package/src/components/manage/Blocks/Container/Data.jsx +32 -0
  88. package/src/components/manage/Blocks/Container/Edit.jsx +174 -0
  89. package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +120 -0
  90. package/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +84 -0
  91. package/src/components/manage/Blocks/Container/SimpleContainerToolbar.jsx +54 -0
  92. package/src/components/manage/Blocks/Grid/Edit.jsx +33 -0
  93. package/src/components/manage/Blocks/Grid/View.jsx +43 -0
  94. package/src/components/manage/Blocks/Grid/adapter.js +14 -0
  95. package/src/components/manage/Blocks/Grid/grid-1.svg +6 -0
  96. package/src/components/manage/Blocks/Grid/grid-2.svg +9 -0
  97. package/src/components/manage/Blocks/Grid/grid-3.svg +10 -0
  98. package/src/components/manage/Blocks/Grid/grid-4.svg +11 -0
  99. package/src/components/manage/Blocks/Grid/schema.js +35 -0
  100. package/src/components/manage/Blocks/Grid/templates.js +47 -0
  101. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +6 -1
  102. package/src/components/manage/Blocks/Image/Edit.jsx +11 -7
  103. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +2 -1
  104. package/src/components/manage/Blocks/Image/schema.js +11 -0
  105. package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
  106. package/src/components/manage/Blocks/Listing/Edit.jsx +0 -14
  107. package/src/components/manage/Blocks/Listing/ListingBody.jsx +30 -8
  108. package/src/components/manage/Blocks/Listing/ListingBody.test.jsx +20 -0
  109. package/src/components/manage/Blocks/Listing/getAsyncData.js +9 -3
  110. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +26 -18
  111. package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +5 -4
  112. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
  113. package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
  114. package/src/components/manage/Blocks/Search/components/Facets.jsx +64 -4
  115. package/src/components/manage/Blocks/Search/components/SearchInput.jsx +9 -2
  116. package/src/components/manage/Blocks/Search/components/index.js +13 -13
  117. package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
  118. package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
  119. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +43 -15
  120. package/src/components/manage/Blocks/Search/layout/LeftColumnFacets.jsx +17 -5
  121. package/src/components/manage/Blocks/Search/layout/RightColumnFacets.jsx +17 -5
  122. package/src/components/manage/Blocks/Search/layout/TopSideFacets.jsx +21 -5
  123. package/src/components/manage/Blocks/Search/schema.js +16 -1
  124. package/src/components/manage/Blocks/Teaser/Body.jsx +0 -1
  125. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +20 -15
  126. package/src/components/manage/Blocks/Teaser/schema.js +5 -0
  127. package/src/components/manage/Blocks/Title/View.jsx +15 -5
  128. package/src/components/manage/Blocks/Title/View.test.jsx +16 -1
  129. package/src/components/manage/Blocks/ToC/Schema.jsx +5 -1
  130. package/src/components/manage/Blocks/ToC/View.jsx +8 -1
  131. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +17 -4
  132. package/src/components/manage/Blocks/ToC/variations/HorizontalMenu.jsx +148 -10
  133. package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
  134. package/src/components/manage/Contents/Contents.jsx +39 -26
  135. package/src/components/manage/Contents/ContentsItem.jsx +6 -0
  136. package/src/components/manage/Contents/ContentsUploadModal.jsx +10 -5
  137. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +3 -3
  138. package/src/components/manage/Controlpanels/Controlpanels.jsx +199 -224
  139. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
  140. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
  141. package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
  142. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
  143. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
  144. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
  145. package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
  146. package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
  147. package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
  148. package/src/components/manage/Form/Form.jsx +5 -3
  149. package/src/components/manage/Form/InlineForm.jsx +39 -9
  150. package/src/components/manage/Form/InlineFormState.js +8 -0
  151. package/src/components/manage/History/History.jsx +11 -1
  152. package/src/components/manage/LinksToItem/LinksToItem.jsx +209 -0
  153. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +97 -0
  154. package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
  155. package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
  156. package/src/components/manage/Preferences/ChangePassword.jsx +2 -2
  157. package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
  158. package/src/components/manage/Sharing/Sharing.jsx +5 -1
  159. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +38 -0
  160. package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +34 -0
  161. package/src/components/manage/TemplateChooser/template.svg +10 -0
  162. package/src/components/manage/Toast/Toast.jsx +2 -2
  163. package/src/components/manage/Toolbar/More.jsx +15 -0
  164. package/src/components/manage/Toolbar/Types.jsx +2 -2
  165. package/src/components/manage/UniversalLink/UniversalLink.jsx +2 -6
  166. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +36 -0
  167. package/src/components/manage/Widgets/ColorPickerWidget.jsx +6 -1
  168. package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
  169. package/src/components/manage/Widgets/FileWidget.jsx +2 -1
  170. package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
  171. package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
  172. package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
  173. package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
  174. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +8 -3
  175. package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
  176. package/src/components/manage/Widgets/SelectUtils.js +1 -1
  177. package/src/components/manage/Widgets/SelectWidget.jsx +1 -1
  178. package/src/components/theme/Anontools/Anontools.jsx +44 -72
  179. package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
  180. package/src/components/theme/Anontools/Anontools.test.jsx +16 -2
  181. package/src/components/theme/Breadcrumbs/Breadcrumbs.jsx +52 -99
  182. package/src/components/theme/Breadcrumbs/Breadcrumbs.stories.jsx +14 -13
  183. package/src/components/theme/Comments/CommentEditModal.jsx +63 -115
  184. package/src/components/theme/Component/Component.jsx +1 -1
  185. package/src/components/theme/ContactForm/ContactForm.jsx +108 -192
  186. package/src/components/theme/ContactForm/ContactForm.stories.jsx +1 -1
  187. package/src/components/theme/ContactForm/ContactForm.test.jsx +2 -3
  188. package/src/components/theme/Footer/Footer.jsx +2 -13
  189. package/src/components/theme/Header/Header.jsx +37 -63
  190. package/src/components/theme/Header/Header.test.jsx +18 -0
  191. package/src/components/theme/Icon/Icon.jsx +2 -2
  192. package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
  193. package/src/components/theme/Login/Login.jsx +1 -0
  194. package/src/components/theme/Logo/Logo.jsx +2 -1
  195. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
  196. package/src/components/theme/Navigation/NavItem.jsx +4 -2
  197. package/src/components/theme/NotFound/NotFound.jsx +55 -41
  198. package/src/components/theme/PasswordReset/PasswordReset.jsx +7 -4
  199. package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +1 -1
  200. package/src/components/theme/SearchWidget/SearchWidget.jsx +38 -98
  201. package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
  202. package/src/components/theme/View/AlbumView.jsx +9 -1
  203. package/src/components/theme/View/DefaultView.jsx +1 -1
  204. package/src/components/theme/View/EventDatesInfo.jsx +2 -1
  205. package/src/components/theme/View/EventView.jsx +6 -2
  206. package/src/components/theme/View/FileView.jsx +23 -18
  207. package/src/components/theme/View/ImageView.jsx +37 -32
  208. package/src/components/theme/View/LinkView.jsx +53 -78
  209. package/src/components/theme/View/ListingView.jsx +33 -27
  210. package/src/components/theme/View/NewsItemView.jsx +10 -5
  211. package/src/components/theme/View/RenderBlocks.jsx +56 -21
  212. package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
  213. package/src/components/theme/View/SummaryView.jsx +47 -38
  214. package/src/components/theme/View/TabularView.jsx +59 -53
  215. package/src/components/theme/Widgets/DateWidget.jsx +2 -1
  216. package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
  217. package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
  218. package/src/config/Blocks.jsx +44 -0
  219. package/src/config/ControlPanels.js +2 -0
  220. package/src/config/NonContentRoutes.jsx +1 -0
  221. package/src/config/RichTextEditor/Blocks.jsx +2 -2
  222. package/src/config/RichTextEditor/FromHTML.jsx +2 -2
  223. package/src/config/RichTextEditor/Styles.jsx +1 -1
  224. package/src/config/Widgets.jsx +2 -0
  225. package/src/config/index.js +24 -0
  226. package/src/config/server.js +2 -0
  227. package/src/constants/ActionTypes.js +4 -0
  228. package/src/constants/Indexes.js +3 -1
  229. package/src/constants/Languages.js +8 -4
  230. package/src/express-middleware/devproxy.js +1 -1
  231. package/src/express-middleware/files.js +3 -3
  232. package/src/express-middleware/images.js +4 -4
  233. package/src/express-middleware/ok.js +16 -0
  234. package/src/express-middleware/robotstxt.js +1 -1
  235. package/src/express-middleware/sitemap.js +37 -5
  236. package/src/express-middleware/static.js +3 -3
  237. package/src/helpers/Api/Api.js +1 -1
  238. package/src/helpers/Blocks/Blocks.js +48 -0
  239. package/src/helpers/Blocks/Blocks.test.js +79 -0
  240. package/src/helpers/Extensions/index.js +2 -1
  241. package/src/helpers/Extensions/withBlockSchemaEnhancer.js +15 -11
  242. package/src/helpers/Extensions/withBlockSchemaEnhancer.test.js +145 -0
  243. package/src/helpers/FormValidation/FormValidation.js +40 -2
  244. package/src/helpers/FormValidation/FormValidation.test.js +73 -0
  245. package/src/helpers/Html/Html.jsx +3 -1
  246. package/src/helpers/Html/Html.test.jsx +5 -0
  247. package/src/helpers/MessageLabels/MessageLabels.js +80 -0
  248. package/src/helpers/Robots/Robots.js +24 -6
  249. package/src/helpers/ScrollToTop/ScrollToTop.jsx +5 -3
  250. package/src/helpers/Sitemap/Sitemap.js +44 -2
  251. package/src/helpers/Url/Url.js +27 -6
  252. package/src/helpers/Url/Url.test.js +26 -0
  253. package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
  254. package/src/helpers/Utils/Utils.js +63 -13
  255. package/src/helpers/Utils/Utils.test.js +4 -4
  256. package/src/helpers/Utils/usePagination.js +67 -14
  257. package/src/helpers/Utils/usePagination.test.js +115 -0
  258. package/src/helpers/index.js +20 -10
  259. package/src/hooks/client/useClient.js +11 -0
  260. package/src/hooks/clipboard/useClipboard.js +26 -0
  261. package/src/hooks/index.js +2 -0
  262. package/src/icons/grid-block.svg +11 -0
  263. package/src/middleware/Api.test.js +54 -0
  264. package/src/middleware/api.js +24 -6
  265. package/src/middleware/index.js +2 -2
  266. package/src/reducers/actions/actions.js +8 -6
  267. package/src/reducers/actions/actions.test.js +70 -0
  268. package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
  269. package/src/reducers/index.js +2 -0
  270. package/src/reducers/navigation/navigation.js +1 -1
  271. package/src/reducers/relations/relations.js +173 -0
  272. package/src/reducers/types/types.js +1 -1
  273. package/src/routes.js +14 -0
  274. package/src/server.jsx +28 -23
  275. package/src/start-server.js +2 -2
  276. package/test-setup-config.js +2 -0
  277. package/theme/themes/pastanaga/extras/blocks.less +3 -1
  278. package/theme/themes/pastanaga/extras/contents.less +1 -0
  279. package/theme/themes/pastanaga/extras/grid.less +426 -0
  280. package/theme/themes/pastanaga/extras/main.less +3 -1
  281. package/theme/themes/pastanaga/extras/search.less +6 -0
  282. package/theme/themes/pastanaga/extras/sidebar.less +4 -0
  283. package/theme/themes/pastanaga/extras/toc.less +29 -0
  284. package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
  285. package/.changelog.draft +0 -31
  286. package/.editorconfig +0 -36
  287. package/.storybook/main.js +0 -127
  288. package/.storybook/manager.js +0 -15
  289. package/.storybook/preview.js +0 -21
  290. package/.storybook/static/previewImage.svg +0 -48
  291. package/.yarnrc.yml +0 -5
  292. package/jsdoc.json +0 -16
  293. package/netlify.toml +0 -5
  294. package/pyvenv.cfg +0 -3
  295. package/share/man/man1/ttx.1 +0 -225
  296. package/src/components/theme/Header/Header.md +0 -27
  297. package/towncrier.toml +0 -33
@@ -0,0 +1,115 @@
1
+ import { renderHook } from '@testing-library/react-hooks';
2
+ import { usePagination } from './usePagination';
3
+ import * as redux from 'react-redux';
4
+ import routeData from 'react-router';
5
+ import { slugify } from '@plone/volto/helpers/Utils/Utils';
6
+
7
+ const searchBlockId = '545b33de-92cf-4747-969d-68851837b317';
8
+ const searchBlockId2 = '454b33de-92cf-4747-969d-68851837b713';
9
+ const searchBlock = {
10
+ '@type': 'search',
11
+ query: {
12
+ b_size: '4',
13
+ query: [
14
+ {
15
+ i: 'path',
16
+ o: 'plone.app.querystring.operation.string.relativePath',
17
+ v: '',
18
+ },
19
+ ],
20
+ sort_order: 'ascending',
21
+ },
22
+ showSearchInput: true,
23
+ showTotalResults: true,
24
+ };
25
+ let state = {
26
+ content: {
27
+ data: {
28
+ blocks: {
29
+ [searchBlockId]: searchBlock,
30
+ },
31
+ blocks_layout: {
32
+ items: [searchBlockId],
33
+ },
34
+ },
35
+ },
36
+ };
37
+
38
+ let mockUseLocationValue = {
39
+ pathname: '/testroute',
40
+ search: '',
41
+ };
42
+
43
+ const setUp = (searchParam, numberOfSearches) => {
44
+ mockUseLocationValue.search = searchParam;
45
+ if (numberOfSearches > 1) {
46
+ state.content.data.blocks[searchBlockId2] = searchBlock;
47
+ state.content.data.blocks_layout.items.push(searchBlockId2);
48
+ }
49
+ return renderHook(({ id, defaultPage }) => usePagination(id, defaultPage), {
50
+ initialProps: {
51
+ id: searchBlockId,
52
+ defaultPage: 1,
53
+ },
54
+ });
55
+ };
56
+
57
+ describe(`Tests for usePagination, for the block ${searchBlockId}`, () => {
58
+ const useLocation = jest.spyOn(routeData, 'useLocation');
59
+ const useHistory = jest.spyOn(routeData, 'useHistory');
60
+ const useSelector = jest.spyOn(redux, 'useSelector');
61
+ beforeEach(() => {
62
+ useLocation.mockReturnValue(mockUseLocationValue);
63
+ useHistory.mockReturnValue({ replace: jest.fn() });
64
+ useSelector.mockImplementation((cb) => cb(state));
65
+ });
66
+
67
+ it('1 paginated block with id and defaultPage 1 - shoud be 1', () => {
68
+ const { result } = setUp();
69
+ expect(result.current.currentPage).toBe(1);
70
+ });
71
+
72
+ it('1 paginated block without params - shoud be 1', () => {
73
+ const { result } = setUp();
74
+ expect(result.current.currentPage).toBe(1);
75
+ });
76
+
77
+ const param1 = '?page=2';
78
+ it(`1 paginated block with params: ${param1} - shoud be 2`, () => {
79
+ const { result } = setUp(param1);
80
+ expect(result.current.currentPage).toBe(2);
81
+ });
82
+
83
+ const param2 = `?${slugify(`page-${searchBlockId}`)}=2`;
84
+ it(`2 paginated blocks with current block in the params: ${param2} - shoud be 2`, () => {
85
+ const { result } = setUp(param2, 2);
86
+ expect(result.current.currentPage).toBe(2);
87
+ });
88
+
89
+ const param3 = `?${slugify(`page-${searchBlockId2}`)}=2`;
90
+ it(`2 paginated blocks with the other block in the params: ${param3} - shoud be 1`, () => {
91
+ const { result } = setUp(param3, 2);
92
+ expect(result.current.currentPage).toBe(1);
93
+ });
94
+
95
+ const param4 = `?${slugify(`page-${searchBlockId}`)}=2&${slugify(
96
+ `page-${searchBlockId2}`,
97
+ )}=1`;
98
+ it(`2 paginated blocks with both blocks in the params, current 2: ${param4} - shoud be 2`, () => {
99
+ const { result } = setUp(param4, 2);
100
+ expect(result.current.currentPage).toBe(2);
101
+ });
102
+
103
+ const param5 = `?${slugify(`page-${searchBlockId}`)}=1&${slugify(
104
+ `page-${searchBlockId2}`,
105
+ )}=2`;
106
+ it(`2 paginated blocks with both blocks in the params, current 1: ${param5} - shoud be 1`, () => {
107
+ const { result } = setUp(param5, 2);
108
+ expect(result.current.currentPage).toBe(1);
109
+ });
110
+
111
+ it(`2 paginated blocks with wrong page param: ${param1} - shoud be 1`, () => {
112
+ const { result } = setUp(param1, 2);
113
+ expect(result.current.currentPage).toBe(1);
114
+ });
115
+ });
@@ -5,9 +5,9 @@
5
5
  */
6
6
 
7
7
  // export { injectLazyLibs } from './Loadable/Loadable';
8
- export Api from '@plone/volto/helpers/Api/Api';
8
+ export { default as Api } from '@plone/volto/helpers/Api/Api';
9
9
  export { getAPIResourceWithAuth } from '@plone/volto/helpers/Api/APIResourceWithAuth';
10
- export Html from '@plone/volto/helpers/Html/Html';
10
+ export { default as Html } from '@plone/volto/helpers/Html/Html';
11
11
  export {
12
12
  getAuthToken,
13
13
  persistAuthToken,
@@ -54,12 +54,14 @@ export {
54
54
  previousBlockId,
55
55
  applyBlockDefaults,
56
56
  applySchemaDefaults,
57
+ blocksFormGenerator,
57
58
  buildStyleClassNamesFromData,
58
59
  buildStyleClassNamesExtenders,
59
60
  getPreviousNextBlock,
61
+ findBlocks,
60
62
  } from '@plone/volto/helpers/Blocks/Blocks';
61
- export BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
62
- export ScrollToTop from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
63
+ export { default as BodyClass } from '@plone/volto/helpers/BodyClass/BodyClass';
64
+ export { default as ScrollToTop } from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
63
65
  export {
64
66
  getBoolean,
65
67
  getVocabName,
@@ -69,9 +71,10 @@ export {
69
71
  getFieldsVocabulary,
70
72
  } from '@plone/volto/helpers/Vocabularies/Vocabularies';
71
73
 
72
- export langmap from './LanguageMap/LanguageMap';
73
- export Helmet from './Helmet/Helmet';
74
- export FormValidation from './FormValidation/FormValidation';
74
+ export { default as langmap } from './LanguageMap/LanguageMap';
75
+ export { default as Helmet } from './Helmet/Helmet';
76
+ export { default as FormValidation } from './FormValidation/FormValidation';
77
+ export { validateFileUploadSize } from './FormValidation/FormValidation';
75
78
  export {
76
79
  difference,
77
80
  getColor,
@@ -80,11 +83,18 @@ export {
80
83
  applyConfig,
81
84
  withServerErrorCode,
82
85
  parseDateTime,
83
- normalizeLanguageName,
84
- toLangUnderscoreRegion,
86
+ toGettextLang,
87
+ normalizeLanguageName, // old name for toGettextLang
88
+ toReactIntlLang,
89
+ toLangUnderscoreRegion, // old name for toReactIntlLang
90
+ toBackendLang,
85
91
  hasApiExpander,
86
92
  replaceItemOfArray,
87
93
  cloneDeepSchema,
94
+ arrayRange,
95
+ reorderArray,
96
+ isInteractiveElement,
97
+ slugify,
88
98
  } from '@plone/volto/helpers/Utils/Utils';
89
99
  export { messages } from './MessageLabels/MessageLabels';
90
100
  export {
@@ -104,7 +114,7 @@ export { useDetectClickOutside } from './Utils/useDetectClickOutside';
104
114
  export { useEvent } from './Utils/useEvent';
105
115
  export { usePrevious } from './Utils/usePrevious';
106
116
  export { usePagination } from './Utils/usePagination';
107
- export useUndoManager from './UndoManager/useUndoManager';
117
+ export { default as useUndoManager } from './UndoManager/useUndoManager';
108
118
  export { getCookieOptions } from './Cookies/cookies';
109
119
  export { getWidgetView } from './Widget/widget';
110
120
  export {
@@ -0,0 +1,11 @@
1
+ //useClient hook to replace repetitive delcaration in the components
2
+ import { useEffect, useState } from 'react';
3
+
4
+ export function useClient() {
5
+ const [isClient, setisClient] = useState(false);
6
+ useEffect(() => {
7
+ setisClient(true);
8
+ }, []);
9
+
10
+ return isClient;
11
+ }
@@ -0,0 +1,26 @@
1
+ import { useState, useRef, useEffect, useCallback } from 'react';
2
+
3
+ export default function useClipboard(clipboardText = '') {
4
+ const stringToCopy = useRef(clipboardText);
5
+ const [copied, setCopied] = useState(false);
6
+
7
+ //synchronous: window.clipboardData.setData(options.format || "text", text);
8
+ const copyToClipboard = async (text) => {
9
+ if ('clipboard' in navigator) {
10
+ return await navigator.clipboard.writeText(text);
11
+ } else {
12
+ return document.execCommand('copy', true, text);
13
+ }
14
+ };
15
+
16
+ const copyAction = useCallback(() => {
17
+ const copiedString = copyToClipboard(stringToCopy.current);
18
+ setCopied(copiedString);
19
+ }, [stringToCopy]);
20
+
21
+ useEffect(() => {
22
+ stringToCopy.current = clipboardText;
23
+ }, [clipboardText]);
24
+
25
+ return [copied, copyAction, setCopied];
26
+ }
@@ -0,0 +1,2 @@
1
+ export useClipboard from '@plone/volto/hooks/clipboard/useClipboard';
2
+ export { useClient } from '@plone/volto/hooks/client/useClient';
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
2
+ <g fill="none" fill-rule="evenodd">
3
+ <rect width="96" height="96" fill="currentcolor" rx="3"/>
4
+ <g fill="#FFF" opacity=".9" transform="translate(8 22)">
5
+ <rect width="18" height="53" x="42"/>
6
+ <rect width="18" height="53" x="63"/>
7
+ <rect width="18" height="53"/>
8
+ <rect width="18" height="53" x="21"/>
9
+ </g>
10
+ </g>
11
+ </svg>
@@ -53,6 +53,60 @@ describe('api middleware helpers', () => {
53
53
  );
54
54
  expect(result).toEqual('/de/mypage/@navigation?expand.navigation.depth=3');
55
55
  });
56
+ it('addExpandersToPath - Path matching, preserve query', () => {
57
+ config.settings.apiExpanders = [
58
+ {
59
+ match: '/de/mypage',
60
+ GET_CONTENT: ['mycustomexpander', 'mycustomexpander2'],
61
+ },
62
+ ];
63
+
64
+ const result = addExpandersToPath(
65
+ '/de/mypage/@navigation?expand.navigation.depth=3',
66
+ GET_CONTENT,
67
+ );
68
+ expect(result).toEqual(
69
+ '/de/mypage/@navigation?expand=mycustomexpander,mycustomexpander2&expand.navigation.depth=3',
70
+ );
71
+ });
72
+ it('addExpandersToPath - Path matching, preserve query with multiple', () => {
73
+ config.settings.apiExpanders = [
74
+ {
75
+ match: '/de/mypage',
76
+ GET_CONTENT: ['mycustomexpander', 'mycustomexpander2'],
77
+ },
78
+ ];
79
+
80
+ const result = addExpandersToPath(
81
+ '/de/mypage/@navigation?expand.navigation.depth=3&expand.other=2',
82
+ GET_CONTENT,
83
+ );
84
+ expect(result).toEqual(
85
+ '/de/mypage/@navigation?expand=mycustomexpander,mycustomexpander2&expand.navigation.depth=3&expand.other=2',
86
+ );
87
+ });
88
+ it('addExpandersToPath - Path not matching, preserve encoded query', () => {
89
+ config.settings.apiExpanders = [
90
+ {
91
+ match: '/de/otherpath',
92
+ GET_CONTENT: ['mycustomexpander'],
93
+ },
94
+ ];
95
+
96
+ const result = addExpandersToPath('/de/mypage?query=a%26b', GET_CONTENT);
97
+ expect(result).toEqual('/de/mypage?query=a%26b');
98
+ });
99
+ it('addExpandersToPath - Path matching, preserve encoded query', () => {
100
+ config.settings.apiExpanders = [
101
+ {
102
+ match: '/de/mypage',
103
+ GET_CONTENT: ['mycustomexpander'],
104
+ },
105
+ ];
106
+
107
+ const result = addExpandersToPath('/de/mypage?query=a%26b', GET_CONTENT);
108
+ expect(result).toEqual('/de/mypage?expand=mycustomexpander&query=a%26b');
109
+ });
56
110
  it('addExpandersToPath - Two custom expanders from settings', () => {
57
111
  config.settings.apiExpanders = [
58
112
  {
@@ -18,7 +18,11 @@ import {
18
18
  SET_APIERROR,
19
19
  } from '@plone/volto/constants/ActionTypes';
20
20
  import { changeLanguage } from '@plone/volto/actions';
21
- import { normalizeLanguageName, getCookieOptions } from '@plone/volto/helpers';
21
+ import {
22
+ toGettextLang,
23
+ toReactIntlLang,
24
+ getCookieOptions,
25
+ } from '@plone/volto/helpers';
22
26
  let socket = null;
23
27
 
24
28
  /**
@@ -43,7 +47,7 @@ export function addExpandersToPath(path, type, isAnonymous) {
43
47
  const {
44
48
  url,
45
49
  query: { expand, ...query },
46
- } = qs.parseUrl(path);
50
+ } = qs.parseUrl(path, { decode: false });
47
51
 
48
52
  const expandersFromConfig = apiExpanders
49
53
  .filter((expand) => matchPath(url, expand.match) && expand[type])
@@ -63,7 +67,15 @@ export function addExpandersToPath(path, type, isAnonymous) {
63
67
 
64
68
  const querystringFromConfig = apiExpanders
65
69
  .filter((expand) => matchPath(url, expand.match) && expand[type])
66
- .reduce((acc, expand) => ({ ...acc, ...expand?.['querystring'] }), {});
70
+ .reduce((acc, expand) => {
71
+ let querystring = expand?.['querystring'];
72
+ // The querystring accepts being a function to be able to take other
73
+ // config parameters
74
+ if (typeof querystring === 'function') {
75
+ querystring = querystring(config);
76
+ }
77
+ return { ...acc, ...querystring };
78
+ }, {});
67
79
 
68
80
  const queryMerge = { ...query, ...querystringFromConfig };
69
81
 
@@ -118,7 +130,13 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
118
130
  ) => {
119
131
  const { settings } = config;
120
132
 
121
- const isAnonymous = !getState().userSession.token;
133
+ const token = getState().userSession.token;
134
+ let isAnonymous = true;
135
+ if (token) {
136
+ const tokenExpiration = jwtDecode(token).exp;
137
+ const currentTime = new Date().getTime() / 1000;
138
+ isAnonymous = !token || currentTime > tokenExpiration;
139
+ }
122
140
 
123
141
  if (typeof action === 'function') {
124
142
  return action(dispatch, getState);
@@ -205,11 +223,11 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
205
223
  const lang = result?.language?.token;
206
224
  if (
207
225
  lang &&
208
- getState().intl.language !== lang &&
226
+ getState().intl.locale !== toReactIntlLang(lang) &&
209
227
  !subrequest &&
210
228
  config.settings.supportedLanguages.includes(lang)
211
229
  ) {
212
- const langFileName = normalizeLanguageName(lang);
230
+ const langFileName = toGettextLang(lang);
213
231
  import('~/../locales/' + langFileName + '.json').then((locale) => {
214
232
  dispatch(changeLanguage(lang, locale.default));
215
233
  });
@@ -4,8 +4,8 @@
4
4
  * @example import { api } from 'middleware';
5
5
  */
6
6
 
7
- export api from '@plone/volto/middleware/api';
8
- export blacklistRoutes from './blacklistRoutes';
7
+ export { default as api } from '@plone/volto/middleware/api';
8
+ export { default as blacklistRoutes } from './blacklistRoutes';
9
9
  export {
10
10
  protectLoadStart,
11
11
  protectLoadEnd,
@@ -46,7 +46,7 @@ export default function actions(state = initialState, action = {}) {
46
46
  'actions',
47
47
  getBaseUrl(flattenToAppURL(action.result['@id'])),
48
48
  );
49
- if (hasExpander) {
49
+ if (hasExpander && !action.subrequest) {
50
50
  return {
51
51
  ...state,
52
52
  error: null,
@@ -57,11 +57,13 @@ export default function actions(state = initialState, action = {}) {
57
57
  }
58
58
  return state;
59
59
  case `${LIST_ACTIONS}_SUCCESS`:
60
- hasExpander = hasApiExpander(
61
- 'actions',
62
- getBaseUrl(flattenToAppURL(action.result['@id'])),
63
- );
64
- if (!hasExpander) {
60
+ // Even if the expander is set or not, if the LIST_ACTIONS is
61
+ // called, we want it to store the data if the actions data is
62
+ // not set in the expander data (['@components']) but in the "normal"
63
+ // action result (we look for the object property returned by the endpoint)
64
+ // Unfortunately, this endpoint returns all the actions in a plain object
65
+ // with no structure :(
66
+ if (action.result.object) {
65
67
  return {
66
68
  ...state,
67
69
  error: null,
@@ -207,4 +207,74 @@ describe('Actions reducer - (ACTIONS)GET_CONTENT', () => {
207
207
  loading: false,
208
208
  });
209
209
  });
210
+
211
+ it('should handle (ACTIONS)LIST_ACTIONS (standalone with apiExpander enabled)', () => {
212
+ expect(
213
+ actions(undefined, {
214
+ type: `${LIST_ACTIONS}_SUCCESS`,
215
+ result: {
216
+ object: [],
217
+ object_buttons: [],
218
+ site_actions: [],
219
+ user: [
220
+ {
221
+ icon: '',
222
+ id: 'preferences',
223
+ title: 'Preferences',
224
+ },
225
+ {
226
+ icon: '',
227
+ id: 'dashboard',
228
+ title: 'Dashboard',
229
+ },
230
+ {
231
+ icon: '',
232
+ id: 'plone_setup',
233
+ title: 'Site Setup',
234
+ },
235
+ {
236
+ icon: '',
237
+ id: 'logout',
238
+ title: 'Log out',
239
+ },
240
+ ],
241
+ document_actions: [],
242
+ portal_tabs: [],
243
+ },
244
+ }),
245
+ ).toEqual({
246
+ error: null,
247
+ actions: {
248
+ object: [],
249
+ object_buttons: [],
250
+ site_actions: [],
251
+ user: [
252
+ {
253
+ icon: '',
254
+ id: 'preferences',
255
+ title: 'Preferences',
256
+ },
257
+ {
258
+ icon: '',
259
+ id: 'dashboard',
260
+ title: 'Dashboard',
261
+ },
262
+ {
263
+ icon: '',
264
+ id: 'plone_setup',
265
+ title: 'Site Setup',
266
+ },
267
+ {
268
+ icon: '',
269
+ id: 'logout',
270
+ title: 'Log out',
271
+ },
272
+ ],
273
+ document_actions: [],
274
+ portal_tabs: [],
275
+ },
276
+ loaded: true,
277
+ loading: false,
278
+ });
279
+ });
210
280
  });
@@ -45,7 +45,7 @@ export default function breadcrumbs(state = initialState, action = {}) {
45
45
  'breadcrumbs',
46
46
  getBaseUrl(flattenToAppURL(action.result['@id'])),
47
47
  );
48
- if (hasExpander) {
48
+ if (hasExpander && !action.subrequest) {
49
49
  return {
50
50
  ...state,
51
51
  error: null,
@@ -25,6 +25,7 @@ import messages from '@plone/volto/reducers/messages/messages';
25
25
  import navigation from '@plone/volto/reducers/navigation/navigation';
26
26
  import querystring from '@plone/volto/reducers/querystring/querystring';
27
27
  import querystringsearch from '@plone/volto/reducers/querystringsearch/querystringsearch';
28
+ import relations from '@plone/volto/reducers/relations/relations';
28
29
  import roles from '@plone/volto/reducers/roles/roles';
29
30
  import rules from '@plone/volto/reducers/rules/rules';
30
31
  import controlpanelrule from '@plone/volto/reducers/controlPanelRule/controlPanelRule';
@@ -80,6 +81,7 @@ const reducers = {
80
81
  navigation,
81
82
  querystring,
82
83
  querystringsearch,
84
+ relations,
83
85
  roles,
84
86
  rules,
85
87
  controlpanelrule,
@@ -60,7 +60,7 @@ export default function navigation(state = initialState, action = {}) {
60
60
  'navigation',
61
61
  getBaseUrl(flattenToAppURL(action.result['@id'])),
62
62
  );
63
- if (hasExpander) {
63
+ if (hasExpander && !action.subrequest) {
64
64
  return {
65
65
  ...state,
66
66
  error: null,