@plone/volto 18.0.0-alpha.17 → 18.0.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +48 -2
  2. package/locales/ca/LC_MESSAGES/volto.po +17 -42
  3. package/locales/ca.json +1 -1
  4. package/locales/de/LC_MESSAGES/volto.po +15 -40
  5. package/locales/de.json +1 -1
  6. package/locales/en/LC_MESSAGES/volto.po +14 -39
  7. package/locales/en.json +1 -1
  8. package/locales/es/LC_MESSAGES/volto.po +15 -40
  9. package/locales/es.json +1 -1
  10. package/locales/eu/LC_MESSAGES/volto.po +15 -40
  11. package/locales/eu.json +1 -1
  12. package/locales/fi/LC_MESSAGES/volto.po +15 -40
  13. package/locales/fi.json +1 -1
  14. package/locales/fr/LC_MESSAGES/volto.po +15 -40
  15. package/locales/fr.json +1 -1
  16. package/locales/it/LC_MESSAGES/volto.po +15 -40
  17. package/locales/it.json +1 -1
  18. package/locales/ja/LC_MESSAGES/volto.po +15 -40
  19. package/locales/ja.json +1 -1
  20. package/locales/nl/LC_MESSAGES/volto.po +14 -39
  21. package/locales/nl.json +1 -1
  22. package/locales/pt/LC_MESSAGES/volto.po +15 -40
  23. package/locales/pt.json +1 -1
  24. package/locales/pt_BR/LC_MESSAGES/volto.po +15 -40
  25. package/locales/pt_BR.json +1 -1
  26. package/locales/ro/LC_MESSAGES/volto.po +15 -40
  27. package/locales/ro.json +1 -1
  28. package/locales/volto.pot +15 -40
  29. package/locales/zh_CN/LC_MESSAGES/volto.po +15 -40
  30. package/locales/zh_CN.json +1 -1
  31. package/package.json +11 -21
  32. package/src/components/index.js +0 -6
  33. package/src/components/manage/Add/Add.jsx +1 -1
  34. package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +8 -2
  35. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +2 -2
  36. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +33 -5
  37. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +12 -0
  38. package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +22 -11
  39. package/src/components/manage/Controlpanels/Groups/RenderGroups.test.jsx +21 -0
  40. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +30 -21
  41. package/src/components/manage/Controlpanels/Users/RenderUsers.test.jsx +27 -1
  42. package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +29 -7
  43. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +51 -3
  44. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +8 -0
  45. package/src/components/manage/Form/Form.jsx +1 -1
  46. package/src/components/theme/SlotRenderer/SlotRenderer.tsx +8 -1
  47. package/src/config/Blocks.jsx +63 -67
  48. package/src/config/Loadables.jsx +0 -22
  49. package/src/config/Widgets.jsx +0 -2
  50. package/src/config/index.js +0 -13
  51. package/src/helpers/User/User.js +29 -0
  52. package/src/helpers/index.js +6 -1
  53. package/test-setup-config.js +0 -30
  54. package/types/components/index.d.ts +0 -6
  55. package/types/config/Blocks.d.ts +0 -51
  56. package/types/config/Loadables.d.ts +0 -10
  57. package/types/config/Widgets.d.ts +0 -2
  58. package/types/helpers/User/User.d.ts +18 -0
  59. package/types/helpers/index.d.ts +1 -1
  60. package/webpack-plugins/webpack-bundle-analyze-plugin.js +1 -1
  61. package/src/components/manage/AnchorPlugin/components/Link/index.jsx +0 -37
  62. package/src/components/manage/AnchorPlugin/components/LinkButton/index.jsx +0 -126
  63. package/src/components/manage/AnchorPlugin/index.jsx +0 -82
  64. package/src/components/manage/AnchorPlugin/linkStrategy.js +0 -21
  65. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +0 -47
  66. package/src/components/manage/Blocks/HeroImageLeft/Data.jsx +0 -29
  67. package/src/components/manage/Blocks/HeroImageLeft/Edit.jsx +0 -493
  68. package/src/components/manage/Blocks/HeroImageLeft/Edit.test.jsx +0 -58
  69. package/src/components/manage/Blocks/HeroImageLeft/View.jsx +0 -37
  70. package/src/components/manage/Blocks/HeroImageLeft/View.test.jsx +0 -9
  71. package/src/components/manage/Blocks/HeroImageLeft/schema.js +0 -43
  72. package/src/components/manage/Blocks/Table/Cell.jsx +0 -206
  73. package/src/components/manage/Blocks/Table/Cell.test.jsx +0 -19
  74. package/src/components/manage/Blocks/Table/Edit.jsx +0 -748
  75. package/src/components/manage/Blocks/Table/Edit.test.jsx +0 -44
  76. package/src/components/manage/Blocks/Table/Readme.md +0 -5
  77. package/src/components/manage/Blocks/Table/View.jsx +0 -51
  78. package/src/components/manage/Blocks/Table/View.test.jsx +0 -41
  79. package/src/components/manage/Blocks/Text/Edit.jsx +0 -372
  80. package/src/components/manage/Blocks/Text/Edit.test.jsx +0 -46
  81. package/src/components/manage/Blocks/Text/Readme.md +0 -5
  82. package/src/components/manage/Blocks/Text/Schema.jsx +0 -31
  83. package/src/components/manage/Blocks/Text/View.jsx +0 -26
  84. package/src/components/manage/Blocks/Text/View.test.jsx +0 -28
  85. package/src/components/manage/LinkDetectionPlugin/link-detection-plugin.jsx +0 -227
  86. package/src/components/manage/LinkDetectionPlugin/utils.js +0 -12
  87. package/src/components/manage/Widgets/WysiwygWidget.jsx +0 -350
  88. package/src/components/manage/Widgets/WysiwygWidget.stories.jsx +0 -24
  89. package/src/components/manage/Widgets/WysiwygWidget.test.jsx +0 -37
  90. package/src/config/RichTextEditor/Blocks.jsx +0 -29
  91. package/src/config/RichTextEditor/FromHTML.jsx +0 -8
  92. package/src/config/RichTextEditor/Plugins.jsx +0 -59
  93. package/src/config/RichTextEditor/Styles.jsx +0 -69
  94. package/src/config/RichTextEditor/ToHTML.jsx +0 -262
  95. package/src/config/RichTextEditor/index.js +0 -25
@@ -9,6 +9,7 @@ import { Dropdown, Table, Checkbox } from 'semantic-ui-react';
9
9
  import trashSVG from '@plone/volto/icons/delete.svg';
10
10
  import ploneSVG from '@plone/volto/icons/plone.svg';
11
11
  import { Icon } from '@plone/volto/components';
12
+ import { canAssignRole } from '@plone/volto/helpers';
12
13
 
13
14
  /**
14
15
  * UsersControlpanelGroups class.
@@ -38,6 +39,7 @@ class RenderGroups extends Component {
38
39
  ).isRequired,
39
40
  inheritedRole: PropTypes.array,
40
41
  onDelete: PropTypes.func.isRequired,
42
+ isUserManager: PropTypes.bool.isRequired,
41
43
  };
42
44
 
43
45
  /**
@@ -69,6 +71,12 @@ class RenderGroups extends Component {
69
71
  isAuthGroup = (roleId) => {
70
72
  return this.props.inheritedRole.includes(roleId);
71
73
  };
74
+
75
+ canDeleteGroup() {
76
+ if (this.props.isUserManager) return true;
77
+ return !this.props.group.roles.includes('Manager');
78
+ }
79
+
72
80
  /**
73
81
  * Render method.
74
82
  * @method render
@@ -98,22 +106,25 @@ class RenderGroups extends Component {
98
106
  }
99
107
  onChange={this.onChange}
100
108
  value={`${this.props.group.id}&role=${role.id}`}
109
+ disabled={!canAssignRole(this.props.isUserManager, role)}
101
110
  />
102
111
  )}
103
112
  </Table.Cell>
104
113
  ))}
105
114
  <Table.Cell textAlign="right">
106
- <Dropdown icon="ellipsis horizontal">
107
- <Dropdown.Menu className="left">
108
- <Dropdown.Item
109
- onClick={this.props.onDelete}
110
- value={this.props.group['@id']}
111
- >
112
- <Icon name={trashSVG} size="15px" />
113
- <FormattedMessage id="Delete" defaultMessage="Delete" />
114
- </Dropdown.Item>
115
- </Dropdown.Menu>
116
- </Dropdown>
115
+ {this.canDeleteGroup() && (
116
+ <Dropdown icon="ellipsis horizontal">
117
+ <Dropdown.Menu className="left">
118
+ <Dropdown.Item
119
+ onClick={this.props.onDelete}
120
+ value={this.props.group['@id']}
121
+ >
122
+ <Icon name={trashSVG} size="15px" />
123
+ <FormattedMessage id="Delete" defaultMessage="Delete" />
124
+ </Dropdown.Item>
125
+ </Dropdown.Menu>
126
+ </Dropdown>
127
+ )}
117
128
  </Table.Cell>
118
129
  </Table.Row>
119
130
  );
@@ -49,6 +49,27 @@ describe('UsersControlpanelGroups', () => {
49
49
  group={testGroups}
50
50
  roles={testRoles}
51
51
  onDelete={() => {}}
52
+ isUserManager={true}
53
+ />
54
+ </Provider>,
55
+ );
56
+ const json = component.toJSON();
57
+ expect(json).toMatchSnapshot();
58
+ });
59
+ it('renders a UsersControlpanelGroups component with no Manager user', () => {
60
+ const store = mockStore({
61
+ intl: {
62
+ locale: 'en',
63
+ messages: {},
64
+ },
65
+ });
66
+ const component = renderer.create(
67
+ <Provider store={store}>
68
+ <RenderGroups
69
+ group={testGroups}
70
+ roles={testRoles}
71
+ onDelete={() => {}}
72
+ isUserManager={false}
52
73
  />
53
74
  </Provider>,
54
75
  );
@@ -13,7 +13,7 @@ import { updateUser } from '@plone/volto/actions';
13
13
  import ploneSVG from '@plone/volto/icons/plone.svg';
14
14
  import { compose } from 'redux';
15
15
  import { connect } from 'react-redux';
16
- import { messages } from '@plone/volto/helpers';
16
+ import { messages, canAssignRole } from '@plone/volto/helpers';
17
17
  import { toast } from 'react-toastify';
18
18
 
19
19
  /**
@@ -39,6 +39,7 @@ class RenderUsers extends Component {
39
39
  }),
40
40
  ).isRequired,
41
41
  onDelete: PropTypes.func.isRequired,
42
+ isUserManager: PropTypes.bool.isRequired,
42
43
  };
43
44
 
44
45
  /**
@@ -110,6 +111,11 @@ class RenderUsers extends Component {
110
111
  this.setState({ user: { ...formData } });
111
112
  }
112
113
 
114
+ canDeleteUser() {
115
+ if (this.props.isUserManager) return true;
116
+ return !this.props.user.roles.includes('Manager');
117
+ }
118
+
113
119
  /**
114
120
  * Render method.
115
121
  * @method render
@@ -139,35 +145,38 @@ class RenderUsers extends Component {
139
145
  checked={this.props.user.roles.includes(role.id)}
140
146
  onChange={this.onChange}
141
147
  value={`${this.props.user.id}&role=${role.id}`}
148
+ disabled={!canAssignRole(this.props.isUserManager, role)}
142
149
  />
143
150
  )}
144
151
  </Table.Cell>
145
152
  ))}
146
153
  <Table.Cell textAlign="right">
147
- <Dropdown icon="ellipsis horizontal">
148
- <Dropdown.Menu className="left">
149
- {this.props.userschema && (
154
+ {this.canDeleteUser() && (
155
+ <Dropdown icon="ellipsis horizontal">
156
+ <Dropdown.Menu className="left">
157
+ {this.props.userschema && (
158
+ <Dropdown.Item
159
+ id="edit-user-button"
160
+ onClick={() => {
161
+ this.onClickEdit({ formData: this.props.user });
162
+ }}
163
+ value={this.props.user['@id']}
164
+ >
165
+ <Icon name={editSVG} size="15px" />
166
+ <FormattedMessage id="Edit" defaultMessage="Edit" />
167
+ </Dropdown.Item>
168
+ )}
150
169
  <Dropdown.Item
151
- id="edit-user-button"
152
- onClick={() => {
153
- this.onClickEdit({ formData: this.props.user });
154
- }}
170
+ id="delete-user-button"
171
+ onClick={this.props.onDelete}
155
172
  value={this.props.user['@id']}
156
173
  >
157
- <Icon name={editSVG} size="15px" />
158
- <FormattedMessage id="Edit" defaultMessage="Edit" />
174
+ <Icon name={trashSVG} size="15px" />
175
+ <FormattedMessage id="Delete" defaultMessage="Delete" />
159
176
  </Dropdown.Item>
160
- )}
161
- <Dropdown.Item
162
- id="delete-user-button"
163
- onClick={this.props.onDelete}
164
- value={this.props.user['@id']}
165
- >
166
- <Icon name={trashSVG} size="15px" />
167
- <FormattedMessage id="Delete" defaultMessage="Delete" />
168
- </Dropdown.Item>
169
- </Dropdown.Menu>
170
- </Dropdown>
177
+ </Dropdown.Menu>
178
+ </Dropdown>
179
+ )}
171
180
  </Table.Cell>
172
181
  {Object.keys(this.state.user).length > 0 &&
173
182
  this.props.userschema.loaded && (
@@ -47,7 +47,33 @@ describe('UsersControlpanelUser', () => {
47
47
  });
48
48
  const component = renderer.create(
49
49
  <Provider store={store}>
50
- <RenderUsers user={testUser} roles={testRoles} onDelete={() => {}} />
50
+ <RenderUsers
51
+ user={testUser}
52
+ roles={testRoles}
53
+ onDelete={() => {}}
54
+ isUserManager={true}
55
+ />
56
+ </Provider>,
57
+ );
58
+ const json = component.toJSON();
59
+ expect(json).toMatchSnapshot();
60
+ });
61
+
62
+ it('renders a UsersControlpanelUser component with options disabled if not allowed', () => {
63
+ const store = mockStore({
64
+ intl: {
65
+ locale: 'en',
66
+ messages: {},
67
+ },
68
+ });
69
+ const component = renderer.create(
70
+ <Provider store={store}>
71
+ <RenderUsers
72
+ user={testUser}
73
+ roles={testRoles}
74
+ onDelete={() => {}}
75
+ isUserManager={false}
76
+ />
51
77
  </Provider>,
52
78
  );
53
79
  const json = component.toJSON();
@@ -1,11 +1,12 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { cloneDeep, uniqBy } from 'lodash';
3
3
  import { useIntl } from 'react-intl';
4
- import { useSelector, useDispatch } from 'react-redux';
4
+ import { useSelector, useDispatch, shallowEqual } from 'react-redux';
5
+ import jwtDecode from 'jwt-decode';
5
6
  import { toast } from 'react-toastify';
6
7
  import { Button, Checkbox } from 'semantic-ui-react';
7
- import { messages } from '@plone/volto/helpers';
8
- import { listGroups } from '@plone/volto/actions';
8
+ import { messages, isManager, canAssignGroup } from '@plone/volto/helpers';
9
+ import { listGroups, getUser } from '@plone/volto/actions';
9
10
  import { Icon, Toast } from '@plone/volto/components';
10
11
  import { updateGroup, listUsers } from '@plone/volto/actions';
11
12
 
@@ -25,6 +26,16 @@ const ListingTemplate = ({
25
26
  const pageSize = 25;
26
27
  const [userLimit, setUserLimit] = useState(pageSize);
27
28
 
29
+ const token = useSelector((state) => state.userSession.token, shallowEqual);
30
+ const user = useSelector((state) => state.users.user);
31
+ const userId = token ? jwtDecode(token).sub : '';
32
+
33
+ useEffect(() => {
34
+ dispatch(getUser(userId));
35
+ }, [dispatch, userId]);
36
+
37
+ const isUserManager = isManager(user);
38
+
28
39
  // y axis
29
40
  let items = useSelector((state) => state.users.users);
30
41
  let show_users =
@@ -51,12 +62,17 @@ const ListingTemplate = ({
51
62
 
52
63
  // x axis
53
64
  let groups = useSelector((state) => state.groups.groups);
65
+
66
+ const getRoles = (group_id) => {
67
+ return groups.find((group) => group.id === group_id)?.roles || [];
68
+ };
69
+
54
70
  let show_matrix_options =
55
71
  !many_groups ||
56
72
  (many_groups && query_group.length > 1) ||
57
73
  groups_filter.length > 0 ||
58
74
  add_joined_groups;
59
- let matrix_options; // list of Objects (value, label)
75
+ let matrix_options; // list of Objects (value, label, roles)
60
76
  if (show_matrix_options) {
61
77
  matrix_options =
62
78
  !many_groups || (many_groups && query_group.length > 1)
@@ -90,6 +106,10 @@ const ListingTemplate = ({
90
106
  }
91
107
  return 0;
92
108
  });
109
+ matrix_options = matrix_options.map((matrix_option) => ({
110
+ ...matrix_option,
111
+ roles: getRoles(matrix_option.value),
112
+ }));
93
113
  } else {
94
114
  matrix_options = [];
95
115
  }
@@ -126,7 +146,7 @@ const ListingTemplate = ({
126
146
  },
127
147
  }),
128
148
  )
129
- .then((resp) => {
149
+ .then(() => {
130
150
  singleClick &&
131
151
  dispatch(
132
152
  listUsers({
@@ -209,13 +229,14 @@ const ListingTemplate = ({
209
229
  <Checkbox
210
230
  className="toggle-target"
211
231
  defaultChecked={false}
212
- onChange={(event, { checked }) =>
232
+ onChange={(_event, { checked }) =>
213
233
  onSelectAllHandler(
214
234
  matrix_option.value,
215
235
  items.map((el) => el.id),
216
236
  checked,
217
237
  )
218
238
  }
239
+ disabled={!canAssignGroup(isUserManager, matrix_option)}
219
240
  />
220
241
  </div>
221
242
  ))}
@@ -251,13 +272,14 @@ const ListingTemplate = ({
251
272
  checked={item.groups?.items
252
273
  ?.map((el) => el.id)
253
274
  .includes(matrix_option.value)}
254
- onChange={(event, { checked }) => {
275
+ onChange={(_event, { checked }) => {
255
276
  onSelectOptionHandler(
256
277
  { y: matrix_option.value, x: item.id },
257
278
  checked,
258
279
  true,
259
280
  );
260
281
  }}
282
+ disabled={!canAssignGroup(isUserManager, matrix_option)}
261
283
  />
262
284
  ))}
263
285
  </div>
@@ -12,7 +12,9 @@ import {
12
12
  updateUser,
13
13
  updateGroup,
14
14
  getUserSchema,
15
+ getUser,
15
16
  } from '@plone/volto/actions';
17
+ import jwtDecode from 'jwt-decode';
16
18
  import {
17
19
  Icon,
18
20
  ModalForm,
@@ -23,7 +25,12 @@ import {
23
25
  Error,
24
26
  } from '@plone/volto/components';
25
27
  import { Link } from 'react-router-dom';
26
- import { Helmet, messages } from '@plone/volto/helpers';
28
+ import {
29
+ Helmet,
30
+ messages,
31
+ isManager,
32
+ canAssignGroup,
33
+ } from '@plone/volto/helpers';
27
34
  import clearSVG from '@plone/volto/icons/clear.svg';
28
35
  import addUserSvg from '@plone/volto/icons/add-user.svg';
29
36
  import saveSVG from '@plone/volto/icons/save.svg';
@@ -77,6 +84,19 @@ class UsersControlpanel extends Component {
77
84
  roles: PropTypes.arrayOf(PropTypes.string),
78
85
  }),
79
86
  ).isRequired,
87
+ user: PropTypes.shape({
88
+ '@id': PropTypes.string,
89
+ id: PropTypes.string,
90
+ description: PropTypes.string,
91
+ email: PropTypes.string,
92
+ fullname: PropTypes.string,
93
+ groups: PropTypes.object,
94
+ location: PropTypes.string,
95
+ portrait: PropTypes.string,
96
+ home_page: PropTypes.string,
97
+ roles: PropTypes.arrayOf(PropTypes.string),
98
+ username: PropTypes.string,
99
+ }).isRequired,
80
100
  };
81
101
 
82
102
  /**
@@ -124,6 +144,7 @@ class UsersControlpanel extends Component {
124
144
  });
125
145
  }
126
146
  await this.props.getUserSchema();
147
+ await this.props.getUser(this.props.userId);
127
148
  };
128
149
 
129
150
  // Because username field needs to be disabled if email login is enabled!
@@ -406,6 +427,20 @@ class UsersControlpanel extends Component {
406
427
  }
407
428
  }
408
429
 
430
+ /**
431
+ * Filters the roles a user can assign when adding a user.
432
+ * @method canAssignAdd
433
+ * @returns {arry}
434
+ */
435
+ canAssignAdd(isManager) {
436
+ if (isManager) return this.props.roles;
437
+ return this.props.user?.roles
438
+ ? this.props.roles.filter((role) =>
439
+ this.props.user.roles.includes(role.id),
440
+ )
441
+ : [];
442
+ }
443
+
409
444
  /**
410
445
  * Render method.
411
446
  * @method render
@@ -426,7 +461,9 @@ class UsersControlpanel extends Component {
426
461
  // of the userschema is changed and it is used like that through
427
462
  // the lifecycle of the application
428
463
  let adduserschema = {};
464
+ let isUserManager = false;
429
465
  if (this.props?.userschema?.loaded) {
466
+ isUserManager = isManager(this.props.user);
430
467
  adduserschema = JSON.parse(
431
468
  JSON.stringify(this.props?.userschema?.userschema),
432
469
  );
@@ -454,13 +491,18 @@ class UsersControlpanel extends Component {
454
491
  adduserschema.properties['roles'] = {
455
492
  title: this.props.intl.formatMessage(messages.addUserFormRolesTitle),
456
493
  type: 'array',
457
- choices: this.props.roles.map((role) => [role.id, role.title]),
494
+ choices: this.canAssignAdd(isUserManager).map((role) => [
495
+ role.id,
496
+ role.title,
497
+ ]),
458
498
  noValueOption: false,
459
499
  };
460
500
  adduserschema.properties['groups'] = {
461
501
  title: this.props.intl.formatMessage(messages.addUserGroupNameTitle),
462
502
  type: 'array',
463
- choices: this.props.groups.map((group) => [group.id, group.id]),
503
+ choices: this.props.groups
504
+ .filter((group) => canAssignGroup(isUserManager, group))
505
+ .map((group) => [group.id, group.id]),
464
506
  noValueOption: false,
465
507
  };
466
508
  if (
@@ -598,6 +640,7 @@ class UsersControlpanel extends Component {
598
640
  inheritedRole={this.props.inheritedRole}
599
641
  userschema={this.props.userschema}
600
642
  listUsers={this.props.listUsers}
643
+ isUserManager={isUserManager}
601
644
  />
602
645
  ))}
603
646
  </Table.Body>
@@ -686,6 +729,10 @@ export default compose(
686
729
  (state, props) => ({
687
730
  roles: state.roles.roles,
688
731
  users: state.users.users,
732
+ user: state.users.user,
733
+ userId: state.userSession.token
734
+ ? jwtDecode(state.userSession.token).sub
735
+ : '',
689
736
  groups: state.groups.groups,
690
737
  many_users: state.controlpanels?.controlpanel?.data?.many_users,
691
738
  many_groups: state.controlpanels?.controlpanel?.data?.many_groups,
@@ -710,6 +757,7 @@ export default compose(
710
757
  updateUser,
711
758
  updateGroup,
712
759
  getUserSchema,
760
+ getUser,
713
761
  },
714
762
  dispatch,
715
763
  ),
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
+ import jwt from 'jsonwebtoken';
5
6
 
6
7
  import UsersControlpanel from './UsersControlpanel';
7
8
 
@@ -11,10 +12,17 @@ jest.mock('../../Toolbar/Toolbar', () => jest.fn(() => <div id="Portal" />));
11
12
  describe('UsersControlpanel', () => {
12
13
  it('renders a user control component', () => {
13
14
  const store = mockStore({
15
+ userSession: {
16
+ token: jwt.sign({ sub: 'john' }, 'secret'),
17
+ },
14
18
  roles: { roles: [] },
15
19
  users: {
16
20
  users: [],
17
21
  create: { loading: false },
22
+ user: {
23
+ roles: ['Manager'],
24
+ '@id': 'admin',
25
+ },
18
26
  },
19
27
  groups: {
20
28
  groups: [],
@@ -309,7 +309,7 @@ class Form extends Component {
309
309
  // Set focus to first input if available
310
310
  document
311
311
  .querySelector(`.field-wrapper-${this.props.metadataFieldFocus} input`)
312
- .focus();
312
+ ?.focus();
313
313
 
314
314
  // Reset focus field
315
315
  this.props.resetMetadataFocus();
@@ -44,7 +44,14 @@ const SlotRenderer = ({
44
44
  }) => {
45
45
  // ^^ Weird compilation issue for Jest tests, that forced to re-declare the type above
46
46
  const SlotComponent = component;
47
- return <SlotComponent key={name} />;
47
+ return (
48
+ <SlotComponent
49
+ key={name}
50
+ content={content}
51
+ pathname={pathname}
52
+ navRoot={navRoot}
53
+ />
54
+ );
48
55
  },
49
56
  )}
50
57
  </>