@strapi/plugin-users-permissions 0.0.0-4fc90398602f

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 (168) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +1 -0
  3. package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
  4. package/admin/src/components/BoundRoute/index.js +72 -0
  5. package/admin/src/components/FormModal/Input/index.js +121 -0
  6. package/admin/src/components/FormModal/index.js +121 -0
  7. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +30 -0
  8. package/admin/src/components/Permissions/PermissionRow/SubCategory.js +114 -0
  9. package/admin/src/components/Permissions/PermissionRow/index.js +53 -0
  10. package/admin/src/components/Permissions/index.js +56 -0
  11. package/admin/src/components/Permissions/init.js +9 -0
  12. package/admin/src/components/Permissions/reducer.js +27 -0
  13. package/admin/src/components/Policies/index.js +60 -0
  14. package/admin/src/components/UsersPermissions/index.js +94 -0
  15. package/admin/src/components/UsersPermissions/init.js +10 -0
  16. package/admin/src/components/UsersPermissions/reducer.js +60 -0
  17. package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
  18. package/admin/src/hooks/index.js +5 -0
  19. package/admin/src/hooks/useFetchRole/index.js +64 -0
  20. package/admin/src/hooks/useFetchRole/reducer.js +31 -0
  21. package/admin/src/hooks/useForm/index.js +70 -0
  22. package/admin/src/hooks/useForm/reducer.js +40 -0
  23. package/admin/src/hooks/usePlugins/index.js +65 -0
  24. package/admin/src/hooks/usePlugins/init.js +5 -0
  25. package/admin/src/hooks/usePlugins/reducer.js +34 -0
  26. package/admin/src/hooks/useRolesList/index.js +63 -0
  27. package/admin/src/hooks/useRolesList/init.js +5 -0
  28. package/admin/src/hooks/useRolesList/reducer.js +31 -0
  29. package/admin/src/index.js +123 -0
  30. package/admin/src/pages/AdvancedSettings/index.js +238 -0
  31. package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
  32. package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
  33. package/admin/src/pages/AdvancedSettings/utils/schema.js +19 -0
  34. package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
  35. package/admin/src/pages/EmailTemplates/components/EmailTable.js +121 -0
  36. package/admin/src/pages/EmailTemplates/index.js +162 -0
  37. package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
  38. package/admin/src/pages/EmailTemplates/utils/schema.js +22 -0
  39. package/admin/src/pages/Providers/index.js +274 -0
  40. package/admin/src/pages/Providers/reducer.js +54 -0
  41. package/admin/src/pages/Providers/utils/api.js +21 -0
  42. package/admin/src/pages/Providers/utils/createProvidersArray.js +21 -0
  43. package/admin/src/pages/Providers/utils/forms.js +244 -0
  44. package/admin/src/pages/Roles/CreatePage/index.js +177 -0
  45. package/admin/src/pages/Roles/CreatePage/utils/schema.js +9 -0
  46. package/admin/src/pages/Roles/EditPage/index.js +190 -0
  47. package/admin/src/pages/Roles/EditPage/utils/schema.js +9 -0
  48. package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
  49. package/admin/src/pages/Roles/ListPage/index.js +216 -0
  50. package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
  51. package/admin/src/pages/Roles/ProtectedCreatePage/index.js +12 -0
  52. package/admin/src/pages/Roles/ProtectedEditPage/index.js +12 -0
  53. package/admin/src/pages/Roles/ProtectedListPage/index.js +15 -0
  54. package/admin/src/pages/Roles/index.js +27 -0
  55. package/admin/src/permissions.js +31 -0
  56. package/admin/src/pluginId.js +5 -0
  57. package/admin/src/translations/ar.json +40 -0
  58. package/admin/src/translations/cs.json +46 -0
  59. package/admin/src/translations/de.json +58 -0
  60. package/admin/src/translations/dk.json +83 -0
  61. package/admin/src/translations/en.json +83 -0
  62. package/admin/src/translations/es.json +83 -0
  63. package/admin/src/translations/fr.json +46 -0
  64. package/admin/src/translations/id.json +58 -0
  65. package/admin/src/translations/it.json +58 -0
  66. package/admin/src/translations/ja.json +44 -0
  67. package/admin/src/translations/ko.json +83 -0
  68. package/admin/src/translations/ms.json +45 -0
  69. package/admin/src/translations/nl.json +44 -0
  70. package/admin/src/translations/pl.json +83 -0
  71. package/admin/src/translations/pt-BR.json +40 -0
  72. package/admin/src/translations/pt.json +44 -0
  73. package/admin/src/translations/ru.json +58 -0
  74. package/admin/src/translations/sk.json +46 -0
  75. package/admin/src/translations/sv.json +58 -0
  76. package/admin/src/translations/th.json +56 -0
  77. package/admin/src/translations/tr.json +44 -0
  78. package/admin/src/translations/uk.json +45 -0
  79. package/admin/src/translations/vi.json +46 -0
  80. package/admin/src/translations/zh-Hans.json +62 -0
  81. package/admin/src/translations/zh.json +44 -0
  82. package/admin/src/utils/axiosInstance.js +36 -0
  83. package/admin/src/utils/cleanPermissions.js +25 -0
  84. package/admin/src/utils/formatPluginName.js +26 -0
  85. package/admin/src/utils/formatPolicies.js +8 -0
  86. package/admin/src/utils/getRequestURL.js +5 -0
  87. package/admin/src/utils/getTrad.js +5 -0
  88. package/admin/src/utils/index.js +5 -0
  89. package/documentation/content-api.yaml +848 -0
  90. package/jest.config.front.js +10 -0
  91. package/package.json +60 -0
  92. package/server/bootstrap/grant-config.js +123 -0
  93. package/server/bootstrap/index.js +133 -0
  94. package/server/bootstrap/users-permissions-actions.js +80 -0
  95. package/server/config.js +23 -0
  96. package/server/content-types/index.js +11 -0
  97. package/server/content-types/permission/index.js +34 -0
  98. package/server/content-types/role/index.js +51 -0
  99. package/server/content-types/user/index.js +72 -0
  100. package/server/content-types/user/schema-config.js +15 -0
  101. package/server/controllers/auth.js +398 -0
  102. package/server/controllers/content-manager-user.js +175 -0
  103. package/server/controllers/index.js +17 -0
  104. package/server/controllers/permissions.js +26 -0
  105. package/server/controllers/role.js +77 -0
  106. package/server/controllers/settings.js +85 -0
  107. package/server/controllers/user.js +198 -0
  108. package/server/controllers/validation/auth.js +57 -0
  109. package/server/controllers/validation/email-template.js +50 -0
  110. package/server/controllers/validation/user.js +26 -0
  111. package/server/graphql/index.js +44 -0
  112. package/server/graphql/mutations/auth/change-password.js +38 -0
  113. package/server/graphql/mutations/auth/email-confirmation.js +39 -0
  114. package/server/graphql/mutations/auth/forgot-password.js +35 -0
  115. package/server/graphql/mutations/auth/login.js +35 -0
  116. package/server/graphql/mutations/auth/register.js +36 -0
  117. package/server/graphql/mutations/auth/reset-password.js +38 -0
  118. package/server/graphql/mutations/crud/role/create-role.js +34 -0
  119. package/server/graphql/mutations/crud/role/delete-role.js +25 -0
  120. package/server/graphql/mutations/crud/role/update-role.js +35 -0
  121. package/server/graphql/mutations/crud/user/create-user.js +45 -0
  122. package/server/graphql/mutations/crud/user/delete-user.js +39 -0
  123. package/server/graphql/mutations/crud/user/update-user.js +46 -0
  124. package/server/graphql/mutations/index.js +43 -0
  125. package/server/graphql/queries/index.js +13 -0
  126. package/server/graphql/queries/me.js +17 -0
  127. package/server/graphql/resolvers-configs.js +42 -0
  128. package/server/graphql/types/create-role-payload.js +11 -0
  129. package/server/graphql/types/delete-role-payload.js +11 -0
  130. package/server/graphql/types/index.js +21 -0
  131. package/server/graphql/types/login-input.js +13 -0
  132. package/server/graphql/types/login-payload.js +12 -0
  133. package/server/graphql/types/me-role.js +14 -0
  134. package/server/graphql/types/me.js +16 -0
  135. package/server/graphql/types/password-payload.js +11 -0
  136. package/server/graphql/types/register-input.js +13 -0
  137. package/server/graphql/types/update-role-payload.js +11 -0
  138. package/server/graphql/utils.js +27 -0
  139. package/server/index.js +21 -0
  140. package/server/middlewares/index.js +7 -0
  141. package/server/middlewares/rateLimit.js +27 -0
  142. package/server/register.js +23 -0
  143. package/server/routes/admin/index.js +10 -0
  144. package/server/routes/admin/permissions.js +20 -0
  145. package/server/routes/admin/role.js +79 -0
  146. package/server/routes/admin/settings.js +95 -0
  147. package/server/routes/content-api/auth.js +82 -0
  148. package/server/routes/content-api/index.js +11 -0
  149. package/server/routes/content-api/permissions.js +9 -0
  150. package/server/routes/content-api/role.js +29 -0
  151. package/server/routes/content-api/user.js +60 -0
  152. package/server/routes/index.js +6 -0
  153. package/server/services/index.js +17 -0
  154. package/server/services/jwt.js +55 -0
  155. package/server/services/providers-registry.js +292 -0
  156. package/server/services/providers.js +115 -0
  157. package/server/services/role.js +177 -0
  158. package/server/services/user.js +140 -0
  159. package/server/services/users-permissions.js +236 -0
  160. package/server/strategies/users-permissions.js +102 -0
  161. package/server/utils/index.d.ts +16 -0
  162. package/server/utils/index.js +12 -0
  163. package/server/utils/sanitize/index.js +9 -0
  164. package/server/utils/sanitize/sanitizers.js +19 -0
  165. package/server/utils/sanitize/visitors/index.js +5 -0
  166. package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +11 -0
  167. package/strapi-admin.js +3 -0
  168. package/strapi-server.js +3 -0
@@ -0,0 +1,244 @@
1
+ import * as yup from 'yup';
2
+ import { translatedErrors } from '@strapi/helper-plugin';
3
+
4
+ import { getTrad } from '../../../utils';
5
+
6
+ const callbackLabel = {
7
+ id: getTrad('PopUpForm.Providers.redirectURL.front-end.label'),
8
+ defaultMessage: 'The redirect URL to your front-end app',
9
+ };
10
+ const callbackPlaceholder = {
11
+ id: 'http://www.client-app.com',
12
+ defaultMessage: 'http://www.client-app.com',
13
+ };
14
+ const enabledDescription = {
15
+ id: getTrad('PopUpForm.Providers.enabled.description'),
16
+ defaultMessage: "If disabled, users won't be able to use this provider.",
17
+ };
18
+ const enabledLabel = {
19
+ id: getTrad('PopUpForm.Providers.enabled.label'),
20
+ defaultMessage: 'Enable',
21
+ };
22
+ const keyLabel = { id: getTrad('PopUpForm.Providers.key.label'), defaultMessage: 'Client ID' };
23
+ const hintLabel = {
24
+ id: getTrad('PopUpForm.Providers.redirectURL.label'),
25
+ defaultMessage: 'The redirect URL to add in your {provider} application configurations',
26
+ };
27
+ const textPlaceholder = {
28
+ id: getTrad('PopUpForm.Providers.key.placeholder'),
29
+ defaultMessage: 'TEXT',
30
+ };
31
+
32
+ const secretLabel = {
33
+ id: getTrad('PopUpForm.Providers.secret.label'),
34
+ defaultMessage: 'Client Secret',
35
+ };
36
+
37
+ const forms = {
38
+ email: {
39
+ form: [
40
+ [
41
+ {
42
+ intlLabel: enabledLabel,
43
+ name: 'enabled',
44
+ type: 'bool',
45
+ description: enabledDescription,
46
+ size: 6,
47
+ // TODO check if still needed
48
+ // validations: {
49
+ // required: true,
50
+ // },
51
+ },
52
+ ],
53
+ ],
54
+ schema: yup.object().shape({
55
+ enabled: yup.bool().required(translatedErrors.required),
56
+ }),
57
+ },
58
+ providers: {
59
+ form: [
60
+ [
61
+ {
62
+ intlLabel: enabledLabel,
63
+ name: 'enabled',
64
+ type: 'bool',
65
+ description: enabledDescription,
66
+ size: 6,
67
+ validations: {
68
+ required: true,
69
+ },
70
+ },
71
+ ],
72
+ [
73
+ {
74
+ intlLabel: keyLabel,
75
+ name: 'key',
76
+ type: 'text',
77
+ placeholder: textPlaceholder,
78
+ size: 12,
79
+ validations: {
80
+ required: true,
81
+ },
82
+ },
83
+ ],
84
+ [
85
+ {
86
+ intlLabel: secretLabel,
87
+ name: 'secret',
88
+ type: 'text',
89
+ placeholder: textPlaceholder,
90
+ size: 12,
91
+ validations: {
92
+ required: true,
93
+ },
94
+ },
95
+ ],
96
+ [
97
+ {
98
+ intlLabel: callbackLabel,
99
+ placeholder: callbackPlaceholder,
100
+ name: 'callback',
101
+ type: 'text',
102
+ size: 12,
103
+ validations: {
104
+ required: true,
105
+ },
106
+ },
107
+ ],
108
+ [
109
+ {
110
+ intlLabel: hintLabel,
111
+ name: 'noName',
112
+ type: 'text',
113
+ validations: {},
114
+ size: 12,
115
+ disabled: true,
116
+ },
117
+ ],
118
+ ],
119
+ schema: yup.object().shape({
120
+ enabled: yup.bool().required(translatedErrors.required),
121
+ key: yup.string().when('enabled', {
122
+ is: true,
123
+ then: yup.string().required(translatedErrors.required),
124
+ otherwise: yup.string(),
125
+ }),
126
+ secret: yup.string().when('enabled', {
127
+ is: true,
128
+ then: yup.string().required(translatedErrors.required),
129
+ otherwise: yup.string(),
130
+ }),
131
+ callback: yup.string().when('enabled', {
132
+ is: true,
133
+ then: yup.string().required(translatedErrors.required),
134
+ otherwise: yup.string(),
135
+ }),
136
+ }),
137
+ },
138
+ providersWithSubdomain: {
139
+ form: [
140
+ [
141
+ {
142
+ intlLabel: enabledLabel,
143
+ name: 'enabled',
144
+ type: 'bool',
145
+ description: enabledDescription,
146
+ size: 6,
147
+ validations: {
148
+ required: true,
149
+ },
150
+ },
151
+ ],
152
+ [
153
+ {
154
+ intlLabel: keyLabel,
155
+ name: 'key',
156
+ type: 'text',
157
+ placeholder: textPlaceholder,
158
+ size: 12,
159
+ validations: {
160
+ required: true,
161
+ },
162
+ },
163
+ ],
164
+ [
165
+ {
166
+ intlLabel: secretLabel,
167
+ name: 'secret',
168
+ type: 'text',
169
+ placeholder: textPlaceholder,
170
+ size: 12,
171
+ validations: {
172
+ required: true,
173
+ },
174
+ },
175
+ ],
176
+
177
+ [
178
+ {
179
+ intlLabel: {
180
+ id: getTrad('PopUpForm.Providers.subdomain.label'),
181
+ defaultMessage: 'Host URI (Subdomain)',
182
+ },
183
+ name: 'subdomain',
184
+ type: 'text',
185
+ placeholder: {
186
+ id: getTrad('PopUpForm.Providers.subdomain.placeholder'),
187
+ defaultMessage: 'my.subdomain.com',
188
+ },
189
+ size: 12,
190
+ validations: {
191
+ required: true,
192
+ },
193
+ },
194
+ ],
195
+ [
196
+ {
197
+ intlLabel: callbackLabel,
198
+ placeholder: callbackPlaceholder,
199
+ name: 'callback',
200
+ type: 'text',
201
+ size: 12,
202
+ validations: {
203
+ required: true,
204
+ },
205
+ },
206
+ ],
207
+ [
208
+ {
209
+ intlLabel: hintLabel,
210
+ name: 'noName',
211
+ type: 'text',
212
+ validations: {},
213
+ size: 12,
214
+ disabled: true,
215
+ },
216
+ ],
217
+ ],
218
+ schema: yup.object().shape({
219
+ enabled: yup.bool().required(translatedErrors.required),
220
+ key: yup.string().when('enabled', {
221
+ is: true,
222
+ then: yup.string().required(translatedErrors.required),
223
+ otherwise: yup.string(),
224
+ }),
225
+ secret: yup.string().when('enabled', {
226
+ is: true,
227
+ then: yup.string().required(translatedErrors.required),
228
+ otherwise: yup.string(),
229
+ }),
230
+ subdomain: yup.string().when('enabled', {
231
+ is: true,
232
+ then: yup.string().required(translatedErrors.required),
233
+ otherwise: yup.string(),
234
+ }),
235
+ callback: yup.string().when('enabled', {
236
+ is: true,
237
+ then: yup.string().required(translatedErrors.required),
238
+ otherwise: yup.string(),
239
+ }),
240
+ }),
241
+ },
242
+ };
243
+
244
+ export default forms;
@@ -0,0 +1,177 @@
1
+ import React, { useState, useRef } from 'react';
2
+ import { useHistory } from 'react-router-dom';
3
+ import { ContentLayout, HeaderLayout } from '@strapi/design-system/Layout';
4
+ import { Main } from '@strapi/design-system/Main';
5
+ import { Button } from '@strapi/design-system/Button';
6
+ import { Stack } from '@strapi/design-system/Stack';
7
+ import { Box } from '@strapi/design-system/Box';
8
+ import { TextInput } from '@strapi/design-system/TextInput';
9
+ import { Textarea } from '@strapi/design-system/Textarea';
10
+ import { Typography } from '@strapi/design-system/Typography';
11
+ import Check from '@strapi/icons/Check';
12
+ import { GridItem, Grid } from '@strapi/design-system/Grid';
13
+ import { Formik } from 'formik';
14
+ import { useIntl } from 'react-intl';
15
+ import {
16
+ useOverlayBlocker,
17
+ SettingsPageTitle,
18
+ useTracking,
19
+ Form,
20
+ useNotification,
21
+ } from '@strapi/helper-plugin';
22
+ import UsersPermissions from '../../../components/UsersPermissions';
23
+ import getTrad from '../../../utils/getTrad';
24
+ import pluginId from '../../../pluginId';
25
+ import { usePlugins } from '../../../hooks';
26
+ import schema from './utils/schema';
27
+ import axiosInstance from '../../../utils/axiosInstance';
28
+
29
+ const EditPage = () => {
30
+ const { formatMessage } = useIntl();
31
+ const [isSubmitting, setIsSubmitting] = useState(false);
32
+ const toggleNotification = useNotification();
33
+ const { goBack } = useHistory();
34
+ const { lockApp, unlockApp } = useOverlayBlocker();
35
+ const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
36
+ const { trackUsage } = useTracking();
37
+ const permissionsRef = useRef();
38
+
39
+ const handleCreateRoleSubmit = async (data) => {
40
+ // Set loading state
41
+ lockApp();
42
+ setIsSubmitting(true);
43
+ try {
44
+ const permissions = permissionsRef.current.getPermissions();
45
+ // Update role in Strapi
46
+ await axiosInstance.post(`/${pluginId}/roles`, { ...data, ...permissions, users: [] });
47
+ // Notify success
48
+ trackUsage('didCreateRole');
49
+ toggleNotification({
50
+ type: 'success',
51
+ message: {
52
+ id: getTrad('Settings.roles.created'),
53
+ defaultMessage: 'Role created',
54
+ },
55
+ });
56
+ // Forcing redirecting since we don't have the id in the response
57
+ goBack();
58
+ } catch (err) {
59
+ console.error(err);
60
+ toggleNotification({
61
+ type: 'warning',
62
+ message: {
63
+ id: 'notification.error',
64
+ defaultMessage: 'An error occurred',
65
+ },
66
+ });
67
+ }
68
+ // Unset loading state
69
+ setIsSubmitting(false);
70
+ unlockApp();
71
+ };
72
+
73
+ return (
74
+ <Main>
75
+ <SettingsPageTitle name="Roles" />
76
+ <Formik
77
+ enableReinitialize
78
+ initialValues={{ name: '', description: '' }}
79
+ onSubmit={handleCreateRoleSubmit}
80
+ validationSchema={schema}
81
+ >
82
+ {({ handleSubmit, values, handleChange, errors }) => (
83
+ <Form noValidate onSubmit={handleSubmit}>
84
+ <HeaderLayout
85
+ primaryAction={
86
+ !isLoadingPlugins && (
87
+ <Button type="submit" loading={isSubmitting} startIcon={<Check />}>
88
+ {formatMessage({
89
+ id: 'global.save',
90
+ defaultMessage: 'Save',
91
+ })}
92
+ </Button>
93
+ )
94
+ }
95
+ title={formatMessage({
96
+ id: 'Settings.roles.create.title',
97
+ defaultMessage: 'Create a role',
98
+ })}
99
+ subtitle={formatMessage({
100
+ id: 'Settings.roles.create.description',
101
+ defaultMessage: 'Define the rights given to the role',
102
+ })}
103
+ />
104
+ <ContentLayout>
105
+ <Stack spacing={7}>
106
+ <Box
107
+ background="neutral0"
108
+ hasRadius
109
+ shadow="filterShadow"
110
+ paddingTop={6}
111
+ paddingBottom={6}
112
+ paddingLeft={7}
113
+ paddingRight={7}
114
+ >
115
+ <Stack spacing={4}>
116
+ <Typography variant="delta" as="h2">
117
+ {formatMessage({
118
+ id: getTrad('EditPage.form.roles'),
119
+ defaultMessage: 'Role details',
120
+ })}
121
+ </Typography>
122
+ <Grid gap={4}>
123
+ <GridItem col={6}>
124
+ <TextInput
125
+ name="name"
126
+ value={values.name || ''}
127
+ onChange={handleChange}
128
+ label={formatMessage({
129
+ id: 'global.name',
130
+ defaultMessage: 'Name',
131
+ })}
132
+ error={
133
+ errors.name
134
+ ? formatMessage({ id: errors.name, defaultMessage: 'Invalid value' })
135
+ : null
136
+ }
137
+ />
138
+ </GridItem>
139
+ <GridItem col={6}>
140
+ <Textarea
141
+ name="description"
142
+ value={values.description || ''}
143
+ onChange={handleChange}
144
+ label={formatMessage({
145
+ id: 'global.description',
146
+ defaultMessage: 'Description',
147
+ })}
148
+ error={
149
+ errors.description
150
+ ? formatMessage({
151
+ id: errors.description,
152
+ defaultMessage: 'Invalid value',
153
+ })
154
+ : null
155
+ }
156
+ />
157
+ </GridItem>
158
+ </Grid>
159
+ </Stack>
160
+ </Box>
161
+ {!isLoadingPlugins && (
162
+ <UsersPermissions
163
+ ref={permissionsRef}
164
+ permissions={permissions}
165
+ routes={routes}
166
+ />
167
+ )}
168
+ </Stack>
169
+ </ContentLayout>
170
+ </Form>
171
+ )}
172
+ </Formik>
173
+ </Main>
174
+ );
175
+ };
176
+
177
+ export default EditPage;
@@ -0,0 +1,9 @@
1
+ import * as yup from 'yup';
2
+ import { translatedErrors } from '@strapi/helper-plugin';
3
+
4
+ const schema = yup.object().shape({
5
+ name: yup.string().required(translatedErrors.required),
6
+ description: yup.string().required(translatedErrors.required),
7
+ });
8
+
9
+ export default schema;
@@ -0,0 +1,190 @@
1
+ import React, { useState, useRef } from 'react';
2
+ import { Formik } from 'formik';
3
+ import { useIntl } from 'react-intl';
4
+ import { useRouteMatch } from 'react-router-dom';
5
+ import {
6
+ useOverlayBlocker,
7
+ SettingsPageTitle,
8
+ LoadingIndicatorPage,
9
+ Form,
10
+ useNotification,
11
+ Link,
12
+ } from '@strapi/helper-plugin';
13
+ import { ContentLayout, HeaderLayout } from '@strapi/design-system/Layout';
14
+ import { Main } from '@strapi/design-system/Main';
15
+ import { Button } from '@strapi/design-system/Button';
16
+ import { Stack } from '@strapi/design-system/Stack';
17
+ import { Box } from '@strapi/design-system/Box';
18
+ import { TextInput } from '@strapi/design-system/TextInput';
19
+ import { Textarea } from '@strapi/design-system/Textarea';
20
+ import { Typography } from '@strapi/design-system/Typography';
21
+ import ArrowLeft from '@strapi/icons/ArrowLeft';
22
+ import Check from '@strapi/icons/Check';
23
+ import { GridItem, Grid } from '@strapi/design-system/Grid';
24
+ import UsersPermissions from '../../../components/UsersPermissions';
25
+ import getTrad from '../../../utils/getTrad';
26
+ import pluginId from '../../../pluginId';
27
+ import { usePlugins, useFetchRole } from '../../../hooks';
28
+ import schema from './utils/schema';
29
+ import axiosInstance from '../../../utils/axiosInstance';
30
+
31
+ const EditPage = () => {
32
+ const { formatMessage } = useIntl();
33
+ const [isSubmitting, setIsSubmitting] = useState(false);
34
+ const toggleNotification = useNotification();
35
+ const { lockApp, unlockApp } = useOverlayBlocker();
36
+ const {
37
+ params: { id },
38
+ } = useRouteMatch(`/settings/${pluginId}/roles/:id`);
39
+ const { isLoading: isLoadingPlugins, routes } = usePlugins();
40
+ const { role, onSubmitSucceeded, isLoading: isLoadingRole } = useFetchRole(id);
41
+ const permissionsRef = useRef();
42
+
43
+ const handleEditRoleSubmit = async (data) => {
44
+ // Set loading state
45
+ lockApp();
46
+ setIsSubmitting(true);
47
+ try {
48
+ const permissions = permissionsRef.current.getPermissions();
49
+ // Update role in Strapi
50
+ await axiosInstance.put(`/${pluginId}/roles/${id}`, { ...data, ...permissions, users: [] });
51
+ // Notify success
52
+ onSubmitSucceeded({ name: data.name, description: data.description });
53
+ toggleNotification({
54
+ type: 'success',
55
+ message: {
56
+ id: getTrad('Settings.roles.edited'),
57
+ defaultMessage: 'Role edited',
58
+ },
59
+ });
60
+ } catch (err) {
61
+ console.error(err);
62
+ toggleNotification({
63
+ type: 'warning',
64
+ message: {
65
+ id: 'notification.error',
66
+ defaultMessage: 'An error occurred',
67
+ },
68
+ });
69
+ }
70
+ // Unset loading state
71
+ setIsSubmitting(false);
72
+ unlockApp();
73
+ };
74
+
75
+ if (isLoadingRole) {
76
+ return <LoadingIndicatorPage />;
77
+ }
78
+
79
+ return (
80
+ <Main>
81
+ <SettingsPageTitle name="Roles" />
82
+ <Formik
83
+ enableReinitialize
84
+ initialValues={{ name: role.name, description: role.description }}
85
+ onSubmit={handleEditRoleSubmit}
86
+ validationSchema={schema}
87
+ >
88
+ {({ handleSubmit, values, handleChange, errors }) => (
89
+ <Form noValidate onSubmit={handleSubmit}>
90
+ <HeaderLayout
91
+ primaryAction={
92
+ !isLoadingPlugins && (
93
+ <Button
94
+ disabled={role.code === 'strapi-super-admin'}
95
+ type="submit"
96
+ loading={isSubmitting}
97
+ startIcon={<Check />}
98
+ >
99
+ {formatMessage({
100
+ id: 'global.save',
101
+ defaultMessage: 'Save',
102
+ })}
103
+ </Button>
104
+ )
105
+ }
106
+ title={role.name}
107
+ subtitle={role.description}
108
+ navigationAction={
109
+ <Link startIcon={<ArrowLeft />} to="/settings/users-permissions/roles">
110
+ {formatMessage({
111
+ id: 'global.back',
112
+ defaultMessage: 'Back',
113
+ })}
114
+ </Link>
115
+ }
116
+ />
117
+ <ContentLayout>
118
+ <Stack spacing={7}>
119
+ <Box
120
+ background="neutral0"
121
+ hasRadius
122
+ shadow="filterShadow"
123
+ paddingTop={6}
124
+ paddingBottom={6}
125
+ paddingLeft={7}
126
+ paddingRight={7}
127
+ >
128
+ <Stack spacing={4}>
129
+ <Typography variant="delta" as="h2">
130
+ {formatMessage({
131
+ id: getTrad('EditPage.form.roles'),
132
+ defaultMessage: 'Role details',
133
+ })}
134
+ </Typography>
135
+ <Grid gap={4}>
136
+ <GridItem col={6}>
137
+ <TextInput
138
+ name="name"
139
+ value={values.name || ''}
140
+ onChange={handleChange}
141
+ label={formatMessage({
142
+ id: 'global.name',
143
+ defaultMessage: 'Name',
144
+ })}
145
+ error={
146
+ errors.name
147
+ ? formatMessage({ id: errors.name, defaultMessage: 'Invalid value' })
148
+ : null
149
+ }
150
+ />
151
+ </GridItem>
152
+ <GridItem col={6}>
153
+ <Textarea
154
+ name="description"
155
+ value={values.description || ''}
156
+ onChange={handleChange}
157
+ label={formatMessage({
158
+ id: 'global.description',
159
+ defaultMessage: 'Description',
160
+ })}
161
+ error={
162
+ errors.description
163
+ ? formatMessage({
164
+ id: errors.description,
165
+ defaultMessage: 'Invalid value',
166
+ })
167
+ : null
168
+ }
169
+ />
170
+ </GridItem>
171
+ </Grid>
172
+ </Stack>
173
+ </Box>
174
+ {!isLoadingPlugins && (
175
+ <UsersPermissions
176
+ ref={permissionsRef}
177
+ permissions={role.permissions}
178
+ routes={routes}
179
+ />
180
+ )}
181
+ </Stack>
182
+ </ContentLayout>
183
+ </Form>
184
+ )}
185
+ </Formik>
186
+ </Main>
187
+ );
188
+ };
189
+
190
+ export default EditPage;
@@ -0,0 +1,9 @@
1
+ import * as yup from 'yup';
2
+ import { translatedErrors } from '@strapi/helper-plugin';
3
+
4
+ const schema = yup.object().shape({
5
+ name: yup.string().required(translatedErrors.required),
6
+ description: yup.string().required(translatedErrors.required),
7
+ });
8
+
9
+ export default schema;