@strapi/plugin-users-permissions 0.0.0-next.f5b09a8e61e059f02784478e27c310c6290be088 → 0.0.0-next.f6dca5adf05ef6bed9605a1535999ab0bbbf063e

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 (192) hide show
  1. package/.eslintrc +4 -1
  2. package/LICENSE +18 -3
  3. package/admin/src/components/BoundRoute/{index.js → index.jsx} +2 -2
  4. package/admin/src/components/FormModal/Input/{index.js → index.jsx} +32 -31
  5. package/admin/src/components/FormModal/index.jsx +115 -0
  6. package/admin/src/components/Permissions/PermissionRow/{CheckboxWrapper.js → CheckboxWrapper.jsx} +4 -3
  7. package/admin/src/components/Permissions/PermissionRow/{SubCategory.js → SubCategory.jsx} +13 -22
  8. package/admin/src/components/Permissions/index.jsx +47 -0
  9. package/admin/src/components/Permissions/reducer.js +1 -1
  10. package/admin/src/components/Policies/{index.js → index.jsx} +7 -5
  11. package/admin/src/components/UsersPermissions/{index.js → index.jsx} +15 -7
  12. package/admin/src/components/UsersPermissions/reducer.js +1 -1
  13. package/admin/src/index.js +15 -32
  14. package/admin/src/pages/AdvancedSettings/index.jsx +214 -0
  15. package/admin/src/pages/AdvancedSettings/utils/layout.js +20 -35
  16. package/admin/src/pages/AdvancedSettings/utils/schema.js +5 -2
  17. package/admin/src/pages/EmailTemplates/components/EmailForm.jsx +156 -0
  18. package/admin/src/pages/EmailTemplates/components/{EmailTable.js → EmailTable.jsx} +20 -17
  19. package/admin/src/pages/EmailTemplates/{index.js → index.jsx} +36 -62
  20. package/admin/src/pages/EmailTemplates/utils/schema.js +18 -6
  21. package/admin/src/pages/Providers/{index.js → index.jsx} +98 -113
  22. package/admin/src/pages/Providers/utils/forms.js +23 -11
  23. package/admin/src/pages/Roles/constants.js +3 -3
  24. package/admin/src/pages/Roles/hooks/usePlugins.js +4 -4
  25. package/admin/src/pages/Roles/index.jsx +24 -0
  26. package/admin/src/pages/Roles/pages/{CreatePage.js → CreatePage.jsx} +53 -58
  27. package/admin/src/pages/Roles/pages/{EditPage.js → EditPage.jsx} +63 -68
  28. package/admin/src/pages/Roles/pages/ListPage/components/{TableBody.js → TableBody.jsx} +27 -31
  29. package/admin/src/pages/Roles/pages/ListPage/{index.js → index.jsx} +79 -55
  30. package/admin/src/translations/en.json +1 -1
  31. package/admin/src/utils/prefixPluginTranslations.js +13 -0
  32. package/dist/_chunks/ar-BguGUqwK.js +44 -0
  33. package/dist/_chunks/ar-BguGUqwK.js.map +1 -0
  34. package/dist/_chunks/ar-CK8BRRXB.mjs +44 -0
  35. package/dist/_chunks/ar-CK8BRRXB.mjs.map +1 -0
  36. package/dist/_chunks/cs-BVigMk0l.mjs +50 -0
  37. package/dist/_chunks/cs-BVigMk0l.mjs.map +1 -0
  38. package/dist/_chunks/cs-BW8-K_GY.js +50 -0
  39. package/dist/_chunks/cs-BW8-K_GY.js.map +1 -0
  40. package/dist/_chunks/de-BKUdRFI4.mjs +62 -0
  41. package/dist/_chunks/de-BKUdRFI4.mjs.map +1 -0
  42. package/dist/_chunks/de-owXpVluI.js +62 -0
  43. package/dist/_chunks/de-owXpVluI.js.map +1 -0
  44. package/dist/_chunks/dk-BQiTK50l.mjs +86 -0
  45. package/dist/_chunks/dk-BQiTK50l.mjs.map +1 -0
  46. package/dist/_chunks/dk-LXAnbuBk.js +86 -0
  47. package/dist/_chunks/dk-LXAnbuBk.js.map +1 -0
  48. package/dist/_chunks/en-DOHtPf-2.mjs +86 -0
  49. package/dist/_chunks/en-DOHtPf-2.mjs.map +1 -0
  50. package/dist/_chunks/en-MHo5mcsU.js +86 -0
  51. package/dist/_chunks/en-MHo5mcsU.js.map +1 -0
  52. package/dist/_chunks/es-BwLCLXAQ.js +86 -0
  53. package/dist/_chunks/es-BwLCLXAQ.js.map +1 -0
  54. package/dist/_chunks/es-DNgOVMjD.mjs +86 -0
  55. package/dist/_chunks/es-DNgOVMjD.mjs.map +1 -0
  56. package/dist/_chunks/fr-DkgRugiU.mjs +50 -0
  57. package/dist/_chunks/fr-DkgRugiU.mjs.map +1 -0
  58. package/dist/_chunks/fr-DkhpSjjm.js +50 -0
  59. package/dist/_chunks/fr-DkhpSjjm.js.map +1 -0
  60. package/dist/_chunks/id-BTemOeTZ.js +62 -0
  61. package/dist/_chunks/id-BTemOeTZ.js.map +1 -0
  62. package/dist/_chunks/id-BdEsvnaF.mjs +62 -0
  63. package/dist/_chunks/id-BdEsvnaF.mjs.map +1 -0
  64. package/dist/_chunks/index-BH6NqE8I.js +245 -0
  65. package/dist/_chunks/index-BH6NqE8I.js.map +1 -0
  66. package/dist/_chunks/index-C3i__jX-.js +281 -0
  67. package/dist/_chunks/index-C3i__jX-.js.map +1 -0
  68. package/dist/_chunks/index-CFzpNgIL.js +640 -0
  69. package/dist/_chunks/index-CFzpNgIL.js.map +1 -0
  70. package/dist/_chunks/index-CJUWqtrZ.mjs +344 -0
  71. package/dist/_chunks/index-CJUWqtrZ.mjs.map +1 -0
  72. package/dist/_chunks/index-CcWTKtCY.js +366 -0
  73. package/dist/_chunks/index-CcWTKtCY.js.map +1 -0
  74. package/dist/_chunks/index-CnX2wiLY.mjs +1142 -0
  75. package/dist/_chunks/index-CnX2wiLY.mjs.map +1 -0
  76. package/dist/_chunks/index-DUWx-KG9-C1E7ADbJ.mjs +11984 -0
  77. package/dist/_chunks/index-DUWx-KG9-C1E7ADbJ.mjs.map +1 -0
  78. package/dist/_chunks/index-DUWx-KG9-fMZ4nmrb.js +12008 -0
  79. package/dist/_chunks/index-DUWx-KG9-fMZ4nmrb.js.map +1 -0
  80. package/dist/_chunks/index-DruWuFWL.js +1172 -0
  81. package/dist/_chunks/index-DruWuFWL.js.map +1 -0
  82. package/dist/_chunks/index-PJoz36kJ.mjs +262 -0
  83. package/dist/_chunks/index-PJoz36kJ.mjs.map +1 -0
  84. package/dist/_chunks/index-R4R0dEOv.mjs +246 -0
  85. package/dist/_chunks/index-R4R0dEOv.mjs.map +1 -0
  86. package/dist/_chunks/index-XOcQhJMB.mjs +617 -0
  87. package/dist/_chunks/index-XOcQhJMB.mjs.map +1 -0
  88. package/dist/_chunks/it-B-rv0E24.mjs +62 -0
  89. package/dist/_chunks/it-B-rv0E24.mjs.map +1 -0
  90. package/dist/_chunks/it-D1rH6V6_.js +62 -0
  91. package/dist/_chunks/it-D1rH6V6_.js.map +1 -0
  92. package/dist/_chunks/ja-C8K-VBPD.mjs +48 -0
  93. package/dist/_chunks/ja-C8K-VBPD.mjs.map +1 -0
  94. package/dist/_chunks/ja-DqShgTMf.js +48 -0
  95. package/dist/_chunks/ja-DqShgTMf.js.map +1 -0
  96. package/dist/_chunks/ko-B9DGEPWH.js +86 -0
  97. package/dist/_chunks/ko-B9DGEPWH.js.map +1 -0
  98. package/dist/_chunks/ko-Busb0wIY.mjs +86 -0
  99. package/dist/_chunks/ko-Busb0wIY.mjs.map +1 -0
  100. package/dist/_chunks/ms-ByvsQjRt.mjs +49 -0
  101. package/dist/_chunks/ms-ByvsQjRt.mjs.map +1 -0
  102. package/dist/_chunks/ms-CPBU3LWf.js +49 -0
  103. package/dist/_chunks/ms-CPBU3LWf.js.map +1 -0
  104. package/dist/_chunks/nl-5qO8Rpcy.mjs +48 -0
  105. package/dist/_chunks/nl-5qO8Rpcy.mjs.map +1 -0
  106. package/dist/_chunks/nl-CwNB6YoO.js +48 -0
  107. package/dist/_chunks/nl-CwNB6YoO.js.map +1 -0
  108. package/dist/_chunks/pl-BdIzifBE.mjs +86 -0
  109. package/dist/_chunks/pl-BdIzifBE.mjs.map +1 -0
  110. package/dist/_chunks/pl-Do9UD69f.js +86 -0
  111. package/dist/_chunks/pl-Do9UD69f.js.map +1 -0
  112. package/dist/_chunks/pt-BIO24ioG.mjs +48 -0
  113. package/dist/_chunks/pt-BIO24ioG.mjs.map +1 -0
  114. package/dist/_chunks/pt-BR-D7dZhxuP.js +44 -0
  115. package/dist/_chunks/pt-BR-D7dZhxuP.js.map +1 -0
  116. package/dist/_chunks/pt-BR-f0p23AQZ.mjs +44 -0
  117. package/dist/_chunks/pt-BR-f0p23AQZ.mjs.map +1 -0
  118. package/dist/_chunks/pt-fdvyOnUp.js +48 -0
  119. package/dist/_chunks/pt-fdvyOnUp.js.map +1 -0
  120. package/dist/_chunks/ru-C94rjPGA.js +86 -0
  121. package/dist/_chunks/ru-C94rjPGA.js.map +1 -0
  122. package/dist/_chunks/ru-VWy-IB7K.mjs +86 -0
  123. package/dist/_chunks/ru-VWy-IB7K.mjs.map +1 -0
  124. package/dist/_chunks/sk-BABEhykl.js +50 -0
  125. package/dist/_chunks/sk-BABEhykl.js.map +1 -0
  126. package/dist/_chunks/sk-B_LIcepm.mjs +50 -0
  127. package/dist/_chunks/sk-B_LIcepm.mjs.map +1 -0
  128. package/dist/_chunks/sv-ABLKOokl.mjs +86 -0
  129. package/dist/_chunks/sv-ABLKOokl.mjs.map +1 -0
  130. package/dist/_chunks/sv-Be43LhA9.js +86 -0
  131. package/dist/_chunks/sv-Be43LhA9.js.map +1 -0
  132. package/dist/_chunks/th-DKyP7ueR.mjs +60 -0
  133. package/dist/_chunks/th-DKyP7ueR.mjs.map +1 -0
  134. package/dist/_chunks/th-DgVhVLhL.js +60 -0
  135. package/dist/_chunks/th-DgVhVLhL.js.map +1 -0
  136. package/dist/_chunks/tr-B_idhkEs.js +85 -0
  137. package/dist/_chunks/tr-B_idhkEs.js.map +1 -0
  138. package/dist/_chunks/tr-qa1Q5UjC.mjs +85 -0
  139. package/dist/_chunks/tr-qa1Q5UjC.mjs.map +1 -0
  140. package/dist/_chunks/uk-BmRqbeQc.mjs +49 -0
  141. package/dist/_chunks/uk-BmRqbeQc.mjs.map +1 -0
  142. package/dist/_chunks/uk-LHOivnhP.js +49 -0
  143. package/dist/_chunks/uk-LHOivnhP.js.map +1 -0
  144. package/dist/_chunks/vi-CdVRdKDw.js +50 -0
  145. package/dist/_chunks/vi-CdVRdKDw.js.map +1 -0
  146. package/dist/_chunks/vi-HW-EdMea.mjs +50 -0
  147. package/dist/_chunks/vi-HW-EdMea.mjs.map +1 -0
  148. package/dist/_chunks/zh-5hKkVPA4.mjs +86 -0
  149. package/dist/_chunks/zh-5hKkVPA4.mjs.map +1 -0
  150. package/dist/_chunks/zh-Cuq8gMnF.js +86 -0
  151. package/dist/_chunks/zh-Cuq8gMnF.js.map +1 -0
  152. package/dist/_chunks/zh-Hans-BHilK-yc.mjs +86 -0
  153. package/dist/_chunks/zh-Hans-BHilK-yc.mjs.map +1 -0
  154. package/dist/_chunks/zh-Hans-GQDMKtY4.js +86 -0
  155. package/dist/_chunks/zh-Hans-GQDMKtY4.js.map +1 -0
  156. package/dist/admin/index.js +4 -0
  157. package/dist/admin/index.js.map +1 -0
  158. package/dist/admin/index.mjs +5 -0
  159. package/dist/admin/index.mjs.map +1 -0
  160. package/package.json +27 -28
  161. package/packup.config.ts +0 -20
  162. package/server/bootstrap/index.js +18 -51
  163. package/server/bootstrap/users-permissions-actions.js +6 -0
  164. package/server/config.js +29 -0
  165. package/server/content-types/user/index.js +0 -1
  166. package/server/controllers/auth.js +62 -63
  167. package/server/controllers/content-manager-user.js +28 -30
  168. package/server/controllers/role.js +17 -4
  169. package/server/controllers/user.js +8 -9
  170. package/server/controllers/validation/auth.js +81 -25
  171. package/server/middlewares/rateLimit.js +1 -1
  172. package/server/register.js +1 -1
  173. package/server/services/jwt.js +3 -3
  174. package/server/services/permission.js +3 -7
  175. package/server/services/providers-registry.js +469 -261
  176. package/server/services/providers.js +10 -5
  177. package/server/services/role.js +15 -13
  178. package/server/services/user.js +56 -19
  179. package/server/services/users-permissions.js +15 -13
  180. package/server/utils/index.d.ts +2 -1
  181. package/server/utils/sanitize/sanitizers.js +7 -3
  182. package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +2 -2
  183. package/admin/src/components/FormModal/index.js +0 -126
  184. package/admin/src/components/Permissions/index.js +0 -55
  185. package/admin/src/pages/AdvancedSettings/index.js +0 -259
  186. package/admin/src/pages/EmailTemplates/components/EmailForm.js +0 -176
  187. package/admin/src/pages/Roles/index.js +0 -33
  188. package/admin/src/pages/Roles/pages/ListPage/utils/api.js +0 -30
  189. package/server/bootstrap/grant-config.js +0 -131
  190. package/strapi-server.js +0 -3
  191. /package/admin/src/components/Permissions/PermissionRow/{index.js → index.jsx} +0 -0
  192. /package/admin/src/contexts/UsersPermissionsContext/{index.js → index.jsx} +0 -0
@@ -1,18 +1,15 @@
1
1
  import * as React from 'react';
2
2
 
3
- import { ContentLayout, HeaderLayout, Main, useNotifyAT } from '@strapi/design-system';
3
+ import { useTracking } from '@strapi/admin/strapi-admin';
4
+ import { useNotifyAT } from '@strapi/design-system';
4
5
  import {
5
- CheckPagePermissions,
6
- LoadingIndicatorPage,
7
- SettingsPageTitle,
6
+ Page,
8
7
  useAPIErrorHandler,
9
- useFetchClient,
10
- useFocusWhenNavigate,
11
8
  useNotification,
12
- useOverlayBlocker,
9
+ useFetchClient,
13
10
  useRBAC,
14
- useTracking,
15
- } from '@strapi/helper-plugin';
11
+ Layouts,
12
+ } from '@strapi/strapi/admin';
16
13
  import { useIntl } from 'react-intl';
17
14
  import { useMutation, useQuery, useQueryClient } from 'react-query';
18
15
 
@@ -23,23 +20,19 @@ import EmailForm from './components/EmailForm';
23
20
  import EmailTable from './components/EmailTable';
24
21
 
25
22
  const ProtectedEmailTemplatesPage = () => (
26
- <CheckPagePermissions permissions={PERMISSIONS.readEmailTemplates}>
23
+ <Page.Protect permissions={PERMISSIONS.readEmailTemplates}>
27
24
  <EmailTemplatesPage />
28
- </CheckPagePermissions>
25
+ </Page.Protect>
29
26
  );
30
-
31
27
  const EmailTemplatesPage = () => {
32
28
  const { formatMessage } = useIntl();
33
29
  const { trackUsage } = useTracking();
34
30
  const { notifyStatus } = useNotifyAT();
35
- const toggleNotification = useNotification();
36
- const { lockApp, unlockApp } = useOverlayBlocker();
31
+ const { toggleNotification } = useNotification();
37
32
  const queryClient = useQueryClient();
38
33
  const { get, put } = useFetchClient();
39
34
  const { formatAPIError } = useAPIErrorHandler();
40
35
 
41
- useFocusWhenNavigate();
42
-
43
36
  const [isModalOpen, setIsModalOpen] = React.useState(false);
44
37
  const [templateToEdit, setTemplateToEdit] = React.useState(null);
45
38
 
@@ -66,7 +59,7 @@ const EmailTemplatesPage = () => {
66
59
  },
67
60
  onError(error) {
68
61
  toggleNotification({
69
- type: 'warning',
62
+ type: 'danger',
70
63
  message: formatAPIError(error),
71
64
  });
72
65
  },
@@ -92,29 +85,24 @@ const EmailTemplatesPage = () => {
92
85
 
93
86
  toggleNotification({
94
87
  type: 'success',
95
- message: { id: 'notification.success.saved', defaultMessage: 'Saved' },
88
+ message: formatMessage({ id: 'notification.success.saved', defaultMessage: 'Saved' }),
96
89
  });
97
90
 
98
91
  trackUsage('didEditEmailTemplates');
99
92
 
100
- unlockApp();
101
93
  handleToggle();
102
94
  },
103
95
  onError(error) {
104
96
  toggleNotification({
105
- type: 'warning',
97
+ type: 'danger',
106
98
  message: formatAPIError(error),
107
99
  });
108
-
109
- unlockApp();
110
100
  },
111
101
  refetchActive: true,
112
102
  }
113
103
  );
114
104
 
115
105
  const handleSubmit = (body) => {
116
- lockApp();
117
-
118
106
  trackUsage('willEditEmailTemplates');
119
107
 
120
108
  const editedTemplates = { ...data, [templateToEdit]: body };
@@ -122,53 +110,39 @@ const EmailTemplatesPage = () => {
122
110
  };
123
111
 
124
112
  if (isLoading) {
125
- return (
126
- <Main aria-busy="true">
127
- <SettingsPageTitle
128
- name={formatMessage({
129
- id: getTrad('HeaderNav.link.emailTemplates'),
130
- defaultMessage: 'Email templates',
131
- })}
132
- />
133
- <HeaderLayout
134
- title={formatMessage({
135
- id: getTrad('HeaderNav.link.emailTemplates'),
136
- defaultMessage: 'Email templates',
137
- })}
138
- />
139
- <ContentLayout>
140
- <LoadingIndicatorPage />
141
- </ContentLayout>
142
- </Main>
143
- );
113
+ return <Page.Loading />;
144
114
  }
145
115
 
146
116
  return (
147
- <Main aria-busy={submitMutation.isLoading}>
148
- <SettingsPageTitle
149
- name={formatMessage({
150
- id: getTrad('HeaderNav.link.emailTemplates'),
151
- defaultMessage: 'Email templates',
152
- })}
153
- />
154
- <HeaderLayout
117
+ <Page.Main aria-busy={submitMutation.isLoading}>
118
+ <Page.Title>
119
+ {formatMessage(
120
+ { id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
121
+ {
122
+ name: formatMessage({
123
+ id: getTrad('HeaderNav.link.emailTemplates'),
124
+ defaultMessage: 'Email templates',
125
+ }),
126
+ }
127
+ )}
128
+ </Page.Title>
129
+ <Layouts.Header
155
130
  title={formatMessage({
156
131
  id: getTrad('HeaderNav.link.emailTemplates'),
157
132
  defaultMessage: 'Email templates',
158
133
  })}
159
134
  />
160
- <ContentLayout>
135
+ <Layouts.Content>
161
136
  <EmailTable onEditClick={handleEditClick} canUpdate={canUpdate} />
162
- {isModalOpen && (
163
- <EmailForm
164
- template={data[templateToEdit]}
165
- onToggle={handleToggle}
166
- onSubmit={handleSubmit}
167
- />
168
- )}
169
- </ContentLayout>
170
- </Main>
137
+ <EmailForm
138
+ template={data[templateToEdit]}
139
+ onToggle={handleToggle}
140
+ open={isModalOpen}
141
+ onSubmit={handleSubmit}
142
+ />
143
+ </Layouts.Content>
144
+ </Page.Main>
171
145
  );
172
146
  };
173
147
 
174
- export default ProtectedEmailTemplatesPage;
148
+ export { ProtectedEmailTemplatesPage, EmailTemplatesPage };
@@ -1,4 +1,4 @@
1
- import { translatedErrors } from '@strapi/helper-plugin';
1
+ import { translatedErrors } from '@strapi/strapi/admin';
2
2
  import * as yup from 'yup';
3
3
 
4
4
  const schema = yup.object().shape({
@@ -8,15 +8,27 @@ const schema = yup.object().shape({
8
8
  from: yup
9
9
  .object()
10
10
  .shape({
11
- name: yup.string().required(translatedErrors.required),
12
- email: yup.string().email(translatedErrors.email).required(translatedErrors.required),
11
+ name: yup.string().required({
12
+ id: translatedErrors.required.id,
13
+ defaultMessage: 'This field is required',
14
+ }),
15
+ email: yup.string().email(translatedErrors.email).required({
16
+ id: translatedErrors.required.id,
17
+ defaultMessage: 'This field is required',
18
+ }),
13
19
  })
14
20
  .required(),
15
21
  response_email: yup.string().email(translatedErrors.email),
16
- object: yup.string().required(translatedErrors.required),
17
- message: yup.string().required(translatedErrors.required),
22
+ object: yup.string().required({
23
+ id: translatedErrors.required.id,
24
+ defaultMessage: 'This field is required',
25
+ }),
26
+ message: yup.string().required({
27
+ id: translatedErrors.required.id,
28
+ defaultMessage: 'This field is required',
29
+ }),
18
30
  })
19
- .required(translatedErrors.required),
31
+ .required(translatedErrors.required.id),
20
32
  });
21
33
 
22
34
  export default schema;
@@ -1,11 +1,8 @@
1
1
  import * as React from 'react';
2
2
 
3
+ import { useTracking, Layouts } from '@strapi/admin/strapi-admin';
3
4
  import {
4
- ContentLayout,
5
- HeaderLayout,
6
5
  IconButton,
7
- Layout,
8
- Main,
9
6
  Table,
10
7
  Tbody,
11
8
  Td,
@@ -14,23 +11,16 @@ import {
14
11
  Tr,
15
12
  Typography,
16
13
  VisuallyHidden,
14
+ useCollator,
17
15
  } from '@strapi/design-system';
16
+ import { Pencil } from '@strapi/icons';
18
17
  import {
19
- CheckPagePermissions,
20
- LoadingIndicatorPage,
21
- onRowClick,
22
- SettingsPageTitle,
23
- stopPropagation,
18
+ Page,
24
19
  useAPIErrorHandler,
25
- useCollator,
26
- useFetchClient,
27
- useFocusWhenNavigate,
28
20
  useNotification,
29
- useOverlayBlocker,
21
+ useFetchClient,
30
22
  useRBAC,
31
- useTracking,
32
- } from '@strapi/helper-plugin';
33
- import { Pencil } from '@strapi/icons';
23
+ } from '@strapi/strapi/admin';
34
24
  import upperFirst from 'lodash/upperFirst';
35
25
  import { useIntl } from 'react-intl';
36
26
  import { useMutation, useQuery, useQueryClient } from 'react-query';
@@ -47,16 +37,13 @@ export const ProvidersPage = () => {
47
37
  const { trackUsage } = useTracking();
48
38
  const [isOpen, setIsOpen] = React.useState(false);
49
39
  const [providerToEditName, setProviderToEditName] = React.useState(null);
50
- const toggleNotification = useNotification();
51
- const { lockApp, unlockApp } = useOverlayBlocker();
40
+ const { toggleNotification } = useNotification();
52
41
  const { get, put } = useFetchClient();
53
42
  const { formatAPIError } = useAPIErrorHandler();
54
43
  const formatter = useCollator(locale, {
55
44
  sensitivity: 'base',
56
45
  });
57
46
 
58
- useFocusWhenNavigate();
59
-
60
47
  const {
61
48
  isLoading: isLoadingPermissions,
62
49
  allowedActions: { canUpdate },
@@ -76,25 +63,22 @@ export const ProvidersPage = () => {
76
63
 
77
64
  const submitMutation = useMutation((body) => put('/users-permissions/providers', body), {
78
65
  async onSuccess() {
79
- await queryClient.invalidateQueries(['users-permissions', 'providers']);
66
+ await queryClient.invalidateQueries(['users-permissions', 'get-providers']);
80
67
 
81
68
  toggleNotification({
82
69
  type: 'success',
83
- message: { id: getTrad('notification.success.submit') },
70
+ message: formatMessage({ id: getTrad('notification.success.submit') }),
84
71
  });
85
72
 
86
73
  trackUsage('didEditAuthenticationProvider');
87
74
 
88
75
  handleToggleModal();
89
- unlockApp();
90
76
  },
91
77
  onError(error) {
92
78
  toggleNotification({
93
- type: 'warning',
79
+ type: 'danger',
94
80
  message: formatAPIError(error),
95
81
  });
96
-
97
- unlockApp();
98
82
  },
99
83
  refetchActive: false,
100
84
  });
@@ -150,104 +134,105 @@ export const ProvidersPage = () => {
150
134
  };
151
135
 
152
136
  const handleSubmit = async (values) => {
153
- lockApp();
154
-
155
137
  trackUsage('willEditAuthenticationProvider');
156
138
 
157
139
  submitMutation.mutate({ providers: { ...data, [providerToEditName]: values } });
158
140
  };
159
141
 
142
+ if (isLoading) {
143
+ return <Page.Loading />;
144
+ }
145
+
160
146
  return (
161
- <Layout>
162
- <SettingsPageTitle
163
- name={formatMessage({
164
- id: getTrad('HeaderNav.link.providers'),
165
- defaultMessage: 'Providers',
166
- })}
167
- />
168
- <Main>
169
- <HeaderLayout
147
+ <Layouts.Root>
148
+ <Page.Title>
149
+ {formatMessage(
150
+ { id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
151
+ {
152
+ name: formatMessage({
153
+ id: getTrad('HeaderNav.link.providers'),
154
+ defaultMessage: 'Providers',
155
+ }),
156
+ }
157
+ )}
158
+ </Page.Title>
159
+ <Page.Main>
160
+ <Layouts.Header
170
161
  title={formatMessage({
171
162
  id: getTrad('HeaderNav.link.providers'),
172
163
  defaultMessage: 'Providers',
173
164
  })}
174
165
  />
175
- {isLoading ? (
176
- <LoadingIndicatorPage />
177
- ) : (
178
- <ContentLayout>
179
- <Table colCount={3} rowCount={providers.length + 1}>
180
- <Thead>
181
- <Tr>
182
- <Th>
183
- <Typography variant="sigma" textColor="neutral600">
184
- {formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
166
+ <Layouts.Content>
167
+ <Table colCount={3} rowCount={providers.length + 1}>
168
+ <Thead>
169
+ <Tr>
170
+ <Th>
171
+ <Typography variant="sigma" textColor="neutral600">
172
+ {formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
173
+ </Typography>
174
+ </Th>
175
+ <Th>
176
+ <Typography variant="sigma" textColor="neutral600">
177
+ {formatMessage({ id: getTrad('Providers.status'), defaultMessage: 'Status' })}
178
+ </Typography>
179
+ </Th>
180
+ <Th>
181
+ <Typography variant="sigma">
182
+ <VisuallyHidden>
183
+ {formatMessage({
184
+ id: 'global.settings',
185
+ defaultMessage: 'Settings',
186
+ })}
187
+ </VisuallyHidden>
188
+ </Typography>
189
+ </Th>
190
+ </Tr>
191
+ </Thead>
192
+ <Tbody>
193
+ {providers.map((provider) => (
194
+ <Tr
195
+ key={provider.name}
196
+ onClick={() => (canUpdate ? handleClickEdit(provider) : undefined)}
197
+ >
198
+ <Td width="45%">
199
+ <Typography fontWeight="semiBold" textColor="neutral800">
200
+ {provider.name}
185
201
  </Typography>
186
- </Th>
187
- <Th>
188
- <Typography variant="sigma" textColor="neutral600">
189
- {formatMessage({ id: getTrad('Providers.status'), defaultMessage: 'Status' })}
202
+ </Td>
203
+ <Td width="65%">
204
+ <Typography
205
+ textColor={provider.enabled ? 'success600' : 'danger600'}
206
+ data-testid={`enable-${provider.name}`}
207
+ >
208
+ {provider.enabled
209
+ ? formatMessage({
210
+ id: 'global.enabled',
211
+ defaultMessage: 'Enabled',
212
+ })
213
+ : formatMessage({
214
+ id: 'global.disabled',
215
+ defaultMessage: 'Disabled',
216
+ })}
190
217
  </Typography>
191
- </Th>
192
- <Th>
193
- <Typography variant="sigma">
194
- <VisuallyHidden>
195
- {formatMessage({
196
- id: 'global.settings',
197
- defaultMessage: 'Settings',
198
- })}
199
- </VisuallyHidden>
200
- </Typography>
201
- </Th>
202
- </Tr>
203
- </Thead>
204
- <Tbody>
205
- {providers.map((provider) => (
206
- <Tr
207
- key={provider.name}
208
- {...onRowClick({
209
- fn: () => handleClickEdit(provider),
210
- condition: canUpdate,
211
- })}
212
- >
213
- <Td width="45%">
214
- <Typography fontWeight="semiBold" textColor="neutral800">
215
- {provider.name}
216
- </Typography>
217
- </Td>
218
- <Td width="65%">
219
- <Typography
220
- textColor={provider.enabled ? 'success600' : 'danger600'}
221
- data-testid={`enable-${provider.name}`}
218
+ </Td>
219
+ <Td onClick={(e) => e.stopPropagation()}>
220
+ {canUpdate && (
221
+ <IconButton
222
+ onClick={() => handleClickEdit(provider)}
223
+ variant="ghost"
224
+ label="Edit"
222
225
  >
223
- {provider.enabled
224
- ? formatMessage({
225
- id: 'global.enabled',
226
- defaultMessage: 'Enabled',
227
- })
228
- : formatMessage({
229
- id: 'global.disabled',
230
- defaultMessage: 'Disabled',
231
- })}
232
- </Typography>
233
- </Td>
234
- <Td {...stopPropagation}>
235
- {canUpdate && (
236
- <IconButton
237
- onClick={() => handleClickEdit(provider)}
238
- noBorder
239
- icon={<Pencil />}
240
- label="Edit"
241
- />
242
- )}
243
- </Td>
244
- </Tr>
245
- ))}
246
- </Tbody>
247
- </Table>
248
- </ContentLayout>
249
- )}
250
- </Main>
226
+ <Pencil />
227
+ </IconButton>
228
+ )}
229
+ </Td>
230
+ </Tr>
231
+ ))}
232
+ </Tbody>
233
+ </Table>
234
+ </Layouts.Content>
235
+ </Page.Main>
251
236
  <FormModal
252
237
  initialData={data[providerToEditName]}
253
238
  isOpen={isOpen}
@@ -264,14 +249,14 @@ export const ProvidersPage = () => {
264
249
  onSubmit={handleSubmit}
265
250
  providerToEditName={providerToEditName}
266
251
  />
267
- </Layout>
252
+ </Layouts.Root>
268
253
  );
269
254
  };
270
255
 
271
256
  const ProtectedProvidersPage = () => (
272
- <CheckPagePermissions permissions={PERMISSIONS.readProviders}>
257
+ <Page.Protect permissions={PERMISSIONS.readProviders}>
273
258
  <ProvidersPage />
274
- </CheckPagePermissions>
259
+ </Page.Protect>
275
260
  );
276
261
 
277
262
  export default ProtectedProvidersPage;
@@ -1,4 +1,4 @@
1
- import { translatedErrors } from '@strapi/helper-plugin';
1
+ import { translatedErrors } from '@strapi/strapi/admin';
2
2
  import * as yup from 'yup';
3
3
 
4
4
  import { getTrad } from '../../../utils';
@@ -34,6 +34,9 @@ const secretLabel = {
34
34
  defaultMessage: 'Client Secret',
35
35
  };
36
36
 
37
+ const CALLBACK_REGEX = /^$|^[a-z][a-z0-9+.-]*:\/\/[^\s/$.?#](?:[^\s]*[^\s/$.?#])?$/i;
38
+ const SUBDOMAIN_REGEX = /^(([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+)(:\d+)?(\/\S*)?$/i;
39
+
37
40
  const forms = {
38
41
  email: {
39
42
  form: [
@@ -52,7 +55,7 @@ const forms = {
52
55
  ],
53
56
  ],
54
57
  schema: yup.object().shape({
55
- enabled: yup.bool().required(translatedErrors.required),
58
+ enabled: yup.bool().required(translatedErrors.required.id),
56
59
  }),
57
60
  },
58
61
  providers: {
@@ -117,20 +120,23 @@ const forms = {
117
120
  ],
118
121
  ],
119
122
  schema: yup.object().shape({
120
- enabled: yup.bool().required(translatedErrors.required),
123
+ enabled: yup.bool().required(translatedErrors.required.id),
121
124
  key: yup.string().when('enabled', {
122
125
  is: true,
123
- then: yup.string().required(translatedErrors.required),
126
+ then: yup.string().required(translatedErrors.required.id),
124
127
  otherwise: yup.string(),
125
128
  }),
126
129
  secret: yup.string().when('enabled', {
127
130
  is: true,
128
- then: yup.string().required(translatedErrors.required),
131
+ then: yup.string().required(translatedErrors.required.id),
129
132
  otherwise: yup.string(),
130
133
  }),
131
134
  callback: yup.string().when('enabled', {
132
135
  is: true,
133
- then: yup.string().required(translatedErrors.required),
136
+ then: yup
137
+ .string()
138
+ .matches(CALLBACK_REGEX, translatedErrors.regex.id)
139
+ .required(translatedErrors.required.id),
134
140
  otherwise: yup.string(),
135
141
  }),
136
142
  }),
@@ -231,25 +237,31 @@ const forms = {
231
237
  ],
232
238
  ],
233
239
  schema: yup.object().shape({
234
- enabled: yup.bool().required(translatedErrors.required),
240
+ enabled: yup.bool().required(translatedErrors.required.id),
235
241
  key: yup.string().when('enabled', {
236
242
  is: true,
237
- then: yup.string().required(translatedErrors.required),
243
+ then: yup.string().required(translatedErrors.required.id),
238
244
  otherwise: yup.string(),
239
245
  }),
240
246
  secret: yup.string().when('enabled', {
241
247
  is: true,
242
- then: yup.string().required(translatedErrors.required),
248
+ then: yup.string().required(translatedErrors.required.id),
243
249
  otherwise: yup.string(),
244
250
  }),
245
251
  subdomain: yup.string().when('enabled', {
246
252
  is: true,
247
- then: yup.string().required(translatedErrors.required),
253
+ then: yup
254
+ .string()
255
+ .matches(SUBDOMAIN_REGEX, translatedErrors.regex.id)
256
+ .required(translatedErrors.required.id),
248
257
  otherwise: yup.string(),
249
258
  }),
250
259
  callback: yup.string().when('enabled', {
251
260
  is: true,
252
- then: yup.string().required(translatedErrors.required),
261
+ then: yup
262
+ .string()
263
+ .matches(CALLBACK_REGEX, translatedErrors.regex.id)
264
+ .required(translatedErrors.required.id),
253
265
  otherwise: yup.string(),
254
266
  }),
255
267
  }),
@@ -1,7 +1,7 @@
1
- import { translatedErrors } from '@strapi/helper-plugin';
1
+ import { translatedErrors } from '@strapi/strapi/admin';
2
2
  import * as yup from 'yup';
3
3
 
4
4
  export const createRoleSchema = yup.object().shape({
5
- name: yup.string().required(translatedErrors.required),
6
- description: yup.string().required(translatedErrors.required),
5
+ name: yup.string().required(translatedErrors.required.id),
6
+ description: yup.string().required(translatedErrors.required.id),
7
7
  });
@@ -1,12 +1,12 @@
1
1
  import { useEffect } from 'react';
2
2
 
3
- import { useNotification, useFetchClient, useAPIErrorHandler } from '@strapi/helper-plugin';
3
+ import { useAPIErrorHandler, useNotification, useFetchClient } from '@strapi/strapi/admin';
4
4
  import { useQueries } from 'react-query';
5
5
 
6
6
  import { cleanPermissions, getTrad } from '../../../utils';
7
7
 
8
8
  export const usePlugins = () => {
9
- const toggleNotification = useNotification();
9
+ const { toggleNotification } = useNotification();
10
10
  const { get } = useFetchClient();
11
11
  const { formatAPIError } = useAPIErrorHandler(getTrad);
12
12
 
@@ -48,7 +48,7 @@ export const usePlugins = () => {
48
48
  useEffect(() => {
49
49
  if (permissionsError) {
50
50
  toggleNotification({
51
- type: 'warning',
51
+ type: 'danger',
52
52
  message: formatAPIError(permissionsError),
53
53
  });
54
54
  }
@@ -57,7 +57,7 @@ export const usePlugins = () => {
57
57
  useEffect(() => {
58
58
  if (routesError) {
59
59
  toggleNotification({
60
- type: 'warning',
60
+ type: 'danger',
61
61
  message: formatAPIError(routesError),
62
62
  });
63
63
  }
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+
3
+ import { Page } from '@strapi/strapi/admin';
4
+ import { Route, Routes } from 'react-router-dom';
5
+
6
+ import { PERMISSIONS } from '../../constants';
7
+
8
+ import { ProtectedRolesCreatePage } from './pages/CreatePage';
9
+ import { ProtectedRolesEditPage } from './pages/EditPage';
10
+ import { ProtectedRolesListPage } from './pages/ListPage';
11
+
12
+ const Roles = () => {
13
+ return (
14
+ <Page.Protect permissions={PERMISSIONS.accessRoles}>
15
+ <Routes>
16
+ <Route index element={<ProtectedRolesListPage />} />
17
+ <Route path="new" element={<ProtectedRolesCreatePage />} />
18
+ <Route path=":id" element={<ProtectedRolesEditPage />} />
19
+ </Routes>
20
+ </Page.Protect>
21
+ );
22
+ };
23
+
24
+ export default Roles;