@plone/volto 17.0.0-alpha.5 → 17.0.0-alpha.7
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/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +91 -13
- package/CONTRIBUTING.md +1 -1
- package/README.md +4 -4
- package/locales/de/LC_MESSAGES/volto.po +17 -17
- package/locales/de.json +1 -1
- package/package.json +3 -2
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/language/language.js +8 -8
- package/src/components/manage/Add/Add.jsx +2 -2
- package/src/components/manage/Blocks/Listing/Edit.jsx +0 -14
- package/src/components/manage/Blocks/Listing/getAsyncData.js +10 -2
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -13
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
- package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
- package/src/components/manage/Contents/Contents.jsx +16 -14
- package/src/components/manage/Controlpanels/Controlpanels.jsx +190 -224
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
- package/src/components/manage/Form/InlineForm.jsx +39 -9
- package/src/components/manage/Form/InlineFormState.js +8 -0
- package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
- package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
- package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
- package/src/components/manage/Toolbar/Types.jsx +2 -2
- package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
- package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
- package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +7 -2
- package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
- package/src/components/theme/Footer/Footer.jsx +2 -13
- package/src/components/theme/Icon/Icon.jsx +2 -2
- package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
- package/src/components/theme/Login/Login.jsx +1 -0
- package/src/components/theme/Logo/Logo.jsx +2 -1
- package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
- package/src/components/theme/Navigation/NavItem.jsx +4 -2
- package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
- package/src/components/theme/View/EventDatesInfo.jsx +2 -1
- package/src/components/theme/Widgets/DateWidget.jsx +2 -1
- package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
- package/src/config/index.js +1 -0
- package/src/helpers/Robots/Robots.js +16 -1
- package/src/helpers/Url/Url.js +8 -3
- package/src/helpers/Url/Url.test.js +14 -0
- package/src/helpers/Utils/Utils.js +38 -13
- package/src/helpers/Utils/Utils.test.js +4 -4
- package/src/helpers/index.js +7 -2
- package/src/middleware/Api.test.js +54 -0
- package/src/middleware/api.js +8 -4
- package/src/server.jsx +28 -23
- package/test-setup-config.js +1 -0
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
- package/.changelog.draft +0 -13
- package/.editorconfig +0 -36
- package/.storybook/main.js +0 -127
- package/.storybook/manager.js +0 -15
- package/.storybook/preview.js +0 -21
- package/.storybook/static/previewImage.svg +0 -48
- package/.vale.ini +0 -10
- package/.yarnrc.yml +0 -5
- package/jsdoc.json +0 -16
- package/netlify.toml +0 -5
- package/pyvenv.cfg +0 -3
- package/share/man/man1/ttx.1 +0 -225
- package/styles/Vocab/Base/accept.txt +0 -0
- package/styles/Vocab/Base/reject.txt +0 -0
- package/styles/Vocab/Plone/accept.txt +0 -10
- package/styles/Vocab/Plone/reject.txt +0 -5
- package/towncrier.toml +0 -33
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* @module components/manage/Controlpanels/Controlpanels
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React, { Component } from 'react';
|
|
7
6
|
import PropTypes from 'prop-types';
|
|
7
|
+
import { useState, useEffect } from 'react';
|
|
8
8
|
import { connect } from 'react-redux';
|
|
9
9
|
import { compose } from 'redux';
|
|
10
10
|
import { Link } from 'react-router-dom';
|
|
11
11
|
import { concat, filter, last, map, uniqBy } from 'lodash';
|
|
12
12
|
import { Portal } from 'react-portal';
|
|
13
|
-
import { Helmet } from '@plone/volto/helpers';
|
|
13
|
+
import { asyncConnect, Helmet } from '@plone/volto/helpers';
|
|
14
14
|
import { Container, Grid, Header, Message, Segment } from 'semantic-ui-react';
|
|
15
|
-
import { FormattedMessage, defineMessages,
|
|
15
|
+
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
16
16
|
|
|
17
17
|
import { listControlpanels, getSystemInformation } from '@plone/volto/actions';
|
|
18
18
|
import { Error, Icon, Toolbar, VersionOverview } from '@plone/volto/components';
|
|
@@ -94,185 +94,126 @@ const messages = defineMessages({
|
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Controlpanels container class.
|
|
97
|
-
* @class Controlpanels
|
|
98
|
-
* @extends Component
|
|
99
97
|
*/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
controlpanels: PropTypes.arrayOf(
|
|
109
|
-
PropTypes.shape({
|
|
110
|
-
'@id': PropTypes.string,
|
|
111
|
-
group: PropTypes.string,
|
|
112
|
-
title: PropTypes.string,
|
|
113
|
-
}),
|
|
114
|
-
).isRequired,
|
|
115
|
-
pathname: PropTypes.string.isRequired,
|
|
116
|
-
};
|
|
98
|
+
function Controlpanels({
|
|
99
|
+
controlpanels,
|
|
100
|
+
controlpanelsRequest,
|
|
101
|
+
systemInformation,
|
|
102
|
+
pathname,
|
|
103
|
+
}) {
|
|
104
|
+
const intl = useIntl();
|
|
105
|
+
const [isClient, setIsClient] = useState(false);
|
|
117
106
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
* @param {Object} props Component properties
|
|
122
|
-
* @constructs EditComponent
|
|
123
|
-
*/
|
|
124
|
-
constructor(props) {
|
|
125
|
-
super(props);
|
|
126
|
-
this.state = {
|
|
127
|
-
error: null,
|
|
128
|
-
isClient: false,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
setIsClient(true);
|
|
109
|
+
}, []);
|
|
131
110
|
|
|
132
|
-
|
|
133
|
-
* Component did mount
|
|
134
|
-
* @method componentDidMount
|
|
135
|
-
* @returns {undefined}
|
|
136
|
-
*/
|
|
137
|
-
componentDidMount() {
|
|
138
|
-
this.props.listControlpanels();
|
|
139
|
-
this.props.getSystemInformation();
|
|
140
|
-
this.setState({ isClient: true });
|
|
141
|
-
}
|
|
111
|
+
const error = controlpanelsRequest?.error;
|
|
142
112
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
this.props.controlpanelsRequest.loading &&
|
|
147
|
-
nextProps.controlpanelsRequest.error
|
|
148
|
-
) {
|
|
149
|
-
this.setState({
|
|
150
|
-
error: nextProps.controlpanelsRequest.error,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
113
|
+
if (error) {
|
|
114
|
+
return <Error error={error} />;
|
|
153
115
|
}
|
|
154
116
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
117
|
+
let customcontrolpanels = config.settings.controlpanels
|
|
118
|
+
? config.settings.controlpanels.map((el) => {
|
|
119
|
+
el.group =
|
|
120
|
+
intl.formatMessage({
|
|
121
|
+
id: el.group,
|
|
122
|
+
defaultMessage: el.group,
|
|
123
|
+
}) || el.group;
|
|
124
|
+
return el;
|
|
125
|
+
})
|
|
126
|
+
: [];
|
|
127
|
+
const { filterControlPanels } = config.settings;
|
|
165
128
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
group: this.props.intl.formatMessage(
|
|
222
|
-
messages.usersControlPanelCategory,
|
|
223
|
-
),
|
|
224
|
-
title: this.props.intl.formatMessage(
|
|
225
|
-
messages.usergroupmemberbership,
|
|
226
|
-
),
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
'@id': '/groups',
|
|
230
|
-
group: this.props.intl.formatMessage(
|
|
231
|
-
messages.usersControlPanelCategory,
|
|
232
|
-
),
|
|
233
|
-
title: this.props.intl.formatMessage(messages.groups),
|
|
234
|
-
},
|
|
235
|
-
],
|
|
236
|
-
),
|
|
237
|
-
(controlpanel) => ({
|
|
238
|
-
...controlpanel,
|
|
239
|
-
id: last(controlpanel['@id'].split('/')),
|
|
240
|
-
}),
|
|
241
|
-
);
|
|
242
|
-
const groups = map(uniqBy(controlpanels, 'group'), 'group');
|
|
243
|
-
const { controlPanelsIcons: icons } = config.settings;
|
|
129
|
+
const filteredControlPanels = map(
|
|
130
|
+
concat(filterControlPanels(controlpanels), customcontrolpanels, [
|
|
131
|
+
{
|
|
132
|
+
'@id': '/addons',
|
|
133
|
+
group: intl.formatMessage(messages.general),
|
|
134
|
+
title: intl.formatMessage(messages.addons),
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
'@id': '/database',
|
|
138
|
+
group: intl.formatMessage(messages.general),
|
|
139
|
+
title: intl.formatMessage(messages.database),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
'@id': '/rules',
|
|
143
|
+
group: intl.formatMessage(messages.content),
|
|
144
|
+
title: intl.formatMessage(messages.contentRules),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
'@id': '/undo',
|
|
148
|
+
group: intl.formatMessage(messages.general),
|
|
149
|
+
title: intl.formatMessage(messages.undo),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
'@id': '/aliases',
|
|
153
|
+
group: intl.formatMessage(messages.general),
|
|
154
|
+
title: intl.formatMessage(messages.urlmanagement),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
'@id': '/moderate-comments',
|
|
158
|
+
group: intl.formatMessage(messages.content),
|
|
159
|
+
title: intl.formatMessage(messages.moderatecomments),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
'@id': '/users',
|
|
163
|
+
group: intl.formatMessage(messages.usersControlPanelCategory),
|
|
164
|
+
title: intl.formatMessage(messages.users),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
'@id': '/usergroupmembership',
|
|
168
|
+
group: intl.formatMessage(messages.usersControlPanelCategory),
|
|
169
|
+
title: intl.formatMessage(messages.usergroupmemberbership),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
'@id': '/groups',
|
|
173
|
+
group: intl.formatMessage(messages.usersControlPanelCategory),
|
|
174
|
+
title: intl.formatMessage(messages.groups),
|
|
175
|
+
},
|
|
176
|
+
]),
|
|
177
|
+
(controlpanel) => ({
|
|
178
|
+
...controlpanel,
|
|
179
|
+
id: last(controlpanel['@id'].split('/')),
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
const groups = map(uniqBy(filteredControlPanels, 'group'), 'group');
|
|
183
|
+
const { controlPanelsIcons: icons } = config.settings;
|
|
244
184
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
{
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<
|
|
273
|
-
<Grid
|
|
274
|
-
|
|
275
|
-
|
|
185
|
+
return (
|
|
186
|
+
<div className="view-wrapper">
|
|
187
|
+
<Helmet title={intl.formatMessage(messages.sitesetup)} />
|
|
188
|
+
<Container className="controlpanel">
|
|
189
|
+
<Segment.Group raised>
|
|
190
|
+
<Segment className="primary">
|
|
191
|
+
<FormattedMessage id="Site Setup" defaultMessage="Site Setup" />
|
|
192
|
+
</Segment>
|
|
193
|
+
{systemInformation && systemInformation.upgrade && (
|
|
194
|
+
<Message attached warning>
|
|
195
|
+
<FormattedMessage
|
|
196
|
+
id="The site configuration is outdated and needs to be upgraded."
|
|
197
|
+
defaultMessage="The site configuration is outdated and needs to be upgraded."
|
|
198
|
+
/>{' '}
|
|
199
|
+
<Link to={`/controlpanel/plone-upgrade`}>
|
|
200
|
+
<FormattedMessage
|
|
201
|
+
id="Please continue with the upgrade."
|
|
202
|
+
defaultMessage="Please continue with the upgrade."
|
|
203
|
+
/>
|
|
204
|
+
</Link>
|
|
205
|
+
</Message>
|
|
206
|
+
)}
|
|
207
|
+
{map(groups, (group) => [
|
|
208
|
+
<Segment key={`header-${group}`} secondary>
|
|
209
|
+
{group}
|
|
210
|
+
</Segment>,
|
|
211
|
+
<Segment key={`body-${group}`} attached>
|
|
212
|
+
<Grid doubling columns={6}>
|
|
213
|
+
<Grid.Row>
|
|
214
|
+
{map(
|
|
215
|
+
filter(filteredControlPanels, { group }),
|
|
216
|
+
(controlpanel) => (
|
|
276
217
|
<Grid.Column key={controlpanel.id}>
|
|
277
218
|
<Link to={`/controlpanel/${controlpanel.id}`}>
|
|
278
219
|
<Header as="h3" icon textAlign="center">
|
|
@@ -286,58 +227,83 @@ class Controlpanels extends Component {
|
|
|
286
227
|
</Header>
|
|
287
228
|
</Link>
|
|
288
229
|
</Grid.Column>
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
</Grid>
|
|
292
|
-
</
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
</Segment>
|
|
302
|
-
<Segment attached>
|
|
303
|
-
{this.props.systemInformation ? (
|
|
304
|
-
<VersionOverview {...this.props.systemInformation} />
|
|
305
|
-
) : null}
|
|
306
|
-
</Segment>
|
|
307
|
-
</Segment.Group>
|
|
308
|
-
</Container>
|
|
309
|
-
{this.state.isClient && (
|
|
310
|
-
<Portal node={document.getElementById('toolbar')}>
|
|
311
|
-
<Toolbar
|
|
312
|
-
pathname={this.props.pathname}
|
|
313
|
-
hideDefaultViewButtons
|
|
314
|
-
inner={
|
|
315
|
-
<Link to="/" className="item">
|
|
316
|
-
<Icon
|
|
317
|
-
name={backSVG}
|
|
318
|
-
className="contents circled"
|
|
319
|
-
size="30px"
|
|
320
|
-
title={this.props.intl.formatMessage(messages.back)}
|
|
321
|
-
/>
|
|
322
|
-
</Link>
|
|
323
|
-
}
|
|
230
|
+
),
|
|
231
|
+
)}
|
|
232
|
+
</Grid.Row>
|
|
233
|
+
</Grid>
|
|
234
|
+
</Segment>,
|
|
235
|
+
])}
|
|
236
|
+
</Segment.Group>
|
|
237
|
+
<Segment.Group raised>
|
|
238
|
+
<Segment className="primary">
|
|
239
|
+
<FormattedMessage
|
|
240
|
+
id="Version Overview"
|
|
241
|
+
defaultMessage="Version Overview"
|
|
324
242
|
/>
|
|
325
|
-
</
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
243
|
+
</Segment>
|
|
244
|
+
<Segment attached>
|
|
245
|
+
{systemInformation ? (
|
|
246
|
+
<VersionOverview {...systemInformation} />
|
|
247
|
+
) : null}
|
|
248
|
+
</Segment>
|
|
249
|
+
</Segment.Group>
|
|
250
|
+
</Container>
|
|
251
|
+
{isClient && (
|
|
252
|
+
<Portal node={document.getElementById('toolbar')}>
|
|
253
|
+
<Toolbar
|
|
254
|
+
pathname={pathname}
|
|
255
|
+
hideDefaultViewButtons
|
|
256
|
+
inner={
|
|
257
|
+
<Link to="/" className="item">
|
|
258
|
+
<Icon
|
|
259
|
+
name={backSVG}
|
|
260
|
+
className="contents circled"
|
|
261
|
+
size="30px"
|
|
262
|
+
title={intl.formatMessage(messages.back)}
|
|
263
|
+
/>
|
|
264
|
+
</Link>
|
|
265
|
+
}
|
|
266
|
+
/>
|
|
267
|
+
</Portal>
|
|
268
|
+
)}
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
330
271
|
}
|
|
331
272
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Property types.
|
|
275
|
+
* @property {Object} propTypes Property types.
|
|
276
|
+
* @static
|
|
277
|
+
*/
|
|
278
|
+
Controlpanels.propTypes = {
|
|
279
|
+
controlpanels: PropTypes.arrayOf(
|
|
280
|
+
PropTypes.shape({
|
|
281
|
+
'@id': PropTypes.string,
|
|
282
|
+
group: PropTypes.string,
|
|
283
|
+
title: PropTypes.string,
|
|
340
284
|
}),
|
|
341
|
-
|
|
342
|
-
|
|
285
|
+
).isRequired,
|
|
286
|
+
pathname: PropTypes.string.isRequired,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export default compose(
|
|
290
|
+
connect((state, props) => ({
|
|
291
|
+
controlpanels: state.controlpanels.controlpanels,
|
|
292
|
+
controlpanelsRequest: state.controlpanels.list,
|
|
293
|
+
pathname: props.location.pathname,
|
|
294
|
+
systemInformation: state.controlpanels.systeminformation,
|
|
295
|
+
})),
|
|
296
|
+
|
|
297
|
+
asyncConnect([
|
|
298
|
+
{
|
|
299
|
+
key: 'controlpanels',
|
|
300
|
+
promise: async ({ location, store: { dispatch } }) =>
|
|
301
|
+
await dispatch(listControlpanels()),
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
key: 'systemInformation',
|
|
305
|
+
promise: async ({ location, store: { dispatch } }) =>
|
|
306
|
+
await dispatch(getSystemInformation()),
|
|
307
|
+
},
|
|
308
|
+
]),
|
|
343
309
|
)(Controlpanels);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import renderer from 'react-test-renderer';
|
|
3
|
-
import configureStore from 'redux-mock-store';
|
|
4
2
|
import { Provider } from 'react-intl-redux';
|
|
5
3
|
import { MemoryRouter } from 'react-router-dom';
|
|
4
|
+
import renderer from 'react-test-renderer';
|
|
5
|
+
import configureStore from 'redux-mock-store';
|
|
6
6
|
|
|
7
|
-
import Controlpanels from './Controlpanels';
|
|
8
7
|
import config from '@plone/volto/registry';
|
|
8
|
+
import Controlpanels from './Controlpanels';
|
|
9
9
|
|
|
10
10
|
const mockStore = configureStore();
|
|
11
11
|
|
|
@@ -20,7 +20,30 @@ jest.mock('./VersionOverview', () =>
|
|
|
20
20
|
describe('Controlpanels', () => {
|
|
21
21
|
it('renders a controlpanels component', () => {
|
|
22
22
|
const store = mockStore({
|
|
23
|
-
controlpanels:
|
|
23
|
+
controlpanels: [
|
|
24
|
+
{
|
|
25
|
+
'@id': 'http://localhost:8080/Plone/@controlpanels/date-and-time',
|
|
26
|
+
group: 'General',
|
|
27
|
+
title: 'Date and Time',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
'@id': 'http://localhost:8080/Plone/@controlpanels/lang',
|
|
31
|
+
group: 'General',
|
|
32
|
+
title: 'Language',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
'@id': 'http://localhost:8080/Plone/@controlpanels/editing',
|
|
36
|
+
group: 'Content',
|
|
37
|
+
title: 'Editing',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
'@id': 'http://localhost:8080/Plone/@controlpanels/security',
|
|
41
|
+
group: 'Security',
|
|
42
|
+
title: 'test',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
reduxAsyncConnect: {
|
|
46
|
+
// Mocked in redux async connect as it isn't fetch client-side.
|
|
24
47
|
controlpanels: [
|
|
25
48
|
{
|
|
26
49
|
'@id': 'http://localhost:8080/Plone/@controlpanels/date-and-time',
|
|
@@ -40,10 +63,11 @@ describe('Controlpanels', () => {
|
|
|
40
63
|
{
|
|
41
64
|
'@id': 'http://localhost:8080/Plone/@controlpanels/security',
|
|
42
65
|
group: 'Security',
|
|
43
|
-
title: '
|
|
66
|
+
title: 'test',
|
|
44
67
|
},
|
|
45
68
|
],
|
|
46
69
|
},
|
|
70
|
+
router: { location: '/blog' },
|
|
47
71
|
intl: {
|
|
48
72
|
locale: 'en',
|
|
49
73
|
messages: {},
|
|
@@ -62,9 +86,24 @@ describe('Controlpanels', () => {
|
|
|
62
86
|
|
|
63
87
|
it('renders an additional control panel', () => {
|
|
64
88
|
const store = mockStore({
|
|
65
|
-
controlpanels:
|
|
66
|
-
|
|
89
|
+
controlpanels: [
|
|
90
|
+
{
|
|
91
|
+
'@id': 'http://localhost:8080/Plone/@controlpanels/security',
|
|
92
|
+
group: 'Security',
|
|
93
|
+
title: 'test',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
reduxAsyncConnect: {
|
|
97
|
+
// Mocked in redux async connect as it isn't fetch client-side.
|
|
98
|
+
controlpanels: [
|
|
99
|
+
{
|
|
100
|
+
'@id': 'http://localhost:8080/Plone/@controlpanels/security',
|
|
101
|
+
group: 'Security',
|
|
102
|
+
title: 'test',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
67
105
|
},
|
|
106
|
+
router: { location: '/blog' },
|
|
68
107
|
intl: {
|
|
69
108
|
locale: 'en',
|
|
70
109
|
messages: {},
|
|
@@ -4,13 +4,21 @@ import { Accordion, Segment, Message } from 'semantic-ui-react';
|
|
|
4
4
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
5
5
|
import AnimateHeight from 'react-animate-height';
|
|
6
6
|
import { keys, map, isEqual } from 'lodash';
|
|
7
|
-
|
|
7
|
+
import { useAtom } from 'jotai';
|
|
8
|
+
import { inlineFormFieldsetsState } from './InlineFormState';
|
|
9
|
+
import {
|
|
10
|
+
insertInArray,
|
|
11
|
+
removeFromArray,
|
|
12
|
+
arrayRange,
|
|
13
|
+
} from '@plone/volto/helpers/Utils/Utils';
|
|
8
14
|
import { Field, Icon } from '@plone/volto/components';
|
|
9
15
|
import { applySchemaDefaults } from '@plone/volto/helpers';
|
|
10
16
|
|
|
11
17
|
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
12
18
|
import downSVG from '@plone/volto/icons/down-key.svg';
|
|
13
19
|
|
|
20
|
+
import config from '@plone/volto/registry';
|
|
21
|
+
|
|
14
22
|
const messages = defineMessages({
|
|
15
23
|
editValues: {
|
|
16
24
|
id: 'Edit values',
|
|
@@ -70,12 +78,34 @@ const InlineForm = (props) => {
|
|
|
70
78
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
71
79
|
}, []);
|
|
72
80
|
|
|
73
|
-
const [currentActiveFieldset, setCurrentActiveFieldset] =
|
|
81
|
+
const [currentActiveFieldset, setCurrentActiveFieldset] = useAtom(
|
|
82
|
+
inlineFormFieldsetsState({
|
|
83
|
+
name: block,
|
|
84
|
+
fielsetList: other,
|
|
85
|
+
initialState: config.settings.blockSettingsTabFieldsetsInitialStateOpen
|
|
86
|
+
? arrayRange(0, other.length - 1, 1)
|
|
87
|
+
: [],
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
|
|
74
91
|
function handleCurrentActiveFieldset(e, blockProps) {
|
|
75
92
|
const { index } = blockProps;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
if (currentActiveFieldset.includes(index)) {
|
|
94
|
+
setCurrentActiveFieldset(
|
|
95
|
+
removeFromArray(
|
|
96
|
+
currentActiveFieldset,
|
|
97
|
+
currentActiveFieldset.indexOf(index),
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
} else {
|
|
101
|
+
setCurrentActiveFieldset(
|
|
102
|
+
insertInArray(
|
|
103
|
+
currentActiveFieldset,
|
|
104
|
+
index,
|
|
105
|
+
currentActiveFieldset.length + 1,
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
79
109
|
}
|
|
80
110
|
|
|
81
111
|
return (
|
|
@@ -136,22 +166,22 @@ const InlineForm = (props) => {
|
|
|
136
166
|
<Accordion fluid styled className="form" key={fieldset.id}>
|
|
137
167
|
<div key={fieldset.id} id={`blockform-fieldset-${fieldset.id}`}>
|
|
138
168
|
<Accordion.Title
|
|
139
|
-
active={currentActiveFieldset
|
|
169
|
+
active={currentActiveFieldset.includes(index)}
|
|
140
170
|
index={index}
|
|
141
171
|
onClick={handleCurrentActiveFieldset}
|
|
142
172
|
>
|
|
143
173
|
{fieldset.title && <>{fieldset.title}</>}
|
|
144
|
-
{currentActiveFieldset
|
|
174
|
+
{currentActiveFieldset.includes(index) ? (
|
|
145
175
|
<Icon name={upSVG} size="20px" />
|
|
146
176
|
) : (
|
|
147
177
|
<Icon name={downSVG} size="20px" />
|
|
148
178
|
)}
|
|
149
179
|
</Accordion.Title>
|
|
150
|
-
<Accordion.Content active={currentActiveFieldset
|
|
180
|
+
<Accordion.Content active={currentActiveFieldset.includes(index)}>
|
|
151
181
|
<AnimateHeight
|
|
152
182
|
animateOpacity
|
|
153
183
|
duration={500}
|
|
154
|
-
height={currentActiveFieldset
|
|
184
|
+
height={currentActiveFieldset.includes(index) ? 'auto' : 0}
|
|
155
185
|
>
|
|
156
186
|
<Segment className="attached">
|
|
157
187
|
{map(fieldset.fields, (field) => (
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { atom } from 'jotai';
|
|
2
|
+
import { atomFamily } from 'jotai/utils';
|
|
3
|
+
import { isEqual } from 'lodash';
|
|
4
|
+
|
|
5
|
+
export const inlineFormFieldsetsState = atomFamily(
|
|
6
|
+
({ name, initialState }) => atom(initialState),
|
|
7
|
+
(a, b) => a.name === b.name && isEqual(a.fielsetList, b.fielsetList),
|
|
8
|
+
);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getTranslationLocator,
|
|
7
7
|
getContent,
|
|
8
8
|
} from '@plone/volto/actions';
|
|
9
|
-
import { flattenToAppURL,
|
|
9
|
+
import { flattenToAppURL, toGettextLang } from '@plone/volto/helpers';
|
|
10
10
|
import config from '@plone/volto/registry';
|
|
11
11
|
|
|
12
12
|
const CreateTranslation = (props) => {
|
|
@@ -33,7 +33,7 @@ const CreateTranslation = (props) => {
|
|
|
33
33
|
return () => {
|
|
34
34
|
// We change the interface language
|
|
35
35
|
if (config.settings.supportedLanguages.includes(language)) {
|
|
36
|
-
const langFileName =
|
|
36
|
+
const langFileName = toGettextLang(language);
|
|
37
37
|
import('@root/../locales/' + langFileName + '.json').then((locale) => {
|
|
38
38
|
dispatch(changeLanguage(language, locale.default));
|
|
39
39
|
});
|