@plone/volto 19.0.0-alpha.1 → 19.0.0-alpha.11

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 (238) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +37 -2
  3. package/CHANGELOG.md +234 -0
  4. package/README.md +18 -14
  5. package/cypress/docker/prefixed-rules.yml +26 -0
  6. package/cypress/docker/prefixed.yml +24 -0
  7. package/cypress/support/commands.js +12 -6
  8. package/cypress/support/guillotina.js +1 -0
  9. package/cypress.config.js +1 -0
  10. package/locales/af.json +1 -0
  11. package/locales/ar.json +1 -0
  12. package/locales/bg.json +1 -0
  13. package/locales/bn.json +1 -0
  14. package/locales/ca/LC_MESSAGES/volto.po +96 -17
  15. package/locales/ca.json +1 -1
  16. package/locales/cs.json +1 -0
  17. package/locales/cy.json +1 -0
  18. package/locales/da.json +1 -0
  19. package/locales/de/LC_MESSAGES/volto.po +104 -25
  20. package/locales/de.json +1 -1
  21. package/locales/el.json +1 -0
  22. package/locales/en/LC_MESSAGES/volto.po +97 -18
  23. package/locales/en.json +1 -1
  24. package/locales/en_AU.json +1 -0
  25. package/locales/en_GB.json +1 -0
  26. package/locales/eo.json +1 -0
  27. package/locales/es/LC_MESSAGES/volto.po +97 -18
  28. package/locales/es.json +1 -1
  29. package/locales/et.json +1 -0
  30. package/locales/eu/LC_MESSAGES/volto.po +96 -17
  31. package/locales/eu.json +1 -1
  32. package/locales/fa.json +1 -0
  33. package/locales/fi/LC_MESSAGES/volto.po +96 -17
  34. package/locales/fi.json +1 -1
  35. package/locales/fr/LC_MESSAGES/volto.po +97 -18
  36. package/locales/fr.json +1 -1
  37. package/locales/fu.json +1 -0
  38. package/locales/gl.json +1 -0
  39. package/locales/he.json +1 -0
  40. package/locales/hi/LC_MESSAGES/volto.po +100 -21
  41. package/locales/hi.json +1 -1
  42. package/locales/hr.json +1 -0
  43. package/locales/hu.json +1 -0
  44. package/locales/hy.json +1 -0
  45. package/locales/id.json +1 -0
  46. package/locales/it/LC_MESSAGES/volto.po +101 -22
  47. package/locales/it.json +1 -1
  48. package/locales/ja/LC_MESSAGES/volto.po +96 -17
  49. package/locales/ja.json +1 -1
  50. package/locales/ka.json +1 -0
  51. package/locales/kn.json +1 -0
  52. package/locales/ko.json +1 -0
  53. package/locales/lt.json +1 -0
  54. package/locales/lv.json +1 -0
  55. package/locales/mi.json +1 -0
  56. package/locales/mk.json +1 -0
  57. package/locales/my.json +1 -0
  58. package/locales/nb_NO.json +1 -0
  59. package/locales/nl/LC_MESSAGES/volto.po +100 -21
  60. package/locales/nl.json +1 -1
  61. package/locales/nn.json +1 -0
  62. package/locales/pl.json +1 -0
  63. package/locales/pt/LC_MESSAGES/volto.po +96 -17
  64. package/locales/pt.json +1 -1
  65. package/locales/pt_BR/LC_MESSAGES/volto.po +116 -37
  66. package/locales/pt_BR.json +1 -1
  67. package/locales/rm.json +1 -0
  68. package/locales/ro/LC_MESSAGES/volto.po +100 -21
  69. package/locales/ro.json +1 -1
  70. package/locales/ru/LC_MESSAGES/volto.po +100 -21
  71. package/locales/ru.json +1 -1
  72. package/locales/sk.json +1 -0
  73. package/locales/sl.json +1 -0
  74. package/locales/sm.json +1 -0
  75. package/locales/sq.json +1 -0
  76. package/locales/sr.json +1 -0
  77. package/locales/sr@cyrl.json +1 -0
  78. package/locales/sr@latn.json +1 -0
  79. package/locales/sv.json +1 -1
  80. package/locales/ta.json +1 -0
  81. package/locales/te.json +1 -0
  82. package/locales/th.json +1 -0
  83. package/locales/to.json +1 -0
  84. package/locales/tr.json +1 -0
  85. package/locales/uk.json +1 -0
  86. package/locales/vi.json +1 -0
  87. package/locales/volto.pot +97 -18
  88. package/locales/zh_CN/LC_MESSAGES/volto.po +96 -17
  89. package/locales/zh_CN.json +1 -1
  90. package/locales/zh_Hant.json +1 -0
  91. package/locales/zh_Hant_HK.json +1 -0
  92. package/package.json +28 -26
  93. package/razzle.config.js +16 -0
  94. package/src/actions/content/content.js +0 -1
  95. package/src/actions/controlpanels/controlpanels.js +13 -7
  96. package/src/actions/controlpanels/controlpanels.test.js +11 -5
  97. package/src/actions/users/users.js +2 -2
  98. package/src/components/manage/Add/Add.jsx +5 -6
  99. package/src/components/manage/Blocks/Block/Edit.jsx +1 -0
  100. package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +9 -4
  101. package/src/components/manage/Blocks/Image/Edit.jsx +5 -1
  102. package/src/components/manage/Blocks/LeadImage/Edit.jsx +2 -2
  103. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +1 -1
  104. package/src/components/manage/Blocks/Listing/ImageGallery.jsx +6 -4
  105. package/src/components/manage/Blocks/Maps/Edit.jsx +2 -1
  106. package/src/components/manage/Blocks/Search/SearchBlockView.jsx +21 -4
  107. package/src/components/manage/Blocks/Teaser/Data.jsx +21 -7
  108. package/src/components/manage/Blocks/Teaser/DefaultBody.jsx +1 -1
  109. package/src/components/manage/Blocks/Teaser/schema.js +8 -3
  110. package/src/components/manage/Blocks/Title/Edit.jsx +8 -2
  111. package/src/components/manage/Blocks/Video/Edit.jsx +2 -1
  112. package/src/components/manage/Contents/Contents.jsx +23 -2
  113. package/src/components/manage/Contents/Contents.test.jsx +7 -0
  114. package/src/components/manage/Contents/ContentsBreadcrumbs.Multilingual.test.jsx +18 -5
  115. package/src/components/manage/Contents/ContentsBreadcrumbs.jsx +20 -26
  116. package/src/components/manage/Contents/ContentsBreadcrumbs.test.jsx +14 -0
  117. package/src/components/manage/Contents/ContentsDeleteModal.jsx +258 -206
  118. package/src/components/manage/Contents/ContentsDeleteModal.stories.jsx +26 -8
  119. package/src/components/manage/Contents/ContentsItem.jsx +10 -2
  120. package/src/components/manage/Contents/ContentsUploadModal.test.jsx +13 -22
  121. package/src/components/manage/Controlpanels/ContentType.jsx +1 -1
  122. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +3 -2
  123. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +156 -175
  124. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +575 -630
  125. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +4 -3
  126. package/src/components/manage/Edit/Edit.jsx +2 -3
  127. package/src/components/manage/Form/Form.jsx +32 -0
  128. package/src/components/manage/Form/Form.test.jsx +22 -18
  129. package/src/components/manage/Form/InlineForm.jsx +2 -2
  130. package/src/components/manage/Multilingual/CompareLanguages.jsx +2 -5
  131. package/src/components/manage/Multilingual/CreateTranslation.jsx +8 -8
  132. package/src/components/manage/Multilingual/ManageTranslations.jsx +4 -2
  133. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +5 -1
  134. package/src/components/manage/Multilingual/TranslationObject.jsx +1 -1
  135. package/src/components/manage/Sidebar/ObjectBrowserNav.jsx +2 -1
  136. package/src/components/manage/Sidebar/SidebarPortal.test.tsx +42 -0
  137. package/src/components/manage/Sidebar/SidebarPortal.tsx +48 -0
  138. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +2 -1
  139. package/src/components/manage/Toolbar/More.jsx +4 -1
  140. package/src/components/manage/Toolbar/More.test.jsx +3 -0
  141. package/src/components/manage/Toolbar/PersonalTools.jsx +2 -1
  142. package/src/components/manage/Toolbar/Toolbar.jsx +3 -4
  143. package/src/components/manage/Toolbar/Types.jsx +7 -7
  144. package/src/components/manage/UniversalLink/UniversalLink.tsx +1 -0
  145. package/src/components/manage/Widgets/DatetimeWidget.jsx +5 -0
  146. package/src/components/manage/Widgets/FileWidget.jsx +14 -8
  147. package/src/components/manage/Widgets/ImageWidget.jsx +171 -38
  148. package/src/components/manage/Widgets/InternalUrlWidget.jsx +2 -0
  149. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +3 -0
  150. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +3 -2
  151. package/src/components/manage/Widgets/SelectAutoComplete.jsx +29 -12
  152. package/src/components/manage/Widgets/SelectWidget.jsx +3 -1
  153. package/src/components/manage/Widgets/UrlWidget.jsx +2 -0
  154. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.jsx +1 -3
  155. package/src/components/theme/AlternateHrefLangs/AlternateHrefLangs.test.jsx +0 -4
  156. package/src/components/theme/App/App.jsx +3 -1
  157. package/src/components/theme/App/App.test.jsx +1 -0
  158. package/src/components/theme/Avatar/Avatar.jsx +2 -1
  159. package/src/components/theme/FormattedDate/FormattedDate.stories.jsx +20 -2
  160. package/src/components/theme/Image/Image.jsx +11 -8
  161. package/src/components/theme/LanguageSelector/{LanguageSelector.test.jsx → LanguageSelector.test.tsx} +6 -6
  162. package/src/components/theme/LanguageSelector/LanguageSelector.tsx +89 -0
  163. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +0 -5
  164. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +8 -12
  165. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.test.jsx +3 -5
  166. package/src/components/theme/Navigation/NavItem.jsx +1 -5
  167. package/src/components/theme/Navigation/Navigation.Multilingual.test.jsx +0 -5
  168. package/src/components/theme/NotFound/NotFound.jsx +5 -2
  169. package/src/components/theme/NotFound/NotFound.test.jsx +3 -0
  170. package/src/components/theme/PreviewImage/PreviewImage.jsx +1 -1
  171. package/src/components/theme/RequestTimeout/RequestTimeout.jsx +1 -1
  172. package/src/components/theme/Sitemap/Sitemap.jsx +6 -5
  173. package/src/components/theme/Sitemap/Sitemap.test.jsx +0 -1
  174. package/src/components/theme/View/FileView.jsx +9 -1
  175. package/src/components/theme/View/View.jsx +1 -1
  176. package/src/components/theme/Widgets/ImageWidget.jsx +2 -1
  177. package/src/config/ControlPanels.js +1 -0
  178. package/src/config/index.js +18 -25
  179. package/src/config/server.js +0 -2
  180. package/src/express-middleware/devproxy.js +20 -5
  181. package/src/helpers/Api/APIResourceWithAuth.js +8 -3
  182. package/src/helpers/Api/Api.js +7 -4
  183. package/src/helpers/AsyncConnect/ssr.js +4 -1
  184. package/src/helpers/Content/Content.js +23 -0
  185. package/src/helpers/Content/Content.test.js +39 -0
  186. package/src/helpers/Content/withClientSideContent.jsx +35 -0
  187. package/src/helpers/Extensions/withBlockSchemaEnhancer.jsx +4 -1
  188. package/src/helpers/Html/Html.jsx +13 -7
  189. package/src/helpers/LanguageMap/LanguageMap.js +115 -8
  190. package/src/helpers/MessageLabels/MessageLabels.js +5 -0
  191. package/src/helpers/Sitemap/Sitemap.js +4 -4
  192. package/src/helpers/Url/Url.js +32 -2
  193. package/src/helpers/Url/Url.test.js +62 -0
  194. package/src/helpers/Utils/withSaveAsDraft.jsx +241 -0
  195. package/src/hooks/user/useUser.js +1 -1
  196. package/src/middleware/Api.test.js +4 -0
  197. package/src/middleware/api.js +77 -28
  198. package/src/middleware/storeProtectLoadUtils.test.js +3 -3
  199. package/src/reducers/content/content.js +3 -18
  200. package/src/reducers/diff/diff.js +5 -1
  201. package/src/reducers/diff/diff.test.js +60 -4
  202. package/src/routes.js +4 -2
  203. package/src/server.jsx +45 -14
  204. package/src/start-client.jsx +9 -6
  205. package/src/start-server.js +9 -3
  206. package/test-setup-config.jsx +0 -2
  207. package/theme/themes/pastanaga/collections/table.overrides +9 -0
  208. package/theme/themes/pastanaga/extras/blocks.less +26 -0
  209. package/theme/themes/pastanaga/extras/contents.less +17 -5
  210. package/theme/themes/pastanaga/extras/main.less +32 -2
  211. package/tsconfig.json +3 -4
  212. package/types/components/manage/Blocks/Teaser/schema.d.ts +1 -0
  213. package/types/components/manage/Controlpanels/Users/RenderUsers.d.ts +18 -2
  214. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +6 -2
  215. package/types/components/manage/Controlpanels/index.d.ts +2 -2
  216. package/types/components/manage/Sidebar/SidebarPortal.d.ts +7 -15
  217. package/types/components/manage/Widgets/ImageWidget.d.ts +41 -1
  218. package/types/components/manage/Widgets/RecurrenceWidget/Utils.d.ts +12 -18
  219. package/types/components/theme/FormattedDate/FormattedDate.stories.d.ts +1 -1
  220. package/types/components/theme/LanguageSelector/LanguageSelector.d.ts +3 -10
  221. package/types/helpers/Content/Content.d.ts +7 -0
  222. package/types/helpers/Content/withClientSideContent.d.ts +1 -0
  223. package/types/helpers/Extensions/withBlockSchemaEnhancer.d.ts +4 -5
  224. package/types/helpers/Helmet/Helmet.d.ts +1 -1
  225. package/types/helpers/LanguageMap/LanguageMap.d.ts +428 -4
  226. package/types/helpers/MessageLabels/MessageLabels.d.ts +68 -62
  227. package/types/helpers/Url/Url.d.ts +14 -0
  228. package/types/helpers/Url/bulkFlattenToAppURL.d.ts +5 -0
  229. package/types/helpers/Utils/withSaveAsDraft.d.ts +1 -0
  230. package/types/middleware/api.d.ts +6 -9
  231. package/types/reducers/index.d.ts +1 -0
  232. package/types/start-client.d.ts +0 -1
  233. package/package-why.json +0 -34
  234. package/src/actions/content/content.multilingual.test.js +0 -17
  235. package/src/components/manage/Sidebar/SidebarPortal.jsx +0 -47
  236. package/src/components/manage/Sidebar/SidebarPortal.test.jsx +0 -26
  237. package/src/components/theme/LanguageSelector/LanguageSelector.jsx +0 -77
  238. package/theme/themes/pastanaga/extras/utils.less +0 -63
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import renderer from 'react-test-renderer';
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 { waitFor } from '@testing-library/react';
6
5
  import ContentsUploadModal from './ContentsUploadModal';
7
6
 
8
7
  const mockStore = configureStore();
@@ -21,19 +20,17 @@ describe('ContentsUploadModal', () => {
21
20
  messages: {},
22
21
  },
23
22
  });
24
- const component = renderer.create(
23
+ const { baseElement } = render(
25
24
  <Provider store={store}>
26
25
  <ContentsUploadModal
27
26
  pathname="/blog"
28
- open={false}
27
+ open={true}
29
28
  onOk={() => {}}
30
29
  onCancel={() => {}}
31
30
  />
32
31
  </Provider>,
33
32
  );
34
- const json = component.toJSON();
35
- await waitFor(() => {});
36
- expect(json).toMatchSnapshot();
33
+ expect(baseElement).toMatchSnapshot();
37
34
  });
38
35
 
39
36
  it('renders a contents upload modal component that only allows images', async () => {
@@ -49,20 +46,18 @@ describe('ContentsUploadModal', () => {
49
46
  messages: {},
50
47
  },
51
48
  });
52
- const component = renderer.create(
49
+ const { baseElement } = render(
53
50
  <Provider store={store}>
54
51
  <ContentsUploadModal
55
52
  pathname="/blog"
56
- open={false}
53
+ open={true}
57
54
  onOk={() => {}}
58
55
  onCancel={() => {}}
59
56
  accept={['image/*']}
60
57
  />
61
58
  </Provider>,
62
59
  );
63
- const json = component.toJSON();
64
- await waitFor(() => {});
65
- expect(json).toMatchSnapshot();
60
+ expect(baseElement).toMatchSnapshot();
66
61
  });
67
62
  it('renders a contents upload modal component that only allows 10MB files', async () => {
68
63
  const store = mockStore({
@@ -77,20 +72,18 @@ describe('ContentsUploadModal', () => {
77
72
  messages: {},
78
73
  },
79
74
  });
80
- const component = renderer.create(
75
+ const { baseElement } = render(
81
76
  <Provider store={store}>
82
77
  <ContentsUploadModal
83
78
  pathname="/blog"
84
- open={false}
79
+ open={true}
85
80
  onOk={() => {}}
86
81
  onCancel={() => {}}
87
82
  maxSize={1000000}
88
83
  />
89
84
  </Provider>,
90
85
  );
91
- const json = component.toJSON();
92
- await waitFor(() => {});
93
- expect(json).toMatchSnapshot();
86
+ expect(baseElement).toMatchSnapshot();
94
87
  });
95
88
  it('renders a contents upload modal component that only allows 1 file', async () => {
96
89
  const store = mockStore({
@@ -105,19 +98,17 @@ describe('ContentsUploadModal', () => {
105
98
  messages: {},
106
99
  },
107
100
  });
108
- const component = renderer.create(
101
+ const { baseElement } = render(
109
102
  <Provider store={store}>
110
103
  <ContentsUploadModal
111
104
  pathname="/blog"
112
- open={false}
105
+ open={true}
113
106
  onOk={() => {}}
114
107
  onCancel={() => {}}
115
108
  multiple={false}
116
109
  />
117
110
  </Provider>,
118
111
  );
119
- const json = component.toJSON();
120
- await waitFor(() => {});
121
- expect(json).toMatchSnapshot();
112
+ expect(baseElement).toMatchSnapshot();
122
113
  });
123
114
  });
@@ -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
- 'A unique identifier for the group. Can not be changed after creation.',
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
- * Users controlpanel user.
3
- * @module components/manage/Controlpanels/UsersControlpanelUser
2
+ * RenderUsers component.
3
+ * @module components/manage/Controlpanels/Users/RenderUsers
4
4
  */
5
5
  import PropTypes from 'prop-types';
6
- import React, { Component } from 'react';
7
- import { FormattedMessage, injectIntl } from 'react-intl';
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
- * UsersControlpanelUser class.
24
- * @class UsersControlpanelUser
25
- * @extends Component
22
+ * RenderUsers functional component.
23
+ * @function RenderUsers
26
24
  */
27
- class RenderUsers extends Component {
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
- * Constructor
50
- * @method constructor
51
- * @param {Object} props Component properties
52
- * @constructs Sharing
53
- */
54
- constructor(props) {
55
- super(props);
56
- this.state = {
57
- user: {},
58
- };
59
- this.onChange = this.onChange.bind(this);
60
- this.onEditUserError = this.onEditUserError.bind(this);
61
- this.onEditUserSubmit = this.onEditUserSubmit.bind(this);
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
- onChange(event, { value }) {
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
- this.props.updateUserData(data.id, data);
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(props) {
113
- const { formData } = props;
114
- this.setState({ user: { ...formData } });
115
- }
88
+ const onClickEdit = (formProps) => {
89
+ const { formData } = formProps;
90
+ setUser({ ...formData });
91
+ };
116
92
 
117
- canDeleteUser() {
118
- if (this.props.isUserManager) return true;
119
- return !this.props.user.roles.includes('Manager');
120
- }
93
+ const canDeleteUser = () => {
94
+ if (isUserManager) return true;
95
+ return !propsUser.roles.includes('Manager');
96
+ };
121
97
 
122
- /**
123
- * Render method.
124
- * @method render
125
- * @returns {string} Markup for the component.
126
- */
127
- render() {
128
- return (
129
- <Table.Row key={this.props.user.username}>
130
- <Table.Cell className="fullname">
131
- {this.props.user.fullname
132
- ? this.props.user.fullname
133
- : this.props.user.username}{' '}
134
- ({this.props.user.username})
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
- {this.props.roles.map((role) => (
137
- <Table.Cell key={role.id}>
138
- {this.props.inheritedRole &&
139
- this.props.inheritedRole.includes(role.id) ? (
140
- <Icon
141
- name={ploneSVG}
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="delete-user-button"
174
- onClick={this.props.onDelete}
175
- value={this.props.user['@id']}
129
+ id="edit-user-button"
130
+ onClick={() => {
131
+ onClickEdit({ formData: propsUser });
132
+ }}
133
+ value={propsUser['@id']}
176
134
  >
177
- <Icon name={trashSVG} size="15px" />
178
- <FormattedMessage id="Delete" defaultMessage="Delete" />
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
- loading={this.props.updateRequest.loading}
196
- schema={this.props.userschema.userschema}
197
- />
198
- )}
199
- </Table.Row>
200
- );
201
- }
202
- }
203
- export default compose(
204
- injectIntl,
205
- connect(
206
- (state, props) => ({
207
- updateRequest: state.users?.update,
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
- { updateUserData: updateUser },
210
- ),
211
- )(RenderUsers);
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;