design-comuni-plone-theme 11.23.2 → 11.24.1
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/.github/workflows/main.yml +1 -1
- package/.github/workflows/npm.yml +1 -1
- package/.github/workflows/prs.yml +1 -1
- package/.github/workflows/release.yml +1 -1
- package/.yarn/cache/{volto-form-block-npm-3.9.2-cb78fb6cd0-a47c5241be.zip → volto-form-block-npm-3.10.0-8cd1c7a976-8ddce2c624.zip} +0 -0
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +39 -0
- package/Makefile +1 -1
- package/RELEASE.md +15 -0
- package/locales/de/LC_MESSAGES/volto.po +5 -0
- package/locales/en/LC_MESSAGES/volto.po +5 -0
- package/locales/es/LC_MESSAGES/volto.po +5 -0
- package/locales/fr/LC_MESSAGES/volto.po +5 -0
- package/locales/it/LC_MESSAGES/volto.po +5 -0
- package/locales/volto.pot +6 -1
- package/package.json +3 -3
- package/publiccode.yml +2 -2
- package/src/components/ItaliaTheme/Blocks/Listing/SimpleCard/Card/SimpleCardDefault.jsx +5 -1
- package/src/components/ItaliaTheme/View/PersonaView/PersonaRuolo.jsx +11 -5
- package/src/config/italiaConfig.js +1 -0
- package/src/customizations/volto/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +709 -0
- package/src/customizations/volto/components/manage/Controlpanels/Groups/RenderGroups.jsx +122 -0
- package/src/customizations/volto/components/manage/Diff/DiffField.jsx +2 -3
- package/src/customizations/volto/components/manage/Widgets/RecurrenceWidget/EndField.jsx +18 -11
- package/src/customizations/volto/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +233 -116
- package/src/customizations/volto-form-block/components/FormView.jsx +44 -40
- package/src/customizations/volto-form-block/components/Sidebar.jsx +4 -1
- package/src/customizations/volto-form-block/components/View.jsx +9 -2
- package/src/customizations/volto-form-block/formSchema.js +18 -0
- package/src/theme/ItaliaTheme/Blocks/common/_searchBlockFilters.scss +10 -4
- package/src/theme/ItaliaTheme/Widgets/_reactSelect.scss +5 -2
- package/src/theme/ItaliaTheme/_common.scss +5 -3
- package/src/theme/_site-variables.scss +1 -1
- package/src/theme/bootstrap-override/bootstrap-italia/_focus.scss +5 -2
- package/src/theme/bootstrap-override/bootstrap-italia/_headercenter.scss +5 -2
package/src/customizations/volto/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx
ADDED
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
// CUSTOMIZATION:
|
|
2
|
+
// - 124: Set AuthenticatedUsers roles as authenticatedRole for all groups
|
|
3
|
+
// - 263: Changed updateGroupRole function to update all checkboxes when changing the AuthenticatedUsers checkboxes
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Users controlpanel container.
|
|
7
|
+
* @module components/manage/Controlpanels/UsersControlpanel
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
createGroup,
|
|
11
|
+
deleteGroup,
|
|
12
|
+
listGroups,
|
|
13
|
+
getControlpanel,
|
|
14
|
+
listRoles,
|
|
15
|
+
updateGroup,
|
|
16
|
+
authenticatedRole,
|
|
17
|
+
} from '@plone/volto/actions';
|
|
18
|
+
import {
|
|
19
|
+
Icon,
|
|
20
|
+
ModalForm,
|
|
21
|
+
Toast,
|
|
22
|
+
Toolbar,
|
|
23
|
+
RenderGroups,
|
|
24
|
+
Pagination,
|
|
25
|
+
Error,
|
|
26
|
+
} from '@plone/volto/components';
|
|
27
|
+
import { Link } from 'react-router-dom';
|
|
28
|
+
import { Helmet, messages } from '@plone/volto/helpers';
|
|
29
|
+
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
30
|
+
import addUserSvg from '@plone/volto/icons/add-user.svg';
|
|
31
|
+
import saveSVG from '@plone/volto/icons/save.svg';
|
|
32
|
+
import ploneSVG from '@plone/volto/icons/plone.svg';
|
|
33
|
+
import { find, map } from 'lodash';
|
|
34
|
+
import PropTypes from 'prop-types';
|
|
35
|
+
import React, { Component } from 'react';
|
|
36
|
+
import { FormattedMessage, injectIntl } from 'react-intl';
|
|
37
|
+
import { Portal } from 'react-portal';
|
|
38
|
+
import { connect } from 'react-redux';
|
|
39
|
+
|
|
40
|
+
import { toast } from 'react-toastify';
|
|
41
|
+
import { bindActionCreators, compose } from 'redux';
|
|
42
|
+
import {
|
|
43
|
+
Confirm,
|
|
44
|
+
Container,
|
|
45
|
+
Button,
|
|
46
|
+
Form,
|
|
47
|
+
Input,
|
|
48
|
+
Segment,
|
|
49
|
+
Table,
|
|
50
|
+
} from 'semantic-ui-react';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* GroupsControlpanel class.
|
|
54
|
+
* @class GroupsControlpanel
|
|
55
|
+
* @extends Component
|
|
56
|
+
*/
|
|
57
|
+
class GroupsControlpanel extends Component {
|
|
58
|
+
/**
|
|
59
|
+
* Property types.
|
|
60
|
+
* @property {Object} propTypes Property types.
|
|
61
|
+
* @static
|
|
62
|
+
*/
|
|
63
|
+
static propTypes = {
|
|
64
|
+
listRoles: PropTypes.func.isRequired,
|
|
65
|
+
listGroups: PropTypes.func.isRequired,
|
|
66
|
+
pathname: PropTypes.string.isRequired,
|
|
67
|
+
roles: PropTypes.arrayOf(
|
|
68
|
+
PropTypes.shape({
|
|
69
|
+
'@id': PropTypes.string,
|
|
70
|
+
'@type': PropTypes.string,
|
|
71
|
+
id: PropTypes.string,
|
|
72
|
+
}),
|
|
73
|
+
).isRequired,
|
|
74
|
+
groups: PropTypes.arrayOf(
|
|
75
|
+
PropTypes.shape({
|
|
76
|
+
Title: PropTypes.string,
|
|
77
|
+
Description: PropTypes.string,
|
|
78
|
+
roles: PropTypes.arrayOf(PropTypes.string),
|
|
79
|
+
groupname: PropTypes.string,
|
|
80
|
+
}),
|
|
81
|
+
).isRequired,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Constructor
|
|
86
|
+
* @method constructor
|
|
87
|
+
* @param {Object} props Component properties
|
|
88
|
+
* @constructs Sharing
|
|
89
|
+
*/
|
|
90
|
+
constructor(props) {
|
|
91
|
+
super(props);
|
|
92
|
+
this.onChangeSearch = this.onChangeSearch.bind(this);
|
|
93
|
+
this.onSearchGroups = this.onSearchGroups.bind(this);
|
|
94
|
+
this.deleteGroup = this.deleteGroup.bind(this);
|
|
95
|
+
this.onDeleteOk = this.onDeleteOk.bind(this);
|
|
96
|
+
this.onDeleteCancel = this.onDeleteCancel.bind(this);
|
|
97
|
+
this.onAddGroupSubmit = this.onAddGroupSubmit.bind(this);
|
|
98
|
+
this.onAddGroupError = this.onAddGroupError.bind(this);
|
|
99
|
+
this.onAddGroupSuccess = this.onAddGroupSuccess.bind(this);
|
|
100
|
+
this.updateGroupRole = this.updateGroupRole.bind(this);
|
|
101
|
+
this.state = {
|
|
102
|
+
search: '',
|
|
103
|
+
isLoading: false,
|
|
104
|
+
addGroupError: '',
|
|
105
|
+
showDelete: false,
|
|
106
|
+
groupToDelete: undefined,
|
|
107
|
+
showAddGroup: false,
|
|
108
|
+
groupEntries: [],
|
|
109
|
+
isClient: false,
|
|
110
|
+
authenticatedRole: props.inheritedRole || [],
|
|
111
|
+
currentPage: 0,
|
|
112
|
+
pageSize: 10,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fetchData = async () => {
|
|
117
|
+
await this.props.getControlpanel('usergroup');
|
|
118
|
+
await this.props.listRoles();
|
|
119
|
+
if (!this.props.many_groups) {
|
|
120
|
+
await this.props.listGroups();
|
|
121
|
+
const inheritedRoles = this.props.groups?.find(
|
|
122
|
+
(el) => el.id === 'AuthenticatedUsers',
|
|
123
|
+
)?.roles;
|
|
124
|
+
this.setState({
|
|
125
|
+
groupEntries: this.props.groups,
|
|
126
|
+
authenticatedRole: inheritedRoles,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Component did mount
|
|
132
|
+
* @method componentDidMount
|
|
133
|
+
* @returns {undefined}
|
|
134
|
+
*/
|
|
135
|
+
componentDidMount() {
|
|
136
|
+
this.setState({
|
|
137
|
+
isClient: true,
|
|
138
|
+
});
|
|
139
|
+
this.fetchData();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
143
|
+
if (
|
|
144
|
+
(this.props.deleteGroupRequest.loading &&
|
|
145
|
+
nextProps.deleteGroupRequest.loaded) ||
|
|
146
|
+
(this.props.createGroupRequest.loading &&
|
|
147
|
+
nextProps.createGroupRequest.loaded)
|
|
148
|
+
) {
|
|
149
|
+
this.props.listGroups(this.state.search);
|
|
150
|
+
}
|
|
151
|
+
if (
|
|
152
|
+
this.props.createGroupRequest.loading &&
|
|
153
|
+
nextProps.createGroupRequest.loaded
|
|
154
|
+
) {
|
|
155
|
+
this.onAddGroupSuccess();
|
|
156
|
+
}
|
|
157
|
+
if (
|
|
158
|
+
this.props.createGroupRequest.loading &&
|
|
159
|
+
nextProps.createGroupRequest.error
|
|
160
|
+
) {
|
|
161
|
+
this.onAddGroupError(nextProps.createGroupRequest.error);
|
|
162
|
+
}
|
|
163
|
+
if (
|
|
164
|
+
this.props.loadRolesRequest.loading &&
|
|
165
|
+
nextProps.loadRolesRequest.error
|
|
166
|
+
) {
|
|
167
|
+
this.setState({
|
|
168
|
+
error: nextProps.loadRolesRequest.error,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getGroupFromProps(value) {
|
|
174
|
+
return find(this.props.groups, ['@id', value]);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
*
|
|
179
|
+
*
|
|
180
|
+
* @param {*} event Event object
|
|
181
|
+
* @memberof GroupsControlpanel
|
|
182
|
+
* @returns {undefined}
|
|
183
|
+
*/
|
|
184
|
+
onSearchGroups(event) {
|
|
185
|
+
this.setState({ isLoading: true });
|
|
186
|
+
event.preventDefault();
|
|
187
|
+
this.props
|
|
188
|
+
.listGroups(this.state.search)
|
|
189
|
+
.then(() => {
|
|
190
|
+
this.setState({ isLoading: false });
|
|
191
|
+
})
|
|
192
|
+
.catch((error) => {
|
|
193
|
+
this.setState({ isLoading: false });
|
|
194
|
+
// eslint-disable-next-line no-console
|
|
195
|
+
console.error('Error searching group', error);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* On change search handler
|
|
201
|
+
* @method onChangeSearch
|
|
202
|
+
* @param {object} event Event object.
|
|
203
|
+
* @returns {undefined}
|
|
204
|
+
*/
|
|
205
|
+
onChangeSearch(event) {
|
|
206
|
+
this.setState({
|
|
207
|
+
search: event.target.value,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
*
|
|
213
|
+
*
|
|
214
|
+
* @param {*} event Event object.
|
|
215
|
+
* @param {*} { value } id (groupname)
|
|
216
|
+
* @memberof GroupsControlpanel
|
|
217
|
+
* @returns {undefined}
|
|
218
|
+
*/
|
|
219
|
+
deleteGroup(event, { value }) {
|
|
220
|
+
if (value) {
|
|
221
|
+
this.setState({
|
|
222
|
+
showDelete: true,
|
|
223
|
+
groupToDelete: this.getGroupFromProps(value),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* On delete ok
|
|
230
|
+
* @method onDeleteOk
|
|
231
|
+
* @returns {undefined}
|
|
232
|
+
*/
|
|
233
|
+
onDeleteOk() {
|
|
234
|
+
if (this.state.groupToDelete) {
|
|
235
|
+
this.props.deleteGroup(this.state.groupToDelete.id);
|
|
236
|
+
this.setState({
|
|
237
|
+
showDelete: false,
|
|
238
|
+
groupToDelete: undefined,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* On delete cancel
|
|
245
|
+
* @method onDeleteCancel
|
|
246
|
+
* @returns {undefined}
|
|
247
|
+
*/
|
|
248
|
+
onDeleteCancel() {
|
|
249
|
+
this.setState({
|
|
250
|
+
showDelete: false,
|
|
251
|
+
itemsToDelete: [],
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
*
|
|
257
|
+
* @param {*} name
|
|
258
|
+
* @param {*} value
|
|
259
|
+
* @memberof GroupsControlpanel
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
updateGroupRole(name, value) {
|
|
263
|
+
this.setState((prevState) => {
|
|
264
|
+
let updatedAuthenticatedRole;
|
|
265
|
+
// check if checkbox is AuthenticatedUsers
|
|
266
|
+
if (name === 'AuthenticatedUsers') {
|
|
267
|
+
// check if that role is already set
|
|
268
|
+
updatedAuthenticatedRole = prevState.authenticatedRole.includes(value)
|
|
269
|
+
? // Remove role if unchecked
|
|
270
|
+
prevState.authenticatedRole.filter((role) => role !== value)
|
|
271
|
+
: // Add role if checked
|
|
272
|
+
[...prevState.authenticatedRole, value];
|
|
273
|
+
} else {
|
|
274
|
+
// if not AuthenticatedUser, do not change the authenticated roles
|
|
275
|
+
updatedAuthenticatedRole = prevState.authenticatedRole;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Handle the groupEntries role update
|
|
279
|
+
const updatedGroupEntries = map(prevState.groupEntries, (entry) => {
|
|
280
|
+
if (entry.id === name) {
|
|
281
|
+
if (entry.roles.includes(value)) {
|
|
282
|
+
// If the role is unchecked, remove it from roles
|
|
283
|
+
return {
|
|
284
|
+
...entry,
|
|
285
|
+
roles: entry.roles.filter((role) => role !== value),
|
|
286
|
+
};
|
|
287
|
+
} else {
|
|
288
|
+
// If the role is checked, add it to roles
|
|
289
|
+
return {
|
|
290
|
+
...entry,
|
|
291
|
+
roles: [...entry.roles, value],
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
} else if (
|
|
295
|
+
name === 'AuthenticatedUsers' &&
|
|
296
|
+
!prevState.authenticatedRole.includes(value)
|
|
297
|
+
) {
|
|
298
|
+
// If 'AuthenticatedUsers' is unchecked, reset the other group roles
|
|
299
|
+
return {
|
|
300
|
+
...entry,
|
|
301
|
+
roles: entry.roles.filter((role) => role !== value), // Remove the role from all other groups
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return entry; // For other entries, return unchanged
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
groupEntries: updatedGroupEntries,
|
|
310
|
+
authenticatedRole: updatedAuthenticatedRole,
|
|
311
|
+
};
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* @param {*} event
|
|
316
|
+
* @memberof GroupsControlpanel
|
|
317
|
+
*/
|
|
318
|
+
updateGroupRoleSubmit = (e) => {
|
|
319
|
+
e.stopPropagation();
|
|
320
|
+
this.state.groupEntries.forEach((item) => {
|
|
321
|
+
this.props.updateGroup(item.id, item);
|
|
322
|
+
});
|
|
323
|
+
this.props.authenticatedRole(this.state.authenticatedRole);
|
|
324
|
+
toast.success(
|
|
325
|
+
<Toast
|
|
326
|
+
success
|
|
327
|
+
title={this.props.intl.formatMessage(messages.success)}
|
|
328
|
+
content={this.props.intl.formatMessage(messages.updateGroups)}
|
|
329
|
+
/>,
|
|
330
|
+
);
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
*
|
|
334
|
+
*
|
|
335
|
+
* @param {object} data Form data from the ModalForm.
|
|
336
|
+
* @param {func} callback to set new form data in the ModalForm
|
|
337
|
+
* @memberof GroupsControlpanel
|
|
338
|
+
* @returns {undefined}
|
|
339
|
+
*/
|
|
340
|
+
onAddGroupSubmit(data, callback) {
|
|
341
|
+
this.props.createGroup(data);
|
|
342
|
+
this.setState({
|
|
343
|
+
addGroupSetFormDataCallback: callback,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Handle Errors after createGroup()
|
|
349
|
+
*
|
|
350
|
+
* @param {*} error object. Requires the property .message
|
|
351
|
+
* @memberof GroupsControlpanel
|
|
352
|
+
* @returns {undefined}
|
|
353
|
+
*/
|
|
354
|
+
onAddGroupError(error) {
|
|
355
|
+
this.setState({
|
|
356
|
+
addGroupError: error.response.body.message,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
componentDidUpdate(prevProps, prevState) {
|
|
361
|
+
if (this.props.groups !== prevProps.groups) {
|
|
362
|
+
this.setState({
|
|
363
|
+
groupEntries: this.props.groups,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Handle Success after createGroup()
|
|
370
|
+
*
|
|
371
|
+
* @memberof GroupsControlpanel
|
|
372
|
+
* @returns {undefined}
|
|
373
|
+
*/
|
|
374
|
+
onAddGroupSuccess() {
|
|
375
|
+
this.state.addGroupSetFormDataCallback({});
|
|
376
|
+
this.setState({
|
|
377
|
+
showAddGroup: false,
|
|
378
|
+
addGroupError: undefined,
|
|
379
|
+
addGroupSetFormDataCallback: undefined,
|
|
380
|
+
});
|
|
381
|
+
toast.success(
|
|
382
|
+
<Toast
|
|
383
|
+
success
|
|
384
|
+
title={this.props.intl.formatMessage(messages.success)}
|
|
385
|
+
content={this.props.intl.formatMessage(messages.groupCreated)}
|
|
386
|
+
/>,
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* On change page
|
|
392
|
+
* @method onChangePage
|
|
393
|
+
* @param {object} event Event object.
|
|
394
|
+
* @param {string} value Page value.
|
|
395
|
+
* @returns {undefined}
|
|
396
|
+
*/
|
|
397
|
+
onChangePage = (event, { value }) => {
|
|
398
|
+
this.setState({
|
|
399
|
+
currentPage: value,
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Render method.
|
|
405
|
+
* @method render
|
|
406
|
+
* @returns {string} Markup for the component.
|
|
407
|
+
*/
|
|
408
|
+
render() {
|
|
409
|
+
if (this.state.error) {
|
|
410
|
+
return <Error error={this.state.error} />;
|
|
411
|
+
}
|
|
412
|
+
/*let fullnameToDelete = this.state.groupToDelete
|
|
413
|
+
? this.state.groupToDelete.fullname
|
|
414
|
+
: '';*/
|
|
415
|
+
let groupNameToDelete = this.state.groupToDelete
|
|
416
|
+
? this.state.groupToDelete.id
|
|
417
|
+
: '';
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<Container className="users-control-panel">
|
|
421
|
+
<Helmet title={this.props.intl.formatMessage(messages.groups)} />
|
|
422
|
+
<div className="container">
|
|
423
|
+
<Confirm
|
|
424
|
+
open={this.state.showDelete}
|
|
425
|
+
header={this.props.intl.formatMessage(
|
|
426
|
+
messages.deleteGroupConfirmTitle,
|
|
427
|
+
)}
|
|
428
|
+
content={
|
|
429
|
+
<div className="content">
|
|
430
|
+
<ul className="content">
|
|
431
|
+
<FormattedMessage
|
|
432
|
+
id="Do you really want to delete the group {groupname}?"
|
|
433
|
+
defaultMessage="Do you really want to delete the group {groupname}?"
|
|
434
|
+
values={{
|
|
435
|
+
groupname: <b>{groupNameToDelete}</b>,
|
|
436
|
+
}}
|
|
437
|
+
/>
|
|
438
|
+
</ul>
|
|
439
|
+
</div>
|
|
440
|
+
}
|
|
441
|
+
onCancel={this.onDeleteCancel}
|
|
442
|
+
onConfirm={this.onDeleteOk}
|
|
443
|
+
size={null}
|
|
444
|
+
/>
|
|
445
|
+
{this.state.showAddGroup ? (
|
|
446
|
+
<ModalForm
|
|
447
|
+
open={this.state.showAddGroup}
|
|
448
|
+
className="modal"
|
|
449
|
+
onSubmit={this.onAddGroupSubmit}
|
|
450
|
+
submitError={this.state.addGroupError}
|
|
451
|
+
onCancel={() => this.setState({ showAddGroup: false })}
|
|
452
|
+
title={this.props.intl.formatMessage(messages.addGroupsFormTitle)}
|
|
453
|
+
loading={this.props.createGroupRequest.loading}
|
|
454
|
+
schema={{
|
|
455
|
+
fieldsets: [
|
|
456
|
+
{
|
|
457
|
+
id: 'default',
|
|
458
|
+
title: 'FIXME: Group Data',
|
|
459
|
+
fields: [
|
|
460
|
+
'title',
|
|
461
|
+
'description',
|
|
462
|
+
'groupname',
|
|
463
|
+
'email',
|
|
464
|
+
'roles',
|
|
465
|
+
],
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
properties: {
|
|
469
|
+
title: {
|
|
470
|
+
title: this.props.intl.formatMessage(
|
|
471
|
+
messages.addGroupsFormTitleTitle,
|
|
472
|
+
),
|
|
473
|
+
type: 'string',
|
|
474
|
+
description: '',
|
|
475
|
+
},
|
|
476
|
+
description: {
|
|
477
|
+
title: this.props.intl.formatMessage(
|
|
478
|
+
messages.addGroupsFormDescriptionTitle,
|
|
479
|
+
),
|
|
480
|
+
type: 'string',
|
|
481
|
+
description: '',
|
|
482
|
+
},
|
|
483
|
+
groupname: {
|
|
484
|
+
title: this.props.intl.formatMessage(
|
|
485
|
+
messages.addGroupsFormGroupNameTitle,
|
|
486
|
+
),
|
|
487
|
+
type: 'string',
|
|
488
|
+
description:
|
|
489
|
+
'A unique identifier for the group. Can not be changed after creation.',
|
|
490
|
+
},
|
|
491
|
+
email: {
|
|
492
|
+
title: this.props.intl.formatMessage(
|
|
493
|
+
messages.addGroupsFormEmailTitle,
|
|
494
|
+
),
|
|
495
|
+
type: 'string',
|
|
496
|
+
description: '',
|
|
497
|
+
widget: 'email',
|
|
498
|
+
},
|
|
499
|
+
roles: {
|
|
500
|
+
title: this.props.intl.formatMessage(
|
|
501
|
+
messages.addGroupsFormRolesTitle,
|
|
502
|
+
),
|
|
503
|
+
type: 'array',
|
|
504
|
+
choices: this.props.roles.map((role) => [
|
|
505
|
+
role.id,
|
|
506
|
+
role.title,
|
|
507
|
+
]),
|
|
508
|
+
noValueOption: false,
|
|
509
|
+
description: '',
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
required: ['groupname'],
|
|
513
|
+
}}
|
|
514
|
+
/>
|
|
515
|
+
) : null}
|
|
516
|
+
</div>
|
|
517
|
+
<Segment.Group raised>
|
|
518
|
+
<Segment className="primary">
|
|
519
|
+
<FormattedMessage id="Groups" defaultMessage="Groups" />
|
|
520
|
+
</Segment>
|
|
521
|
+
<Segment secondary>
|
|
522
|
+
<FormattedMessage
|
|
523
|
+
id="Groups are logical collections of users, such as departments and business units. Groups are not directly related to permissions on a global level, you normally use Roles for that - and let certain Groups have a particular role. The symbol{plone_svg}indicates a role inherited from membership in another group."
|
|
524
|
+
defaultMessage="Groups are logical collections of users, such as departments and business units. Groups are not directly related to permissions on a global level, you normally use Roles for that - and let certain Groups have a particular role. The symbol{plone_svg}indicates a role inherited from membership in another group."
|
|
525
|
+
values={{
|
|
526
|
+
plone_svg: (
|
|
527
|
+
<Icon
|
|
528
|
+
name={ploneSVG}
|
|
529
|
+
size="20px"
|
|
530
|
+
color="#007EB1"
|
|
531
|
+
title={'plone-svg'}
|
|
532
|
+
/>
|
|
533
|
+
),
|
|
534
|
+
}}
|
|
535
|
+
/>
|
|
536
|
+
</Segment>
|
|
537
|
+
<Segment>
|
|
538
|
+
<Form onSubmit={this.onSearchGroups}>
|
|
539
|
+
<Form.Field>
|
|
540
|
+
<Input
|
|
541
|
+
name="SearchableText"
|
|
542
|
+
action={{
|
|
543
|
+
icon: 'search',
|
|
544
|
+
loading: this.state.isLoading,
|
|
545
|
+
disabled: this.state.isLoading,
|
|
546
|
+
}}
|
|
547
|
+
placeholder={this.props.intl.formatMessage(
|
|
548
|
+
messages.searchGroups,
|
|
549
|
+
)}
|
|
550
|
+
onChange={this.onChangeSearch}
|
|
551
|
+
id="group-search-input"
|
|
552
|
+
/>
|
|
553
|
+
</Form.Field>
|
|
554
|
+
</Form>
|
|
555
|
+
</Segment>
|
|
556
|
+
<Form>
|
|
557
|
+
<div className="table">
|
|
558
|
+
{((this.props.many_groups &&
|
|
559
|
+
this.state.groupEntries.length > 0) ||
|
|
560
|
+
!this.props.many_groups) && (
|
|
561
|
+
<Table padded striped attached unstackable>
|
|
562
|
+
<Table.Header>
|
|
563
|
+
<Table.Row>
|
|
564
|
+
<Table.HeaderCell>
|
|
565
|
+
<FormattedMessage
|
|
566
|
+
id="Groupname"
|
|
567
|
+
defaultMessage="Groupname"
|
|
568
|
+
/>
|
|
569
|
+
</Table.HeaderCell>
|
|
570
|
+
{this.props.roles.map((role) => (
|
|
571
|
+
<Table.HeaderCell key={role.id}>
|
|
572
|
+
{role.title}
|
|
573
|
+
</Table.HeaderCell>
|
|
574
|
+
))}
|
|
575
|
+
<Table.HeaderCell>
|
|
576
|
+
<FormattedMessage
|
|
577
|
+
id="Actions"
|
|
578
|
+
defaultMessage="Actions"
|
|
579
|
+
/>
|
|
580
|
+
</Table.HeaderCell>
|
|
581
|
+
</Table.Row>
|
|
582
|
+
</Table.Header>
|
|
583
|
+
<Table.Body data-group="groups">
|
|
584
|
+
{this.state.groupEntries
|
|
585
|
+
.slice(
|
|
586
|
+
this.state.currentPage * 10,
|
|
587
|
+
this.state.pageSize * (this.state.currentPage + 1),
|
|
588
|
+
)
|
|
589
|
+
.map((group) => (
|
|
590
|
+
<RenderGroups
|
|
591
|
+
key={group.id}
|
|
592
|
+
onDelete={this.deleteGroup}
|
|
593
|
+
roles={this.props.roles}
|
|
594
|
+
group={group}
|
|
595
|
+
updateGroups={this.updateGroupRole}
|
|
596
|
+
inheritedRole={this.state.authenticatedRole}
|
|
597
|
+
/>
|
|
598
|
+
))}
|
|
599
|
+
</Table.Body>
|
|
600
|
+
</Table>
|
|
601
|
+
)}
|
|
602
|
+
{this.state.groupEntries.length === 0 && this.state.search && (
|
|
603
|
+
<Segment>
|
|
604
|
+
{this.props.intl.formatMessage(messages.groupSearchNoResults)}
|
|
605
|
+
</Segment>
|
|
606
|
+
)}
|
|
607
|
+
</div>
|
|
608
|
+
<div className="contents-pagination">
|
|
609
|
+
<Pagination
|
|
610
|
+
current={this.state.currentPage}
|
|
611
|
+
total={Math.ceil(
|
|
612
|
+
this.state.groupEntries?.length / this.state.pageSize,
|
|
613
|
+
)}
|
|
614
|
+
onChangePage={this.onChangePage}
|
|
615
|
+
/>
|
|
616
|
+
</div>
|
|
617
|
+
</Form>
|
|
618
|
+
</Segment.Group>
|
|
619
|
+
{this.state.isClient && (
|
|
620
|
+
<Portal node={document.getElementById('toolbar')}>
|
|
621
|
+
<Toolbar
|
|
622
|
+
pathname={this.props.pathname}
|
|
623
|
+
hideDefaultViewButtons
|
|
624
|
+
inner={
|
|
625
|
+
<>
|
|
626
|
+
<Button
|
|
627
|
+
id="toolbar-save"
|
|
628
|
+
className="save"
|
|
629
|
+
aria-label={this.props.intl.formatMessage(messages.save)}
|
|
630
|
+
onClick={this.updateGroupRoleSubmit}
|
|
631
|
+
loading={this.props.createGroupRequest.loading}
|
|
632
|
+
>
|
|
633
|
+
<Icon
|
|
634
|
+
name={saveSVG}
|
|
635
|
+
className="circled"
|
|
636
|
+
size="30px"
|
|
637
|
+
title={this.props.intl.formatMessage(messages.save)}
|
|
638
|
+
/>
|
|
639
|
+
</Button>
|
|
640
|
+
<Link to="/controlpanel" className="cancel">
|
|
641
|
+
<Icon
|
|
642
|
+
name={clearSVG}
|
|
643
|
+
className="circled"
|
|
644
|
+
aria-label={this.props.intl.formatMessage(
|
|
645
|
+
messages.cancel,
|
|
646
|
+
)}
|
|
647
|
+
size="30px"
|
|
648
|
+
title={this.props.intl.formatMessage(messages.cancel)}
|
|
649
|
+
/>
|
|
650
|
+
</Link>
|
|
651
|
+
<Button
|
|
652
|
+
id="toolbar-add"
|
|
653
|
+
aria-label={this.props.intl.formatMessage(
|
|
654
|
+
messages.addGroupsButtonTitle,
|
|
655
|
+
)}
|
|
656
|
+
onClick={() => {
|
|
657
|
+
this.setState({ showAddGroup: true });
|
|
658
|
+
}}
|
|
659
|
+
loading={this.props.createGroupRequest.loading}
|
|
660
|
+
>
|
|
661
|
+
<Icon
|
|
662
|
+
name={addUserSvg}
|
|
663
|
+
size="45px"
|
|
664
|
+
color="#826A6A"
|
|
665
|
+
title={this.props.intl.formatMessage(
|
|
666
|
+
messages.addGroupsButtonTitle,
|
|
667
|
+
)}
|
|
668
|
+
/>
|
|
669
|
+
</Button>
|
|
670
|
+
</>
|
|
671
|
+
}
|
|
672
|
+
/>
|
|
673
|
+
</Portal>
|
|
674
|
+
)}
|
|
675
|
+
</Container>
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
export default compose(
|
|
681
|
+
injectIntl,
|
|
682
|
+
connect(
|
|
683
|
+
(state, props) => ({
|
|
684
|
+
roles: state.roles.roles,
|
|
685
|
+
groups: state.groups.groups,
|
|
686
|
+
description: state.description,
|
|
687
|
+
many_users: state.controlpanels?.controlpanel?.data?.many_users,
|
|
688
|
+
many_groups: state.controlpanels?.controlpanel?.data?.many_groups,
|
|
689
|
+
pathname: props.location.pathname,
|
|
690
|
+
deleteGroupRequest: state.groups.delete,
|
|
691
|
+
createGroupRequest: state.groups.create,
|
|
692
|
+
loadRolesRequest: state.roles,
|
|
693
|
+
inheritedRole: state.authRole.authenticatedRole,
|
|
694
|
+
}),
|
|
695
|
+
(dispatch) =>
|
|
696
|
+
bindActionCreators(
|
|
697
|
+
{
|
|
698
|
+
listRoles,
|
|
699
|
+
listGroups,
|
|
700
|
+
deleteGroup,
|
|
701
|
+
getControlpanel,
|
|
702
|
+
createGroup,
|
|
703
|
+
updateGroup,
|
|
704
|
+
authenticatedRole,
|
|
705
|
+
},
|
|
706
|
+
dispatch,
|
|
707
|
+
),
|
|
708
|
+
),
|
|
709
|
+
)(GroupsControlpanel);
|