@plone/volto 18.0.0-alpha.10 → 18.0.0-alpha.12

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 (31) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/cypress/support/commands.js +51 -3
  3. package/package.json +4 -4
  4. package/razzle.config.js +14 -0
  5. package/src/actions/form/form.js +19 -0
  6. package/src/actions/form/form.test.js +14 -0
  7. package/src/actions/index.js +7 -1
  8. package/src/actions/sidebar/sidebar.js +45 -1
  9. package/src/actions/sidebar/sidebar.test.js +42 -2
  10. package/src/components/manage/Add/Add.jsx +1 -0
  11. package/src/components/manage/Blocks/Listing/getAsyncData.js +23 -8
  12. package/src/components/manage/Edit/Edit.jsx +1 -0
  13. package/src/components/manage/Form/Form.jsx +207 -76
  14. package/src/components/manage/Multilingual/TranslationObject.jsx +0 -1
  15. package/src/components/theme/App/App.jsx +1 -0
  16. package/src/components/theme/AppExtras/AppExtras.jsx +2 -0
  17. package/src/components/theme/AppExtras/AppExtras.test.jsx +20 -0
  18. package/src/constants/ActionTypes.js +4 -0
  19. package/src/reducers/form/form.js +15 -3
  20. package/src/reducers/form/form.test.js +13 -1
  21. package/src/reducers/sidebar/sidebar.js +26 -1
  22. package/src/reducers/sidebar/sidebar.test.js +50 -1
  23. package/theme/themes/default/elements/step.overrides +2 -2
  24. package/theme/themes/pastanaga/elements/step.overrides +1 -1
  25. package/types/actions/form/form.d.ts +7 -0
  26. package/types/actions/form/form.test.d.ts +1 -0
  27. package/types/actions/index.d.ts +2 -1
  28. package/types/actions/sidebar/sidebar.d.ts +21 -0
  29. package/types/components/manage/Blocks/Listing/getAsyncData.d.ts +1 -7
  30. package/types/constants/ActionTypes.d.ts +4 -0
  31. package/types/reducers/form/form.d.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -17,6 +17,43 @@ myst:
17
17
 
18
18
  <!-- towncrier release notes start -->
19
19
 
20
+ ## 18.0.0-alpha.12 (2024-02-21)
21
+
22
+ ### Feature
23
+
24
+ - Add accordion to metadata form. @robgietema [#5760](https://github.com/plone/volto/issues/5760)
25
+
26
+ ## 18.0.0-alpha.11 (2024-02-18)
27
+
28
+ ### Breaking
29
+
30
+ - Remove the isDisabled from all fields in the left side form of the babel view, make them read only instead @sneridagh [#5762](https://github.com/plone/volto/issues/5762)
31
+
32
+ ### Feature
33
+
34
+ - Added the `ignore` property to allow exceptions to rules that are applied to all routes. @dobri1408 [#5621](https://github.com/plone/volto/issues/5621)
35
+ - Add global form state. @robgietema [#5721](https://github.com/plone/volto/issues/5721)
36
+
37
+ ### Bugfix
38
+
39
+ - Fixed listing SSR rendering by sending `subrequestId` instead of `id` only within `getAsyncData`, similar to calling `getQueryStringResults` directly. @ichim-david [#5688](https://github.com/plone/volto/issues/5688)
40
+ - Enhanced Makefile paths to address whitespace compatibility issues. @Vivek-04022001 [#5715](https://github.com/plone/volto/issues/5715)
41
+ - Fix console logging in acceptance server Makefile commands. @davisagli [#5748](https://github.com/plone/volto/issues/5748)
42
+ - Add extra wait calls to listing block tests to avoid sporadic failures. @ichim-david [#5753](https://github.com/plone/volto/issues/5753)
43
+ - Add @plone/components as external library.
44
+ Make the Terser plugin accept ESNext features.
45
+ Fix inline `svg` elements in LESS files. @sneridagh [#5766](https://github.com/plone/volto/issues/5766)
46
+
47
+ ### Documentation
48
+
49
+ - Overhaul environment variables documentation. @stevepiercy [#4581](https://github.com/plone/volto/issues/4581)
50
+ - Reorganize `README.md`, merging content into authoritative locations. Add `awesome_bot` to check links in all READMEs. @stevepiercy [#5437](https://github.com/plone/volto/issues/5437)
51
+ - Replace outdated diff with a link to current file. @stevepiercy [#5703](https://github.com/plone/volto/issues/5703)
52
+ - Document when the 'links and references' view was added. @davisagli [#5756](https://github.com/plone/volto/issues/5756)
53
+ - Update links to Redux and React developer extensions for Chrome. @stevepiercy [#5757](https://github.com/plone/volto/issues/5757)
54
+ - Chromewebstore recently changed its URL and has "too many redirects", so it needs to be excluded from linkcheck. @stevepiercy [#5761](https://github.com/plone/volto/issues/5761)
55
+ - Add Git as a pre-requisite. @stevepiercy [#5769](https://github.com/plone/volto/issues/5769)
56
+
20
57
  ## 18.0.0-alpha.10 (2024-02-02)
21
58
 
22
59
  ### Feature
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  import { getIfExists } from '../helpers';
2
3
  import { ploneAuth } from './constants';
3
4
 
@@ -39,6 +40,30 @@ Cypress.Commands.add('isInViewport', (element) => {
39
40
  });
40
41
  });
41
42
 
43
+ // --- isInHTML ----------------------------------------------------------
44
+ Cypress.Commands.add('isInHTML', ({ parent = 'body', content }) => {
45
+ cy.url().then((currentUrl) => {
46
+ // sometimes the cy command is called when the url is still at content/edit
47
+ // we want to query the html markup of the content, not the edit form
48
+ const url =
49
+ currentUrl.indexOf('/edit') !== -1
50
+ ? currentUrl.split('/edit')[0]
51
+ : currentUrl;
52
+ cy.request({
53
+ method: 'GET',
54
+ url: url,
55
+ }).then((response) => {
56
+ const html = Cypress.$(response.body);
57
+ if (content.startsWith('.') || content.startsWith('#')) {
58
+ return expect(html.find(parent)).to.have.descendants(content);
59
+ } else {
60
+ // check if parent contains the content text string in its HTML output
61
+ return expect(html.find(parent)).to.contain(content);
62
+ }
63
+ });
64
+ });
65
+ });
66
+
42
67
  // --- AUTOLOGIN -------------------------------------------------------------
43
68
  Cypress.Commands.add('autologin', (usr, pass) => {
44
69
  let api_url, user, password;
@@ -695,7 +720,7 @@ Cypress.Commands.add('clearSlate', (selector) => {
695
720
  return cy
696
721
  .get(selector)
697
722
  .focus()
698
- .click()
723
+ .click({ force: true }) // fix sporadic failure this element is currently animating
699
724
  .wait(1000)
700
725
  .type('{selectAll}')
701
726
  .wait(1000)
@@ -819,7 +844,6 @@ function getTextNode(el, match) {
819
844
  return walk.nextNode();
820
845
  }
821
846
 
822
- const nodes = [];
823
847
  let node;
824
848
  while ((node = walk.nextNode())) {
825
849
  if (node.wholeText.includes(match)) {
@@ -848,7 +872,7 @@ function createHtmlPasteEvent(htmlContent) {
848
872
 
849
873
  Cypress.Commands.add('addNewBlock', (blockName, createNewSlate = false) => {
850
874
  let block;
851
- block = cy.getSlate(createNewSlate).type(`/${blockName}{enter}`);
875
+ block = cy.getSlate(createNewSlate).click().type(`/${blockName}{enter}`);
852
876
  return block;
853
877
  });
854
878
 
@@ -902,9 +926,33 @@ Cypress.Commands.add('configureListingWith', (contentType) => {
902
926
  '.querystring-widget .fields:first-of-type > .field .react-select__menu .react-select__option',
903
927
  )
904
928
  .contains(contentType)
929
+
905
930
  .click();
906
931
  });
907
932
 
933
+ Cypress.Commands.add(
934
+ 'addLocationQuerystring',
935
+ (option = 'Relative path', value) => {
936
+ cy.get('.block-editor-listing').click();
937
+ cy.get('.querystring-widget .fields').contains('Add criteria').click();
938
+ cy.get('.querystring-widget .react-select__menu .react-select__option')
939
+ .contains('Location')
940
+ .click();
941
+
942
+ cy.get('.querystring-widget .fields').contains('Absolute path').click();
943
+ cy.get(
944
+ '.querystring-widget .fields .react-select__menu .react-select__option',
945
+ )
946
+ .contains(option)
947
+ .click();
948
+ if (value) {
949
+ cy.get('.querystring-widget .fields .input')
950
+ .click()
951
+ .type(`${value}{enter}`);
952
+ }
953
+ },
954
+ );
955
+
908
956
  Cypress.Commands.add('queryCounter', (path, steps, number = 1) => {
909
957
  cy.intercept(path, cy.spy().as('counterName'));
910
958
  steps.forEach((element) => {
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  }
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "18.0.0-alpha.10",
12
+ "version": "18.0.0-alpha.12",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git@github.com:plone/volto.git"
@@ -312,7 +312,7 @@
312
312
  "webpack-node-externals": "3.0.0",
313
313
  "xmlrpc": "1.3.2",
314
314
  "yarnhook": "0.5.1",
315
- "@plone/registry": "1.2.2",
315
+ "@plone/registry": "1.3.1",
316
316
  "@plone/scripts": "3.3.2",
317
317
  "@plone/volto-slate": "18.0.0-alpha.6"
318
318
  },
@@ -362,8 +362,8 @@
362
362
  "use-trace-update": "1.3.2",
363
363
  "wait-on": "6.0.0",
364
364
  "why": "0.6.2",
365
- "@plone/volto-coresandbox": "1.0.0",
366
- "@plone/types": "1.0.0-alpha.3"
365
+ "@plone/types": "1.0.0-alpha.3",
366
+ "@plone/volto-coresandbox": "1.0.0"
367
367
  },
368
368
  "volta": {
369
369
  "node": "20.9.0"
package/razzle.config.js CHANGED
@@ -166,6 +166,19 @@ const defaultModify = ({
166
166
  }),
167
167
  );
168
168
 
169
+ // Make the TerserPlugin accept ESNext features, since we are in 2024
170
+ // If this is not true, libraries already compiled for using only ESNext features
171
+ // won't work (eg. using a chaining operator)
172
+ config.optimization = Object.assign({}, config.optimization, {
173
+ minimizer: [
174
+ new TerserPlugin({
175
+ terserOptions: {
176
+ parse: { ecma: 'ESNext' },
177
+ },
178
+ }),
179
+ ],
180
+ });
181
+
169
182
  // Razzle sets some of its basic env vars in the default config injecting them (for
170
183
  // the client use, mainly) in a `DefinePlugin` instance. However, this also ends in
171
184
  // the server build, removing the ability of the server node process to read from
@@ -328,6 +341,7 @@ const defaultModify = ({
328
341
  // Add support for addons to include externals (ie. node_modules npm published packages)
329
342
  ...addonsAsExternals,
330
343
  /^@plone\/volto/,
344
+ /^@plone\/components/,
331
345
  ].filter(Boolean),
332
346
  }),
333
347
  ]
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Form actions.
3
+ * @module actions/form/form
4
+ */
5
+
6
+ import { SET_FORM_DATA } from '@plone/volto/constants/ActionTypes';
7
+
8
+ /**
9
+ * Set form data function.
10
+ * @function setFormData
11
+ * @param {Object} data New form data.
12
+ * @returns {Object} Set sidebar action.
13
+ */
14
+ export function setFormData(data) {
15
+ return {
16
+ type: SET_FORM_DATA,
17
+ data,
18
+ };
19
+ }
@@ -0,0 +1,14 @@
1
+ import { setFormData } from './form';
2
+ import { SET_FORM_DATA } from '@plone/volto/constants/ActionTypes';
3
+
4
+ describe('Form action', () => {
5
+ describe('setFormData', () => {
6
+ it('should create an action to set the form data', () => {
7
+ const data = { foo: 'bar' };
8
+ const action = setFormData(data);
9
+
10
+ expect(action.type).toEqual(SET_FORM_DATA);
11
+ expect(action.data).toEqual(data);
12
+ });
13
+ });
14
+ });
@@ -150,7 +150,13 @@ export {
150
150
  } from '@plone/volto/actions/workflow/workflow';
151
151
  export { getQuerystring } from '@plone/volto/actions/querystring/querystring';
152
152
  export { getQueryStringResults } from '@plone/volto/actions/querystringsearch/querystringsearch';
153
- export { setSidebarTab } from '@plone/volto/actions/sidebar/sidebar';
153
+ export {
154
+ setMetadataFieldsets,
155
+ setMetadataFocus,
156
+ resetMetadataFocus,
157
+ setSidebarTab,
158
+ } from '@plone/volto/actions/sidebar/sidebar';
159
+ export { setFormData } from '@plone/volto/actions/form/form';
154
160
  export {
155
161
  deleteLinkTranslation,
156
162
  getTranslationLocator,
@@ -3,7 +3,51 @@
3
3
  * @module actions/sidebar/sidebar
4
4
  */
5
5
 
6
- import { SET_SIDEBAR_TAB } from '@plone/volto/constants/ActionTypes';
6
+ import {
7
+ SET_METADATA_FIELDSETS,
8
+ SET_METADATA_FOCUS,
9
+ RESET_METADATA_FOCUS,
10
+ SET_SIDEBAR_TAB,
11
+ } from '@plone/volto/constants/ActionTypes';
12
+
13
+ /**
14
+ * Set metadata fieldsets function.
15
+ * @function setMetadataFieldsets
16
+ * @param {Array} fieldsets New fieldsets.
17
+ * @returns {Object} Set metadata fieldsets action.
18
+ */
19
+ export function setMetadataFieldsets(fieldsets) {
20
+ return {
21
+ type: SET_METADATA_FIELDSETS,
22
+ fieldsets,
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Set metadata focus function.
28
+ * @function setMetadataFocus
29
+ * @param {String} fieldset Fieldset of the field.
30
+ * @param {String} field Field to set focus too.
31
+ * @returns {Object} Set metadata focus action.
32
+ */
33
+ export function setMetadataFocus(fieldset, field) {
34
+ return {
35
+ type: SET_METADATA_FOCUS,
36
+ fieldset,
37
+ field,
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Resets metadata focus function.
43
+ * @function resetMetadataFocus
44
+ * @returns {Object} Set metadata focus action.
45
+ */
46
+ export function resetMetadataFocus() {
47
+ return {
48
+ type: RESET_METADATA_FOCUS,
49
+ };
50
+ }
7
51
 
8
52
  /**
9
53
  * Set sidebar tab function.
@@ -1,7 +1,47 @@
1
- import { setSidebarTab } from './sidebar';
2
- import { SET_SIDEBAR_TAB } from '@plone/volto/constants/ActionTypes';
1
+ import {
2
+ setMetadataFieldsets,
3
+ setMetadataFocus,
4
+ resetMetadataFocus,
5
+ setSidebarTab,
6
+ } from './sidebar';
7
+ import {
8
+ SET_METADATA_FIELDSETS,
9
+ SET_METADATA_FOCUS,
10
+ RESET_METADATA_FOCUS,
11
+ SET_SIDEBAR_TAB,
12
+ } from '@plone/volto/constants/ActionTypes';
3
13
 
4
14
  describe('Sidebar action', () => {
15
+ describe('setMetadataFieldsets', () => {
16
+ it('should create an action to set the metadata fieldsets', () => {
17
+ const fieldsets = ['default'];
18
+ const action = setMetadataFieldsets(fieldsets);
19
+
20
+ expect(action.type).toEqual(SET_METADATA_FIELDSETS);
21
+ expect(action.fieldsets).toEqual(fieldsets);
22
+ });
23
+ });
24
+
25
+ describe('setMetadataFocus', () => {
26
+ it('should create an action to set the metadata focus', () => {
27
+ const fieldset = ['default'];
28
+ const field = ['title'];
29
+ const action = setMetadataFocus(fieldset, field);
30
+
31
+ expect(action.type).toEqual(SET_METADATA_FOCUS);
32
+ expect(action.fieldset).toEqual(fieldset);
33
+ expect(action.field).toEqual(field);
34
+ });
35
+ });
36
+
37
+ describe('resetMetadataFocus', () => {
38
+ it('should create an action to reset the metadata focus', () => {
39
+ const action = resetMetadataFocus();
40
+
41
+ expect(action.type).toEqual(RESET_METADATA_FOCUS);
42
+ });
43
+ });
44
+
5
45
  describe('setSidebarTab', () => {
6
46
  it('should create an action to set the sidebar', () => {
7
47
  const index = 1;
@@ -364,6 +364,7 @@ class Add extends Component {
364
364
  onSelectForm={() => {
365
365
  this.setState({ formSelected: 'addForm' });
366
366
  }}
367
+ global
367
368
  />
368
369
  {this.state.isClient && (
369
370
  <Portal node={document.getElementById('toolbar')}>
@@ -1,15 +1,29 @@
1
1
  import { getQueryStringResults } from '@plone/volto/actions';
2
2
  import { resolveBlockExtensions } from '@plone/volto/helpers';
3
+ import qs from 'query-string';
4
+ import { slugify } from '@plone/volto/helpers/Utils/Utils';
5
+
6
+ const getCurrentPage = (location, id) => {
7
+ const pageQueryParam = qs.parse(location.search);
8
+ switch (Object.keys(pageQueryParam).length) {
9
+ case 0:
10
+ return 1;
11
+ case 1:
12
+ // when there is only one query param, it could be the simple page number or the sluggified block id
13
+ return pageQueryParam['page'] || pageQueryParam[slugify(`page-${id}`)];
14
+ default:
15
+ return pageQueryParam[slugify(`page-${id}`)];
16
+ }
17
+ };
18
+
19
+ export default function getListingBlockAsyncData(props) {
20
+ const { data, path, location, id, dispatch, blocksConfig, content } = props;
3
21
 
4
- export default function getListingBlockAsyncData({
5
- dispatch,
6
- id,
7
- data,
8
- path,
9
- blocksConfig,
10
- }) {
11
22
  const { resolvedExtensions } = resolveBlockExtensions(data, blocksConfig);
12
23
 
24
+ const subrequestID = content?.UID ? `${content?.UID}-${id}` : id;
25
+ const currentPage = getCurrentPage(location, id);
26
+
13
27
  return [
14
28
  dispatch(
15
29
  getQueryStringResults(
@@ -20,7 +34,8 @@ export default function getListingBlockAsyncData({
20
34
  ? { fullobjects: 1 }
21
35
  : { metadata_fields: '_all' }),
22
36
  },
23
- id,
37
+ subrequestID,
38
+ currentPage,
24
39
  ),
25
40
  ),
26
41
  ];
@@ -307,6 +307,7 @@ class Edit extends Component {
307
307
  onSelectForm={() => {
308
308
  this.setState({ formSelected: 'editForm' });
309
309
  }}
310
+ global
310
311
  />
311
312
  );
312
313