@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.
- package/.changelog.draft +6 -2
- package/.readthedocs.yaml +4 -5
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +31 -0
- package/locales/ca/LC_MESSAGES/volto.po +55 -13
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +56 -14
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +55 -13
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +55 -13
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +55 -13
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +55 -13
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +55 -13
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +55 -13
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +55 -13
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +55 -13
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +55 -13
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +55 -13
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +55 -13
- package/locales/ro.json +1 -1
- package/locales/volto.pot +56 -14
- package/locales/zh_CN/LC_MESSAGES/volto.po +55 -13
- package/locales/zh_CN.json +1 -1
- package/package.json +1 -1
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/aliases/aliases.js +27 -7
- package/src/actions/aliases/aliases.test.js +1 -1
- package/src/components/manage/Controlpanels/Aliases.jsx +542 -583
- package/src/components/manage/Controlpanels/Aliases.test.jsx +7 -0
- package/src/components/manage/Form/ModalForm.jsx +3 -1
- package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +23 -0
- package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +135 -0
- package/src/components/theme/View/View.jsx +2 -0
- package/src/constants/ActionTypes.js +1 -0
- package/src/express-middleware/devproxy.js +7 -2
- package/src/helpers/Api/Api.js +12 -1
- package/src/middleware/api.js +3 -0
- package/.python-version +0 -1
- package/packages/README.md +0 -7
|
@@ -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
|
-
//
|
|
14
|
-
|
|
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;
|
package/src/helpers/Api/Api.js
CHANGED
|
@@ -50,7 +50,14 @@ class Api {
|
|
|
50
50
|
methods.forEach((method) => {
|
|
51
51
|
this[method] = (
|
|
52
52
|
path,
|
|
53
|
-
{
|
|
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 &&
|
package/src/middleware/api.js
CHANGED
|
@@ -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
|
package/packages/README.md
DELETED