@plone/volto 18.32.0 → 18.32.2
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/.eslintignore +1 -0
- package/CHANGELOG.md +40 -0
- package/README.md +0 -4
- package/locales/af/LC_MESSAGES/volto.po +5 -0
- package/locales/af.json +1 -1
- package/locales/ar/LC_MESSAGES/volto.po +5 -0
- package/locales/ar.json +1 -1
- package/locales/bg/LC_MESSAGES/volto.po +5 -0
- package/locales/bg.json +1 -1
- package/locales/bn/LC_MESSAGES/volto.po +5 -0
- package/locales/bn.json +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +5 -0
- package/locales/ca.json +1 -1
- package/locales/cs/LC_MESSAGES/volto.po +5 -0
- package/locales/cs.json +1 -1
- package/locales/cy/LC_MESSAGES/volto.po +5 -0
- package/locales/cy.json +1 -1
- package/locales/da/LC_MESSAGES/volto.po +5 -0
- package/locales/da.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +5 -0
- package/locales/de.json +1 -1
- package/locales/el/LC_MESSAGES/volto.po +5 -0
- package/locales/el.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +5 -0
- package/locales/en.json +1 -1
- package/locales/en_AU/LC_MESSAGES/volto.po +5 -0
- package/locales/en_AU.json +1 -1
- package/locales/en_GB/LC_MESSAGES/volto.po +5 -0
- package/locales/en_GB.json +1 -1
- package/locales/eo/LC_MESSAGES/volto.po +5 -0
- package/locales/eo.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +5 -0
- package/locales/es.json +1 -1
- package/locales/et/LC_MESSAGES/volto.po +5 -0
- package/locales/et.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +5 -0
- package/locales/eu.json +1 -1
- package/locales/fa/LC_MESSAGES/volto.po +5 -0
- package/locales/fa.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +5 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +5 -0
- package/locales/fr.json +1 -1
- package/locales/fu/LC_MESSAGES/volto.po +5 -0
- package/locales/fu.json +1 -1
- package/locales/gl/LC_MESSAGES/volto.po +5 -0
- package/locales/gl.json +1 -1
- package/locales/he/LC_MESSAGES/volto.po +5 -0
- package/locales/he.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +5 -0
- package/locales/hi.json +1 -1
- package/locales/hr/LC_MESSAGES/volto.po +5 -0
- package/locales/hr.json +1 -1
- package/locales/hu/LC_MESSAGES/volto.po +5 -0
- package/locales/hu.json +1 -1
- package/locales/hy/LC_MESSAGES/volto.po +5 -0
- package/locales/hy.json +1 -1
- package/locales/id/LC_MESSAGES/volto.po +5 -0
- package/locales/id.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +5 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +5 -0
- package/locales/ja.json +1 -1
- package/locales/ka/LC_MESSAGES/volto.po +5 -0
- package/locales/ka.json +1 -1
- package/locales/kn/LC_MESSAGES/volto.po +5 -0
- package/locales/kn.json +1 -1
- package/locales/ko/LC_MESSAGES/volto.po +5 -0
- package/locales/ko.json +1 -1
- package/locales/lt/LC_MESSAGES/volto.po +5 -0
- package/locales/lt.json +1 -1
- package/locales/lv/LC_MESSAGES/volto.po +5 -0
- package/locales/lv.json +1 -1
- package/locales/mi/LC_MESSAGES/volto.po +5 -0
- package/locales/mi.json +1 -1
- package/locales/mk/LC_MESSAGES/volto.po +5 -0
- package/locales/mk.json +1 -1
- package/locales/my/LC_MESSAGES/volto.po +5 -0
- package/locales/my.json +1 -1
- package/locales/nb_NO/LC_MESSAGES/volto.po +5 -0
- package/locales/nb_NO.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +5 -0
- package/locales/nl.json +1 -1
- package/locales/nn/LC_MESSAGES/volto.po +5 -0
- package/locales/nn.json +1 -1
- package/locales/pl/LC_MESSAGES/volto.po +5 -0
- package/locales/pl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +5 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +5 -0
- package/locales/pt_BR.json +1 -1
- package/locales/rm/LC_MESSAGES/volto.po +5 -0
- package/locales/rm.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +5 -0
- package/locales/ro.json +1 -1
- package/locales/ru/LC_MESSAGES/volto.po +5 -0
- package/locales/ru.json +1 -1
- package/locales/sk/LC_MESSAGES/volto.po +5 -0
- package/locales/sk.json +1 -1
- package/locales/sl/LC_MESSAGES/volto.po +5 -0
- package/locales/sl.json +1 -1
- package/locales/sm/LC_MESSAGES/volto.po +5 -0
- package/locales/sm.json +1 -1
- package/locales/sq/LC_MESSAGES/volto.po +5 -0
- package/locales/sq.json +1 -1
- package/locales/sr/LC_MESSAGES/volto.po +5 -0
- package/locales/sr.json +1 -1
- package/locales/sr@cyrl/LC_MESSAGES/volto.po +5 -0
- package/locales/sr@cyrl.json +1 -1
- package/locales/sr@latn/LC_MESSAGES/volto.po +5 -0
- package/locales/sr@latn.json +1 -1
- package/locales/sv/LC_MESSAGES/volto.po +5 -0
- package/locales/sv.json +1 -1
- package/locales/ta/LC_MESSAGES/volto.po +5 -0
- package/locales/ta.json +1 -1
- package/locales/te/LC_MESSAGES/volto.po +5 -0
- package/locales/te.json +1 -1
- package/locales/th/LC_MESSAGES/volto.po +5 -0
- package/locales/th.json +1 -1
- package/locales/to/LC_MESSAGES/volto.po +5 -0
- package/locales/to.json +1 -1
- package/locales/tr/LC_MESSAGES/volto.po +5 -0
- package/locales/tr.json +1 -1
- package/locales/uk/LC_MESSAGES/volto.po +5 -0
- package/locales/uk.json +1 -1
- package/locales/vi/LC_MESSAGES/volto.po +5 -0
- package/locales/vi.json +1 -1
- package/locales/volto.pot +5 -0
- package/locales/zh_CN/LC_MESSAGES/volto.po +5 -0
- package/locales/zh_CN.json +1 -1
- package/locales/zh_Hant/LC_MESSAGES/volto.po +5 -0
- package/locales/zh_Hant.json +1 -1
- package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +5 -0
- package/locales/zh_Hant_HK.json +1 -1
- package/package.json +6 -5
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +10 -7
- package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +2 -9
- package/src/components/manage/Blocks/Block/Order/Item.jsx +9 -3
- package/src/components/manage/Blocks/Block/Order/Order.jsx +116 -67
- package/src/components/manage/Blocks/Block/Order/utilities.js +28 -11
- package/src/components/manage/Blocks/Listing/Edit.jsx +1 -0
- package/src/components/manage/Controlpanels/ContentTypeSchema.jsx +1 -1
- package/src/components/manage/Sharing/Sharing.jsx +10 -12
- package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +5 -1
- package/src/components/manage/UniversalLink/UniversalLink.test.jsx +16 -0
- package/src/components/manage/UniversalLink/UniversalLink.tsx +1 -0
- package/src/components/theme/App/App.jsx +3 -1
- package/src/components/theme/ConnectionRefused/ConnectionRefused.jsx +3 -2
- package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
- package/src/components/theme/View/RenderBlocks.jsx +8 -10
- package/src/components/theme/View/RenderBlocks.test.jsx +14 -4
- package/src/config/index.js +1 -1
- package/src/helpers/AuthToken/AuthToken.js +1 -6
- package/src/helpers/Blocks/Blocks.js +109 -24
- package/src/helpers/Blocks/Blocks.test.js +100 -0
- package/src/helpers/FormValidation/validators.ts +16 -4
- package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
- package/types/components/theme/ConnectionRefused/ConnectionRefused.d.ts +2 -2
- package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
- package/types/config/Views.d.ts +1 -1
- package/types/helpers/Blocks/Blocks.d.ts +4 -0
- package/types/helpers/FormValidation/validators.d.ts +11 -1
- package/types/routes.d.ts +7 -5
|
@@ -34,27 +34,44 @@ export function getProjection(
|
|
|
34
34
|
depth = minDepth;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
return { depth, maxDepth, minDepth,
|
|
37
|
+
return { depth, maxDepth, minDepth, ...getParent() };
|
|
38
38
|
|
|
39
|
-
function
|
|
39
|
+
function getParent() {
|
|
40
40
|
if (depth === 0 || !previousItem) {
|
|
41
|
-
return
|
|
41
|
+
return {
|
|
42
|
+
parentId: null,
|
|
43
|
+
parentType: null,
|
|
44
|
+
};
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
if (depth <= previousItem.depth) {
|
|
45
|
-
return
|
|
48
|
+
return {
|
|
49
|
+
parentId: previousItem.parentId,
|
|
50
|
+
parentType: previousItem.parentType,
|
|
51
|
+
};
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
if (depth > previousItem.depth) {
|
|
49
|
-
return
|
|
55
|
+
return {
|
|
56
|
+
parentId: previousItem.id,
|
|
57
|
+
parentType: previousItem.data?.['@type'] || null,
|
|
58
|
+
};
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
const newParent = newItems
|
|
53
62
|
.slice(0, overItemIndex)
|
|
54
63
|
.reverse()
|
|
55
|
-
.find((item) => item.depth === depth)
|
|
56
|
-
|
|
57
|
-
return newParent
|
|
64
|
+
.find((item) => item.depth === depth);
|
|
65
|
+
|
|
66
|
+
return newParent
|
|
67
|
+
? {
|
|
68
|
+
parentId: newParent.parentId,
|
|
69
|
+
parentType: newParent.parentType,
|
|
70
|
+
}
|
|
71
|
+
: {
|
|
72
|
+
parentId: null,
|
|
73
|
+
parentType: null,
|
|
74
|
+
};
|
|
58
75
|
}
|
|
59
76
|
}
|
|
60
77
|
|
|
@@ -79,12 +96,12 @@ function getMinDepth({ nextItem }) {
|
|
|
79
96
|
return 0;
|
|
80
97
|
}
|
|
81
98
|
|
|
82
|
-
function flatten(items = [], parentId = null, depth = 0) {
|
|
99
|
+
function flatten(items = [], parentId = null, parentType = null, depth = 0) {
|
|
83
100
|
return items.reduce((acc, item, index) => {
|
|
84
101
|
return [
|
|
85
102
|
...acc,
|
|
86
|
-
{ ...item, parentId, depth, index },
|
|
87
|
-
...flatten(item.children, item.id, depth + 1),
|
|
103
|
+
{ ...item, parentId, parentType, depth, index },
|
|
104
|
+
...flatten(item.children, item.id, item.data?.['@type'], depth + 1),
|
|
88
105
|
];
|
|
89
106
|
}, []);
|
|
90
107
|
}
|
|
@@ -169,7 +169,7 @@ class ContentTypeSchema extends Component {
|
|
|
169
169
|
error
|
|
170
170
|
title={this.props.intl.formatMessage(messages.error)}
|
|
171
171
|
content={JSON.stringify(
|
|
172
|
-
nextProps.schemaRequest.put.error.response.body ||
|
|
172
|
+
nextProps.schemaRequest.put.error.response.body?.message ||
|
|
173
173
|
nextProps.schemaRequest.put.error.response.text,
|
|
174
174
|
)}
|
|
175
175
|
/>,
|
|
@@ -485,11 +485,19 @@ class SharingComponent extends Component {
|
|
|
485
485
|
/>
|
|
486
486
|
</p>
|
|
487
487
|
</Segment>
|
|
488
|
-
<Segment className="actions" attached clearing>
|
|
488
|
+
<Segment className="right aligned actions" attached clearing>
|
|
489
|
+
<Button
|
|
490
|
+
basic
|
|
491
|
+
secondary
|
|
492
|
+
aria-label={this.props.intl.formatMessage(messages.cancel)}
|
|
493
|
+
title={this.props.intl.formatMessage(messages.cancel)}
|
|
494
|
+
onClick={this.onCancel}
|
|
495
|
+
>
|
|
496
|
+
<Icon className="circled" name={clearSVG} size="30px" />
|
|
497
|
+
</Button>
|
|
489
498
|
<Button
|
|
490
499
|
basic
|
|
491
500
|
primary
|
|
492
|
-
floated="right"
|
|
493
501
|
type="submit"
|
|
494
502
|
aria-label={this.props.intl.formatMessage(messages.save)}
|
|
495
503
|
title={this.props.intl.formatMessage(messages.save)}
|
|
@@ -498,16 +506,6 @@ class SharingComponent extends Component {
|
|
|
498
506
|
>
|
|
499
507
|
<Icon className="circled" name={aheadSVG} size="30px" />
|
|
500
508
|
</Button>
|
|
501
|
-
<Button
|
|
502
|
-
basic
|
|
503
|
-
secondary
|
|
504
|
-
aria-label={this.props.intl.formatMessage(messages.cancel)}
|
|
505
|
-
title={this.props.intl.formatMessage(messages.cancel)}
|
|
506
|
-
floated="right"
|
|
507
|
-
onClick={this.onCancel}
|
|
508
|
-
>
|
|
509
|
-
<Icon className="circled" name={clearSVG} size="30px" />
|
|
510
|
-
</Button>
|
|
511
509
|
</Segment>
|
|
512
510
|
</Form>
|
|
513
511
|
</Plug>
|
|
@@ -144,10 +144,14 @@ class ObjectBrowserBody extends Component {
|
|
|
144
144
|
showSearchInput: false,
|
|
145
145
|
// In image mode, the searchable types default to the image types which
|
|
146
146
|
// can be overridden with the property if specified.
|
|
147
|
+
// If selectableTypes are passed, the searchableTypes are the selectableTypes
|
|
147
148
|
searchableTypes:
|
|
148
149
|
this.props.mode === 'image'
|
|
149
150
|
? this.props.searchableTypes || config.settings.imageObjects
|
|
150
|
-
:
|
|
151
|
+
: [
|
|
152
|
+
...(this.props.searchableTypes ?? []),
|
|
153
|
+
...(this.props.selectableTypes ?? []),
|
|
154
|
+
],
|
|
151
155
|
view: this.props.mode === 'image' ? 'icons' : 'list',
|
|
152
156
|
};
|
|
153
157
|
this.searchInputRef = React.createRef();
|
|
@@ -89,6 +89,22 @@ describe('UniversalLink', () => {
|
|
|
89
89
|
);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
it('check UniversalLink append http when user has not entered the protocol', () => {
|
|
93
|
+
const { getByTitle } = render(
|
|
94
|
+
<Provider store={store}>
|
|
95
|
+
<MemoryRouter>
|
|
96
|
+
<UniversalLink href="www.github.com" title="Volto GitHub repository">
|
|
97
|
+
<h1>Title</h1>
|
|
98
|
+
</UniversalLink>
|
|
99
|
+
</MemoryRouter>
|
|
100
|
+
</Provider>,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(getByTitle('Volto GitHub repository').getAttribute('href')).toBe(
|
|
104
|
+
'http://www.github.com',
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
92
108
|
it('check UniversalLink set target attribute for ext links', () => {
|
|
93
109
|
const { getByTitle } = render(
|
|
94
110
|
<Provider store={store}>
|
|
@@ -174,7 +174,9 @@ export class App extends Component {
|
|
|
174
174
|
<main ref={this.mainRef}>
|
|
175
175
|
<OutdatedBrowser />
|
|
176
176
|
{this.props.connectionRefused ? (
|
|
177
|
-
<ConnectionRefusedView
|
|
177
|
+
<ConnectionRefusedView
|
|
178
|
+
staticContext={this.props.staticContext}
|
|
179
|
+
/>
|
|
178
180
|
) : this.state.hasError ? (
|
|
179
181
|
<Error
|
|
180
182
|
message={this.state.error.message}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Connection refused error page.
|
|
3
3
|
* @module components/theme/ConnectionRefused/ConnectionRefused
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -7,6 +7,7 @@ import React from 'react';
|
|
|
7
7
|
import { FormattedMessage } from 'react-intl';
|
|
8
8
|
import { Container } from 'semantic-ui-react';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
10
|
+
import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
|
|
10
11
|
|
|
11
12
|
const ConnectionRefused = () => (
|
|
12
13
|
<Container
|
|
@@ -71,4 +72,4 @@ const ConnectionRefused = () => (
|
|
|
71
72
|
</Container>
|
|
72
73
|
);
|
|
73
74
|
|
|
74
|
-
export default ConnectionRefused;
|
|
75
|
+
export default withServerErrorCode(503)(ConnectionRefused);
|
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
* @module components/theme/PasswordReset/PasswordReset
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import { compose } from 'redux';
|
|
10
|
-
import { Link, withRouter } from 'react-router-dom';
|
|
6
|
+
import { useState, useEffect } from 'react';
|
|
7
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
8
|
+
import { Link, useHistory, useParams } from 'react-router-dom';
|
|
11
9
|
import Helmet from '@plone/volto/helpers/Helmet/Helmet';
|
|
12
10
|
import { Container } from 'semantic-ui-react';
|
|
13
|
-
import { FormattedMessage, defineMessages,
|
|
11
|
+
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
14
12
|
|
|
15
13
|
import { Form } from '@plone/volto/components/manage/Form';
|
|
16
14
|
import { setInitialPassword } from '@plone/volto/actions/users/users';
|
|
@@ -90,220 +88,139 @@ const messages = defineMessages({
|
|
|
90
88
|
});
|
|
91
89
|
|
|
92
90
|
/**
|
|
93
|
-
* PasswordReset
|
|
94
|
-
* @
|
|
95
|
-
* @extends Component
|
|
91
|
+
* @function PasswordReset
|
|
92
|
+
* @returns {JSX.Element}
|
|
96
93
|
*/
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* @static
|
|
102
|
-
*/
|
|
103
|
-
static propTypes = {
|
|
104
|
-
loading: PropTypes.bool.isRequired,
|
|
105
|
-
loaded: PropTypes.bool.isRequired,
|
|
106
|
-
error: PropTypes.string,
|
|
107
|
-
token: PropTypes.string.isRequired,
|
|
108
|
-
setInitialPassword: PropTypes.func.isRequired,
|
|
109
|
-
};
|
|
94
|
+
function PasswordReset() {
|
|
95
|
+
const dispatch = useDispatch();
|
|
96
|
+
const history = useHistory();
|
|
97
|
+
const { token } = useParams();
|
|
110
98
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
* @static
|
|
115
|
-
*/
|
|
116
|
-
static defaultProps = {
|
|
117
|
-
error: null,
|
|
118
|
-
};
|
|
99
|
+
const loading = useSelector((state) => state.users.initial.loading);
|
|
100
|
+
const loaded = useSelector((state) => state.users.initial.loaded);
|
|
101
|
+
const error = useSelector((state) => state.users.initial.error);
|
|
119
102
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* @param {Object} props Component properties
|
|
124
|
-
* @constructs Controlpanel
|
|
125
|
-
*/
|
|
126
|
-
constructor(props) {
|
|
127
|
-
super(props);
|
|
128
|
-
this.onCancel = this.onCancel.bind(this);
|
|
129
|
-
this.onSubmit = this.onSubmit.bind(this);
|
|
130
|
-
this.state = {
|
|
131
|
-
error: null,
|
|
132
|
-
isSuccessful: false,
|
|
133
|
-
};
|
|
103
|
+
const [localError, setLocalError] = useState(null);
|
|
104
|
+
const [isSuccessful, setIsSuccessful] = useState(false);
|
|
105
|
+
const intl = useIntl();
|
|
134
106
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
107
|
+
const identifierField = config.settings.useEmailAsLogin
|
|
108
|
+
? 'email'
|
|
109
|
+
: 'username';
|
|
138
110
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
111
|
+
const identifierTitle =
|
|
112
|
+
identifierField === 'email'
|
|
113
|
+
? intl.formatMessage(messages.emailTitle)
|
|
114
|
+
: intl.formatMessage(messages.usernameTitle);
|
|
143
115
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
116
|
+
const identifierDescription =
|
|
117
|
+
identifierField === 'email'
|
|
118
|
+
? intl.formatMessage(messages.emailDescription)
|
|
119
|
+
: intl.formatMessage(messages.usernameDescription);
|
|
149
120
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
* @param {Object} nextProps Next properties
|
|
154
|
-
* @returns {undefined}
|
|
155
|
-
*/
|
|
156
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
157
|
-
if (this.props.loading && nextProps.loaded) {
|
|
158
|
-
this.setState({ isSuccessful: true });
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (!loading && loaded) {
|
|
123
|
+
setIsSuccessful(true);
|
|
159
124
|
}
|
|
160
|
-
}
|
|
125
|
+
}, [loading, loaded]);
|
|
161
126
|
|
|
162
127
|
/**
|
|
163
128
|
* Submit handler
|
|
164
129
|
* @method onSubmit
|
|
165
130
|
* @param {object} data Form data.
|
|
166
|
-
* @param {object} event Form data.
|
|
167
131
|
* @returns {undefined}
|
|
168
132
|
*/
|
|
169
|
-
onSubmit(data) {
|
|
133
|
+
const onSubmit = (data) => {
|
|
170
134
|
if (data.password === data.passwordRepeat) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
this.props.token,
|
|
174
|
-
data.password,
|
|
175
|
-
);
|
|
176
|
-
this.setState({
|
|
177
|
-
error: null,
|
|
178
|
-
});
|
|
135
|
+
dispatch(setInitialPassword(data[identifierField], token, data.password));
|
|
136
|
+
setLocalError(null);
|
|
179
137
|
} else {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
message: this.props.intl.formatMessage(messages.passwordsDoNotMatch),
|
|
183
|
-
},
|
|
138
|
+
setLocalError({
|
|
139
|
+
message: intl.formatMessage(messages.passwordsDoNotMatch),
|
|
184
140
|
});
|
|
185
141
|
}
|
|
186
|
-
}
|
|
142
|
+
};
|
|
187
143
|
|
|
188
144
|
/**
|
|
189
145
|
* Cancel handler
|
|
190
146
|
* @method onCancel
|
|
191
147
|
* @returns {undefined}
|
|
192
148
|
*/
|
|
193
|
-
onCancel() {
|
|
194
|
-
|
|
149
|
+
const onCancel = () => {
|
|
150
|
+
history.goBack();
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
if (isSuccessful) {
|
|
154
|
+
return (
|
|
155
|
+
<Container>
|
|
156
|
+
<h1 className="documentFirstHeading">
|
|
157
|
+
<FormattedMessage {...messages.successRedirectToLoginTitle} />
|
|
158
|
+
</h1>
|
|
159
|
+
<p className="description">
|
|
160
|
+
<FormattedMessage
|
|
161
|
+
{...messages.successRedirectToLoginBody}
|
|
162
|
+
values={{
|
|
163
|
+
link: (
|
|
164
|
+
<Link to="/login">{intl.formatMessage({ id: 'Log In' })}</Link>
|
|
165
|
+
),
|
|
166
|
+
}}
|
|
167
|
+
/>
|
|
168
|
+
</p>
|
|
169
|
+
</Container>
|
|
170
|
+
);
|
|
195
171
|
}
|
|
196
172
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
render() {
|
|
203
|
-
if (this.state.isSuccessful) {
|
|
204
|
-
return (
|
|
173
|
+
if (token) {
|
|
174
|
+
const errmsg = error ? error.response?.body?.error || error : null;
|
|
175
|
+
return (
|
|
176
|
+
<div id="page-password-reset">
|
|
177
|
+
<Helmet title={intl.formatMessage(messages.passwordReset)} />
|
|
205
178
|
<Container>
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
<Link to="/login">
|
|
219
|
-
{this.props.intl.formatMessage({ id: 'Log In' })}
|
|
220
|
-
</Link>
|
|
221
|
-
),
|
|
222
|
-
}}
|
|
223
|
-
/>
|
|
224
|
-
</p>
|
|
225
|
-
</Container>
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
if (this.props.token) {
|
|
229
|
-
const errmsg = this.props.error
|
|
230
|
-
? this.props.error.response.body.error
|
|
231
|
-
: null;
|
|
232
|
-
return (
|
|
233
|
-
<div id="page-password-reset">
|
|
234
|
-
<Helmet
|
|
235
|
-
title={this.props.intl.formatMessage(messages.passwordReset)}
|
|
236
|
-
/>
|
|
237
|
-
<Container>
|
|
238
|
-
<Form
|
|
239
|
-
title={this.props.intl.formatMessage(messages.title)}
|
|
240
|
-
description={this.props.intl.formatMessage(messages.description)}
|
|
241
|
-
onSubmit={this.onSubmit}
|
|
242
|
-
onCancel={this.onCancel}
|
|
243
|
-
error={this.state.error || errmsg}
|
|
244
|
-
schema={{
|
|
245
|
-
fieldsets: [
|
|
246
|
-
{
|
|
247
|
-
id: 'default',
|
|
248
|
-
title: this.props.intl.formatMessage(messages.default),
|
|
249
|
-
fields: [
|
|
250
|
-
this.identifierField,
|
|
251
|
-
'password',
|
|
252
|
-
'passwordRepeat',
|
|
253
|
-
],
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
properties: {
|
|
257
|
-
[this.identifierField]: {
|
|
258
|
-
type: 'string',
|
|
259
|
-
title: this.identifierTitle,
|
|
260
|
-
description: this.identifierDescription,
|
|
261
|
-
},
|
|
262
|
-
password: {
|
|
263
|
-
description: this.props.intl.formatMessage(
|
|
264
|
-
messages.passwordDescription,
|
|
265
|
-
),
|
|
266
|
-
title: this.props.intl.formatMessage(
|
|
267
|
-
messages.passwordTitle,
|
|
268
|
-
),
|
|
269
|
-
type: 'string',
|
|
270
|
-
widget: 'password',
|
|
271
|
-
},
|
|
272
|
-
passwordRepeat: {
|
|
273
|
-
description: this.props.intl.formatMessage(
|
|
274
|
-
messages.passwordRepeatDescription,
|
|
275
|
-
),
|
|
276
|
-
title: this.props.intl.formatMessage(
|
|
277
|
-
messages.passwordRepeatTitle,
|
|
278
|
-
),
|
|
279
|
-
type: 'string',
|
|
280
|
-
widget: 'password',
|
|
281
|
-
},
|
|
179
|
+
<Form
|
|
180
|
+
title={intl.formatMessage(messages.title)}
|
|
181
|
+
description={intl.formatMessage(messages.description)}
|
|
182
|
+
onSubmit={onSubmit}
|
|
183
|
+
onCancel={onCancel}
|
|
184
|
+
error={localError || errmsg}
|
|
185
|
+
schema={{
|
|
186
|
+
fieldsets: [
|
|
187
|
+
{
|
|
188
|
+
id: 'default',
|
|
189
|
+
title: intl.formatMessage(messages.default),
|
|
190
|
+
fields: [identifierField, 'password', 'passwordRepeat'],
|
|
282
191
|
},
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
192
|
+
],
|
|
193
|
+
properties: {
|
|
194
|
+
[identifierField]: {
|
|
195
|
+
type: 'string',
|
|
196
|
+
title: identifierTitle,
|
|
197
|
+
description: identifierDescription,
|
|
198
|
+
},
|
|
199
|
+
password: {
|
|
200
|
+
description: intl.formatMessage(messages.passwordDescription),
|
|
201
|
+
title: intl.formatMessage(messages.passwordTitle),
|
|
202
|
+
type: 'string',
|
|
203
|
+
widget: 'password',
|
|
204
|
+
},
|
|
205
|
+
passwordRepeat: {
|
|
206
|
+
description: intl.formatMessage(
|
|
207
|
+
messages.passwordRepeatDescription,
|
|
208
|
+
),
|
|
209
|
+
title: intl.formatMessage(messages.passwordRepeatTitle),
|
|
210
|
+
type: 'string',
|
|
211
|
+
widget: 'password',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
submitLabel: intl.formatMessage(messages.setMyPassword),
|
|
215
|
+
required: [identifierField, 'password', 'passwordRepeat'],
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
</Container>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
294
221
|
}
|
|
222
|
+
|
|
223
|
+
return <div />;
|
|
295
224
|
}
|
|
296
225
|
|
|
297
|
-
export default
|
|
298
|
-
withRouter,
|
|
299
|
-
injectIntl,
|
|
300
|
-
connect(
|
|
301
|
-
(state, props) => ({
|
|
302
|
-
loading: state.users.initial.loading,
|
|
303
|
-
loaded: state.users.initial.loaded,
|
|
304
|
-
error: state.users.initial.error,
|
|
305
|
-
token: props.match.params.token,
|
|
306
|
-
}),
|
|
307
|
-
{ setInitialPassword },
|
|
308
|
-
),
|
|
309
|
-
)(PasswordReset);
|
|
226
|
+
export default PasswordReset;
|
|
@@ -5,8 +5,7 @@ import map from 'lodash/map';
|
|
|
5
5
|
import MaybeWrap from '@plone/volto/components/manage/MaybeWrap/MaybeWrap';
|
|
6
6
|
import {
|
|
7
7
|
applyBlockDefaults,
|
|
8
|
-
|
|
9
|
-
getBlocksLayoutFieldname,
|
|
8
|
+
getBlocks,
|
|
10
9
|
hasBlocksData,
|
|
11
10
|
} from '@plone/volto/helpers/Blocks/Blocks';
|
|
12
11
|
import StyleWrapper from '@plone/volto/components/manage/Blocks/Block/StyleWrapper';
|
|
@@ -28,26 +27,25 @@ const messages = defineMessages({
|
|
|
28
27
|
const RenderBlocks = (props) => {
|
|
29
28
|
const { blockWrapperTag, content, location, isContainer, metadata } = props;
|
|
30
29
|
const intl = useIntl();
|
|
31
|
-
const blocksFieldname = getBlocksFieldname(content);
|
|
32
|
-
const blocksLayoutFieldname = getBlocksLayoutFieldname(content);
|
|
33
30
|
const blocksConfig = props.blocksConfig || config.blocks.blocksConfig;
|
|
34
31
|
const CustomTag = props.as || React.Fragment;
|
|
35
32
|
|
|
33
|
+
const blockList = getBlocks(content);
|
|
34
|
+
|
|
36
35
|
return hasBlocksData(content) ? (
|
|
37
36
|
<CustomTag>
|
|
38
|
-
{map(
|
|
37
|
+
{map(blockList, ([block, rawBlockData]) => {
|
|
39
38
|
const Block =
|
|
40
|
-
blocksConfig[
|
|
41
|
-
ViewDefaultBlock;
|
|
39
|
+
blocksConfig[rawBlockData?.['@type']]?.view || ViewDefaultBlock;
|
|
42
40
|
|
|
43
41
|
const blockData = applyBlockDefaults({
|
|
44
|
-
data:
|
|
42
|
+
data: rawBlockData,
|
|
45
43
|
intl,
|
|
46
44
|
metadata,
|
|
47
45
|
properties: content,
|
|
48
46
|
});
|
|
49
47
|
|
|
50
|
-
if (
|
|
48
|
+
if (rawBlockData?.['@type'] === 'empty') {
|
|
51
49
|
return (
|
|
52
50
|
<MaybeWrap
|
|
53
51
|
key={block}
|
|
@@ -91,7 +89,7 @@ const RenderBlocks = (props) => {
|
|
|
91
89
|
return (
|
|
92
90
|
<div key={block}>
|
|
93
91
|
{intl.formatMessage(messages.unknownBlock, {
|
|
94
|
-
block:
|
|
92
|
+
block: rawBlockData?.['@type'],
|
|
95
93
|
})}
|
|
96
94
|
</div>
|
|
97
95
|
);
|
|
@@ -90,14 +90,14 @@ test('Provides path to blocks', () => {
|
|
|
90
90
|
expect(container).toMatchSnapshot();
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
test('
|
|
93
|
+
test('Filters out invalid blocks', () => {
|
|
94
94
|
const store = mockStore({
|
|
95
95
|
intl: {
|
|
96
96
|
locale: 'en',
|
|
97
97
|
messages: {},
|
|
98
98
|
},
|
|
99
99
|
});
|
|
100
|
-
const { queryAllByText } = render(
|
|
100
|
+
const { queryAllByText, queryByText } = render(
|
|
101
101
|
<Provider store={store}>
|
|
102
102
|
<RenderBlocks
|
|
103
103
|
blocksConfig={{
|
|
@@ -113,7 +113,14 @@ test('Renders invalid blocks', () => {
|
|
|
113
113
|
}}
|
|
114
114
|
content={{
|
|
115
115
|
blocks_layout: {
|
|
116
|
-
items: [
|
|
116
|
+
items: [
|
|
117
|
+
'MISSING-YOU-1',
|
|
118
|
+
'a',
|
|
119
|
+
'MISSING-YOU-2',
|
|
120
|
+
null,
|
|
121
|
+
undefined,
|
|
122
|
+
'undefined',
|
|
123
|
+
],
|
|
117
124
|
},
|
|
118
125
|
blocks: {
|
|
119
126
|
a: {
|
|
@@ -126,7 +133,10 @@ test('Renders invalid blocks', () => {
|
|
|
126
133
|
/>
|
|
127
134
|
</Provider>,
|
|
128
135
|
);
|
|
136
|
+
// Invalid blocks (missing from blocks object or invalid IDs) are filtered out and not rendered
|
|
129
137
|
expect(
|
|
130
138
|
queryAllByText('Invalid block - Will be removed on saving'),
|
|
131
|
-
).toHaveLength(
|
|
139
|
+
).toHaveLength(0);
|
|
140
|
+
// Only valid blocks are rendered
|
|
141
|
+
expect(queryByText('id: a - text: bar - path: /foo')).not.toBeNull();
|
|
132
142
|
});
|
package/src/config/index.js
CHANGED
|
@@ -119,7 +119,7 @@ let config = {
|
|
|
119
119
|
defaultBlockType: 'slate',
|
|
120
120
|
verticalFormTabs: false,
|
|
121
121
|
useEmailAsLogin: false,
|
|
122
|
-
persistentReducers: ['blocksClipboard'],
|
|
122
|
+
persistentReducers: ['blocksClipboard.cut', 'blocksClipboard.copy'],
|
|
123
123
|
initialReducersBlacklist: [], // reducers in this list won't be hydrated in windows.__data
|
|
124
124
|
asyncPropsExtenders: [getSiteAsyncPropExtender], // per route asyncConnect customizers
|
|
125
125
|
contentIcons: contentIcons,
|