@plone/volto 19.0.0-alpha.32 → 19.0.0-alpha.34

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 (33) hide show
  1. package/AGENTS.md +47 -0
  2. package/CHANGELOG.md +27 -0
  3. package/README.md +0 -1
  4. package/package.json +16 -19
  5. package/src/actions/controlpanels/controlpanels.js +7 -12
  6. package/src/actions/controlpanels/controlpanels.test.js +2 -3
  7. package/src/components/manage/Contents/Contents.jsx +410 -323
  8. package/src/components/manage/Contents/Contents.test.jsx +1 -1
  9. package/src/components/manage/Contents/ContentsIndexHeader.jsx +47 -81
  10. package/src/components/manage/Contents/ContentsIndexHeader.test.jsx +10 -3
  11. package/src/components/manage/Contents/ContentsItem.jsx +226 -278
  12. package/src/components/manage/Contents/ContentsItem.test.jsx +10 -6
  13. package/src/components/manage/Controlpanels/ContentType.jsx +131 -222
  14. package/src/components/manage/Controlpanels/Controlpanel.jsx +122 -218
  15. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +1 -29
  16. package/src/components/manage/Form/Field.jsx +1 -69
  17. package/src/components/manage/Widgets/ArrayWidget.jsx +111 -88
  18. package/src/components/manage/Widgets/ArrayWidget.test.jsx +0 -6
  19. package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.jsx +56 -50
  20. package/src/components/manage/Widgets/SelectStyling.jsx +52 -20
  21. package/src/config/Loadables.jsx +1 -5
  22. package/src/server.jsx +7 -1
  23. package/theme/themes/default/globals/site.variables +3 -3
  24. package/theme/themes/pastanaga/extras/contents.less +0 -4
  25. package/theme/themes/pastanaga/globals/site.variables +0 -3
  26. package/types/components/manage/Contents/Contents.d.ts +1 -1
  27. package/types/components/manage/Contents/ContentsIndexHeader.d.ts +6 -11
  28. package/types/components/manage/Contents/ContentsItem.d.ts +3 -10
  29. package/types/components/manage/Controlpanels/ContentType.d.ts +2 -2
  30. package/types/components/manage/Controlpanels/Controlpanel.d.ts +2 -5
  31. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  32. package/types/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthIndexField.d.ts +22 -5
  33. package/types/components/manage/Widgets/SelectStyling.d.ts +1 -0
@@ -1,16 +1,10 @@
1
- /**
2
- * Content Type component.
3
- * @module components/manage/Controlpanels/ContentType
4
- */
5
-
6
- import React, { Component } from 'react';
7
- import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
9
- import { compose } from 'redux';
1
+ import { useEffect, useState, useRef } from 'react';
2
+ import { useDispatch, useSelector } from 'react-redux';
3
+ import { useHistory, useLocation } from 'react-router-dom';
10
4
  import { getParentUrl } from '@plone/volto/helpers/Url/Url';
11
5
  import { createPortal } from 'react-dom';
12
6
  import { Button, Header } from 'semantic-ui-react';
13
- import { defineMessages, injectIntl } from 'react-intl';
7
+ import { defineMessages, useIntl } from 'react-intl';
14
8
  import { toast } from 'react-toastify';
15
9
  import last from 'lodash/last';
16
10
  import nth from 'lodash/nth';
@@ -24,6 +18,7 @@ import {
24
18
  getControlpanel,
25
19
  updateControlpanel,
26
20
  } from '@plone/volto/actions/controlpanels/controlpanels';
21
+ import { useClient } from '@plone/volto/hooks/client/useClient';
27
22
 
28
23
  import saveSVG from '@plone/volto/icons/save.svg';
29
24
  import clearSVG from '@plone/volto/icons/clear.svg';
@@ -55,228 +50,142 @@ const messages = defineMessages({
55
50
  },
56
51
  });
57
52
 
58
- /**
59
- * ContentType class.
60
- * @class ContentType
61
- * @extends Component
62
- */
63
- class ContentType extends Component {
64
- /**
65
- * Property types.
66
- * @property {Object} propTypes Property types.
67
- * @static
68
- */
69
- static propTypes = {
70
- updateControlpanel: PropTypes.func.isRequired,
71
- getControlpanel: PropTypes.func.isRequired,
72
- id: PropTypes.string.isRequired,
73
- parent: PropTypes.string.isRequired,
74
- cpanelRequest: PropTypes.objectOf(PropTypes.any).isRequired,
75
- controlpanel: PropTypes.shape({
76
- '@id': PropTypes.string,
77
- data: PropTypes.object,
78
- schema: PropTypes.object,
79
- title: PropTypes.string,
80
- }),
81
- pathname: PropTypes.string.isRequired,
82
- };
83
-
84
- /**
85
- * Default properties.
86
- * @property {Object} defaultProps Default properties.
87
- * @static
88
- */
89
- static defaultProps = {
90
- controlpanel: null,
91
- };
92
-
93
- /**
94
- * Constructor
95
- * @method constructor
96
- * @param {Object} props Component properties
97
- * @constructs ContentType
98
- */
99
- constructor(props) {
100
- super(props);
101
-
102
- this.state = {
103
- visual: false,
104
- error: null,
105
- isClient: false,
106
- };
107
-
108
- this.onCancel = this.onCancel.bind(this);
109
- this.onSubmit = this.onSubmit.bind(this);
110
- this.form = React.createRef();
111
- }
112
-
113
- /**
114
- * Component did mount
115
- * @method componentDidMount
116
- * @returns {undefined}
117
- */
118
- componentDidMount() {
119
- this.props.getControlpanel(join([this.props.parent, this.props.id], '/'));
120
- this.setState({ isClient: true });
121
- }
122
-
123
- /**
124
- * Component will receive props
125
- * @method componentWillReceiveProps
126
- * @param {Object} nextProps Next properties
127
- * @returns {undefined}
128
- */
129
- UNSAFE_componentWillReceiveProps(nextProps) {
130
- // Control Panel GET
131
- if (
132
- this.props.cpanelRequest.get.loading &&
133
- nextProps.cpanelRequest.get.error
134
- ) {
135
- this.setState({
136
- error: nextProps.cpanelRequest.get.error,
53
+ function ContentType() {
54
+ const dispatch = useDispatch();
55
+ const intl = useIntl();
56
+ const isClient = useClient();
57
+ const history = useHistory();
58
+ const pathname = useLocation().pathname;
59
+
60
+ const controlpanel = useSelector((state) => state.controlpanels.controlpanel);
61
+ const cpanelRequest = useSelector((state) => state.controlpanels);
62
+
63
+ const id = last(pathname.split('/'));
64
+ const parent = nth(pathname.split('/'), -2);
65
+
66
+ const [visual] = useState(false);
67
+ const [error, setError] = useState(null);
68
+
69
+ const form = useRef(null);
70
+
71
+ useEffect(() => {
72
+ dispatch(getControlpanel(join([parent, id], '/'))).catch((err) => {
73
+ setError(err);
74
+ });
75
+ }, [dispatch, parent, id]);
76
+
77
+ const onSubmit = (data) => {
78
+ if (controlpanel?.['@id']) {
79
+ dispatch(updateControlpanel(controlpanel['@id'], data)).then(() => {
80
+ toast.info(
81
+ <Toast
82
+ info
83
+ title={intl.formatMessage(messages.info)}
84
+ content={intl.formatMessage(messages.changesSaved)}
85
+ />,
86
+ );
137
87
  });
138
88
  }
89
+ };
139
90
 
140
- // Control Panel PATCH
141
- if (
142
- this.props.cpanelRequest.update.loading &&
143
- nextProps.cpanelRequest.update.loaded
144
- ) {
145
- toast.info(
146
- <Toast
147
- info
148
- title={this.props.intl.formatMessage(messages.info)}
149
- content={this.props.intl.formatMessage(messages.changesSaved)}
150
- />,
151
- );
152
- }
153
- }
91
+ const onCancel = () => {
92
+ history.push(getParentUrl(pathname));
93
+ };
154
94
 
155
- /**
156
- * Submit handler
157
- * @method onSubmit
158
- * @param {object} data Form data.
159
- * @returns {undefined}
160
- */
161
- onSubmit(data) {
162
- this.props.updateControlpanel(this.props.controlpanel['@id'], data);
95
+ if (error) {
96
+ return <Error error={error} />;
163
97
  }
164
98
 
165
- /**
166
- * Cancel handler
167
- * @method onCancel
168
- * @returns {undefined}
169
- */
170
- onCancel() {
171
- this.props.history.push(getParentUrl(this.props.pathname));
172
- }
99
+ if (controlpanel?.data) {
100
+ const localControlpanel = {
101
+ ...controlpanel,
102
+ data: {
103
+ ...controlpanel.data,
104
+ },
105
+ };
173
106
 
174
- /**
175
- * Render method.
176
- * @method render
177
- * @returns {string} Markup for the component.
178
- */
179
- render() {
180
- // Error
181
- if (this.state.error) {
182
- return <Error error={this.state.error} />;
107
+ if (localControlpanel?.data?.filter_content_types === false) {
108
+ localControlpanel.data.filter_content_types = {
109
+ title: 'all',
110
+ token: 'all',
111
+ };
183
112
  }
184
-
185
- if (this.props.controlpanel?.data) {
186
- let controlpanel = this.props.controlpanel;
187
- if (controlpanel?.data?.filter_content_types === false) {
188
- controlpanel.data.filter_content_types = { title: 'all', token: 'all' };
113
+ if (localControlpanel?.data?.filter_content_types === true) {
114
+ if ((localControlpanel?.data?.allowed_content_types || []).length) {
115
+ localControlpanel.data.filter_content_types = {
116
+ title: 'some',
117
+ token: 'some',
118
+ };
119
+ } else {
120
+ localControlpanel.data.filter_content_types = {
121
+ title: 'none',
122
+ token: 'none',
123
+ };
189
124
  }
190
- if (controlpanel?.data?.filter_content_types === true) {
191
- if ((controlpanel?.data?.allowed_content_types || []).length) {
192
- controlpanel.data.filter_content_types = {
193
- title: 'some',
194
- token: 'some',
195
- };
196
- } else {
197
- controlpanel.data.filter_content_types = {
198
- title: 'none',
199
- token: 'none',
200
- };
201
- }
202
- }
203
- return (
204
- <div id="page-controlpanel" className="ui container">
205
- <Header disabled>
206
- {this.props.intl.formatMessage(messages.title, {
207
- id: controlpanel.title,
208
- })}
209
- </Header>
210
- <Form
211
- isEditForm
212
- ref={this.form}
213
- schema={controlpanel.schema}
214
- formData={controlpanel.data}
215
- onSubmit={this.onSubmit}
216
- onCancel={this.onCancel}
217
- pathname={this.props.pathname}
218
- visual={this.state.visual}
219
- hideActions
220
- loading={this.props.cpanelRequest.update.loading}
221
- />
222
- {this.state.isClient &&
223
- createPortal(
224
- <Toolbar
225
- pathname={this.props.pathname}
226
- hideDefaultViewButtons
227
- inner={
228
- <>
229
- <Button
230
- id="toolbar-save"
231
- className="save"
232
- aria-label={this.props.intl.formatMessage(messages.save)}
233
- onClick={() => this.form.current.onSubmit()}
234
- disabled={this.props.cpanelRequest.update.loading}
235
- loading={this.props.cpanelRequest.update.loading}
236
- >
237
- <Icon
238
- name={saveSVG}
239
- className="circled"
240
- size="30px"
241
- title={this.props.intl.formatMessage(messages.save)}
242
- />
243
- </Button>
244
- <Button
245
- className="cancel"
246
- aria-label={this.props.intl.formatMessage(
247
- messages.cancel,
248
- )}
249
- onClick={() => this.onCancel()}
250
- >
251
- <Icon
252
- name={clearSVG}
253
- className="circled"
254
- size="30px"
255
- title={this.props.intl.formatMessage(messages.cancel)}
256
- />
257
- </Button>
258
- </>
259
- }
260
- />,
261
- document.getElementById('toolbar'),
262
- )}
263
- </div>
264
- );
265
125
  }
266
- return <div />;
126
+
127
+ return (
128
+ <div id="page-controlpanel" className="ui container">
129
+ <Header disabled>
130
+ {intl.formatMessage(messages.title, {
131
+ id: localControlpanel.title,
132
+ })}
133
+ </Header>
134
+ <Form
135
+ isEditForm
136
+ ref={form}
137
+ schema={localControlpanel.schema}
138
+ formData={localControlpanel.data}
139
+ onSubmit={onSubmit}
140
+ onCancel={onCancel}
141
+ pathname={pathname}
142
+ visual={visual}
143
+ hideActions
144
+ loading={cpanelRequest.update?.loading}
145
+ />
146
+ {isClient &&
147
+ createPortal(
148
+ <Toolbar
149
+ pathname={pathname}
150
+ hideDefaultViewButtons
151
+ inner={
152
+ <>
153
+ <Button
154
+ id="toolbar-save"
155
+ className="save"
156
+ aria-label={intl.formatMessage(messages.save)}
157
+ onClick={() => form.current.onSubmit()}
158
+ disabled={cpanelRequest.update?.loading}
159
+ loading={cpanelRequest.update?.loading}
160
+ >
161
+ <Icon
162
+ name={saveSVG}
163
+ className="circled"
164
+ size="30px"
165
+ title={intl.formatMessage(messages.save)}
166
+ />
167
+ </Button>
168
+ <Button
169
+ className="cancel"
170
+ aria-label={intl.formatMessage(messages.cancel)}
171
+ onClick={() => onCancel()}
172
+ >
173
+ <Icon
174
+ name={clearSVG}
175
+ className="circled"
176
+ size="30px"
177
+ title={intl.formatMessage(messages.cancel)}
178
+ />
179
+ </Button>
180
+ </>
181
+ }
182
+ />,
183
+ document.getElementById('toolbar'),
184
+ )}
185
+ </div>
186
+ );
267
187
  }
188
+ return <div />;
268
189
  }
269
190
 
270
- export default compose(
271
- injectIntl,
272
- connect(
273
- (state, props) => ({
274
- controlpanel: state.controlpanels.controlpanel,
275
- cpanelRequest: state.controlpanels,
276
- pathname: props.location.pathname,
277
- id: last(props.location.pathname.split('/')),
278
- parent: nth(props.location.pathname.split('/'), -2),
279
- }),
280
- { getControlpanel, updateControlpanel },
281
- ),
282
- )(ContentType);
191
+ export default ContentType;