@plone/volto 16.32.1 → 16.34.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 (49) hide show
  1. package/.changelog.draft +6 -2
  2. package/.readthedocs.yaml +4 -5
  3. package/.yarn/install-state.gz +0 -0
  4. package/CHANGELOG.md +31 -0
  5. package/locales/ca/LC_MESSAGES/volto.po +55 -13
  6. package/locales/ca.json +1 -1
  7. package/locales/de/LC_MESSAGES/volto.po +56 -14
  8. package/locales/de.json +1 -1
  9. package/locales/en/LC_MESSAGES/volto.po +55 -13
  10. package/locales/en.json +1 -1
  11. package/locales/es/LC_MESSAGES/volto.po +55 -13
  12. package/locales/es.json +1 -1
  13. package/locales/eu/LC_MESSAGES/volto.po +55 -13
  14. package/locales/eu.json +1 -1
  15. package/locales/fi/LC_MESSAGES/volto.po +55 -13
  16. package/locales/fi.json +1 -1
  17. package/locales/fr/LC_MESSAGES/volto.po +55 -13
  18. package/locales/fr.json +1 -1
  19. package/locales/it/LC_MESSAGES/volto.po +55 -13
  20. package/locales/it.json +1 -1
  21. package/locales/ja/LC_MESSAGES/volto.po +55 -13
  22. package/locales/ja.json +1 -1
  23. package/locales/nl/LC_MESSAGES/volto.po +55 -13
  24. package/locales/nl.json +1 -1
  25. package/locales/pt/LC_MESSAGES/volto.po +55 -13
  26. package/locales/pt.json +1 -1
  27. package/locales/pt_BR/LC_MESSAGES/volto.po +55 -13
  28. package/locales/pt_BR.json +1 -1
  29. package/locales/ro/LC_MESSAGES/volto.po +55 -13
  30. package/locales/ro.json +1 -1
  31. package/locales/volto.pot +56 -14
  32. package/locales/zh_CN/LC_MESSAGES/volto.po +55 -13
  33. package/locales/zh_CN.json +1 -1
  34. package/package.json +1 -1
  35. package/packages/volto-slate/package.json +1 -1
  36. package/src/actions/aliases/aliases.js +27 -7
  37. package/src/actions/aliases/aliases.test.js +1 -1
  38. package/src/components/manage/Controlpanels/Aliases.jsx +542 -583
  39. package/src/components/manage/Controlpanels/Aliases.test.jsx +7 -0
  40. package/src/components/manage/Form/ModalForm.jsx +3 -1
  41. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +23 -0
  42. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +135 -0
  43. package/src/components/theme/View/View.jsx +2 -0
  44. package/src/constants/ActionTypes.js +1 -0
  45. package/src/express-middleware/devproxy.js +7 -2
  46. package/src/helpers/Api/Api.js +12 -1
  47. package/src/middleware/api.js +3 -0
  48. package/.python-version +0 -1
  49. package/packages/README.md +0 -7
@@ -58,6 +58,13 @@ describe('Aliases', () => {
58
58
  locale: 'en',
59
59
  messages: {},
60
60
  },
61
+ site: {
62
+ data: {
63
+ features: {
64
+ filter_aliases_by_date: true,
65
+ },
66
+ },
67
+ },
61
68
  });
62
69
  const component = renderer.create(
63
70
  <Provider store={store}>
@@ -69,6 +69,7 @@ class ModalForm extends Component {
69
69
  required: PropTypes.arrayOf(PropTypes.string),
70
70
  }).isRequired,
71
71
  title: PropTypes.string.isRequired,
72
+ description: PropTypes.objectOf(PropTypes.any),
72
73
  formData: PropTypes.objectOf(PropTypes.any),
73
74
  submitError: PropTypes.string,
74
75
  onSubmit: PropTypes.func.isRequired,
@@ -210,7 +211,7 @@ class ModalForm extends Component {
210
211
  * @returns {string} Markup for the component.
211
212
  */
212
213
  render() {
213
- const { schema, onCancel } = this.props;
214
+ const { schema, onCancel, description } = this.props;
214
215
  const currentFieldset = schema.fieldsets[this.state.currentTab];
215
216
 
216
217
  const fields = map(currentFieldset.fields, (field) => ({
@@ -244,6 +245,7 @@ class ModalForm extends Component {
244
245
  onSubmit={this.onSubmit}
245
246
  error={state_errors || Boolean(this.props.submitError)}
246
247
  >
248
+ {description}
247
249
  <Message error>
248
250
  {state_errors ? (
249
251
  <FormattedMessage
@@ -0,0 +1,23 @@
1
+ import config from '@plone/volto/registry';
2
+ import Helmet from '@plone/volto/helpers/Helmet/Helmet';
3
+
4
+ const AlternateHrefLangs = (props) => {
5
+ const { content } = props;
6
+ return (
7
+ <Helmet>
8
+ {config.settings.isMultilingual &&
9
+ content['@components']?.translations?.items?.map((item, key) => {
10
+ return (
11
+ <link
12
+ key={key}
13
+ rel="alternate"
14
+ hrefLang={item.language}
15
+ href={item['@id']}
16
+ />
17
+ );
18
+ })}
19
+ </Helmet>
20
+ );
21
+ };
22
+
23
+ export { AlternateHrefLangs };
@@ -0,0 +1,135 @@
1
+ import React from 'react';
2
+ import Helmet from '@plone/volto/helpers/Helmet/Helmet';
3
+
4
+ import renderer from 'react-test-renderer';
5
+ import configureStore from 'redux-mock-store';
6
+ import { Provider } from 'react-intl-redux';
7
+ import config from '@plone/volto/registry';
8
+
9
+ import { AlternateHrefLangs } from './AlternateHrefLangs';
10
+
11
+ const mockStore = configureStore();
12
+
13
+ describe('AlternateHrefLangs', () => {
14
+ beforeEach(() => {});
15
+ it('non multilingual site, renders nothing', () => {
16
+ config.settings.isMultilingual = false;
17
+ const content = {
18
+ '@id': '/',
19
+ '@components': {},
20
+ };
21
+ const store = mockStore({
22
+ intl: {
23
+ locale: 'en',
24
+ messages: {},
25
+ },
26
+ });
27
+ // We need to force the component rendering
28
+ // to fill the Helmet
29
+ renderer.create(
30
+ <Provider store={store}>
31
+ <AlternateHrefLangs content={content} />
32
+ </Provider>,
33
+ );
34
+
35
+ const helmetLinks = Helmet.peek().linkTags;
36
+ expect(helmetLinks.length).toBe(0);
37
+ });
38
+ it('multilingual site, with some translations', () => {
39
+ config.settings.isMultilingual = true;
40
+ config.settings.supportedLanguages = ['en', 'es', 'eu'];
41
+
42
+ const content = {
43
+ '@components': {
44
+ translations: {
45
+ items: [
46
+ { '@id': '/en', language: 'en' },
47
+ { '@id': '/es', language: 'es' },
48
+ ],
49
+ },
50
+ },
51
+ };
52
+
53
+ const store = mockStore({
54
+ intl: {
55
+ locale: 'en',
56
+ messages: {},
57
+ },
58
+ });
59
+
60
+ // We need to force the component rendering
61
+ // to fill the Helmet
62
+ renderer.create(
63
+ <Provider store={store}>
64
+ <>
65
+ <AlternateHrefLangs content={content} />
66
+ </>
67
+ </Provider>,
68
+ );
69
+ const helmetLinks = Helmet.peek().linkTags;
70
+
71
+ expect(helmetLinks.length).toBe(2);
72
+
73
+ expect(helmetLinks).toContainEqual({
74
+ rel: 'alternate',
75
+ href: '/es',
76
+ hrefLang: 'es',
77
+ });
78
+ expect(helmetLinks).toContainEqual({
79
+ rel: 'alternate',
80
+ href: '/en',
81
+ hrefLang: 'en',
82
+ });
83
+ });
84
+ it('multilingual site, with all available translations', () => {
85
+ config.settings.isMultilingual = true;
86
+ config.settings.supportedLanguages = ['en', 'es', 'eu'];
87
+ const store = mockStore({
88
+ intl: {
89
+ locale: 'en',
90
+ messages: {},
91
+ },
92
+ });
93
+
94
+ const content = {
95
+ '@components': {
96
+ translations: {
97
+ items: [
98
+ { '@id': '/en', language: 'en' },
99
+ { '@id': '/eu', language: 'eu' },
100
+ { '@id': '/es', language: 'es' },
101
+ ],
102
+ },
103
+ },
104
+ };
105
+
106
+ // We need to force the component rendering
107
+ // to fill the Helmet
108
+ renderer.create(
109
+ <Provider store={store}>
110
+ <AlternateHrefLangs content={content} />
111
+ </Provider>,
112
+ );
113
+
114
+ const helmetLinks = Helmet.peek().linkTags;
115
+
116
+ // We expect having 3 links
117
+ expect(helmetLinks.length).toBe(3);
118
+
119
+ expect(helmetLinks).toContainEqual({
120
+ rel: 'alternate',
121
+ href: '/eu',
122
+ hrefLang: 'eu',
123
+ });
124
+ expect(helmetLinks).toContainEqual({
125
+ rel: 'alternate',
126
+ href: '/es',
127
+ hrefLang: 'es',
128
+ });
129
+ expect(helmetLinks).toContainEqual({
130
+ rel: 'alternate',
131
+ href: '/en',
132
+ hrefLang: 'en',
133
+ });
134
+ });
135
+ });
@@ -18,6 +18,7 @@ import {
18
18
  Tags,
19
19
  Toolbar,
20
20
  } from '@plone/volto/components';
21
+ import { AlternateHrefLangs } from '@plone/volto/components/theme/AlternateHrefLangs/AlternateHrefLangs';
21
22
  import { listActions, getContent } from '@plone/volto/actions';
22
23
  import {
23
24
  BodyClass,
@@ -236,6 +237,7 @@ class View extends Component {
236
237
  return (
237
238
  <div id="view">
238
239
  <ContentMetadataTags content={this.props.content} />
240
+ <AlternateHrefLangs content={this.props.content} />
239
241
  {/* Body class if displayName in component is set */}
240
242
  <BodyClass
241
243
  className={
@@ -135,6 +135,7 @@ export const MOVE_CONTENT_RULE = 'MOVE_CONTENT_RULE';
135
135
  export const GET_ALIASES = 'GET_ALIASES';
136
136
  export const ADD_ALIASES = 'ADD_ALIASES';
137
137
  export const REMOVE_ALIASES = 'REMOVE_ALIASES';
138
+ export const UPLOAD_ALIASES = 'UPLOAD_ALIASES';
138
139
  export const GET_USERSCHEMA = 'GET_USERSCHEMA';
139
140
  export const GET_UPGRADE = 'GET_UPGRADE';
140
141
  export const POST_UPGRADE = 'POST_UPGRADE';
@@ -10,8 +10,13 @@ import querystring from 'querystring';
10
10
  import { parse as parseUrl } from 'url';
11
11
 
12
12
  const filter = function (pathname, req) {
13
- // This is the proxy to the API in case the accept header is 'application/json'
14
- return config.settings.devProxyToApiPath && pathname.startsWith('/++api++');
13
+ // Check if pathname is defined, there are some corner cases that pathname is null
14
+ if (pathname) {
15
+ // This is the proxy to the API in case the accept header is 'application/json'
16
+ return config.settings.devProxyToApiPath && pathname.startsWith('/++api++');
17
+ } else {
18
+ return false;
19
+ }
15
20
  };
16
21
 
17
22
  let _env = null;
@@ -50,7 +50,14 @@ class Api {
50
50
  methods.forEach((method) => {
51
51
  this[method] = (
52
52
  path,
53
- { params, data, type, headers = {}, checkUrl = false } = {},
53
+ {
54
+ params,
55
+ data,
56
+ type,
57
+ headers = {},
58
+ checkUrl = false,
59
+ attach = [],
60
+ } = {},
54
61
  ) => {
55
62
  let request;
56
63
  let promise = new Promise((resolve, reject) => {
@@ -88,6 +95,10 @@ class Api {
88
95
  request.send(data);
89
96
  }
90
97
 
98
+ attach.forEach((attachment) => {
99
+ request.attach.apply(request, attachment);
100
+ });
101
+
91
102
  request.end((err, response) => {
92
103
  if (
93
104
  checkUrl &&
@@ -170,6 +170,7 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
170
170
  checkUrl: settings.actions_raising_api_errors.includes(
171
171
  action.type,
172
172
  ),
173
+ attach: item.attach,
173
174
  },
174
175
  ).then((reqres) => {
175
176
  return [...acc, reqres];
@@ -186,6 +187,7 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
186
187
  checkUrl: settings.actions_raising_api_errors.includes(
187
188
  action.type,
188
189
  ),
190
+ attach: item.attach,
189
191
  }),
190
192
  ),
191
193
  )
@@ -195,6 +197,7 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
195
197
  headers: request.headers,
196
198
  params: request.params,
197
199
  checkUrl: settings.actions_raising_api_errors.includes(action.type),
200
+ attach: request.attach,
198
201
  });
199
202
  actionPromise.then(
200
203
  (result) => {
package/.python-version DELETED
@@ -1 +0,0 @@
1
- 3.9.13
@@ -1,7 +0,0 @@
1
- # Packages
2
-
3
- This directory is intended to contain packages related to Volto ecosystem.
4
-
5
- It was never intended to convert this repo in a monorepo.
6
-
7
- Main Volto package is still located in the root, and it's intended to continue doing so.