@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.
Files changed (203) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +0 -3
  3. package/CHANGELOG.md +69 -0
  4. package/README.md +0 -1
  5. package/babel.js +0 -6
  6. package/locales/af/LC_MESSAGES/volto.po +5455 -0
  7. package/locales/af.json +1 -1
  8. package/locales/ar/LC_MESSAGES/volto.po +5455 -0
  9. package/locales/ar.json +1 -1
  10. package/locales/bg/LC_MESSAGES/volto.po +5455 -0
  11. package/locales/bg.json +1 -1
  12. package/locales/bn/LC_MESSAGES/volto.po +5455 -0
  13. package/locales/bn.json +1 -1
  14. package/locales/ca/LC_MESSAGES/volto.po +406 -345
  15. package/locales/ca.json +1 -1
  16. package/locales/cs/LC_MESSAGES/volto.po +5455 -0
  17. package/locales/cs.json +1 -1
  18. package/locales/cy/LC_MESSAGES/volto.po +5455 -0
  19. package/locales/cy.json +1 -1
  20. package/locales/da/LC_MESSAGES/volto.po +5455 -0
  21. package/locales/da.json +1 -1
  22. package/locales/de/LC_MESSAGES/volto.po +70 -8
  23. package/locales/de.json +1 -1
  24. package/locales/el/LC_MESSAGES/volto.po +5455 -0
  25. package/locales/el.json +1 -1
  26. package/locales/en/LC_MESSAGES/volto.po +66 -0
  27. package/locales/en.json +1 -1
  28. package/locales/en_AU/LC_MESSAGES/volto.po +5455 -0
  29. package/locales/en_AU.json +1 -1
  30. package/locales/en_GB/LC_MESSAGES/volto.po +5455 -0
  31. package/locales/en_GB.json +1 -1
  32. package/locales/eo/LC_MESSAGES/volto.po +5455 -0
  33. package/locales/eo.json +1 -1
  34. package/locales/es/LC_MESSAGES/volto.po +173 -112
  35. package/locales/es.json +1 -1
  36. package/locales/et/LC_MESSAGES/volto.po +5455 -0
  37. package/locales/et.json +1 -1
  38. package/locales/eu/LC_MESSAGES/volto.po +256 -195
  39. package/locales/eu.json +1 -1
  40. package/locales/fa/LC_MESSAGES/volto.po +5455 -0
  41. package/locales/fa.json +1 -1
  42. package/locales/fi/LC_MESSAGES/volto.po +62 -1
  43. package/locales/fi.json +1 -1
  44. package/locales/fr/LC_MESSAGES/volto.po +61 -0
  45. package/locales/fr.json +1 -1
  46. package/locales/fu/LC_MESSAGES/volto.po +5455 -0
  47. package/locales/fu.json +1 -1
  48. package/locales/gl/LC_MESSAGES/volto.po +5456 -0
  49. package/locales/gl.json +1 -1
  50. package/locales/he/LC_MESSAGES/volto.po +5455 -0
  51. package/locales/he.json +1 -1
  52. package/locales/hi/LC_MESSAGES/volto.po +66 -0
  53. package/locales/hi.json +1 -1
  54. package/locales/hr/LC_MESSAGES/volto.po +5455 -0
  55. package/locales/hr.json +1 -1
  56. package/locales/hu/LC_MESSAGES/volto.po +5455 -0
  57. package/locales/hu.json +1 -1
  58. package/locales/hy/LC_MESSAGES/volto.po +5455 -0
  59. package/locales/hy.json +1 -1
  60. package/locales/id/LC_MESSAGES/volto.po +5455 -0
  61. package/locales/id.json +1 -1
  62. package/locales/it/LC_MESSAGES/volto.po +90 -24
  63. package/locales/it.json +1 -1
  64. package/locales/ja/LC_MESSAGES/volto.po +105 -43
  65. package/locales/ja.json +1 -1
  66. package/locales/ka/LC_MESSAGES/volto.po +5455 -0
  67. package/locales/ka.json +1 -1
  68. package/locales/kn/LC_MESSAGES/volto.po +5455 -0
  69. package/locales/kn.json +1 -1
  70. package/locales/ko/LC_MESSAGES/volto.po +5455 -0
  71. package/locales/ko.json +1 -1
  72. package/locales/lt/LC_MESSAGES/volto.po +5455 -0
  73. package/locales/lt.json +1 -1
  74. package/locales/lv/LC_MESSAGES/volto.po +5455 -0
  75. package/locales/lv.json +1 -1
  76. package/locales/mi/LC_MESSAGES/volto.po +5455 -0
  77. package/locales/mi.json +1 -1
  78. package/locales/mk/LC_MESSAGES/volto.po +5455 -0
  79. package/locales/mk.json +1 -1
  80. package/locales/my/LC_MESSAGES/volto.po +5455 -0
  81. package/locales/my.json +1 -1
  82. package/locales/nb_NO/LC_MESSAGES/volto.po +5455 -0
  83. package/locales/nb_NO.json +1 -1
  84. package/locales/nl/LC_MESSAGES/volto.po +93 -31
  85. package/locales/nl.json +1 -1
  86. package/locales/nn/LC_MESSAGES/volto.po +5455 -0
  87. package/locales/nn.json +1 -1
  88. package/locales/pl/LC_MESSAGES/volto.po +5455 -0
  89. package/locales/pl.json +1 -1
  90. package/locales/pt/LC_MESSAGES/volto.po +723 -662
  91. package/locales/pt.json +1 -1
  92. package/locales/pt_BR/LC_MESSAGES/volto.po +61 -0
  93. package/locales/pt_BR.json +1 -1
  94. package/locales/rm/LC_MESSAGES/volto.po +5455 -0
  95. package/locales/rm.json +1 -1
  96. package/locales/ro/LC_MESSAGES/volto.po +61 -0
  97. package/locales/ro.json +1 -1
  98. package/locales/ru/LC_MESSAGES/volto.po +61 -0
  99. package/locales/ru.json +1 -1
  100. package/locales/sk/LC_MESSAGES/volto.po +5455 -0
  101. package/locales/sk.json +1 -1
  102. package/locales/sl/LC_MESSAGES/volto.po +5455 -0
  103. package/locales/sl.json +1 -1
  104. package/locales/sm/LC_MESSAGES/volto.po +5455 -0
  105. package/locales/sm.json +1 -1
  106. package/locales/sq/LC_MESSAGES/volto.po +5455 -0
  107. package/locales/sq.json +1 -1
  108. package/locales/sr/LC_MESSAGES/volto.po +5455 -0
  109. package/locales/sr.json +1 -1
  110. package/locales/sr@cyrl/LC_MESSAGES/volto.po +5455 -0
  111. package/locales/sr@cyrl.json +1 -1
  112. package/locales/sr@latn/LC_MESSAGES/volto.po +5455 -0
  113. package/locales/sr@latn.json +1 -1
  114. package/locales/sv/LC_MESSAGES/volto.po +5455 -0
  115. package/locales/sv.json +1 -1
  116. package/locales/ta/LC_MESSAGES/volto.po +5456 -0
  117. package/locales/ta.json +1 -1
  118. package/locales/te/LC_MESSAGES/volto.po +5455 -0
  119. package/locales/te.json +1 -1
  120. package/locales/th/LC_MESSAGES/volto.po +5455 -0
  121. package/locales/th.json +1 -1
  122. package/locales/to/LC_MESSAGES/volto.po +5455 -0
  123. package/locales/to.json +1 -1
  124. package/locales/tr/LC_MESSAGES/volto.po +5456 -0
  125. package/locales/tr.json +1 -1
  126. package/locales/uk/LC_MESSAGES/volto.po +5455 -0
  127. package/locales/uk.json +1 -1
  128. package/locales/vi/LC_MESSAGES/volto.po +5455 -0
  129. package/locales/vi.json +1 -1
  130. package/locales/volto.pot +62 -1
  131. package/locales/zh_CN/LC_MESSAGES/volto.po +62 -0
  132. package/locales/zh_CN.json +1 -1
  133. package/locales/zh_Hant/LC_MESSAGES/volto.po +5455 -0
  134. package/locales/zh_Hant.json +1 -1
  135. package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +5455 -0
  136. package/locales/zh_Hant_HK.json +1 -1
  137. package/package.json +19 -35
  138. package/razzle.config.js +12 -5
  139. package/src/actions/blockTypes/blockTypes.ts +24 -0
  140. package/src/components/manage/Add/Add.jsx +7 -6
  141. package/src/components/manage/Blocks/Block/Order/Item.jsx +9 -3
  142. package/src/components/manage/Blocks/Block/Order/Order.jsx +116 -67
  143. package/src/components/manage/Blocks/Block/Order/utilities.js +28 -11
  144. package/src/components/manage/Blocks/Listing/Edit.jsx +1 -0
  145. package/src/components/manage/Blocks/Title/Edit.jsx +5 -0
  146. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +7 -0
  147. package/src/components/manage/Controlpanels/BlockType.tsx +166 -0
  148. package/src/components/manage/Controlpanels/BlockTypes.tsx +145 -0
  149. package/src/components/manage/Controlpanels/Controlpanels.jsx +28 -5
  150. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +10 -0
  151. package/src/components/manage/Controlpanels/DatabaseInformation.jsx +9 -0
  152. package/src/components/manage/Controlpanels/ModerateComments.jsx +8 -0
  153. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +4 -5
  154. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +57 -11
  155. package/src/components/manage/Diff/Diff.jsx +201 -298
  156. package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -5
  157. package/src/components/manage/Multilingual/ManageTranslations.jsx +1 -1
  158. package/src/components/manage/Multilingual/TranslationObject.jsx +9 -6
  159. package/src/components/manage/Preferences/PersonalPreferences.jsx +8 -5
  160. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +5 -1
  161. package/src/components/manage/Toolbar/Types.crash.test.jsx +48 -0
  162. package/src/components/manage/Widgets/FileWidget.jsx +7 -0
  163. package/src/components/manage/Widgets/RegistryImageWidget.jsx +1 -1
  164. package/src/components/theme/PasswordReset/PasswordReset.jsx +108 -191
  165. package/src/config/ControlPanels.js +2 -0
  166. package/src/config/index.js +1 -1
  167. package/src/config/validation.ts +8 -0
  168. package/src/constants/ActionTypes.js +1 -0
  169. package/src/express-middleware/devproxy.js +3 -1
  170. package/src/helpers/Blocks/Blocks.js +81 -18
  171. package/src/helpers/FormValidation/FormValidation.test.js +31 -0
  172. package/src/helpers/FormValidation/validators.ts +21 -0
  173. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  174. package/src/helpers/Utils/Utils.jsx +17 -0
  175. package/src/helpers/Utils/Utils.test.jsx +39 -0
  176. package/src/middleware/api.js +7 -3
  177. package/src/reducers/blockTypes/blockTypes.js +38 -0
  178. package/src/reducers/index.js +2 -0
  179. package/src/reducers/users/users.js +1 -1
  180. package/src/routes.js +10 -0
  181. package/src/server.jsx +7 -5
  182. package/test-setup-globals.js +26 -0
  183. package/theme/themes/pastanaga/extras/block-types.less +17 -0
  184. package/theme/themes/pastanaga/extras/main.less +1 -2
  185. package/types/actions/blockTypes/blockTypes.d.ts +7 -0
  186. package/types/components/index.d.ts +1 -1
  187. package/types/components/manage/Blocks/Block/Order/utilities.d.ts +2 -1
  188. package/types/components/manage/Controlpanels/BlockType.d.ts +7 -0
  189. package/types/components/manage/Controlpanels/BlockTypes.d.ts +7 -0
  190. package/types/components/manage/Diff/Diff.d.ts +7 -2
  191. package/types/components/manage/Toolbar/Types.crash.test.d.ts +1 -0
  192. package/types/components/theme/PasswordReset/PasswordReset.d.ts +6 -2
  193. package/types/config/ControlPanels.d.ts +1 -0
  194. package/types/constants/ActionTypes.d.ts +1 -0
  195. package/types/helpers/Blocks/Blocks.d.ts +3 -0
  196. package/types/helpers/FormValidation/validators.d.ts +7 -0
  197. package/types/helpers/MessageLabels/MessageLabels.d.ts +100 -94
  198. package/types/helpers/Utils/Utils.d.ts +1 -0
  199. package/types/reducers/blockTypes/blockTypes.d.ts +16 -0
  200. package/types/reducers/index.d.ts +2 -0
  201. package/types/routes.d.ts +7 -5
  202. package/vitest.config.mjs +84 -42
  203. 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 React, { Component } from 'react';
7
- import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
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, injectIntl } from 'react-intl';
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 class.
94
- * @class PasswordReset
95
- * @extends Component
91
+ * @function PasswordReset
92
+ * @returns {JSX.Element}
96
93
  */
97
- class PasswordReset extends Component {
98
- /**
99
- * Property types.
100
- * @property {Object} propTypes Property types.
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
- * Default properties.
113
- * @property {Object} defaultProps Default properties.
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
- * Constructor
122
- * @method constructor
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
- this.identifierField = config.settings.useEmailAsLogin
136
- ? 'email'
137
- : 'username';
107
+ const identifierField = config.settings.useEmailAsLogin
108
+ ? 'email'
109
+ : 'username';
138
110
 
139
- this.identifierTitle =
140
- this.identifierField === 'email'
141
- ? this.props.intl.formatMessage(messages.emailTitle)
142
- : this.props.intl.formatMessage(messages.usernameTitle);
111
+ const identifierTitle =
112
+ identifierField === 'email'
113
+ ? intl.formatMessage(messages.emailTitle)
114
+ : intl.formatMessage(messages.usernameTitle);
143
115
 
144
- this.identifierDescription =
145
- this.identifierField === 'email'
146
- ? this.props.intl.formatMessage(messages.emailDescription)
147
- : this.props.intl.formatMessage(messages.usernameDescription);
148
- }
116
+ const identifierDescription =
117
+ identifierField === 'email'
118
+ ? intl.formatMessage(messages.emailDescription)
119
+ : intl.formatMessage(messages.usernameDescription);
149
120
 
150
- /**
151
- * Component will receive props
152
- * @method componentWillReceiveProps
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
- this.props.setInitialPassword(
172
- data[this.identifierField],
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
- this.setState({
181
- error: {
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
- this.props.history.goBack();
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
- * Render method.
199
- * @method render
200
- * @returns {string} Markup for the component.
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
- <h1 className="documentFirstHeading">
207
- <FormattedMessage
208
- id="Account activation completed"
209
- defaultMessage="Account activation completed"
210
- />
211
- </h1>
212
- <p className="description">
213
- <FormattedMessage
214
- id="Your password has been set successfully. You may now {link} with your new password."
215
- defaultMessage="Your password has been set successfully. You may now {link} with your new password."
216
- values={{
217
- link: (
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
- submitLabel: this.props.intl.formatMessage(
284
- messages.setMyPassword,
285
- ),
286
- required: [this.identifierField, 'password', 'passwordRepeat'],
287
- }}
288
- />
289
- </Container>
290
- </div>
291
- );
292
- }
293
- return <div />;
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 compose(
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 = []) => {
@@ -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,
@@ -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
- }:${apiPathURL.port}${instancePath}/++api++/VirtualHostRoot${vhSubpath}`;
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
- ? getBlocksHierarchy(properties?.[blocksFieldName]?.[n])
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
- formData[blocksFieldName][source.parent][blocksFieldName][source.id];
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
- formData.blocks[containerId] &&
984
- Object.keys(formData.blocks[containerId]).includes('blocks') &&
985
- Object.keys(formData.blocks[containerId]).includes('blocks_layout')
1005
+ block &&
1006
+ Object.keys(block).includes('blocks') &&
1007
+ Object.keys(block).includes('blocks_layout')
986
1008
  ) {
987
- return formData.blocks[containerId];
1009
+ return block;
988
1010
  }
989
1011
 
990
1012
  let container;
991
1013
  Object.keys(formData.blocks).every((blockId) => {
992
- const block = formData.blocks[blockId];
1014
+ const subBlock = formData.blocks[blockId].data || formData.blocks[blockId];
993
1015
  if (
994
- formData.blocks[blockId] &&
995
- Object.keys(formData.blocks[blockId]).includes('blocks') &&
996
- Object.keys(formData.blocks[blockId]).includes('blocks_layout')
1016
+ subBlock &&
1017
+ Object.keys(subBlock).includes('blocks') &&
1018
+ Object.keys(subBlock).includes('blocks_layout')
997
1019
  ) {
998
- container = findContainer(block, { containerId });
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
  };