@plone/volto 19.0.0-alpha.26 → 19.0.0-alpha.28
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/.eslintrc +0 -3
- package/CHANGELOG.md +69 -0
- package/README.md +0 -1
- package/babel.js +0 -6
- package/locales/af/LC_MESSAGES/volto.po +5455 -0
- package/locales/af.json +1 -1
- package/locales/ar/LC_MESSAGES/volto.po +5455 -0
- package/locales/ar.json +1 -1
- package/locales/bg/LC_MESSAGES/volto.po +5455 -0
- package/locales/bg.json +1 -1
- package/locales/bn/LC_MESSAGES/volto.po +5455 -0
- package/locales/bn.json +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +406 -345
- package/locales/ca.json +1 -1
- package/locales/cs/LC_MESSAGES/volto.po +5455 -0
- package/locales/cs.json +1 -1
- package/locales/cy/LC_MESSAGES/volto.po +5455 -0
- package/locales/cy.json +1 -1
- package/locales/da/LC_MESSAGES/volto.po +5455 -0
- package/locales/da.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +70 -8
- package/locales/de.json +1 -1
- package/locales/el/LC_MESSAGES/volto.po +5455 -0
- package/locales/el.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +66 -0
- package/locales/en.json +1 -1
- package/locales/en_AU/LC_MESSAGES/volto.po +5455 -0
- package/locales/en_AU.json +1 -1
- package/locales/en_GB/LC_MESSAGES/volto.po +5455 -0
- package/locales/en_GB.json +1 -1
- package/locales/eo/LC_MESSAGES/volto.po +5455 -0
- package/locales/eo.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +173 -112
- package/locales/es.json +1 -1
- package/locales/et/LC_MESSAGES/volto.po +5455 -0
- package/locales/et.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +256 -195
- package/locales/eu.json +1 -1
- package/locales/fa/LC_MESSAGES/volto.po +5455 -0
- package/locales/fa.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +62 -1
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +61 -0
- package/locales/fr.json +1 -1
- package/locales/fu/LC_MESSAGES/volto.po +5455 -0
- package/locales/fu.json +1 -1
- package/locales/gl/LC_MESSAGES/volto.po +5456 -0
- package/locales/gl.json +1 -1
- package/locales/he/LC_MESSAGES/volto.po +5455 -0
- package/locales/he.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +66 -0
- package/locales/hi.json +1 -1
- package/locales/hr/LC_MESSAGES/volto.po +5455 -0
- package/locales/hr.json +1 -1
- package/locales/hu/LC_MESSAGES/volto.po +5455 -0
- package/locales/hu.json +1 -1
- package/locales/hy/LC_MESSAGES/volto.po +5455 -0
- package/locales/hy.json +1 -1
- package/locales/id/LC_MESSAGES/volto.po +5455 -0
- package/locales/id.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +90 -24
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +105 -43
- package/locales/ja.json +1 -1
- package/locales/ka/LC_MESSAGES/volto.po +5455 -0
- package/locales/ka.json +1 -1
- package/locales/kn/LC_MESSAGES/volto.po +5455 -0
- package/locales/kn.json +1 -1
- package/locales/ko/LC_MESSAGES/volto.po +5455 -0
- package/locales/ko.json +1 -1
- package/locales/lt/LC_MESSAGES/volto.po +5455 -0
- package/locales/lt.json +1 -1
- package/locales/lv/LC_MESSAGES/volto.po +5455 -0
- package/locales/lv.json +1 -1
- package/locales/mi/LC_MESSAGES/volto.po +5455 -0
- package/locales/mi.json +1 -1
- package/locales/mk/LC_MESSAGES/volto.po +5455 -0
- package/locales/mk.json +1 -1
- package/locales/my/LC_MESSAGES/volto.po +5455 -0
- package/locales/my.json +1 -1
- package/locales/nb_NO/LC_MESSAGES/volto.po +5455 -0
- package/locales/nb_NO.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +93 -31
- package/locales/nl.json +1 -1
- package/locales/nn/LC_MESSAGES/volto.po +5455 -0
- package/locales/nn.json +1 -1
- package/locales/pl/LC_MESSAGES/volto.po +5455 -0
- package/locales/pl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +723 -662
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +61 -0
- package/locales/pt_BR.json +1 -1
- package/locales/rm/LC_MESSAGES/volto.po +5455 -0
- package/locales/rm.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +61 -0
- package/locales/ro.json +1 -1
- package/locales/ru/LC_MESSAGES/volto.po +61 -0
- package/locales/ru.json +1 -1
- package/locales/sk/LC_MESSAGES/volto.po +5455 -0
- package/locales/sk.json +1 -1
- package/locales/sl/LC_MESSAGES/volto.po +5455 -0
- package/locales/sl.json +1 -1
- package/locales/sm/LC_MESSAGES/volto.po +5455 -0
- package/locales/sm.json +1 -1
- package/locales/sq/LC_MESSAGES/volto.po +5455 -0
- package/locales/sq.json +1 -1
- package/locales/sr/LC_MESSAGES/volto.po +5455 -0
- package/locales/sr.json +1 -1
- package/locales/sr@cyrl/LC_MESSAGES/volto.po +5455 -0
- package/locales/sr@cyrl.json +1 -1
- package/locales/sr@latn/LC_MESSAGES/volto.po +5455 -0
- package/locales/sr@latn.json +1 -1
- package/locales/sv/LC_MESSAGES/volto.po +5455 -0
- package/locales/sv.json +1 -1
- package/locales/ta/LC_MESSAGES/volto.po +5456 -0
- package/locales/ta.json +1 -1
- package/locales/te/LC_MESSAGES/volto.po +5455 -0
- package/locales/te.json +1 -1
- package/locales/th/LC_MESSAGES/volto.po +5455 -0
- package/locales/th.json +1 -1
- package/locales/to/LC_MESSAGES/volto.po +5455 -0
- package/locales/to.json +1 -1
- package/locales/tr/LC_MESSAGES/volto.po +5456 -0
- package/locales/tr.json +1 -1
- package/locales/uk/LC_MESSAGES/volto.po +5455 -0
- package/locales/uk.json +1 -1
- package/locales/vi/LC_MESSAGES/volto.po +5455 -0
- package/locales/vi.json +1 -1
- package/locales/volto.pot +62 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +62 -0
- package/locales/zh_CN.json +1 -1
- package/locales/zh_Hant/LC_MESSAGES/volto.po +5455 -0
- package/locales/zh_Hant.json +1 -1
- package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +5455 -0
- package/locales/zh_Hant_HK.json +1 -1
- package/package.json +19 -35
- package/razzle.config.js +12 -5
- package/src/actions/blockTypes/blockTypes.ts +24 -0
- package/src/components/manage/Add/Add.jsx +7 -6
- 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/Blocks/Title/Edit.jsx +5 -0
- package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +7 -0
- package/src/components/manage/Controlpanels/BlockType.tsx +166 -0
- package/src/components/manage/Controlpanels/BlockTypes.tsx +145 -0
- package/src/components/manage/Controlpanels/Controlpanels.jsx +28 -5
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +10 -0
- package/src/components/manage/Controlpanels/DatabaseInformation.jsx +9 -0
- package/src/components/manage/Controlpanels/ModerateComments.jsx +8 -0
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +4 -5
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +57 -11
- package/src/components/manage/Diff/Diff.jsx +201 -298
- package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -5
- package/src/components/manage/Multilingual/ManageTranslations.jsx +1 -1
- package/src/components/manage/Multilingual/TranslationObject.jsx +9 -6
- package/src/components/manage/Preferences/PersonalPreferences.jsx +8 -5
- package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +5 -1
- package/src/components/manage/Toolbar/Types.crash.test.jsx +48 -0
- package/src/components/manage/Widgets/FileWidget.jsx +7 -0
- package/src/components/manage/Widgets/RegistryImageWidget.jsx +1 -1
- package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
- package/src/config/ControlPanels.js +2 -0
- package/src/config/index.js +1 -1
- package/src/config/validation.ts +8 -0
- package/src/constants/ActionTypes.js +1 -0
- package/src/express-middleware/devproxy.js +3 -1
- package/src/helpers/Blocks/Blocks.js +81 -18
- package/src/helpers/FormValidation/FormValidation.test.js +31 -0
- package/src/helpers/FormValidation/validators.ts +21 -0
- package/src/helpers/MessageLabels/MessageLabels.js +5 -0
- package/src/helpers/Utils/Utils.jsx +17 -0
- package/src/helpers/Utils/Utils.test.jsx +39 -0
- package/src/middleware/api.js +7 -3
- package/src/reducers/blockTypes/blockTypes.js +38 -0
- package/src/reducers/index.js +2 -0
- package/src/reducers/users/users.js +1 -1
- package/src/routes.js +10 -0
- package/src/server.jsx +7 -5
- package/test-setup-globals.js +26 -0
- package/theme/themes/pastanaga/extras/block-types.less +17 -0
- package/theme/themes/pastanaga/extras/main.less +1 -2
- package/types/actions/blockTypes/blockTypes.d.ts +7 -0
- package/types/components/index.d.ts +1 -1
- package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
- package/types/components/manage/Controlpanels/BlockType.d.ts +7 -0
- package/types/components/manage/Controlpanels/BlockTypes.d.ts +7 -0
- package/types/components/manage/Diff/Diff.d.ts +7 -2
- package/types/components/manage/Toolbar/Types.crash.test.d.ts +1 -0
- package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
- package/types/config/ControlPanels.d.ts +1 -0
- package/types/constants/ActionTypes.d.ts +1 -0
- package/types/helpers/Blocks/Blocks.d.ts +3 -0
- package/types/helpers/FormValidation/validators.d.ts +7 -0
- package/types/helpers/MessageLabels/MessageLabels.d.ts +100 -94
- package/types/helpers/Utils/Utils.d.ts +1 -0
- package/types/reducers/blockTypes/blockTypes.d.ts +16 -0
- package/types/reducers/index.d.ts +2 -0
- package/types/routes.d.ts +7 -5
- package/vitest.config.mjs +84 -42
- package/webpack-plugins/webpack-less-plugin.js +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer from 'react-test-renderer';
|
|
3
|
+
import configureStore from 'redux-mock-store';
|
|
4
|
+
import { Provider } from 'react-intl-redux';
|
|
5
|
+
import thunk from 'redux-thunk';
|
|
6
|
+
|
|
7
|
+
import Types from './Types';
|
|
8
|
+
|
|
9
|
+
const mockStore = configureStore([thunk]);
|
|
10
|
+
|
|
11
|
+
describe('Types Defensive', () => {
|
|
12
|
+
it('does not crash when a language is missing from langmap', () => {
|
|
13
|
+
const store = mockStore({
|
|
14
|
+
site: {
|
|
15
|
+
data: {
|
|
16
|
+
'plone.available_languages': ['en', 'fr_HT'], // fr_HT is missing from langmap
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
types: { types: [{ title: 'Document' }] },
|
|
20
|
+
content: {
|
|
21
|
+
data: {
|
|
22
|
+
'@id': '/test',
|
|
23
|
+
'@type': 'Document',
|
|
24
|
+
language: { token: 'en' },
|
|
25
|
+
'@components': {
|
|
26
|
+
translations: { items: [] },
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
intl: {
|
|
31
|
+
locale: 'en',
|
|
32
|
+
messages: {},
|
|
33
|
+
},
|
|
34
|
+
userSession: {
|
|
35
|
+
token: 'thetoken',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// This should not throw TypeError: Cannot read properties of undefined (reading 'nativeName')
|
|
40
|
+
const component = renderer.create(
|
|
41
|
+
<Provider store={store}>
|
|
42
|
+
<Types pathname="/test" active />
|
|
43
|
+
</Provider>,
|
|
44
|
+
);
|
|
45
|
+
const json = component.toJSON();
|
|
46
|
+
expect(json).toBeDefined();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -59,6 +59,10 @@ const messages = defineMessages({
|
|
|
59
59
|
id: 'File is not of the accepted type {accept}',
|
|
60
60
|
defaultMessage: 'File is not of the accepted type {accept}',
|
|
61
61
|
},
|
|
62
|
+
dragAndDropActionA11y: {
|
|
63
|
+
id: 'Press Enter to browse files from your computer.',
|
|
64
|
+
defaultMessage: 'Press Enter to browse files from your computer.',
|
|
65
|
+
},
|
|
62
66
|
});
|
|
63
67
|
|
|
64
68
|
/**
|
|
@@ -205,6 +209,9 @@ const FileWidget = (props) => {
|
|
|
205
209
|
{value
|
|
206
210
|
? intl.formatMessage(messages.replaceFile)
|
|
207
211
|
: intl.formatMessage(messages.addNewFile)}
|
|
212
|
+
<span className="visually-hidden">
|
|
213
|
+
{intl.formatMessage(messages.dragAndDropActionA11y)}
|
|
214
|
+
</span>
|
|
208
215
|
</label>
|
|
209
216
|
<input
|
|
210
217
|
{...getInputProps({
|
|
@@ -99,7 +99,7 @@ const RegistryImageWidget = (props) => {
|
|
|
99
99
|
|
|
100
100
|
readAsDataURL(file).then((data) => {
|
|
101
101
|
const fields = data.match(/^data:(.*);(.*),(.*)$/);
|
|
102
|
-
onChange(id, `filenameb64:${btoa(file.name)};datab64:${fields[3]}
|
|
102
|
+
onChange(id, `filenameb64:${btoa(file.name)};datab64:${fields[3]}`);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
let reader = new FileReader();
|
|
@@ -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;
|
|
@@ -19,6 +19,7 @@ import rulesSVG from '@plone/volto/icons/content-existing.svg';
|
|
|
19
19
|
import undoControlPanelSVG from '@plone/volto/icons/undo-control-panel.svg';
|
|
20
20
|
import linkSVG from '@plone/volto/icons/link.svg';
|
|
21
21
|
import relationsSVG from '@plone/volto/icons/ahead.svg';
|
|
22
|
+
import contentListingSVG from '@plone/volto/icons/content-listing.svg';
|
|
22
23
|
import config from '@plone/volto/registry';
|
|
23
24
|
|
|
24
25
|
export const controlPanelsIcons = {
|
|
@@ -43,6 +44,7 @@ export const controlPanelsIcons = {
|
|
|
43
44
|
undo: undoControlPanelSVG,
|
|
44
45
|
aliases: linkSVG,
|
|
45
46
|
relations: relationsSVG,
|
|
47
|
+
'block-types': contentListingSVG,
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
export const filterControlPanels = (controlpanels = []) => {
|
package/src/config/index.js
CHANGED
|
@@ -121,7 +121,7 @@ let config = {
|
|
|
121
121
|
defaultBlockType: 'slate',
|
|
122
122
|
verticalFormTabs: false,
|
|
123
123
|
useEmailAsLogin: false,
|
|
124
|
-
persistentReducers: ['blocksClipboard'],
|
|
124
|
+
persistentReducers: ['blocksClipboard.cut', 'blocksClipboard.copy'],
|
|
125
125
|
initialReducersBlacklist: [], // reducers in this list won't be hydrated in windows.__data
|
|
126
126
|
asyncPropsExtenders: [getSiteAsyncPropExtender], // per route asyncConnect customizers
|
|
127
127
|
contentIcons: contentIcons,
|
package/src/config/validation.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
endEventDateRangeValidator,
|
|
17
17
|
patternValidator,
|
|
18
18
|
defaultLanguageControlPanelValidator,
|
|
19
|
+
sizeValidator,
|
|
19
20
|
} from '@plone/volto/helpers/FormValidation/validators';
|
|
20
21
|
|
|
21
22
|
const registerValidators = (config: ConfigType) => {
|
|
@@ -33,6 +34,13 @@ const registerValidators = (config: ConfigType) => {
|
|
|
33
34
|
method: maxLengthValidator,
|
|
34
35
|
});
|
|
35
36
|
|
|
37
|
+
config.registerUtility({
|
|
38
|
+
name: 'size',
|
|
39
|
+
type: 'validator',
|
|
40
|
+
dependencies: { fieldType: 'object' },
|
|
41
|
+
method: sizeValidator,
|
|
42
|
+
});
|
|
43
|
+
|
|
36
44
|
config.registerUtility({
|
|
37
45
|
name: 'pattern',
|
|
38
46
|
type: 'validator',
|
|
@@ -148,3 +148,4 @@ export const GET_NAVROOT = 'GET_NAVROOT';
|
|
|
148
148
|
export const SET_FORM_DATA = 'SET_FORM_DATA';
|
|
149
149
|
export const SET_UI_STATE = 'SET_UI_STATE';
|
|
150
150
|
export const UPDATE_UPLOADED_FILES = 'UPDATE_UPLOADED_FILES';
|
|
151
|
+
export const GET_BLOCKTYPES_INDEX = 'GET_BLOCKTYPES_INDEX';
|
|
@@ -88,11 +88,13 @@ export default function devProxyMiddleware() {
|
|
|
88
88
|
.map((part) => '/_vh_' + part)
|
|
89
89
|
.join('')
|
|
90
90
|
: '';
|
|
91
|
+
const port =
|
|
92
|
+
apiPathURL.port || (apiPathURL.protocol === 'https:' ? 443 : 80);
|
|
91
93
|
const target =
|
|
92
94
|
config.settings.proxyRewriteTarget ||
|
|
93
95
|
`/VirtualHostBase/${apiPathURL.protocol.slice(0, -1)}/${
|
|
94
96
|
apiPathURL.hostname
|
|
95
|
-
}:${
|
|
97
|
+
}:${port}${instancePath}/++api++/VirtualHostRoot${vhSubpath}`;
|
|
96
98
|
|
|
97
99
|
return `${target}${path.replace(`${config.settings.subpathPrefix}/++api++`, '')}`;
|
|
98
100
|
},
|
|
@@ -151,12 +151,28 @@ export function deleteBlock(formData, blockId, intl) {
|
|
|
151
151
|
|
|
152
152
|
let newFormData = {
|
|
153
153
|
...formData,
|
|
154
|
-
[blocksLayoutFieldname]: {
|
|
155
|
-
items: without(formData[blocksLayoutFieldname].items, blockId),
|
|
156
|
-
},
|
|
157
|
-
[blocksFieldname]: omit(formData[blocksFieldname], [blockId]),
|
|
158
154
|
};
|
|
159
155
|
|
|
156
|
+
let container = findParent(newFormData, {
|
|
157
|
+
blockId,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (container) {
|
|
161
|
+
container[blocksLayoutFieldname].items = without(
|
|
162
|
+
container[blocksLayoutFieldname].items,
|
|
163
|
+
blockId,
|
|
164
|
+
);
|
|
165
|
+
container[blocksFieldname] = omit(container[blocksFieldname], [blockId]);
|
|
166
|
+
} else {
|
|
167
|
+
newFormData[blocksLayoutFieldname].items = without(
|
|
168
|
+
newFormData[blocksLayoutFieldname].items,
|
|
169
|
+
blockId,
|
|
170
|
+
);
|
|
171
|
+
newFormData[blocksFieldname] = omit(newFormData[blocksFieldname], [
|
|
172
|
+
blockId,
|
|
173
|
+
]);
|
|
174
|
+
}
|
|
175
|
+
|
|
160
176
|
if (newFormData[blocksLayoutFieldname].items.length === 0) {
|
|
161
177
|
newFormData = addBlock(
|
|
162
178
|
newFormData,
|
|
@@ -839,7 +855,9 @@ export const getBlocksHierarchy = (properties) => {
|
|
|
839
855
|
title: properties?.[blocksFieldName]?.[n]?.['@type'],
|
|
840
856
|
data: properties?.[blocksFieldName]?.[n],
|
|
841
857
|
children: isBlockContainer(properties?.[blocksFieldName]?.[n])
|
|
842
|
-
?
|
|
858
|
+
? properties?.[blocksFieldName]?.[n]?.data
|
|
859
|
+
? getBlocksHierarchy(properties?.[blocksFieldName]?.[n]?.data)
|
|
860
|
+
: getBlocksHierarchy(properties?.[blocksFieldName]?.[n])
|
|
843
861
|
: [],
|
|
844
862
|
}));
|
|
845
863
|
};
|
|
@@ -933,8 +951,13 @@ export function moveBlockEnhanced(formData, { source, destination }) {
|
|
|
933
951
|
const destinationContainer = findContainer(clonedFormData, {
|
|
934
952
|
containerId: destination.parent,
|
|
935
953
|
});
|
|
954
|
+
const sourceContainer = findContainer(clonedFormData, {
|
|
955
|
+
containerId: source.parent,
|
|
956
|
+
});
|
|
957
|
+
|
|
936
958
|
destinationContainer[blocksFieldName][source.id] =
|
|
937
|
-
|
|
959
|
+
sourceContainer[blocksFieldName]?.[source.id] ||
|
|
960
|
+
sourceContainer.data?.[blocksFieldName][source.id];
|
|
938
961
|
|
|
939
962
|
destinationContainer[blocksLayoutFieldname].items = insertInArray(
|
|
940
963
|
destinationContainer[blocksLayoutFieldname].items,
|
|
@@ -943,9 +966,6 @@ export function moveBlockEnhanced(formData, { source, destination }) {
|
|
|
943
966
|
);
|
|
944
967
|
|
|
945
968
|
// Remove the source block from the source parent
|
|
946
|
-
const sourceContainer = findContainer(clonedFormData, {
|
|
947
|
-
containerId: source.parent,
|
|
948
|
-
});
|
|
949
969
|
delete sourceContainer[blocksFieldName][source.id];
|
|
950
970
|
sourceContainer[blocksLayoutFieldname].items = removeFromArray(
|
|
951
971
|
sourceContainer[blocksLayoutFieldname].items,
|
|
@@ -979,23 +999,25 @@ export function moveBlockEnhanced(formData, { source, destination }) {
|
|
|
979
999
|
* @returns {object|undefined} - The container object if found, otherwise undefined.
|
|
980
1000
|
*/
|
|
981
1001
|
export const findContainer = (formData, { containerId }) => {
|
|
1002
|
+
const block =
|
|
1003
|
+
formData.blocks[containerId]?.data || formData.blocks[containerId];
|
|
982
1004
|
if (
|
|
983
|
-
|
|
984
|
-
Object.keys(
|
|
985
|
-
Object.keys(
|
|
1005
|
+
block &&
|
|
1006
|
+
Object.keys(block).includes('blocks') &&
|
|
1007
|
+
Object.keys(block).includes('blocks_layout')
|
|
986
1008
|
) {
|
|
987
|
-
return
|
|
1009
|
+
return block;
|
|
988
1010
|
}
|
|
989
1011
|
|
|
990
1012
|
let container;
|
|
991
1013
|
Object.keys(formData.blocks).every((blockId) => {
|
|
992
|
-
const
|
|
1014
|
+
const subBlock = formData.blocks[blockId].data || formData.blocks[blockId];
|
|
993
1015
|
if (
|
|
994
|
-
|
|
995
|
-
Object.keys(
|
|
996
|
-
Object.keys(
|
|
1016
|
+
subBlock &&
|
|
1017
|
+
Object.keys(subBlock).includes('blocks') &&
|
|
1018
|
+
Object.keys(subBlock).includes('blocks_layout')
|
|
997
1019
|
) {
|
|
998
|
-
container = findContainer(
|
|
1020
|
+
container = findContainer(subBlock, { containerId });
|
|
999
1021
|
}
|
|
1000
1022
|
if (container) {
|
|
1001
1023
|
return false;
|
|
@@ -1007,6 +1029,47 @@ export const findContainer = (formData, { containerId }) => {
|
|
|
1007
1029
|
return container;
|
|
1008
1030
|
};
|
|
1009
1031
|
|
|
1032
|
+
/**
|
|
1033
|
+
* Finds parent container of the specified blockId in the given formData.
|
|
1034
|
+
*
|
|
1035
|
+
* @param {object} formData - The form data object.
|
|
1036
|
+
* @param {object} options - The options object.
|
|
1037
|
+
* @param {string} options.blockId - The ID of the block to find.
|
|
1038
|
+
* @returns {object|undefined} - The container object if found, otherwise undefined.
|
|
1039
|
+
*/
|
|
1040
|
+
export const findParent = (formData, { blockId }) => {
|
|
1041
|
+
const block = formData.data || formData;
|
|
1042
|
+
|
|
1043
|
+
if (block && block.blocks && Object.keys(block.blocks).includes(blockId)) {
|
|
1044
|
+
return block;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
let found = false;
|
|
1048
|
+
|
|
1049
|
+
if (block && block.blocks) {
|
|
1050
|
+
Object.keys(block.blocks).every((subBlockId) => {
|
|
1051
|
+
const subBlock =
|
|
1052
|
+
block.blocks[subBlockId].data || block.blocks[subBlockId];
|
|
1053
|
+
if (subBlock && subBlock.blocks) {
|
|
1054
|
+
if (Object.keys(subBlock.blocks).includes(blockId)) {
|
|
1055
|
+
found = subBlock;
|
|
1056
|
+
}
|
|
1057
|
+
const parent = findParent(subBlock, { blockId });
|
|
1058
|
+
if (parent) {
|
|
1059
|
+
found = parent;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
if (found) {
|
|
1063
|
+
return false;
|
|
1064
|
+
} else {
|
|
1065
|
+
return true;
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
return found;
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1010
1073
|
const _dummyIntl = {
|
|
1011
1074
|
formatMessage() {},
|
|
1012
1075
|
};
|