@plone/volto 19.0.0-alpha.5 → 19.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/.eslintrc +20 -0
- package/CHANGELOG.md +73 -0
- package/README.md +2 -2
- package/cypress/support/commands.js +5 -6
- package/locales/af.json +1 -1
- package/locales/ar.json +1 -1
- package/locales/bg.json +1 -1
- package/locales/bn.json +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +25 -5
- package/locales/ca.json +1 -1
- package/locales/cs.json +1 -1
- package/locales/cy.json +1 -1
- package/locales/da.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +25 -5
- package/locales/de.json +1 -1
- package/locales/el.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +25 -5
- package/locales/en.json +1 -1
- package/locales/en_AU.json +1 -1
- package/locales/en_GB.json +1 -1
- package/locales/eo.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +25 -5
- package/locales/es.json +1 -1
- package/locales/et.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +25 -5
- package/locales/eu.json +1 -1
- package/locales/fa.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +25 -5
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +25 -5
- package/locales/fr.json +1 -1
- package/locales/fu.json +1 -1
- package/locales/gl.json +1 -1
- package/locales/he.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +25 -5
- package/locales/hi.json +1 -1
- package/locales/hr.json +1 -1
- package/locales/hu.json +1 -1
- package/locales/hy.json +1 -1
- package/locales/id.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +26 -6
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +25 -5
- package/locales/ja.json +1 -1
- package/locales/ka.json +1 -1
- package/locales/kn.json +1 -1
- package/locales/ko.json +1 -1
- package/locales/lt.json +1 -1
- package/locales/lv.json +1 -1
- package/locales/mi.json +1 -1
- package/locales/mk.json +1 -1
- package/locales/my.json +1 -1
- package/locales/nb_NO.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +25 -5
- package/locales/nl.json +1 -1
- package/locales/nn.json +1 -1
- package/locales/pl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +25 -5
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +36 -16
- package/locales/pt_BR.json +1 -1
- package/locales/rm.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +25 -5
- package/locales/ro.json +1 -1
- package/locales/ru/LC_MESSAGES/volto.po +25 -5
- package/locales/ru.json +1 -1
- package/locales/sk.json +1 -1
- package/locales/sl.json +1 -1
- package/locales/sm.json +1 -1
- package/locales/sq.json +1 -1
- package/locales/sr.json +1 -1
- package/locales/sr@cyrl.json +1 -1
- package/locales/sr@latn.json +1 -1
- package/locales/sv.json +1 -1
- package/locales/ta.json +1 -1
- package/locales/te.json +1 -1
- package/locales/th.json +1 -1
- package/locales/to.json +1 -1
- package/locales/tr.json +1 -1
- package/locales/uk.json +1 -1
- package/locales/vi.json +1 -1
- package/locales/volto.pot +26 -6
- package/locales/zh_CN/LC_MESSAGES/volto.po +25 -5
- package/locales/zh_CN.json +1 -1
- package/locales/zh_Hant.json +1 -1
- package/locales/zh_Hant_HK.json +1 -1
- package/package.json +10 -10
- package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +9 -4
- package/src/components/manage/Blocks/LeadImage/Edit.jsx +2 -2
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +1 -1
- package/src/components/manage/Blocks/Maps/Edit.jsx +2 -1
- package/src/components/manage/Blocks/Teaser/Data.jsx +20 -6
- package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +1 -1
- package/src/components/manage/Blocks/Video/Edit.jsx +2 -1
- package/src/components/manage/Contents/Contents.jsx +20 -2
- package/src/components/manage/Controlpanels/ContentType.jsx +1 -1
- package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +3 -2
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +156 -175
- package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
- package/src/components/manage/TemplateChooser/TemplateChooser.jsx +2 -1
- package/src/components/manage/Toolbar/PersonalTools.jsx +2 -1
- package/src/components/manage/Widgets/DatetimeWidget.jsx +5 -0
- package/src/components/manage/Widgets/FileWidget.jsx +14 -8
- package/src/components/manage/Widgets/ImageWidget.jsx +2 -2
- package/src/components/manage/Widgets/InternalUrlWidget.jsx +2 -0
- package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +3 -0
- package/src/components/manage/Widgets/UrlWidget.jsx +2 -0
- package/src/components/theme/Avatar/Avatar.jsx +2 -1
- package/src/components/theme/PreviewImage/PreviewImage.jsx +1 -1
- package/src/components/theme/Widgets/ImageWidget.jsx +2 -1
- package/src/helpers/Content/withClientSideContent.jsx +35 -0
- package/src/helpers/Html/Html.jsx +1 -9
- package/src/helpers/MessageLabels/MessageLabels.js +5 -0
- package/src/middleware/api.js +3 -3
- package/src/routes.js +3 -1
- package/theme/themes/pastanaga/extras/contents.less +12 -0
- package/theme/themes/pastanaga/extras/main.less +4 -0
- package/types/components/manage/Controlpanels/Users/RenderUsers.d.ts +18 -2
- package/types/components/manage/Controlpanels/index.d.ts +1 -1
- package/types/helpers/Content/withClientSideContent.d.ts +1 -0
- package/types/helpers/MessageLabels/MessageLabels.d.ts +68 -62
- package/src/helpers/Url/bulkFlattenToAppURL.test.ts +0 -122
- package/src/helpers/Url/bulkFlattenToAppURL.ts +0 -24
|
@@ -29,6 +29,16 @@ const messages = defineMessages({
|
|
|
29
29
|
},
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
+
function getImageField(resp) {
|
|
33
|
+
if (!resp) return null;
|
|
34
|
+
|
|
35
|
+
if (resp.preview_image_link) return 'preview_image_link';
|
|
36
|
+
if (resp.preview_image) return 'preview_image';
|
|
37
|
+
if (resp.image) return 'image';
|
|
38
|
+
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
32
42
|
const TeaserData = (props) => {
|
|
33
43
|
const {
|
|
34
44
|
block,
|
|
@@ -58,16 +68,20 @@ const TeaserData = (props) => {
|
|
|
58
68
|
'@type': resp?.['@type'],
|
|
59
69
|
Description: resp?.description,
|
|
60
70
|
Title: resp.title,
|
|
61
|
-
hasPreviewImage: resp
|
|
71
|
+
hasPreviewImage: getImageField(resp) ? true : false,
|
|
62
72
|
head_title: resp.head_title ?? null,
|
|
63
|
-
image_field: resp
|
|
64
|
-
? 'preview_image'
|
|
65
|
-
: resp?.image
|
|
66
|
-
? 'image'
|
|
67
|
-
: null,
|
|
73
|
+
image_field: getImageField(resp),
|
|
68
74
|
image_scales: {
|
|
69
75
|
preview_image: [resp?.preview_image],
|
|
70
76
|
image: [resp?.image],
|
|
77
|
+
preview_image_link: resp?.preview_image_link
|
|
78
|
+
? [
|
|
79
|
+
{
|
|
80
|
+
...resp?.preview_image_link?.['image_scales']?.image?.[0],
|
|
81
|
+
base_path: resp?.preview_image_link?.['@id'],
|
|
82
|
+
},
|
|
83
|
+
]
|
|
84
|
+
: [],
|
|
71
85
|
},
|
|
72
86
|
title: resp.title,
|
|
73
87
|
};
|
|
@@ -33,7 +33,7 @@ const TeaserDefaultTemplate = (props) => {
|
|
|
33
33
|
{!href && isEditMode && (
|
|
34
34
|
<Message>
|
|
35
35
|
<div className="teaser-item placeholder">
|
|
36
|
-
<
|
|
36
|
+
<Image src={imageBlockSVG} alt="" />
|
|
37
37
|
<p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
|
|
38
38
|
</div>
|
|
39
39
|
</Message>
|
|
@@ -12,6 +12,7 @@ import aheadSVG from '@plone/volto/icons/ahead.svg';
|
|
|
12
12
|
import videoBlockSVG from '@plone/volto/components/manage/Blocks/Video/block-video.svg';
|
|
13
13
|
import Body from '@plone/volto/components/manage/Blocks/Video/Body';
|
|
14
14
|
import { withBlockExtensions } from '@plone/volto/helpers/Extensions';
|
|
15
|
+
import Image from '@plone/volto/components/theme/Image/Image';
|
|
15
16
|
|
|
16
17
|
const messages = defineMessages({
|
|
17
18
|
VideoFormDescription: {
|
|
@@ -82,7 +83,7 @@ const Edit = (props) => {
|
|
|
82
83
|
) : (
|
|
83
84
|
<Message>
|
|
84
85
|
<center>
|
|
85
|
-
<
|
|
86
|
+
<Image src={videoBlockSVG} alt="" />
|
|
86
87
|
<div className="toolbar-inner">
|
|
87
88
|
<Input
|
|
88
89
|
onKeyDown={onKeyDownVariantMenuForm}
|
|
@@ -264,6 +264,10 @@ const messages = defineMessages({
|
|
|
264
264
|
id: 'All',
|
|
265
265
|
defaultMessage: 'All',
|
|
266
266
|
},
|
|
267
|
+
resultCount: {
|
|
268
|
+
id: 'resultCount',
|
|
269
|
+
defaultMessage: 'Result count',
|
|
270
|
+
},
|
|
267
271
|
});
|
|
268
272
|
|
|
269
273
|
/**
|
|
@@ -1218,8 +1222,9 @@ class Contents extends Component {
|
|
|
1218
1222
|
as={Button}
|
|
1219
1223
|
onClick={this.upload}
|
|
1220
1224
|
className="upload"
|
|
1225
|
+
aria-controls="contents-table-wrapper"
|
|
1221
1226
|
aria-label={this.props.intl.formatMessage(
|
|
1222
|
-
messages.
|
|
1227
|
+
messages.filter,
|
|
1223
1228
|
)}
|
|
1224
1229
|
>
|
|
1225
1230
|
<Icon
|
|
@@ -1551,7 +1556,20 @@ class Contents extends Component {
|
|
|
1551
1556
|
</Dropdown.Menu>
|
|
1552
1557
|
</Dropdown>
|
|
1553
1558
|
</Segment>
|
|
1554
|
-
<div
|
|
1559
|
+
<div
|
|
1560
|
+
id="contents-table-wrapper"
|
|
1561
|
+
className="contents-table-wrapper"
|
|
1562
|
+
role="region"
|
|
1563
|
+
>
|
|
1564
|
+
<span
|
|
1565
|
+
aria-live="polite"
|
|
1566
|
+
className="search-feedback"
|
|
1567
|
+
role="status"
|
|
1568
|
+
>
|
|
1569
|
+
{`${this.props.intl.formatMessage(
|
|
1570
|
+
messages.resultCount,
|
|
1571
|
+
)}: ${this.props.total || 0}`}
|
|
1572
|
+
</span>
|
|
1555
1573
|
<Table selectable compact singleLine attached>
|
|
1556
1574
|
<Table.Header>
|
|
1557
1575
|
<Table.Row>
|
|
@@ -182,7 +182,7 @@ class ContentType extends Component {
|
|
|
182
182
|
return <Error error={this.state.error} />;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
if (this.props.controlpanel) {
|
|
185
|
+
if (this.props.controlpanel?.data) {
|
|
186
186
|
let controlpanel = this.props.controlpanel;
|
|
187
187
|
if (controlpanel?.data?.filter_content_types === false) {
|
|
188
188
|
controlpanel.data.filter_content_types = { title: 'all', token: 'all' };
|
|
@@ -494,8 +494,9 @@ class GroupsControlpanel extends Component {
|
|
|
494
494
|
messages.addGroupsFormGroupNameTitle,
|
|
495
495
|
),
|
|
496
496
|
type: 'string',
|
|
497
|
-
description:
|
|
498
|
-
|
|
497
|
+
description: this.props.intl.formatMessage(
|
|
498
|
+
messages.addGroupsFormGroupNameDescription,
|
|
499
|
+
),
|
|
499
500
|
},
|
|
500
501
|
email: {
|
|
501
502
|
title: this.props.intl.formatMessage(
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @module components/manage/Controlpanels/
|
|
2
|
+
* RenderUsers component.
|
|
3
|
+
* @module components/manage/Controlpanels/Users/RenderUsers
|
|
4
4
|
*/
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
|
-
import
|
|
7
|
-
import { FormattedMessage,
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
import { FormattedMessage, useIntl } from 'react-intl';
|
|
8
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
8
9
|
import { Dropdown, Table, Checkbox } from 'semantic-ui-react';
|
|
9
10
|
import trashSVG from '@plone/volto/icons/delete.svg';
|
|
10
11
|
import editSVG from '@plone/volto/icons/editing.svg';
|
|
@@ -13,199 +14,179 @@ import Toast from '@plone/volto/components/manage/Toast/Toast';
|
|
|
13
14
|
import { ModalForm } from '@plone/volto/components/manage/Form';
|
|
14
15
|
import { updateUser } from '@plone/volto/actions/users/users';
|
|
15
16
|
import ploneSVG from '@plone/volto/icons/plone.svg';
|
|
16
|
-
import { compose } from 'redux';
|
|
17
|
-
import { connect } from 'react-redux';
|
|
18
17
|
import { messages } from '@plone/volto/helpers/MessageLabels/MessageLabels';
|
|
19
18
|
import { canAssignRole } from '@plone/volto/helpers/User/User';
|
|
20
19
|
import { toast } from 'react-toastify';
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
|
-
*
|
|
24
|
-
* @
|
|
25
|
-
* @extends Component
|
|
22
|
+
* RenderUsers functional component.
|
|
23
|
+
* @function RenderUsers
|
|
26
24
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* Property types.
|
|
30
|
-
* @property {Object} propTypes Property types.
|
|
31
|
-
* @static
|
|
32
|
-
*/
|
|
33
|
-
static propTypes = {
|
|
34
|
-
user: PropTypes.shape({
|
|
35
|
-
username: PropTypes.string,
|
|
36
|
-
fullname: PropTypes.string,
|
|
37
|
-
roles: PropTypes.arrayOf(PropTypes.string),
|
|
38
|
-
}).isRequired,
|
|
39
|
-
roles: PropTypes.arrayOf(
|
|
40
|
-
PropTypes.shape({
|
|
41
|
-
id: PropTypes.string,
|
|
42
|
-
}),
|
|
43
|
-
).isRequired,
|
|
44
|
-
onDelete: PropTypes.func.isRequired,
|
|
45
|
-
isUserManager: PropTypes.bool.isRequired,
|
|
46
|
-
};
|
|
25
|
+
const RenderUsers = (props) => {
|
|
26
|
+
const [user, setUser] = useState({});
|
|
47
27
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
28
|
+
const intl = useIntl();
|
|
29
|
+
const dispatch = useDispatch();
|
|
30
|
+
const updateRequest = useSelector((state) => state.users?.update);
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
user: propsUser,
|
|
34
|
+
listUsers,
|
|
35
|
+
updateUser: updateUserRole,
|
|
36
|
+
isUserManager,
|
|
37
|
+
roles,
|
|
38
|
+
inheritedRole,
|
|
39
|
+
userschema,
|
|
40
|
+
onDelete,
|
|
41
|
+
} = props;
|
|
42
|
+
|
|
43
|
+
// Use dispatch to call updateUser action
|
|
44
|
+
const updateUserData = (userId, userData) => {
|
|
45
|
+
dispatch(updateUser(userId, userData))
|
|
46
|
+
.then(() => {
|
|
47
|
+
// Handle success
|
|
48
|
+
setUser({});
|
|
49
|
+
if (listUsers) {
|
|
50
|
+
listUsers();
|
|
51
|
+
}
|
|
52
|
+
toast.success(
|
|
53
|
+
<Toast
|
|
54
|
+
success
|
|
55
|
+
title={intl.formatMessage(messages.success)}
|
|
56
|
+
content={intl.formatMessage(messages.updateUserSuccess)}
|
|
57
|
+
/>,
|
|
58
|
+
);
|
|
59
|
+
})
|
|
60
|
+
.catch(() => {
|
|
61
|
+
// Handle error
|
|
62
|
+
toast.error(
|
|
63
|
+
<Toast
|
|
64
|
+
error
|
|
65
|
+
title={intl.formatMessage(messages.error)}
|
|
66
|
+
content={intl.formatMessage(messages.thereWereSomeErrors)}
|
|
67
|
+
/>,
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
};
|
|
63
71
|
|
|
64
72
|
/**
|
|
65
73
|
* @param {*} event
|
|
66
74
|
* @param {*} { value }
|
|
67
|
-
* @memberof UsersControlpanelUser
|
|
68
75
|
*/
|
|
76
|
+
const onChange = (_event, { value }) => {
|
|
77
|
+
const [userId, role] = value.split('&role=');
|
|
78
|
+
updateUserRole(userId, role);
|
|
79
|
+
};
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
const [user, role] = value.split('&role=');
|
|
72
|
-
this.props.updateUser(user, role);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
componentDidUpdate(prevProps) {
|
|
76
|
-
if (
|
|
77
|
-
prevProps.updateRequest.loading &&
|
|
78
|
-
this.props.updateRequest.loaded &&
|
|
79
|
-
this.state?.user?.id === this.props?.user?.id
|
|
80
|
-
) {
|
|
81
|
-
this.setState({ user: {} });
|
|
82
|
-
this.props.listUsers();
|
|
83
|
-
return toast.success(
|
|
84
|
-
<Toast
|
|
85
|
-
success
|
|
86
|
-
title={this.props.intl.formatMessage(messages.success)}
|
|
87
|
-
content={this.props.intl.formatMessage(messages.updateUserSuccess)}
|
|
88
|
-
/>,
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
onEditUserSubmit(data, callback) {
|
|
81
|
+
const onEditUserSubmit = (data) => {
|
|
94
82
|
// Do not handle groups and roles in this form
|
|
95
83
|
delete data.groups;
|
|
96
84
|
delete data.roles;
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
onEditUserError() {
|
|
101
|
-
return toast.error(
|
|
102
|
-
<Toast
|
|
103
|
-
error
|
|
104
|
-
title={this.props.intl.formatMessage(messages.error)}
|
|
105
|
-
content={this.props.intl.formatMessage(
|
|
106
|
-
messages.addUserFormPasswordAndSendPasswordTogetherNotAllowed,
|
|
107
|
-
)}
|
|
108
|
-
/>,
|
|
109
|
-
);
|
|
110
|
-
}
|
|
85
|
+
updateUserData(data.id, data);
|
|
86
|
+
};
|
|
111
87
|
|
|
112
|
-
onClickEdit(
|
|
113
|
-
const { formData } =
|
|
114
|
-
|
|
115
|
-
}
|
|
88
|
+
const onClickEdit = (formProps) => {
|
|
89
|
+
const { formData } = formProps;
|
|
90
|
+
setUser({ ...formData });
|
|
91
|
+
};
|
|
116
92
|
|
|
117
|
-
canDeleteUser() {
|
|
118
|
-
if (
|
|
119
|
-
return !
|
|
120
|
-
}
|
|
93
|
+
const canDeleteUser = () => {
|
|
94
|
+
if (isUserManager) return true;
|
|
95
|
+
return !propsUser.roles.includes('Manager');
|
|
96
|
+
};
|
|
121
97
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
98
|
+
return (
|
|
99
|
+
<Table.Row key={propsUser.username}>
|
|
100
|
+
<Table.Cell className="fullname">
|
|
101
|
+
{propsUser.fullname ? propsUser.fullname : propsUser.username} (
|
|
102
|
+
{propsUser.username})
|
|
103
|
+
</Table.Cell>
|
|
104
|
+
{roles.map((role) => (
|
|
105
|
+
<Table.Cell key={role.id}>
|
|
106
|
+
{inheritedRole && inheritedRole.includes(role.id) ? (
|
|
107
|
+
<Icon
|
|
108
|
+
name={ploneSVG}
|
|
109
|
+
size="20px"
|
|
110
|
+
color="#007EB1"
|
|
111
|
+
title={'plone-svg'}
|
|
112
|
+
/>
|
|
113
|
+
) : (
|
|
114
|
+
<Checkbox
|
|
115
|
+
checked={propsUser.roles.includes(role.id)}
|
|
116
|
+
onChange={onChange}
|
|
117
|
+
value={`${propsUser.id}&role=${role.id}`}
|
|
118
|
+
disabled={!canAssignRole(isUserManager, role)}
|
|
119
|
+
/>
|
|
120
|
+
)}
|
|
135
121
|
</Table.Cell>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
size="20px"
|
|
143
|
-
color="#007EB1"
|
|
144
|
-
title={'plone-svg'}
|
|
145
|
-
/>
|
|
146
|
-
) : (
|
|
147
|
-
<Checkbox
|
|
148
|
-
checked={this.props.user.roles.includes(role.id)}
|
|
149
|
-
onChange={this.onChange}
|
|
150
|
-
value={`${this.props.user.id}&role=${role.id}`}
|
|
151
|
-
disabled={!canAssignRole(this.props.isUserManager, role)}
|
|
152
|
-
/>
|
|
153
|
-
)}
|
|
154
|
-
</Table.Cell>
|
|
155
|
-
))}
|
|
156
|
-
<Table.Cell textAlign="right">
|
|
157
|
-
{this.canDeleteUser() && (
|
|
158
|
-
<Dropdown icon="ellipsis horizontal">
|
|
159
|
-
<Dropdown.Menu className="left">
|
|
160
|
-
{this.props.userschema && (
|
|
161
|
-
<Dropdown.Item
|
|
162
|
-
id="edit-user-button"
|
|
163
|
-
onClick={() => {
|
|
164
|
-
this.onClickEdit({ formData: this.props.user });
|
|
165
|
-
}}
|
|
166
|
-
value={this.props.user['@id']}
|
|
167
|
-
>
|
|
168
|
-
<Icon name={editSVG} size="15px" />
|
|
169
|
-
<FormattedMessage id="Edit" defaultMessage="Edit" />
|
|
170
|
-
</Dropdown.Item>
|
|
171
|
-
)}
|
|
122
|
+
))}
|
|
123
|
+
<Table.Cell textAlign="right">
|
|
124
|
+
{canDeleteUser() && (
|
|
125
|
+
<Dropdown icon="ellipsis horizontal">
|
|
126
|
+
<Dropdown.Menu className="left">
|
|
127
|
+
{userschema && (
|
|
172
128
|
<Dropdown.Item
|
|
173
|
-
id="
|
|
174
|
-
onClick={
|
|
175
|
-
|
|
129
|
+
id="edit-user-button"
|
|
130
|
+
onClick={() => {
|
|
131
|
+
onClickEdit({ formData: propsUser });
|
|
132
|
+
}}
|
|
133
|
+
value={propsUser['@id']}
|
|
176
134
|
>
|
|
177
|
-
<Icon name={
|
|
178
|
-
<FormattedMessage id="
|
|
135
|
+
<Icon name={editSVG} size="15px" />
|
|
136
|
+
<FormattedMessage id="Edit" defaultMessage="Edit" />
|
|
179
137
|
</Dropdown.Item>
|
|
180
|
-
</Dropdown.Menu>
|
|
181
|
-
</Dropdown>
|
|
182
|
-
)}
|
|
183
|
-
</Table.Cell>
|
|
184
|
-
{Object.keys(this.state.user).length > 0 &&
|
|
185
|
-
this.props.userschema.loaded && (
|
|
186
|
-
<ModalForm
|
|
187
|
-
className="modal"
|
|
188
|
-
onSubmit={this.onEditUserSubmit}
|
|
189
|
-
submitError={this.state.editUserError}
|
|
190
|
-
formData={this.state.user}
|
|
191
|
-
onCancel={() => this.setState({ user: {} })}
|
|
192
|
-
title={this.props.intl.formatMessage(
|
|
193
|
-
messages.updateUserFormTitle,
|
|
194
138
|
)}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
139
|
+
<Dropdown.Item
|
|
140
|
+
id="delete-user-button"
|
|
141
|
+
onClick={onDelete}
|
|
142
|
+
value={propsUser['@id']}
|
|
143
|
+
>
|
|
144
|
+
<Icon name={trashSVG} size="15px" />
|
|
145
|
+
<FormattedMessage id="Delete" defaultMessage="Delete" />
|
|
146
|
+
</Dropdown.Item>
|
|
147
|
+
</Dropdown.Menu>
|
|
148
|
+
</Dropdown>
|
|
149
|
+
)}
|
|
150
|
+
</Table.Cell>
|
|
151
|
+
{Object.keys(user).length > 0 && userschema.loaded && (
|
|
152
|
+
<ModalForm
|
|
153
|
+
className="modal"
|
|
154
|
+
onSubmit={onEditUserSubmit}
|
|
155
|
+
submitError={user.editUserError}
|
|
156
|
+
formData={user}
|
|
157
|
+
onCancel={() => setUser({})}
|
|
158
|
+
title={intl.formatMessage(messages.updateUserFormTitle)}
|
|
159
|
+
loading={updateRequest.loading}
|
|
160
|
+
schema={userschema.userschema}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
</Table.Row>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// PropTypes to the component
|
|
168
|
+
RenderUsers.propTypes = {
|
|
169
|
+
user: PropTypes.shape({
|
|
170
|
+
id: PropTypes.string,
|
|
171
|
+
username: PropTypes.string,
|
|
172
|
+
fullname: PropTypes.string,
|
|
173
|
+
roles: PropTypes.arrayOf(PropTypes.string),
|
|
174
|
+
'@id': PropTypes.string,
|
|
175
|
+
}).isRequired,
|
|
176
|
+
roles: PropTypes.arrayOf(
|
|
177
|
+
PropTypes.shape({
|
|
178
|
+
id: PropTypes.string,
|
|
208
179
|
}),
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
180
|
+
).isRequired,
|
|
181
|
+
onDelete: PropTypes.func.isRequired,
|
|
182
|
+
isUserManager: PropTypes.bool.isRequired,
|
|
183
|
+
listUsers: PropTypes.func,
|
|
184
|
+
updateUser: PropTypes.func.isRequired,
|
|
185
|
+
inheritedRole: PropTypes.arrayOf(PropTypes.string),
|
|
186
|
+
userschema: PropTypes.shape({
|
|
187
|
+
loaded: PropTypes.bool,
|
|
188
|
+
userschema: PropTypes.object,
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export default RenderUsers;
|
|
@@ -3,6 +3,7 @@ import { Button, Segment, Popup } from 'semantic-ui-react';
|
|
|
3
3
|
import { useIntl, defineMessages } from 'react-intl';
|
|
4
4
|
import cx from 'classnames';
|
|
5
5
|
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
6
|
+
import Image from '@plone/volto/components/theme/Image/Image';
|
|
6
7
|
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
7
8
|
import { getContentIcon } from '@plone/volto/helpers/Content/Content';
|
|
8
9
|
import config from '@plone/volto/registry';
|
|
@@ -69,7 +70,7 @@ const ObjectBrowserNav = ({
|
|
|
69
70
|
}
|
|
70
71
|
>
|
|
71
72
|
{item['@type'] === 'Image' ? (
|
|
72
|
-
<
|
|
73
|
+
<Image
|
|
73
74
|
src={`${item['@id']}/@@images/image/preview`}
|
|
74
75
|
alt={item.title}
|
|
75
76
|
style={{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
3
|
import { Button, Grid, Message } from 'semantic-ui-react';
|
|
4
|
+
import Image from '@plone/volto/components/theme/Image/Image';
|
|
4
5
|
|
|
5
6
|
const TemplateChooser = ({ templates, onSelectTemplate }) => {
|
|
6
7
|
const intl = useIntl();
|
|
@@ -15,7 +16,7 @@ const TemplateChooser = ({ templates, onSelectTemplate }) => {
|
|
|
15
16
|
className="template-chooser-item"
|
|
16
17
|
onClick={() => onSelectTemplate(index)}
|
|
17
18
|
>
|
|
18
|
-
<
|
|
19
|
+
<Image src={template.image} alt="" />
|
|
19
20
|
<div className="template-chooser-title">
|
|
20
21
|
{intl.formatMessage({
|
|
21
22
|
id: template.id,
|
|
@@ -7,6 +7,7 @@ import cx from 'classnames';
|
|
|
7
7
|
import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
|
|
8
8
|
|
|
9
9
|
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
10
|
+
import Image from '@plone/volto/components/theme/Image/Image';
|
|
10
11
|
import { getUser } from '@plone/volto/actions/users/users';
|
|
11
12
|
import { Pluggable } from '@plone/volto/components/manage/Pluggable';
|
|
12
13
|
import { expandToBackendURL, getBaseUrl } from '@plone/volto/helpers/Url/Url';
|
|
@@ -96,7 +97,7 @@ const PersonalTools = (props) => {
|
|
|
96
97
|
</header>
|
|
97
98
|
<div className={cx('avatar', { default: !user.portrait })}>
|
|
98
99
|
{user.portrait ? (
|
|
99
|
-
<
|
|
100
|
+
<Image
|
|
100
101
|
src={expandToBackendURL(user.portrait)}
|
|
101
102
|
alt={intl.formatMessage(messages.userAvatar)}
|
|
102
103
|
/>
|
|
@@ -27,6 +27,10 @@ const messages = defineMessages({
|
|
|
27
27
|
id: 'Time',
|
|
28
28
|
defaultMessage: 'Time',
|
|
29
29
|
},
|
|
30
|
+
clearDateTime: {
|
|
31
|
+
id: 'Clear date/time',
|
|
32
|
+
defaultMessage: 'Clear date and time',
|
|
33
|
+
},
|
|
30
34
|
});
|
|
31
35
|
|
|
32
36
|
const PrevIcon = () => (
|
|
@@ -207,6 +211,7 @@ const DatetimeWidgetComponent = (props) => {
|
|
|
207
211
|
disabled={isDisabled || !datetime}
|
|
208
212
|
onClick={onResetDates}
|
|
209
213
|
className="item ui noborder button"
|
|
214
|
+
aria-label={intl.formatMessage(messages.clearDateTime)}
|
|
210
215
|
>
|
|
211
216
|
<Icon name={clearSVG} size="24px" className="close" />
|
|
212
217
|
</button>
|
|
@@ -15,7 +15,6 @@ import UniversalLink from '@plone/volto/components/manage/UniversalLink/Universa
|
|
|
15
15
|
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
16
16
|
import Image from '@plone/volto/components/theme/Image/Image';
|
|
17
17
|
import loadable from '@loadable/component';
|
|
18
|
-
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
|
|
19
18
|
import { validateFileUploadSize } from '@plone/volto/helpers/FormValidation/FormValidation';
|
|
20
19
|
import { defineMessages, useIntl } from 'react-intl';
|
|
21
20
|
import { toast } from 'react-toastify';
|
|
@@ -90,18 +89,25 @@ const FileWidget = (props) => {
|
|
|
90
89
|
const [fileType, setFileType] = React.useState(false);
|
|
91
90
|
const intl = useIntl();
|
|
92
91
|
|
|
92
|
+
const imgAttrs = React.useMemo(() => {
|
|
93
|
+
const data = {};
|
|
94
|
+
if (value?.download) {
|
|
95
|
+
data.item = {
|
|
96
|
+
'@id': value.download.substring(0, value.download.indexOf('/@@images')),
|
|
97
|
+
image: value,
|
|
98
|
+
};
|
|
99
|
+
} else if (value?.data) {
|
|
100
|
+
data.src = `data:${value['content-type']};${value.encoding},${value.data}`;
|
|
101
|
+
}
|
|
102
|
+
return data;
|
|
103
|
+
}, [value]);
|
|
104
|
+
|
|
93
105
|
React.useEffect(() => {
|
|
94
106
|
if (value && imageMimetypes.includes(value['content-type'])) {
|
|
95
107
|
setFileType(true);
|
|
96
108
|
}
|
|
97
109
|
}, [value]);
|
|
98
110
|
|
|
99
|
-
const imgsrc = value?.download
|
|
100
|
-
? `${flattenToAppURL(value?.download)}?id=${Date.now()}`
|
|
101
|
-
: null || value?.data
|
|
102
|
-
? `data:${value['content-type']};${value.encoding},${value.data}`
|
|
103
|
-
: null;
|
|
104
|
-
|
|
105
111
|
/**
|
|
106
112
|
* Drop handler
|
|
107
113
|
* @method onDrop
|
|
@@ -175,7 +181,7 @@ const FileWidget = (props) => {
|
|
|
175
181
|
<Image
|
|
176
182
|
className="image-preview small ui image"
|
|
177
183
|
id={`field-${id}-image`}
|
|
178
|
-
|
|
184
|
+
{...imgAttrs}
|
|
179
185
|
/>
|
|
180
186
|
) : (
|
|
181
187
|
<div className="dropzone-placeholder">
|
|
@@ -291,7 +291,7 @@ const UnconnectedImageInput = (props) => {
|
|
|
291
291
|
{isRelationChoice ? (
|
|
292
292
|
<Image item={value} width="fit-content" height="auto" loading="lazy" />
|
|
293
293
|
) : (
|
|
294
|
-
<
|
|
294
|
+
<Image
|
|
295
295
|
className={props.className}
|
|
296
296
|
src={
|
|
297
297
|
isInternalURL(imageValue)
|
|
@@ -341,7 +341,7 @@ const UnconnectedImageInput = (props) => {
|
|
|
341
341
|
</Loader>
|
|
342
342
|
</Dimmer>
|
|
343
343
|
)}
|
|
344
|
-
<
|
|
344
|
+
<Image src={imageBlockSVG} alt="" className="placeholder" />
|
|
345
345
|
<p>{description || intl.formatMessage(messages.addImage)}</p>
|
|
346
346
|
<div className="toolbar-wrapper">
|
|
347
347
|
<div className="toolbar-inner" ref={linkEditor.anchorNode}>
|
|
@@ -100,6 +100,7 @@ export const InternalUrlWidget = (props) => {
|
|
|
100
100
|
{value?.length > 0 ? (
|
|
101
101
|
<Button.Group>
|
|
102
102
|
<Button
|
|
103
|
+
type="button"
|
|
103
104
|
basic
|
|
104
105
|
className="cancel"
|
|
105
106
|
aria-label="clearUrlBrowser"
|
|
@@ -115,6 +116,7 @@ export const InternalUrlWidget = (props) => {
|
|
|
115
116
|
) : (
|
|
116
117
|
<Button.Group>
|
|
117
118
|
<Button
|
|
119
|
+
type="button"
|
|
118
120
|
basic
|
|
119
121
|
icon
|
|
120
122
|
aria-label="openUrlBrowser"
|