@plone/volto 18.32.3 → 18.32.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -17,6 +17,23 @@ myst:
17
17
 
18
18
  <!-- towncrier release notes start -->
19
19
 
20
+ ## 18.32.4 (2026-03-12)
21
+
22
+ ### Feature
23
+
24
+ - If a delete operation fails, display the error message returned by the API (if any). @cekk [#7888](https://github.com/plone/volto/issues/7888)
25
+
26
+ ### Bugfix
27
+
28
+ - Update the users controlpanel to be compatible with the new response format of the users endpoint introduced in https://github.com/plone/plone.restapi/pull/1971. @jnptk
29
+
30
+ ### Internal
31
+
32
+ - Remove the `immutable` dependency, since it is not a direct dependency. @wesleybl [#7974](https://github.com/plone/volto/issues/7974)
33
+ - Update pnpm to 9.15.9. @wesleybl [#7975](https://github.com/plone/volto/issues/7975)
34
+ - Revert: "Backport #7672: Convert FormFieldWrapper to functional component (18.x.x)" @sneridagh [#7994](https://github.com/plone/volto/issues/7994)
35
+ - Update dependencies: webpack 5.105.4 @davisagli
36
+
20
37
  ## 18.32.3 (2026-03-04)
21
38
 
22
39
  ### Bugfix
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  }
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "18.32.3",
12
+ "version": "18.32.4",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git@github.com:plone/volto.git"
@@ -168,7 +168,6 @@
168
168
  "hoist-non-react-statics": "3.3.2",
169
169
  "http-proxy-middleware": "2.0.1",
170
170
  "image-extensions": "1.1.0",
171
- "immutable": "3",
172
171
  "is-hotkey": "0.2.0",
173
172
  "is-url": "1.2.4",
174
173
  "jotai": "2.11.3",
@@ -363,7 +362,7 @@
363
362
  "use-trace-update": "1.3.2",
364
363
  "vitest": "^3.0.4",
365
364
  "wait-on": "6.0.0",
366
- "webpack": "5.90.1",
365
+ "webpack": "5.105.4",
367
366
  "webpack-bundle-analyzer": "4.10.1",
368
367
  "webpack-dev-server": "4.11.1",
369
368
  "webpack-node-externals": "3.0.0",
@@ -504,11 +504,17 @@ class Contents extends Component {
504
504
  }
505
505
 
506
506
  if (this.props.deleteRequest.loading && nextProps.deleteRequest.error) {
507
+ const deleteErrorMessageTitle = this.props.intl.formatMessage(
508
+ messages.deleteError,
509
+ );
510
+ const deleteErrorMessageContent =
511
+ nextProps.deleteRequest.error?.response?.body?.message ||
512
+ deleteErrorMessageTitle;
507
513
  this.props.toastify.toast.error(
508
514
  <Toast
509
515
  error
510
- title={this.props.intl.formatMessage(messages.deleteError)}
511
- content={this.props.intl.formatMessage(messages.deleteError)}
516
+ title={deleteErrorMessageTitle}
517
+ content={deleteErrorMessageContent}
512
518
  />,
513
519
  );
514
520
  }
@@ -2,12 +2,12 @@
2
2
  * FormFieldWrapper component.
3
3
  * @module components/manage/Widgets/FormFieldWrapper
4
4
  */
5
- import React from 'react';
5
+ import React, { Component } from 'react';
6
6
  import PropTypes from 'prop-types';
7
7
  import { Form, Grid, Icon as IconOld, Label } from 'semantic-ui-react';
8
8
  import map from 'lodash/map';
9
9
  import cx from 'classnames';
10
- import { defineMessages, useIntl } from 'react-intl';
10
+ import { defineMessages, injectIntl } from 'react-intl';
11
11
  import LanguageSVG from '@plone/volto/icons/language.svg';
12
12
  import Icon from '@plone/volto/components/theme/Icon/Icon';
13
13
 
@@ -31,156 +31,178 @@ const messages = defineMessages({
31
31
  },
32
32
  });
33
33
  /**
34
- * FormFieldWrapper component.
35
- * @function FormFieldWrapper
36
- * @param {Object} props - Component props
37
- * @returns {JSX.Element} Markup for the component.
34
+ * FormFieldWrapper component class.
35
+ * @class FormFieldWrapper
36
+ * @extends Component
38
37
  */
39
- const FormFieldWrapper = ({
40
- id,
41
- title,
42
- description = null,
43
- fieldSet,
44
- required = false,
45
- error = [],
46
- wrapped = true,
47
- columns = 2,
48
- draggable = null,
49
- onEdit,
50
- className,
51
- isDisabled = null,
52
- onDelete = null,
53
- noForInFieldLabel,
54
- multilingual_options,
55
- children,
56
- }) => {
57
- const intl = useIntl();
58
- const languageIndependent = multilingual_options?.language_independent;
38
+ class FormFieldWrapper extends Component {
39
+ /**
40
+ * Property types.
41
+ * @property {Object} propTypes Property types.
42
+ * @static
43
+ */
44
+ static propTypes = {
45
+ id: PropTypes.string.isRequired,
46
+ title: PropTypes.string.isRequired,
47
+ description: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
48
+ required: PropTypes.bool,
49
+ error: PropTypes.arrayOf(PropTypes.string),
50
+ wrapped: PropTypes.bool,
51
+ columns: PropTypes.number,
52
+ draggable: PropTypes.bool,
53
+ isDisabled: PropTypes.bool,
54
+ onEdit: PropTypes.func,
55
+ className: PropTypes.string,
56
+ onDelete: PropTypes.func,
57
+ intl: PropTypes.object,
58
+ };
59
+
60
+ /**
61
+ * Default properties
62
+ * @property {Object} defaultProps Default properties.
63
+ * @static
64
+ */
65
+ static defaultProps = {
66
+ description: null,
67
+ required: false,
68
+ error: [],
69
+ wrapped: true,
70
+ columns: 2,
71
+ onDelete: null,
72
+ intl: null,
73
+ isDisabled: null,
74
+ draggable: null,
75
+ };
76
+
77
+ /**
78
+ * Render method.
79
+ * @method render
80
+ * @returns {string} Markup for the component.
81
+ */
82
+ render() {
83
+ const {
84
+ id,
85
+ title,
86
+ description,
87
+ fieldSet,
88
+ required,
89
+ error,
90
+ wrapped,
91
+ columns,
92
+ draggable,
93
+ onEdit,
94
+ className,
95
+ isDisabled,
96
+ onDelete,
97
+ intl,
98
+ noForInFieldLabel,
99
+ multilingual_options,
100
+ } = this.props;
101
+
102
+ const languageIndependent = multilingual_options?.language_independent;
59
103
 
60
- const wdg = (
61
- <>
62
- {children}
104
+ const wdg = (
105
+ <>
106
+ {this.props.children}
63
107
 
64
- {map(error, (message) => (
65
- <Label key={message} basic color="red" className="form-error-label">
66
- {message}
67
- </Label>
68
- ))}
69
- </>
70
- );
108
+ {map(error, (message) => (
109
+ <Label key={message} basic color="red" className="form-error-label">
110
+ {message}
111
+ </Label>
112
+ ))}
113
+ </>
114
+ );
71
115
 
72
- return wrapped ? (
73
- <Form.Field
74
- inline
75
- required={required}
76
- error={error && error.length > 0}
77
- className={cx(
78
- description ? 'help' : '',
79
- className,
80
- `field-wrapper-${id}`,
81
- languageIndependent ? 'language-independent-field' : null,
82
- )}
83
- >
84
- <Grid>
85
- <Grid.Row stretched>
86
- {columns === 2 && (
87
- <Grid.Column width="4">
88
- <div className="wrapper">
89
- <label
90
- id={`fieldset-${fieldSet}-field-label-${id}`}
91
- htmlFor={noForInFieldLabel ? null : `field-${id}`}
92
- >
93
- {draggable && onEdit && (
94
- <i
95
- aria-hidden="true"
96
- className="grey bars icon drag handle"
97
- />
98
- )}
99
- {title}
100
- {languageIndependent && (
101
- <div className="languageIndependent-icon">
102
- <Icon
103
- title={intl.formatMessage(
104
- messages.language_independent_icon_title,
105
- )}
106
- name={LanguageSVG}
107
- size="24px"
108
- color="#555"
116
+ return wrapped ? (
117
+ <Form.Field
118
+ inline
119
+ required={required}
120
+ error={error && error.length > 0}
121
+ className={cx(
122
+ description ? 'help' : '',
123
+ className,
124
+ `field-wrapper-${id}`,
125
+ languageIndependent ? 'language-independent-field' : null,
126
+ )}
127
+ >
128
+ <Grid>
129
+ <Grid.Row stretched>
130
+ {columns === 2 && (
131
+ <Grid.Column width="4">
132
+ <div className="wrapper">
133
+ <label
134
+ id={`fieldset-${fieldSet}-field-label-${id}`}
135
+ htmlFor={noForInFieldLabel ? null : `field-${id}`}
136
+ >
137
+ {draggable && onEdit && (
138
+ <i
139
+ aria-hidden="true"
140
+ className="grey bars icon drag handle"
109
141
  />
110
- </div>
111
- )}
112
- </label>
113
- </div>
114
- </Grid.Column>
115
- )}
116
- <Grid.Column width={columns === 2 ? 8 : 12}>
117
- {onEdit && !isDisabled && (
118
- <div className="toolbar" style={{ zIndex: '2' }}>
119
- <button
120
- aria-label={intl.formatMessage(messages.edit)}
121
- className="item ui noborder button"
122
- onClick={(evt) => {
123
- evt.preventDefault();
124
- onEdit(id);
125
- }}
126
- >
127
- <IconOld name="write square" size="large" color="blue" />
128
- </button>
129
- <button
130
- aria-label={intl.formatMessage(messages.delete)}
131
- className="item ui noborder button"
132
- onClick={(evt) => {
133
- evt.preventDefault();
134
- onDelete(id);
135
- }}
136
- >
137
- <IconOld name="close" size="large" color="red" />
138
- </button>
139
- </div>
142
+ )}
143
+ {title}
144
+ {languageIndependent && (
145
+ <div className="languageIndependent-icon">
146
+ <Icon
147
+ title={intl.formatMessage(
148
+ messages.language_independent_icon_title,
149
+ )}
150
+ name={LanguageSVG}
151
+ size="24px"
152
+ color="#555"
153
+ />
154
+ </div>
155
+ )}
156
+ </label>
157
+ </div>
158
+ </Grid.Column>
140
159
  )}
141
- {wdg}
142
- </Grid.Column>
143
- </Grid.Row>
144
- {description && (
145
- <Grid.Row stretched>
146
- <Grid.Column stretched width="12">
147
- <p className="help">
148
- {multilingual_options
149
- ? `${intl.formatMessage(messages.language_independent)} `
150
- : null}
151
- {description}
152
- </p>
160
+ <Grid.Column width={columns === 2 ? 8 : 12}>
161
+ {onEdit && !isDisabled && (
162
+ <div className="toolbar" style={{ zIndex: '2' }}>
163
+ <button
164
+ aria-label={intl.formatMessage(messages.edit)}
165
+ className="item ui noborder button"
166
+ onClick={(evt) => {
167
+ evt.preventDefault();
168
+ onEdit(id);
169
+ }}
170
+ >
171
+ <IconOld name="write square" size="large" color="blue" />
172
+ </button>
173
+ <button
174
+ aria-label={intl.formatMessage(messages.delete)}
175
+ className="item ui noborder button"
176
+ onClick={(evt) => {
177
+ evt.preventDefault();
178
+ onDelete(id);
179
+ }}
180
+ >
181
+ <IconOld name="close" size="large" color="red" />
182
+ </button>
183
+ </div>
184
+ )}
185
+ {wdg}
153
186
  </Grid.Column>
154
187
  </Grid.Row>
155
- )}
156
- </Grid>
157
- </Form.Field>
158
- ) : (
159
- <>{wdg}</>
160
- );
161
- };
162
-
163
- /**
164
- * Property types.
165
- * @property {Object} propTypes Property types.
166
- */
167
- FormFieldWrapper.propTypes = {
168
- id: PropTypes.string.isRequired,
169
- title: PropTypes.string.isRequired,
170
- description: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
171
- required: PropTypes.bool,
172
- error: PropTypes.arrayOf(PropTypes.string),
173
- wrapped: PropTypes.bool,
174
- columns: PropTypes.number,
175
- draggable: PropTypes.bool,
176
- isDisabled: PropTypes.bool,
177
- onEdit: PropTypes.func,
178
- className: PropTypes.string,
179
- onDelete: PropTypes.func,
180
- fieldSet: PropTypes.string,
181
- noForInFieldLabel: PropTypes.bool,
182
- multilingual_options: PropTypes.object,
183
- children: PropTypes.node,
184
- };
188
+ {description && (
189
+ <Grid.Row stretched>
190
+ <Grid.Column stretched width="12">
191
+ <p className="help">
192
+ {this.props.multilingual_options
193
+ ? `${intl.formatMessage(messages.language_independent)} `
194
+ : null}
195
+ {description}
196
+ </p>
197
+ </Grid.Column>
198
+ </Grid.Row>
199
+ )}
200
+ </Grid>
201
+ </Form.Field>
202
+ ) : (
203
+ <>{wdg}</>
204
+ );
205
+ }
206
+ }
185
207
 
186
- export default FormFieldWrapper;
208
+ export default injectIntl(FormFieldWrapper);
@@ -117,7 +117,7 @@ export default function users(state = initialState, action = {}) {
117
117
  case `${LIST_USERS}_SUCCESS`:
118
118
  return {
119
119
  ...state,
120
- users: action.result,
120
+ users: action.result.items ? action.result.items : action.result,
121
121
  [getRequestKey(action.type)]: {
122
122
  loading: false,
123
123
  loaded: true,
@@ -391,8 +391,6 @@ button {
391
391
  }
392
392
 
393
393
  .users-control-panel .table {
394
- overflow-x: scroll;
395
-
396
394
  &::-webkit-scrollbar {
397
395
  width: 3px;
398
396
  height: 3px; /* scrollbar height */
@@ -1,28 +1,5 @@
1
- export default FormFieldWrapper;
2
- /**
3
- * FormFieldWrapper component.
4
- * @function FormFieldWrapper
5
- * @param {Object} props - Component props
6
- * @returns {JSX.Element} Markup for the component.
7
- */
8
- declare function FormFieldWrapper({ id, title, description, fieldSet, required, error, wrapped, columns, draggable, onEdit, className, isDisabled, onDelete, noForInFieldLabel, multilingual_options, children, }: any): JSX.Element;
9
- declare namespace FormFieldWrapper {
10
- namespace propTypes {
11
- let id: any;
12
- let title: any;
13
- let description: any;
14
- let required: any;
15
- let error: any;
16
- let wrapped: any;
17
- let columns: any;
18
- let draggable: any;
19
- let isDisabled: any;
20
- let onEdit: any;
21
- let className: any;
22
- let onDelete: any;
23
- let fieldSet: any;
24
- let noForInFieldLabel: any;
25
- let multilingual_options: any;
26
- let children: any;
27
- }
28
- }
1
+ declare const _default: React.FC<import("react-intl").WithIntlProps<any>> & {
2
+ WrappedComponent: React.ComponentType<any>;
3
+ };
4
+ export default _default;
5
+ import React from 'react';
@@ -121,4 +121,4 @@ export declare const ColorPickerWidget: import("@loadable/component").LoadableCo
121
121
  export declare const DatetimeWidget: import("@loadable/component").LoadableClassComponent<any>;
122
122
  export declare const TimeWidget: import("@loadable/component").LoadableClassComponent<any>;
123
123
  export declare const RecurrenceWidget: import("@loadable/component").LoadableClassComponent<any>;
124
- export declare const FormFieldWrapper: import("@loadable/component").LoadableComponent<any>;
124
+ export declare const FormFieldWrapper: import("@loadable/component").LoadableComponent<import("react-intl").WithIntlProps<any>>;