@strapi/plugin-users-permissions 0.0.0-next.dff425769af4d4d006725a10c395f59637403653 → 0.0.0-next.e09d30edcbd16960a838997778a31d50e9c60bc4

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 (193) hide show
  1. package/.eslintignore +1 -2
  2. package/.eslintrc +17 -0
  3. package/admin/src/components/BoundRoute/{index.js → index.jsx} +5 -3
  4. package/admin/src/components/FormModal/Input/{index.js → index.jsx} +6 -3
  5. package/admin/src/components/FormModal/{index.js → index.jsx} +13 -10
  6. package/admin/src/components/Permissions/PermissionRow/{SubCategory.js → SubCategory.jsx} +26 -5
  7. package/admin/src/components/Permissions/PermissionRow/{index.js → index.jsx} +4 -2
  8. package/admin/src/components/Permissions/{index.js → index.jsx} +6 -5
  9. package/admin/src/components/Policies/{index.js → index.jsx} +3 -2
  10. package/admin/src/components/UsersPermissions/{index.js → index.jsx} +8 -5
  11. package/admin/src/{permissions.js → constants.js} +1 -3
  12. package/admin/src/contexts/UsersPermissionsContext/{index.js → index.jsx} +1 -0
  13. package/admin/src/index.js +19 -28
  14. package/admin/src/pages/AdvancedSettings/{index.js → index.jsx} +68 -52
  15. package/admin/src/pages/AdvancedSettings/utils/schema.js +1 -1
  16. package/admin/src/pages/EmailTemplates/components/{EmailForm.js → EmailForm.jsx} +14 -13
  17. package/admin/src/pages/EmailTemplates/components/{EmailTable.js → EmailTable.jsx} +9 -7
  18. package/admin/src/pages/EmailTemplates/{index.js → index.jsx} +77 -63
  19. package/admin/src/pages/EmailTemplates/utils/schema.js +1 -1
  20. package/admin/src/pages/Providers/{index.js → index.jsx} +91 -86
  21. package/admin/src/pages/Providers/utils/forms.js +1 -1
  22. package/admin/src/pages/Roles/{CreatePage/utils/schema.js → constants.js} +2 -4
  23. package/admin/src/pages/Roles/hooks/usePlugins.js +78 -0
  24. package/admin/src/pages/Roles/index.jsx +33 -0
  25. package/admin/src/pages/Roles/pages/CreatePage.jsx +199 -0
  26. package/admin/src/pages/Roles/pages/EditPage.jsx +220 -0
  27. package/admin/src/pages/Roles/{ListPage/components/TableBody.js → pages/ListPage/components/TableBody.jsx} +46 -15
  28. package/admin/src/pages/Roles/{ListPage/index.js → pages/ListPage/index.jsx} +67 -49
  29. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/utils/api.js +3 -4
  30. package/admin/src/translations/ru.json +50 -26
  31. package/admin/src/translations/zh-Hans.json +80 -80
  32. package/admin/src/utils/index.js +1 -2
  33. package/dist/_chunks/ar-MvD8Ghac.mjs +44 -0
  34. package/dist/_chunks/ar-MvD8Ghac.mjs.map +1 -0
  35. package/dist/_chunks/ar-t5qTFaAD.js +44 -0
  36. package/dist/_chunks/ar-t5qTFaAD.js.map +1 -0
  37. package/dist/_chunks/cs-BMuXwxA1.mjs +50 -0
  38. package/dist/_chunks/cs-BMuXwxA1.mjs.map +1 -0
  39. package/dist/_chunks/cs-I8N4u-Sd.js +50 -0
  40. package/dist/_chunks/cs-I8N4u-Sd.js.map +1 -0
  41. package/dist/_chunks/de-YTjtq89K.js +62 -0
  42. package/dist/_chunks/de-YTjtq89K.js.map +1 -0
  43. package/dist/_chunks/de-zs2qqc0W.mjs +62 -0
  44. package/dist/_chunks/de-zs2qqc0W.mjs.map +1 -0
  45. package/dist/_chunks/dk-HctVBMsG.mjs +86 -0
  46. package/dist/_chunks/dk-HctVBMsG.mjs.map +1 -0
  47. package/dist/_chunks/dk-TF-dWjzl.js +86 -0
  48. package/dist/_chunks/dk-TF-dWjzl.js.map +1 -0
  49. package/dist/_chunks/en-CE3wEy_c.mjs +86 -0
  50. package/dist/_chunks/en-CE3wEy_c.mjs.map +1 -0
  51. package/dist/_chunks/en-m608rMZx.js +86 -0
  52. package/dist/_chunks/en-m608rMZx.js.map +1 -0
  53. package/dist/_chunks/es-9381tih_.mjs +86 -0
  54. package/dist/_chunks/es-9381tih_.mjs.map +1 -0
  55. package/dist/_chunks/es-XBQsB8_9.js +86 -0
  56. package/dist/_chunks/es-XBQsB8_9.js.map +1 -0
  57. package/dist/_chunks/fr-6cz3U-IF.js +50 -0
  58. package/dist/_chunks/fr-6cz3U-IF.js.map +1 -0
  59. package/dist/_chunks/fr-CMSc77If.mjs +50 -0
  60. package/dist/_chunks/fr-CMSc77If.mjs.map +1 -0
  61. package/dist/_chunks/id-RJ934rq-.js +62 -0
  62. package/dist/_chunks/id-RJ934rq-.js.map +1 -0
  63. package/dist/_chunks/id-SDuyIkZa.mjs +62 -0
  64. package/dist/_chunks/id-SDuyIkZa.mjs.map +1 -0
  65. package/dist/_chunks/index-1uupZmu0.js +638 -0
  66. package/dist/_chunks/index-1uupZmu0.js.map +1 -0
  67. package/dist/_chunks/index-6Kdo3KXv.js +407 -0
  68. package/dist/_chunks/index-6Kdo3KXv.js.map +1 -0
  69. package/dist/_chunks/index-O9AAUvyy.js +249 -0
  70. package/dist/_chunks/index-O9AAUvyy.js.map +1 -0
  71. package/dist/_chunks/index-Un-J-cxQ.js +320 -0
  72. package/dist/_chunks/index-Un-J-cxQ.js.map +1 -0
  73. package/dist/_chunks/index-X0yw_GgN.mjs +301 -0
  74. package/dist/_chunks/index-X0yw_GgN.mjs.map +1 -0
  75. package/dist/_chunks/index-XqdaO5WZ.js +1191 -0
  76. package/dist/_chunks/index-XqdaO5WZ.js.map +1 -0
  77. package/dist/_chunks/index-a9oKDd3C.mjs +385 -0
  78. package/dist/_chunks/index-a9oKDd3C.mjs.map +1 -0
  79. package/dist/_chunks/index-ethhTEkj.mjs +615 -0
  80. package/dist/_chunks/index-ethhTEkj.mjs.map +1 -0
  81. package/dist/_chunks/index-iNtwnT3f.mjs +250 -0
  82. package/dist/_chunks/index-iNtwnT3f.mjs.map +1 -0
  83. package/dist/_chunks/index-rryiT0-Z.mjs +1159 -0
  84. package/dist/_chunks/index-rryiT0-Z.mjs.map +1 -0
  85. package/dist/_chunks/it-YhZOlM2X.js +62 -0
  86. package/dist/_chunks/it-YhZOlM2X.js.map +1 -0
  87. package/dist/_chunks/it-bvH7DgQo.mjs +62 -0
  88. package/dist/_chunks/it-bvH7DgQo.mjs.map +1 -0
  89. package/dist/_chunks/ja-o_-JPvQv.mjs +48 -0
  90. package/dist/_chunks/ja-o_-JPvQv.mjs.map +1 -0
  91. package/dist/_chunks/ja-xssHUXFv.js +48 -0
  92. package/dist/_chunks/ja-xssHUXFv.js.map +1 -0
  93. package/dist/_chunks/ko-C3mHUSJa.js +86 -0
  94. package/dist/_chunks/ko-C3mHUSJa.js.map +1 -0
  95. package/dist/_chunks/ko-XJbPSez_.mjs +86 -0
  96. package/dist/_chunks/ko-XJbPSez_.mjs.map +1 -0
  97. package/dist/_chunks/ms-II5Ea73J.mjs +49 -0
  98. package/dist/_chunks/ms-II5Ea73J.mjs.map +1 -0
  99. package/dist/_chunks/ms-d0hfg65Z.js +49 -0
  100. package/dist/_chunks/ms-d0hfg65Z.js.map +1 -0
  101. package/dist/_chunks/nl-TA7TfK_5.js +48 -0
  102. package/dist/_chunks/nl-TA7TfK_5.js.map +1 -0
  103. package/dist/_chunks/nl-vEy6TN0K.mjs +48 -0
  104. package/dist/_chunks/nl-vEy6TN0K.mjs.map +1 -0
  105. package/dist/_chunks/pl-0pUL9hdA.js +86 -0
  106. package/dist/_chunks/pl-0pUL9hdA.js.map +1 -0
  107. package/dist/_chunks/pl-2VowaFGt.mjs +86 -0
  108. package/dist/_chunks/pl-2VowaFGt.mjs.map +1 -0
  109. package/dist/_chunks/pt-BR-WNOhafR4.js +44 -0
  110. package/dist/_chunks/pt-BR-WNOhafR4.js.map +1 -0
  111. package/dist/_chunks/pt-BR-sS1Xp3Jt.mjs +44 -0
  112. package/dist/_chunks/pt-BR-sS1Xp3Jt.mjs.map +1 -0
  113. package/dist/_chunks/pt-Rf9W51IO.mjs +48 -0
  114. package/dist/_chunks/pt-Rf9W51IO.mjs.map +1 -0
  115. package/dist/_chunks/pt-guNR9Gax.js +48 -0
  116. package/dist/_chunks/pt-guNR9Gax.js.map +1 -0
  117. package/dist/_chunks/ru-X3BMXDds.js +86 -0
  118. package/dist/_chunks/ru-X3BMXDds.js.map +1 -0
  119. package/dist/_chunks/ru-qKHnd5or.mjs +86 -0
  120. package/dist/_chunks/ru-qKHnd5or.mjs.map +1 -0
  121. package/dist/_chunks/sk-NWPw1oTN.js +50 -0
  122. package/dist/_chunks/sk-NWPw1oTN.js.map +1 -0
  123. package/dist/_chunks/sk-_Ryr-eTT.mjs +50 -0
  124. package/dist/_chunks/sk-_Ryr-eTT.mjs.map +1 -0
  125. package/dist/_chunks/sv-76NnbB__.js +86 -0
  126. package/dist/_chunks/sv-76NnbB__.js.map +1 -0
  127. package/dist/_chunks/sv-BqzScFXS.mjs +86 -0
  128. package/dist/_chunks/sv-BqzScFXS.mjs.map +1 -0
  129. package/dist/_chunks/th-WsknMEpq.mjs +60 -0
  130. package/dist/_chunks/th-WsknMEpq.mjs.map +1 -0
  131. package/dist/_chunks/th-cbppX21D.js +60 -0
  132. package/dist/_chunks/th-cbppX21D.js.map +1 -0
  133. package/dist/_chunks/tr-6mm_Fmz7.js +85 -0
  134. package/dist/_chunks/tr-6mm_Fmz7.js.map +1 -0
  135. package/dist/_chunks/tr-_DB1F1GW.mjs +85 -0
  136. package/dist/_chunks/tr-_DB1F1GW.mjs.map +1 -0
  137. package/dist/_chunks/uk-sI2I1ogF.js +49 -0
  138. package/dist/_chunks/uk-sI2I1ogF.js.map +1 -0
  139. package/dist/_chunks/uk-yxMSQAwI.mjs +49 -0
  140. package/dist/_chunks/uk-yxMSQAwI.mjs.map +1 -0
  141. package/dist/_chunks/vi-A3zJxaiI.js +50 -0
  142. package/dist/_chunks/vi-A3zJxaiI.js.map +1 -0
  143. package/dist/_chunks/vi-xY0zCW3d.mjs +50 -0
  144. package/dist/_chunks/vi-xY0zCW3d.mjs.map +1 -0
  145. package/dist/_chunks/zh-72SpmFXa.js +86 -0
  146. package/dist/_chunks/zh-72SpmFXa.js.map +1 -0
  147. package/dist/_chunks/zh-Hans-ArWWtyP4.js +86 -0
  148. package/dist/_chunks/zh-Hans-ArWWtyP4.js.map +1 -0
  149. package/dist/_chunks/zh-Hans-E84cu4kP.mjs +86 -0
  150. package/dist/_chunks/zh-Hans-E84cu4kP.mjs.map +1 -0
  151. package/dist/_chunks/zh-OFeldzbX.mjs +86 -0
  152. package/dist/_chunks/zh-OFeldzbX.mjs.map +1 -0
  153. package/dist/admin/index.js +5 -0
  154. package/dist/admin/index.js.map +1 -0
  155. package/dist/admin/index.mjs +6 -0
  156. package/dist/admin/index.mjs.map +1 -0
  157. package/documentation/content-api.yaml +23 -15
  158. package/jest.config.front.js +2 -0
  159. package/package.json +47 -31
  160. package/packup.config.ts +22 -0
  161. package/server/bootstrap/index.js +36 -0
  162. package/server/controllers/auth.js +51 -8
  163. package/server/controllers/user.js +12 -1
  164. package/server/middlewares/rateLimit.js +41 -21
  165. package/server/register.js +7 -1
  166. package/server/services/providers-registry.js +1 -1
  167. package/.eslintrc.js +0 -14
  168. package/admin/src/hooks/index.js +0 -5
  169. package/admin/src/hooks/useFetchRole/index.js +0 -64
  170. package/admin/src/hooks/useFetchRole/reducer.js +0 -31
  171. package/admin/src/hooks/useForm/index.js +0 -70
  172. package/admin/src/hooks/useForm/reducer.js +0 -40
  173. package/admin/src/hooks/usePlugins/index.js +0 -67
  174. package/admin/src/hooks/usePlugins/init.js +0 -5
  175. package/admin/src/hooks/usePlugins/reducer.js +0 -34
  176. package/admin/src/hooks/useRolesList/index.js +0 -63
  177. package/admin/src/hooks/useRolesList/init.js +0 -5
  178. package/admin/src/hooks/useRolesList/reducer.js +0 -31
  179. package/admin/src/pages/AdvancedSettings/utils/api.js +0 -17
  180. package/admin/src/pages/EmailTemplates/utils/api.js +0 -17
  181. package/admin/src/pages/Providers/reducer.js +0 -54
  182. package/admin/src/pages/Providers/utils/api.js +0 -25
  183. package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
  184. package/admin/src/pages/Roles/CreatePage/index.js +0 -182
  185. package/admin/src/pages/Roles/EditPage/index.js +0 -194
  186. package/admin/src/pages/Roles/EditPage/utils/schema.js +0 -9
  187. package/admin/src/pages/Roles/ProtectedCreatePage/index.js +0 -12
  188. package/admin/src/pages/Roles/ProtectedEditPage/index.js +0 -12
  189. package/admin/src/pages/Roles/ProtectedListPage/index.js +0 -15
  190. package/admin/src/pages/Roles/index.js +0 -27
  191. package/admin/src/utils/getRequestURL.js +0 -5
  192. package/strapi-admin.js +0 -3
  193. package/admin/src/components/Permissions/PermissionRow/{CheckboxWrapper.js → CheckboxWrapper.jsx} +1 -1
@@ -0,0 +1,199 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ Button,
5
+ ContentLayout,
6
+ Flex,
7
+ Grid,
8
+ GridItem,
9
+ HeaderLayout,
10
+ Main,
11
+ Textarea,
12
+ TextInput,
13
+ Typography,
14
+ } from '@strapi/design-system';
15
+ import {
16
+ CheckPagePermissions,
17
+ Form,
18
+ SettingsPageTitle,
19
+ useFetchClient,
20
+ useNotification,
21
+ useOverlayBlocker,
22
+ useTracking,
23
+ } from '@strapi/helper-plugin';
24
+ import { Check } from '@strapi/icons';
25
+ import { Formik } from 'formik';
26
+ import { useIntl } from 'react-intl';
27
+ import { useMutation } from 'react-query';
28
+ import { useHistory } from 'react-router-dom';
29
+
30
+ import UsersPermissions from '../../../components/UsersPermissions';
31
+ import { PERMISSIONS } from '../../../constants';
32
+ import getTrad from '../../../utils/getTrad';
33
+ import { createRoleSchema } from '../constants';
34
+ import { usePlugins } from '../hooks/usePlugins';
35
+
36
+ export const CreatePage = () => {
37
+ const { formatMessage } = useIntl();
38
+ const toggleNotification = useNotification();
39
+ const { goBack } = useHistory();
40
+ const { lockApp, unlockApp } = useOverlayBlocker();
41
+ const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
42
+ const { trackUsage } = useTracking();
43
+ const permissionsRef = React.useRef();
44
+ const { post } = useFetchClient();
45
+ const mutation = useMutation((body) => post(`/users-permissions/roles`, body), {
46
+ onError() {
47
+ toggleNotification({
48
+ type: 'warning',
49
+ message: {
50
+ id: 'notification.error',
51
+ defaultMessage: 'An error occurred',
52
+ },
53
+ });
54
+ },
55
+
56
+ onSuccess() {
57
+ trackUsage('didCreateRole');
58
+
59
+ toggleNotification({
60
+ type: 'success',
61
+ message: {
62
+ id: getTrad('Settings.roles.created'),
63
+ defaultMessage: 'Role created',
64
+ },
65
+ });
66
+
67
+ // Forcing redirecting since we don't have the id in the response
68
+ goBack();
69
+ },
70
+ });
71
+
72
+ const handleCreateRoleSubmit = async (data) => {
73
+ lockApp();
74
+
75
+ // TODO: refactor. Child -> parent component communication is evil;
76
+ // We should either move the provider one level up or move the state
77
+ // straight into redux.
78
+ const permissions = permissionsRef.current.getPermissions();
79
+
80
+ await mutation.mutate({ ...data, ...permissions, users: [] });
81
+
82
+ unlockApp();
83
+ };
84
+
85
+ return (
86
+ <Main>
87
+ {/* TODO: This needs to be translated */}
88
+ <SettingsPageTitle name="Roles" />
89
+ <Formik
90
+ enableReinitialize
91
+ initialValues={{ name: '', description: '' }}
92
+ onSubmit={handleCreateRoleSubmit}
93
+ validationSchema={createRoleSchema}
94
+ >
95
+ {({ handleSubmit, values, handleChange, errors }) => (
96
+ <Form noValidate onSubmit={handleSubmit}>
97
+ <HeaderLayout
98
+ primaryAction={
99
+ !isLoadingPlugins && (
100
+ <Button type="submit" loading={mutation.isLoading} startIcon={<Check />}>
101
+ {formatMessage({
102
+ id: 'global.save',
103
+ defaultMessage: 'Save',
104
+ })}
105
+ </Button>
106
+ )
107
+ }
108
+ title={formatMessage({
109
+ id: 'Settings.roles.create.title',
110
+ defaultMessage: 'Create a role',
111
+ })}
112
+ subtitle={formatMessage({
113
+ id: 'Settings.roles.create.description',
114
+ defaultMessage: 'Define the rights given to the role',
115
+ })}
116
+ />
117
+ <ContentLayout>
118
+ <Flex
119
+ background="neutral0"
120
+ direction="column"
121
+ alignItems="stretch"
122
+ gap={7}
123
+ hasRadius
124
+ paddingTop={6}
125
+ paddingBottom={6}
126
+ paddingLeft={7}
127
+ paddingRight={7}
128
+ shadow="filterShadow"
129
+ >
130
+ <Flex direction="column" alignItems="stretch">
131
+ <Typography variant="delta" as="h2">
132
+ {formatMessage({
133
+ id: getTrad('EditPage.form.roles'),
134
+ defaultMessage: 'Role details',
135
+ })}
136
+ </Typography>
137
+
138
+ <Grid gap={4}>
139
+ <GridItem col={6}>
140
+ <TextInput
141
+ name="name"
142
+ value={values.name || ''}
143
+ onChange={handleChange}
144
+ label={formatMessage({
145
+ id: 'global.name',
146
+ defaultMessage: 'Name',
147
+ })}
148
+ error={
149
+ errors?.name
150
+ ? formatMessage({ id: errors.name, defaultMessage: 'Name is required' })
151
+ : false
152
+ }
153
+ required
154
+ />
155
+ </GridItem>
156
+ <GridItem col={6}>
157
+ <Textarea
158
+ id="description"
159
+ value={values.description || ''}
160
+ onChange={handleChange}
161
+ label={formatMessage({
162
+ id: 'global.description',
163
+ defaultMessage: 'Description',
164
+ })}
165
+ error={
166
+ errors?.description
167
+ ? formatMessage({
168
+ id: errors.description,
169
+ defaultMessage: 'Description is required',
170
+ })
171
+ : false
172
+ }
173
+ required
174
+ />
175
+ </GridItem>
176
+ </Grid>
177
+ </Flex>
178
+
179
+ {!isLoadingPlugins && (
180
+ <UsersPermissions
181
+ ref={permissionsRef}
182
+ permissions={permissions}
183
+ routes={routes}
184
+ />
185
+ )}
186
+ </Flex>
187
+ </ContentLayout>
188
+ </Form>
189
+ )}
190
+ </Formik>
191
+ </Main>
192
+ );
193
+ };
194
+
195
+ export const ProtectedRolesCreatePage = () => (
196
+ <CheckPagePermissions permissions={PERMISSIONS.createRole}>
197
+ <CreatePage />
198
+ </CheckPagePermissions>
199
+ );
@@ -0,0 +1,220 @@
1
+ import * as React from 'react';
2
+
3
+ import {
4
+ ContentLayout,
5
+ HeaderLayout,
6
+ Main,
7
+ Button,
8
+ Flex,
9
+ TextInput,
10
+ Textarea,
11
+ Typography,
12
+ GridItem,
13
+ Grid,
14
+ } from '@strapi/design-system';
15
+ import {
16
+ CheckPagePermissions,
17
+ useOverlayBlocker,
18
+ SettingsPageTitle,
19
+ LoadingIndicatorPage,
20
+ Form,
21
+ useAPIErrorHandler,
22
+ useFetchClient,
23
+ useNotification,
24
+ Link,
25
+ } from '@strapi/helper-plugin';
26
+ import { ArrowLeft, Check } from '@strapi/icons';
27
+ import { Formik } from 'formik';
28
+ import { useIntl } from 'react-intl';
29
+ import { useQuery, useMutation } from 'react-query';
30
+ import { useRouteMatch } from 'react-router-dom';
31
+
32
+ import UsersPermissions from '../../../components/UsersPermissions';
33
+ import { PERMISSIONS } from '../../../constants';
34
+ import getTrad from '../../../utils/getTrad';
35
+ import { createRoleSchema } from '../constants';
36
+ import { usePlugins } from '../hooks/usePlugins';
37
+
38
+ export const EditPage = () => {
39
+ const { formatMessage } = useIntl();
40
+ const toggleNotification = useNotification();
41
+ const { lockApp, unlockApp } = useOverlayBlocker();
42
+ const {
43
+ params: { id },
44
+ } = useRouteMatch(`/settings/users-permissions/roles/:id`);
45
+ const { get } = useFetchClient();
46
+ const { isLoading: isLoadingPlugins, routes } = usePlugins();
47
+ const {
48
+ data: role,
49
+ isLoading: isLoadingRole,
50
+ refetch: refetchRole,
51
+ } = useQuery(['users-permissions', 'role', id], async () => {
52
+ // TODO: why doesn't this endpoint follow the admin API conventions?
53
+ const {
54
+ data: { role },
55
+ } = await get(`/users-permissions/roles/${id}`);
56
+
57
+ return role;
58
+ });
59
+
60
+ const permissionsRef = React.useRef();
61
+ const { put } = useFetchClient();
62
+ const { formatAPIError } = useAPIErrorHandler();
63
+ const mutation = useMutation((body) => put(`/users-permissions/roles/${id}`, body), {
64
+ onError(error) {
65
+ toggleNotification({
66
+ type: 'warning',
67
+ message: formatAPIError(error),
68
+ });
69
+ },
70
+
71
+ async onSuccess() {
72
+ toggleNotification({
73
+ type: 'success',
74
+ message: {
75
+ id: getTrad('Settings.roles.created'),
76
+ defaultMessage: 'Role edited',
77
+ },
78
+ });
79
+
80
+ await refetchRole();
81
+ },
82
+ });
83
+
84
+ const handleEditRoleSubmit = async (data) => {
85
+ // Set loading state
86
+ lockApp();
87
+
88
+ const permissions = permissionsRef.current.getPermissions();
89
+
90
+ await mutation.mutate({ ...data, ...permissions, users: [] });
91
+
92
+ unlockApp();
93
+ };
94
+
95
+ if (isLoadingRole) {
96
+ return <LoadingIndicatorPage />;
97
+ }
98
+
99
+ return (
100
+ <Main>
101
+ {/* TODO: this needs to be translated */}
102
+ <SettingsPageTitle name="Roles" />
103
+ <Formik
104
+ enableReinitialize
105
+ initialValues={{ name: role.name, description: role.description }}
106
+ onSubmit={handleEditRoleSubmit}
107
+ validationSchema={createRoleSchema}
108
+ >
109
+ {({ handleSubmit, values, handleChange, errors }) => (
110
+ <Form noValidate onSubmit={handleSubmit}>
111
+ <HeaderLayout
112
+ primaryAction={
113
+ !isLoadingPlugins && (
114
+ <Button
115
+ disabled={role.code === 'strapi-super-admin'}
116
+ type="submit"
117
+ loading={mutation.isLoading}
118
+ startIcon={<Check />}
119
+ >
120
+ {formatMessage({
121
+ id: 'global.save',
122
+ defaultMessage: 'Save',
123
+ })}
124
+ </Button>
125
+ )
126
+ }
127
+ title={role.name}
128
+ subtitle={role.description}
129
+ navigationAction={
130
+ <Link startIcon={<ArrowLeft />} to="/settings/users-permissions/roles">
131
+ {formatMessage({
132
+ id: 'global.back',
133
+ defaultMessage: 'Back',
134
+ })}
135
+ </Link>
136
+ }
137
+ />
138
+ <ContentLayout>
139
+ <Flex
140
+ background="neutral0"
141
+ direction="column"
142
+ alignItems="stretch"
143
+ gap={7}
144
+ hasRadius
145
+ paddingTop={6}
146
+ paddingBottom={6}
147
+ paddingLeft={7}
148
+ paddingRight={7}
149
+ shadow="filterShadow"
150
+ >
151
+ <Flex direction="column" alignItems="stretch" gap={4}>
152
+ <Typography variant="delta" as="h2">
153
+ {formatMessage({
154
+ id: getTrad('EditPage.form.roles'),
155
+ defaultMessage: 'Role details',
156
+ })}
157
+ </Typography>
158
+
159
+ <Grid gap={4}>
160
+ <GridItem col={6}>
161
+ <TextInput
162
+ name="name"
163
+ value={values.name || ''}
164
+ onChange={handleChange}
165
+ label={formatMessage({
166
+ id: 'global.name',
167
+ defaultMessage: 'Name',
168
+ })}
169
+ error={
170
+ errors?.name
171
+ ? formatMessage({ id: errors.name, defaultMessage: 'Name is required' })
172
+ : false
173
+ }
174
+ required
175
+ />
176
+ </GridItem>
177
+ <GridItem col={6}>
178
+ <Textarea
179
+ id="description"
180
+ value={values.description || ''}
181
+ onChange={handleChange}
182
+ label={formatMessage({
183
+ id: 'global.description',
184
+ defaultMessage: 'Description',
185
+ })}
186
+ error={
187
+ errors?.description
188
+ ? formatMessage({
189
+ id: errors.description,
190
+ defaultMessage: 'Description is required',
191
+ })
192
+ : false
193
+ }
194
+ required
195
+ />
196
+ </GridItem>
197
+ </Grid>
198
+ </Flex>
199
+
200
+ {!isLoadingPlugins && (
201
+ <UsersPermissions
202
+ ref={permissionsRef}
203
+ permissions={role.permissions}
204
+ routes={routes}
205
+ />
206
+ )}
207
+ </Flex>
208
+ </ContentLayout>
209
+ </Form>
210
+ )}
211
+ </Formik>
212
+ </Main>
213
+ );
214
+ };
215
+
216
+ export const ProtectedRolesEditPage = () => (
217
+ <CheckPagePermissions permissions={PERMISSIONS.updateRole}>
218
+ <EditPage />
219
+ </CheckPagePermissions>
220
+ );
@@ -1,12 +1,39 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { IconButton, Typography, Flex, Tbody, Tr, Td } from '@strapi/design-system';
2
+
3
+ import { Flex, IconButton, Link, Tbody, Td, Tr, Typography } from '@strapi/design-system';
4
+ import { CheckPermissions, onRowClick, pxToRem, stopPropagation } from '@strapi/helper-plugin';
4
5
  import { Pencil, Trash } from '@strapi/icons';
5
- import { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
6
+ import PropTypes from 'prop-types';
6
7
  import { useIntl } from 'react-intl';
7
8
  import { useHistory } from 'react-router-dom';
9
+ import styled from 'styled-components';
10
+
11
+ const EditLink = styled(Link)`
12
+ align-items: center;
13
+ height: ${pxToRem(32)};
14
+ display: flex;
15
+ justify-content: center;
16
+ padding: ${({ theme }) => `${theme.spaces[2]}}`};
17
+ width: ${pxToRem(32)};
8
18
 
9
- import pluginId from '../../../../pluginId';
19
+ svg {
20
+ height: ${pxToRem(12)};
21
+ width: ${pxToRem(12)};
22
+
23
+ path {
24
+ fill: ${({ theme }) => theme.colors.neutral500};
25
+ }
26
+ }
27
+
28
+ &:hover,
29
+ &:focus {
30
+ svg {
31
+ path {
32
+ fill: ${({ theme }) => theme.colors.neutral800};
33
+ }
34
+ }
35
+ }
36
+ `;
10
37
 
11
38
  const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
12
39
  const { formatMessage } = useIntl();
@@ -22,7 +49,7 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
22
49
  };
23
50
 
24
51
  const handleClickEdit = (id) => {
25
- push(`/settings/${pluginId}/roles/${id}`);
52
+ push(`/settings/users-permissions/roles/${id}`);
26
53
  };
27
54
 
28
55
  return (
@@ -37,25 +64,29 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
37
64
  </Td>
38
65
  <Td width="30%">
39
66
  <Typography>
40
- {`${role.nb_users} ${formatMessage({
41
- id: 'global.users',
42
- defaultMessage: 'users',
43
- }).toLowerCase()}`}
67
+ {formatMessage(
68
+ {
69
+ id: 'Roles.RoleRow.user-count',
70
+ defaultMessage: '{number, plural, =0 {# user} one {# user} other {# users}}',
71
+ },
72
+ { number: role.nb_users }
73
+ )}
44
74
  </Typography>
45
75
  </Td>
46
76
  <Td>
47
77
  <Flex justifyContent="end" {...stopPropagation}>
48
78
  <CheckPermissions permissions={permissions.updateRole}>
49
- <IconButton
50
- onClick={() => handleClickEdit(role.id)}
51
- noBorder
52
- icon={<Pencil />}
53
- label={formatMessage(
79
+ <EditLink
80
+ to={`/settings/users-permissions/roles/${role.id}`}
81
+ aria-label={formatMessage(
54
82
  { id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
55
83
  { target: `${role.name}` }
56
84
  )}
57
- />
85
+ >
86
+ <Pencil />
87
+ </EditLink>
58
88
  </CheckPermissions>
89
+
59
90
  {checkCanDeleteRole(role) && (
60
91
  <CheckPermissions permissions={permissions.deleteRole}>
61
92
  <IconButton