@plone/volto 17.0.0-alpha.24 → 17.0.0-alpha.26
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 +92 -4
- package/CONTRIBUTING.md +5 -1
- package/README.md +9 -7
- package/cypress/support/commands.js +12 -9
- package/cypress.config.js +1 -0
- package/locales/ca/LC_MESSAGES/volto.po +41 -15
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +41 -15
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +40 -14
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +69 -43
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +40 -14
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +40 -14
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +41 -15
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +40 -14
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +40 -14
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +41 -15
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +41 -15
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +40 -14
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +41 -15
- package/locales/ro.json +1 -1
- package/locales/volto.pot +41 -15
- package/locales/zh_CN/LC_MESSAGES/volto.po +41 -15
- package/locales/zh_CN.json +1 -1
- package/package.json +4 -4
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +90 -0
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +6 -0
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +6 -0
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +6 -0
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +10 -0
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +10 -0
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +30 -0
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +10 -0
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +6 -0
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +6 -0
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/editor/render.jsx +2 -3
- package/src/actions/index.js +4 -0
- package/src/actions/navroot/navroot.js +16 -0
- package/src/actions/navroot/navroot.test.js +15 -0
- package/src/actions/relations/relations.js +17 -0
- package/src/actions/site/site.js +16 -0
- package/src/actions/site/site.test.js +15 -0
- package/src/actions/userSession/userSession.js +17 -1
- package/src/components/manage/Blocks/Block/Settings.jsx +2 -0
- package/src/components/manage/Blocks/Block/Settings.test.jsx +90 -0
- package/src/components/manage/Blocks/Image/schema.js +5 -1
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -11
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +42 -25
- package/src/components/manage/Blocks/ToC/View.jsx +75 -13
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +4 -13
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +44 -0
- package/src/components/manage/Contents/Contents.jsx +27 -0
- package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +65 -38
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +11 -9
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +3 -3
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +8 -7
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +15 -9
- package/src/components/manage/Controlpanels/Rules/AddRule.jsx +1 -1
- package/src/components/manage/Controlpanels/Rules/EditRule.jsx +1 -1
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +95 -5
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +127 -99
- package/src/components/manage/Diff/DiffField.jsx +25 -1
- package/src/components/manage/Form/BlockDataForm.jsx +3 -2
- package/src/components/manage/Form/BlockDataForm.test.jsx +34 -2
- package/src/components/manage/LinksToItem/LinksToItem.jsx +1 -1
- package/src/components/manage/LinksToItem/LinksToItem.test.jsx +5 -2
- package/src/components/manage/Messages/Messages.jsx +32 -99
- package/src/components/manage/Messages/Messages.test.jsx +0 -1
- package/src/components/manage/Sharing/Sharing.jsx +50 -21
- package/src/components/manage/UniversalLink/UniversalLink.jsx +4 -6
- package/src/components/manage/Widgets/ArrayWidget.jsx +3 -1
- package/src/components/manage/Widgets/ArrayWidget.test.jsx +45 -1
- package/src/components/manage/Widgets/FormFieldWrapper.jsx +1 -1
- package/src/components/manage/Widgets/RegistryImageWidget.jsx +210 -0
- package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +91 -0
- package/src/components/manage/Widgets/SelectWidget.jsx +15 -1
- package/src/components/manage/Widgets/SelectWidget.test.jsx +45 -1
- package/src/components/theme/Comments/Comment.stories.jsx +84 -0
- package/src/components/theme/Comments/Comments.jsx +273 -378
- package/src/components/theme/ContentMetadataTags/ContentMetadataTags.jsx +37 -3
- package/src/components/theme/Login/Login.jsx +159 -241
- package/src/components/theme/Logo/Logo.Multilingual.test.jsx +131 -1
- package/src/components/theme/Logo/Logo.jsx +35 -29
- package/src/components/theme/Logo/Logo.test.jsx +135 -1
- package/src/components/theme/Logout/Logout.jsx +36 -83
- package/src/components/theme/Navigation/Navigation.jsx +86 -171
- package/src/components/theme/Search/SearchTags.jsx +30 -60
- package/src/components/theme/SearchWidget/SearchWidget.jsx +15 -3
- package/src/components/theme/SearchWidget/SearchWidget.test.jsx +8 -0
- package/src/components/theme/Sitemap/Sitemap.jsx +24 -13
- package/src/components/theme/Sitemap/Sitemap.test.jsx +23 -2
- package/src/components/theme/View/View.jsx +2 -0
- package/src/config/ControlPanels.js +0 -1
- package/src/config/Widgets.jsx +2 -0
- package/src/config/index.js +15 -3
- package/src/constants/ActionTypes.js +4 -0
- package/src/express-middleware/images.js +1 -0
- package/src/helpers/MessageLabels/MessageLabels.js +26 -4
- package/src/helpers/Site/index.js +21 -0
- package/src/helpers/index.js +1 -0
- package/src/reducers/index.js +4 -0
- package/src/reducers/navroot/navroot.js +79 -0
- package/src/reducers/navroot/navroot.test.js +110 -0
- package/src/reducers/relations/relations.js +74 -46
- package/src/reducers/site/site.js +51 -0
- package/src/reducers/site/site.test.js +67 -0
- package/src/reducers/userSession/userSession.js +15 -1
- package/src/server.jsx +9 -0
- package/test-setup-config.js +1 -0
- package/theme/themes/pastanaga/collections/form.overrides +46 -0
- package/theme/themes/pastanaga/elements/input.overrides +10 -0
- package/theme/themes/pastanaga/elements/label.overrides +10 -0
- package/theme/themes/pastanaga/extras/login.less +3 -0
- package/webpack-plugins/webpack-less-plugin.js +19 -0
- package/.gitignore~ +0 -71
- package/news/4547.breaking~ +0 -1
- package/package.json~ +0 -444
- package/src/config/index.js~ +0 -223
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getControlpanel,
|
|
12
12
|
updateUser,
|
|
13
13
|
updateGroup,
|
|
14
|
+
getUserSchema,
|
|
14
15
|
} from '@plone/volto/actions';
|
|
15
16
|
import {
|
|
16
17
|
Icon,
|
|
@@ -98,6 +99,7 @@ class UsersControlpanel extends Component {
|
|
|
98
99
|
this.updateUserRole = this.updateUserRole.bind(this);
|
|
99
100
|
this.state = {
|
|
100
101
|
search: '',
|
|
102
|
+
isLoading: false,
|
|
101
103
|
showAddUser: false,
|
|
102
104
|
showAddUserErrorConfirm: false,
|
|
103
105
|
addUserError: '',
|
|
@@ -107,6 +109,7 @@ class UsersControlpanel extends Component {
|
|
|
107
109
|
isClient: false,
|
|
108
110
|
currentPage: 0,
|
|
109
111
|
pageSize: 10,
|
|
112
|
+
loginUsingEmail: false,
|
|
110
113
|
};
|
|
111
114
|
}
|
|
112
115
|
|
|
@@ -120,6 +123,15 @@ class UsersControlpanel extends Component {
|
|
|
120
123
|
entries: this.props.users,
|
|
121
124
|
});
|
|
122
125
|
}
|
|
126
|
+
await this.props.getUserSchema();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Because username field needs to be disabled if email login is enabled!
|
|
130
|
+
checkLoginUsingEmailStatus = async () => {
|
|
131
|
+
await this.props.getControlpanel('security');
|
|
132
|
+
this.setState({
|
|
133
|
+
loginUsingEmail: this.props.controlPanelData?.data.use_email_as_login,
|
|
134
|
+
});
|
|
123
135
|
};
|
|
124
136
|
|
|
125
137
|
/**
|
|
@@ -132,6 +144,7 @@ class UsersControlpanel extends Component {
|
|
|
132
144
|
isClient: true,
|
|
133
145
|
});
|
|
134
146
|
this.fetchData();
|
|
147
|
+
this.checkLoginUsingEmailStatus();
|
|
135
148
|
}
|
|
136
149
|
|
|
137
150
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
@@ -171,9 +184,19 @@ class UsersControlpanel extends Component {
|
|
|
171
184
|
*/
|
|
172
185
|
onSearch(event) {
|
|
173
186
|
event.preventDefault();
|
|
174
|
-
this.
|
|
175
|
-
|
|
176
|
-
|
|
187
|
+
this.setState({ isLoading: true });
|
|
188
|
+
this.props
|
|
189
|
+
.listUsers({
|
|
190
|
+
search: this.state.search,
|
|
191
|
+
})
|
|
192
|
+
.then(() => {
|
|
193
|
+
this.setState({ isLoading: false });
|
|
194
|
+
})
|
|
195
|
+
.catch((error) => {
|
|
196
|
+
this.setState({ isLoading: false });
|
|
197
|
+
// eslint-disable-next-line no-console
|
|
198
|
+
console.error('Error searching users', error);
|
|
199
|
+
});
|
|
177
200
|
}
|
|
178
201
|
|
|
179
202
|
/**
|
|
@@ -255,12 +278,28 @@ class UsersControlpanel extends Component {
|
|
|
255
278
|
* @returns {undefined}
|
|
256
279
|
*/
|
|
257
280
|
onAddUserSubmit(data, callback) {
|
|
258
|
-
const { groups, sendPasswordReset } = data;
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
281
|
+
const { groups, sendPasswordReset, password } = data;
|
|
282
|
+
if (
|
|
283
|
+
sendPasswordReset !== undefined &&
|
|
284
|
+
sendPasswordReset === true &&
|
|
285
|
+
password !== undefined
|
|
286
|
+
) {
|
|
287
|
+
toast.error(
|
|
288
|
+
<Toast
|
|
289
|
+
error
|
|
290
|
+
title={this.props.intl.formatMessage(messages.error)}
|
|
291
|
+
content={this.props.intl.formatMessage(
|
|
292
|
+
messages.addUserFormPasswordAndSendPasswordTogetherNotAllowed,
|
|
293
|
+
)}
|
|
294
|
+
/>,
|
|
295
|
+
);
|
|
296
|
+
} else {
|
|
297
|
+
if (groups && groups.length > 0) this.addUserToGroup(data);
|
|
298
|
+
this.props.createUser(data, sendPasswordReset);
|
|
299
|
+
this.setState({
|
|
300
|
+
addUserSetFormDataCallback: callback,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
264
303
|
}
|
|
265
304
|
|
|
266
305
|
/**
|
|
@@ -382,6 +421,65 @@ class UsersControlpanel extends Component {
|
|
|
382
421
|
let usernameToDelete = this.state.userToDelete
|
|
383
422
|
? this.state.userToDelete.username
|
|
384
423
|
: '';
|
|
424
|
+
// Copy the userschema using JSON serialization/deserialization
|
|
425
|
+
// this is really ugly, but if we don't do this the original value
|
|
426
|
+
// of the userschema is changed and it is used like that through
|
|
427
|
+
// the lifecycle of the application
|
|
428
|
+
let adduserschema = {};
|
|
429
|
+
if (this.props?.userschema?.loaded) {
|
|
430
|
+
adduserschema = JSON.parse(
|
|
431
|
+
JSON.stringify(this.props?.userschema?.userschema),
|
|
432
|
+
);
|
|
433
|
+
adduserschema.properties['username'] = {
|
|
434
|
+
title: this.props.intl.formatMessage(messages.addUserFormUsernameTitle),
|
|
435
|
+
type: 'string',
|
|
436
|
+
description: this.props.intl.formatMessage(
|
|
437
|
+
messages.addUserFormUsernameDescription,
|
|
438
|
+
),
|
|
439
|
+
};
|
|
440
|
+
adduserschema.properties['password'] = {
|
|
441
|
+
title: this.props.intl.formatMessage(messages.addUserFormPasswordTitle),
|
|
442
|
+
type: 'password',
|
|
443
|
+
description: this.props.intl.formatMessage(
|
|
444
|
+
messages.addUserFormPasswordDescription,
|
|
445
|
+
),
|
|
446
|
+
widget: 'password',
|
|
447
|
+
};
|
|
448
|
+
adduserschema.properties['sendPasswordReset'] = {
|
|
449
|
+
title: this.props.intl.formatMessage(
|
|
450
|
+
messages.addUserFormSendPasswordResetTitle,
|
|
451
|
+
),
|
|
452
|
+
type: 'boolean',
|
|
453
|
+
};
|
|
454
|
+
adduserschema.properties['roles'] = {
|
|
455
|
+
title: this.props.intl.formatMessage(messages.addUserFormRolesTitle),
|
|
456
|
+
type: 'array',
|
|
457
|
+
choices: this.props.roles.map((role) => [role.id, role.title]),
|
|
458
|
+
noValueOption: false,
|
|
459
|
+
};
|
|
460
|
+
adduserschema.properties['groups'] = {
|
|
461
|
+
title: this.props.intl.formatMessage(messages.addUserGroupNameTitle),
|
|
462
|
+
type: 'array',
|
|
463
|
+
choices: this.props.groups.map((group) => [group.id, group.id]),
|
|
464
|
+
noValueOption: false,
|
|
465
|
+
};
|
|
466
|
+
if (
|
|
467
|
+
adduserschema.fieldsets &&
|
|
468
|
+
adduserschema.fieldsets.length > 0 &&
|
|
469
|
+
!adduserschema.fieldsets[0]['fields'].includes('username')
|
|
470
|
+
) {
|
|
471
|
+
adduserschema.fieldsets[0]['fields'] = adduserschema.fieldsets[0][
|
|
472
|
+
'fields'
|
|
473
|
+
].concat([
|
|
474
|
+
'username',
|
|
475
|
+
'password',
|
|
476
|
+
'sendPasswordReset',
|
|
477
|
+
'roles',
|
|
478
|
+
'groups',
|
|
479
|
+
]);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
385
483
|
return (
|
|
386
484
|
<Container className="users-control-panel">
|
|
387
485
|
<Helmet title={this.props.intl.formatMessage(messages.users)} />
|
|
@@ -408,7 +506,7 @@ class UsersControlpanel extends Component {
|
|
|
408
506
|
onConfirm={this.onDeleteOk}
|
|
409
507
|
size={null}
|
|
410
508
|
/>
|
|
411
|
-
{this.state.showAddUser ? (
|
|
509
|
+
{this.props?.userschema?.loaded && this.state.showAddUser ? (
|
|
412
510
|
<ModalForm
|
|
413
511
|
open={this.state.showAddUser}
|
|
414
512
|
className="modal"
|
|
@@ -419,92 +517,7 @@ class UsersControlpanel extends Component {
|
|
|
419
517
|
}
|
|
420
518
|
title={this.props.intl.formatMessage(messages.addUserFormTitle)}
|
|
421
519
|
loading={this.props.createRequest.loading}
|
|
422
|
-
schema={
|
|
423
|
-
fieldsets: [
|
|
424
|
-
{
|
|
425
|
-
id: 'default',
|
|
426
|
-
title: 'FIXME: User Data',
|
|
427
|
-
fields: [
|
|
428
|
-
'username',
|
|
429
|
-
'fullname',
|
|
430
|
-
'email',
|
|
431
|
-
'password',
|
|
432
|
-
'sendPasswordReset',
|
|
433
|
-
'roles',
|
|
434
|
-
'groups',
|
|
435
|
-
],
|
|
436
|
-
},
|
|
437
|
-
],
|
|
438
|
-
properties: {
|
|
439
|
-
username: {
|
|
440
|
-
title: this.props.intl.formatMessage(
|
|
441
|
-
messages.addUserFormUsernameTitle,
|
|
442
|
-
),
|
|
443
|
-
type: 'string',
|
|
444
|
-
description: this.props.intl.formatMessage(
|
|
445
|
-
messages.addUserFormUsernameDescription,
|
|
446
|
-
),
|
|
447
|
-
},
|
|
448
|
-
fullname: {
|
|
449
|
-
title: this.props.intl.formatMessage(
|
|
450
|
-
messages.addUserFormFullnameTitle,
|
|
451
|
-
),
|
|
452
|
-
type: 'string',
|
|
453
|
-
description: this.props.intl.formatMessage(
|
|
454
|
-
messages.addUserFormFullnameDescription,
|
|
455
|
-
),
|
|
456
|
-
},
|
|
457
|
-
email: {
|
|
458
|
-
title: this.props.intl.formatMessage(
|
|
459
|
-
messages.addUserFormEmailTitle,
|
|
460
|
-
),
|
|
461
|
-
type: 'string',
|
|
462
|
-
description: this.props.intl.formatMessage(
|
|
463
|
-
messages.addUserFormEmailDescription,
|
|
464
|
-
),
|
|
465
|
-
widget: 'email',
|
|
466
|
-
},
|
|
467
|
-
password: {
|
|
468
|
-
title: this.props.intl.formatMessage(
|
|
469
|
-
messages.addUserFormPasswordTitle,
|
|
470
|
-
),
|
|
471
|
-
type: 'password',
|
|
472
|
-
description: this.props.intl.formatMessage(
|
|
473
|
-
messages.addUserFormPasswordDescription,
|
|
474
|
-
),
|
|
475
|
-
widget: 'password',
|
|
476
|
-
},
|
|
477
|
-
sendPasswordReset: {
|
|
478
|
-
title: this.props.intl.formatMessage(
|
|
479
|
-
messages.addUserFormSendPasswordResetTitle,
|
|
480
|
-
),
|
|
481
|
-
type: 'boolean',
|
|
482
|
-
},
|
|
483
|
-
roles: {
|
|
484
|
-
title: this.props.intl.formatMessage(
|
|
485
|
-
messages.addUserFormRolesTitle,
|
|
486
|
-
),
|
|
487
|
-
type: 'array',
|
|
488
|
-
choices: this.props.roles.map((role) => [
|
|
489
|
-
role.id,
|
|
490
|
-
role.title,
|
|
491
|
-
]),
|
|
492
|
-
noValueOption: false,
|
|
493
|
-
},
|
|
494
|
-
groups: {
|
|
495
|
-
title: this.props.intl.formatMessage(
|
|
496
|
-
messages.addUserGroupNameTitle,
|
|
497
|
-
),
|
|
498
|
-
type: 'array',
|
|
499
|
-
choices: this.props.groups.map((group) => [
|
|
500
|
-
group.id,
|
|
501
|
-
group.id,
|
|
502
|
-
]),
|
|
503
|
-
noValueOption: false,
|
|
504
|
-
},
|
|
505
|
-
},
|
|
506
|
-
required: ['username', 'email'],
|
|
507
|
-
}}
|
|
520
|
+
schema={adduserschema}
|
|
508
521
|
/>
|
|
509
522
|
) : null}
|
|
510
523
|
</div>
|
|
@@ -533,7 +546,11 @@ class UsersControlpanel extends Component {
|
|
|
533
546
|
<Form.Field>
|
|
534
547
|
<Input
|
|
535
548
|
name="SearchableText"
|
|
536
|
-
action={{
|
|
549
|
+
action={{
|
|
550
|
+
icon: 'search',
|
|
551
|
+
loading: this.state.isLoading,
|
|
552
|
+
disabled: this.state.isLoading,
|
|
553
|
+
}}
|
|
537
554
|
placeholder={this.props.intl.formatMessage(
|
|
538
555
|
messages.searchUsers,
|
|
539
556
|
)}
|
|
@@ -544,7 +561,8 @@ class UsersControlpanel extends Component {
|
|
|
544
561
|
</Form>
|
|
545
562
|
</Segment>
|
|
546
563
|
<Form>
|
|
547
|
-
|
|
564
|
+
{((this.props.many_users && this.state.entries.length > 0) ||
|
|
565
|
+
!this.props.many_users) && (
|
|
548
566
|
<Table padded striped attached unstackable>
|
|
549
567
|
<Table.Header>
|
|
550
568
|
<Table.Row>
|
|
@@ -578,11 +596,18 @@ class UsersControlpanel extends Component {
|
|
|
578
596
|
user={user}
|
|
579
597
|
updateUser={this.updateUserRole}
|
|
580
598
|
inheritedRole={this.props.inheritedRole}
|
|
599
|
+
userschema={this.props.userschema}
|
|
600
|
+
listUsers={this.props.listUsers}
|
|
581
601
|
/>
|
|
582
602
|
))}
|
|
583
603
|
</Table.Body>
|
|
584
604
|
</Table>
|
|
585
|
-
|
|
605
|
+
)}
|
|
606
|
+
{this.state.entries.length === 0 && this.state.search && (
|
|
607
|
+
<Segment>
|
|
608
|
+
{this.props.intl.formatMessage(messages.userSearchNoResults)}
|
|
609
|
+
</Segment>
|
|
610
|
+
)}
|
|
586
611
|
<div className="contents-pagination">
|
|
587
612
|
<Pagination
|
|
588
613
|
current={this.state.currentPage}
|
|
@@ -670,6 +695,8 @@ export default compose(
|
|
|
670
695
|
createRequest: state.users.create,
|
|
671
696
|
loadRolesRequest: state.roles,
|
|
672
697
|
inheritedRole: state.authRole.authenticatedRole,
|
|
698
|
+
userschema: state.userschema,
|
|
699
|
+
controlPanelData: state.controlpanels?.controlpanel,
|
|
673
700
|
}),
|
|
674
701
|
(dispatch) =>
|
|
675
702
|
bindActionCreators(
|
|
@@ -682,6 +709,7 @@ export default compose(
|
|
|
682
709
|
createUser,
|
|
683
710
|
updateUser,
|
|
684
711
|
updateGroup,
|
|
712
|
+
getUserSchema,
|
|
685
713
|
},
|
|
686
714
|
dispatch,
|
|
687
715
|
),
|
|
@@ -17,6 +17,7 @@ import { useSelector } from 'react-redux';
|
|
|
17
17
|
import { Api } from '@plone/volto/helpers';
|
|
18
18
|
import configureStore from '@plone/volto/store';
|
|
19
19
|
import { DefaultView } from '@plone/volto/components/';
|
|
20
|
+
import { serializeNodes } from '@plone/volto-slate/editor/render';
|
|
20
21
|
|
|
21
22
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
22
23
|
|
|
@@ -69,7 +70,7 @@ const DiffField = ({
|
|
|
69
70
|
.replace('\u202F', ' '),
|
|
70
71
|
);
|
|
71
72
|
break;
|
|
72
|
-
case 'json':
|
|
73
|
+
case 'json': {
|
|
73
74
|
const api = new Api();
|
|
74
75
|
const history = createBrowserHistory();
|
|
75
76
|
const store = configureStore(window.__data, history, api);
|
|
@@ -90,6 +91,29 @@ const DiffField = ({
|
|
|
90
91
|
),
|
|
91
92
|
);
|
|
92
93
|
break;
|
|
94
|
+
}
|
|
95
|
+
case 'slate': {
|
|
96
|
+
const api = new Api();
|
|
97
|
+
const history = createBrowserHistory();
|
|
98
|
+
const store = configureStore(window.__data, history, api);
|
|
99
|
+
parts = diffWords(
|
|
100
|
+
ReactDOMServer.renderToStaticMarkup(
|
|
101
|
+
<Provider store={store}>
|
|
102
|
+
<ConnectedRouter history={history}>
|
|
103
|
+
{serializeNodes(one)}
|
|
104
|
+
</ConnectedRouter>
|
|
105
|
+
</Provider>,
|
|
106
|
+
),
|
|
107
|
+
ReactDOMServer.renderToStaticMarkup(
|
|
108
|
+
<Provider store={store}>
|
|
109
|
+
<ConnectedRouter history={history}>
|
|
110
|
+
{serializeNodes(two)}
|
|
111
|
+
</ConnectedRouter>
|
|
112
|
+
</Provider>,
|
|
113
|
+
),
|
|
114
|
+
);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
93
117
|
case 'textarea':
|
|
94
118
|
default:
|
|
95
119
|
parts = diffWords(one, two);
|
|
@@ -5,7 +5,7 @@ import { withVariationSchemaEnhancer } from '@plone/volto/helpers';
|
|
|
5
5
|
const EnhancedBlockDataForm = withVariationSchemaEnhancer(InlineForm);
|
|
6
6
|
|
|
7
7
|
export default function BlockDataForm(props) {
|
|
8
|
-
const { onChangeBlock, block } = props;
|
|
8
|
+
const { onChangeBlock, block, applySchemaEnhancers = true } = props;
|
|
9
9
|
|
|
10
10
|
if (!onChangeBlock) {
|
|
11
11
|
// eslint-disable-next-line no-console
|
|
@@ -19,8 +19,9 @@ export default function BlockDataForm(props) {
|
|
|
19
19
|
[block, onChangeBlock],
|
|
20
20
|
);
|
|
21
21
|
|
|
22
|
+
const Form = applySchemaEnhancers ? EnhancedBlockDataForm : InlineForm;
|
|
22
23
|
return (
|
|
23
|
-
<
|
|
24
|
+
<Form
|
|
24
25
|
{...props}
|
|
25
26
|
onChangeFormData={onChangeBlock ? onChangeFormData : undefined}
|
|
26
27
|
/>
|
|
@@ -72,7 +72,7 @@ beforeAll(() => {
|
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
describe('BlockDataForm', () => {
|
|
75
|
-
it('should
|
|
75
|
+
it('should not add variations to schema when unneeded', () => {
|
|
76
76
|
const WrappedBlockDataForm = withStateManagement(BlockDataForm);
|
|
77
77
|
const store = mockStore({
|
|
78
78
|
intl: {
|
|
@@ -103,7 +103,7 @@ describe('BlockDataForm', () => {
|
|
|
103
103
|
expect(testSchema.fieldsets[0].fields).toStrictEqual([]);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
it('should
|
|
106
|
+
it('should not add variations when only one variation', () => {
|
|
107
107
|
const WrappedBlockDataForm = withStateManagement(BlockDataForm);
|
|
108
108
|
const store = mockStore({
|
|
109
109
|
intl: {
|
|
@@ -164,4 +164,36 @@ describe('BlockDataForm', () => {
|
|
|
164
164
|
// schema is cloned, not mutated in place
|
|
165
165
|
expect(testSchema.fieldsets[0].fields).toStrictEqual([]);
|
|
166
166
|
});
|
|
167
|
+
|
|
168
|
+
it('should not add variations to schema when explicitly disabled', () => {
|
|
169
|
+
const WrappedBlockDataForm = withStateManagement(BlockDataForm);
|
|
170
|
+
const store = mockStore({
|
|
171
|
+
intl: {
|
|
172
|
+
locale: 'en',
|
|
173
|
+
messages: {},
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
const testSchema = {
|
|
177
|
+
fieldsets: [{ title: 'Default', id: 'default', fields: [] }],
|
|
178
|
+
properties: {},
|
|
179
|
+
required: [],
|
|
180
|
+
};
|
|
181
|
+
const formData = {
|
|
182
|
+
'@type': 'testBlock',
|
|
183
|
+
};
|
|
184
|
+
const { container } = render(
|
|
185
|
+
<Provider store={store}>
|
|
186
|
+
<WrappedBlockDataForm
|
|
187
|
+
formData={formData}
|
|
188
|
+
schema={testSchema}
|
|
189
|
+
onChangeField={(id, value) => {}}
|
|
190
|
+
applySchemaEnhancers={false}
|
|
191
|
+
/>
|
|
192
|
+
</Provider>,
|
|
193
|
+
);
|
|
194
|
+
expect(container).toMatchSnapshot();
|
|
195
|
+
|
|
196
|
+
// schema is cloned, not mutated in place
|
|
197
|
+
expect(testSchema.fieldsets[0].fields).toStrictEqual([]);
|
|
198
|
+
});
|
|
167
199
|
});
|
|
@@ -44,7 +44,7 @@ const LinksToItem = (props) => {
|
|
|
44
44
|
|
|
45
45
|
const title = useSelector((state) => state.content.data?.title || '');
|
|
46
46
|
const myrelations = useSelector(
|
|
47
|
-
(state) => state.relations.subrequests[itempath]?.
|
|
47
|
+
(state) => state.relations.subrequests[itempath]?.data,
|
|
48
48
|
);
|
|
49
49
|
const actions = useSelector((state) => state.actions?.actions ?? {});
|
|
50
50
|
const ploneSetupAction = find(actions.user, {
|
|
@@ -3,6 +3,7 @@ import renderer from 'react-test-renderer';
|
|
|
3
3
|
import { Provider } from 'react-intl-redux';
|
|
4
4
|
import configureMockStore from 'redux-mock-store';
|
|
5
5
|
import thunk from 'redux-thunk';
|
|
6
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
6
7
|
|
|
7
8
|
import LinksToItem from './LinksToItem';
|
|
8
9
|
|
|
@@ -20,7 +21,7 @@ describe('LinksToItem', () => {
|
|
|
20
21
|
relations: {
|
|
21
22
|
subrequests: {
|
|
22
23
|
'/page-1': {
|
|
23
|
-
|
|
24
|
+
data: {
|
|
24
25
|
isReferencing: {
|
|
25
26
|
items: [
|
|
26
27
|
{
|
|
@@ -88,7 +89,9 @@ describe('LinksToItem', () => {
|
|
|
88
89
|
});
|
|
89
90
|
const component = renderer.create(
|
|
90
91
|
<Provider store={store}>
|
|
91
|
-
<
|
|
92
|
+
<MemoryRouter>
|
|
93
|
+
<LinksToItem location={{ pathname: '/page-1/links-to-item' }} />
|
|
94
|
+
</MemoryRouter>
|
|
92
95
|
</Provider>,
|
|
93
96
|
);
|
|
94
97
|
const json = component.toJSON();
|
|
@@ -1,107 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
* Messages component.
|
|
3
|
-
* @module components/manage/Messages/Messages
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React, { Component } from 'react';
|
|
7
|
-
import PropTypes from 'prop-types';
|
|
8
|
-
import { connect } from 'react-redux';
|
|
1
|
+
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|
9
2
|
import { Message, Container } from 'semantic-ui-react';
|
|
10
3
|
import { map } from 'lodash';
|
|
11
4
|
|
|
12
5
|
import { removeMessage } from '@plone/volto/actions';
|
|
13
6
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* @class Messages
|
|
17
|
-
* @extends Component
|
|
18
|
-
*/
|
|
19
|
-
class Messages extends Component {
|
|
20
|
-
/**
|
|
21
|
-
* Property types.
|
|
22
|
-
* @property {Object} propTypes Property types.
|
|
23
|
-
* @static
|
|
24
|
-
*/
|
|
25
|
-
static propTypes = {
|
|
26
|
-
removeMessage: PropTypes.func.isRequired,
|
|
27
|
-
messages: PropTypes.arrayOf(
|
|
28
|
-
PropTypes.shape({
|
|
29
|
-
title: PropTypes.string,
|
|
30
|
-
body: PropTypes.string,
|
|
31
|
-
level: PropTypes.string,
|
|
32
|
-
}),
|
|
33
|
-
).isRequired,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Constructor
|
|
38
|
-
* @method constructor
|
|
39
|
-
* @param {Object} props Component properties
|
|
40
|
-
* @constructs Messages
|
|
41
|
-
*/
|
|
42
|
-
constructor(props) {
|
|
43
|
-
super(props);
|
|
44
|
-
this.onDismiss = this.onDismiss.bind(this);
|
|
45
|
-
}
|
|
7
|
+
const Messages = () => {
|
|
8
|
+
const dispatch = useDispatch();
|
|
46
9
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// * @returns {undefined}
|
|
52
|
-
// */
|
|
53
|
-
// componentWillReceiveProps(nextProps) {
|
|
54
|
-
// if (nextProps.messages.length > this.props.messages.length) {
|
|
55
|
-
// window.setTimeout(() => {
|
|
56
|
-
// if (this.props.messages.length > 0) {
|
|
57
|
-
// this.props.removeMessage(-1);
|
|
58
|
-
// }
|
|
59
|
-
// }, 6000);
|
|
60
|
-
// }
|
|
61
|
-
// }
|
|
10
|
+
const messages = useSelector(
|
|
11
|
+
(state) => state.messages.messages,
|
|
12
|
+
shallowEqual,
|
|
13
|
+
);
|
|
62
14
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
* @param {Object} event Event object
|
|
67
|
-
* @param {number} value Index of message
|
|
68
|
-
* @returns {undefined}
|
|
69
|
-
*/
|
|
70
|
-
onDismiss(event, { value }) {
|
|
71
|
-
this.props.removeMessage(value);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Render method.
|
|
76
|
-
* @method render
|
|
77
|
-
* @returns {string} Markup for the component.
|
|
78
|
-
*/
|
|
79
|
-
render() {
|
|
80
|
-
return (
|
|
81
|
-
this.props.messages && (
|
|
82
|
-
<Container className="messages">
|
|
83
|
-
{map(this.props.messages, (message, index) => (
|
|
84
|
-
<Message
|
|
85
|
-
key={message.id}
|
|
86
|
-
value={index}
|
|
87
|
-
onDismiss={this.onDismiss}
|
|
88
|
-
error={message.level === 'error'}
|
|
89
|
-
success={message.level === 'success'}
|
|
90
|
-
warning={message.level === 'warning'}
|
|
91
|
-
info={message.level === 'info'}
|
|
92
|
-
header={message.title}
|
|
93
|
-
content={message.body}
|
|
94
|
-
/>
|
|
95
|
-
))}
|
|
96
|
-
</Container>
|
|
97
|
-
)
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
15
|
+
const onDismiss = (event, { value }) => {
|
|
16
|
+
dispatch(removeMessage(value));
|
|
17
|
+
};
|
|
101
18
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
19
|
+
return (
|
|
20
|
+
messages && (
|
|
21
|
+
<Container className="messages">
|
|
22
|
+
{map(messages, (message, index) => (
|
|
23
|
+
<Message
|
|
24
|
+
key={message.id}
|
|
25
|
+
value={index}
|
|
26
|
+
onDismiss={onDismiss}
|
|
27
|
+
error={message.level === 'error'}
|
|
28
|
+
success={message.level === 'success'}
|
|
29
|
+
warning={message.level === 'warning'}
|
|
30
|
+
info={message.level === 'info'}
|
|
31
|
+
header={message.title}
|
|
32
|
+
content={message.body}
|
|
33
|
+
/>
|
|
34
|
+
))}
|
|
35
|
+
</Container>
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default Messages;
|