@strapi/plugin-users-permissions 0.0.0-next.d1dda661d262d4773c59ee693c38542d9b0dc54c → 0.0.0-next.d2c02ba7d58eb81b8c45c3d12076d6413ecde204

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 (40) hide show
  1. package/admin/src/components/Permissions/index.js +2 -4
  2. package/admin/src/index.js +7 -8
  3. package/admin/src/pages/AdvancedSettings/index.js +46 -30
  4. package/admin/src/pages/EmailTemplates/index.js +64 -53
  5. package/admin/src/pages/Providers/index.js +64 -62
  6. package/admin/src/{hooks → pages/Roles/hooks}/usePlugins.js +15 -8
  7. package/admin/src/pages/Roles/index.js +10 -7
  8. package/admin/src/pages/Roles/pages/CreatePage.js +199 -0
  9. package/admin/src/pages/Roles/pages/EditPage.js +220 -0
  10. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/components/TableBody.js +44 -14
  11. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/index.js +29 -30
  12. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/utils/api.js +2 -4
  13. package/admin/src/translations/zh-Hans.json +80 -80
  14. package/admin/src/utils/index.js +0 -1
  15. package/documentation/content-api.yaml +1 -1
  16. package/jest.config.front.js +1 -1
  17. package/package.json +11 -11
  18. package/server/bootstrap/index.js +36 -0
  19. package/server/controllers/auth.js +51 -14
  20. package/server/controllers/user.js +12 -1
  21. package/server/middlewares/rateLimit.js +41 -21
  22. package/admin/src/hooks/index.js +0 -5
  23. package/admin/src/hooks/useFetchRole/index.js +0 -67
  24. package/admin/src/hooks/useFetchRole/reducer.js +0 -31
  25. package/admin/src/hooks/useForm/index.js +0 -70
  26. package/admin/src/hooks/useForm/reducer.js +0 -40
  27. package/admin/src/hooks/useRolesList/index.js +0 -65
  28. package/admin/src/hooks/useRolesList/init.js +0 -5
  29. package/admin/src/hooks/useRolesList/reducer.js +0 -31
  30. package/admin/src/pages/AdvancedSettings/utils/api.js +0 -18
  31. package/admin/src/pages/EmailTemplates/utils/api.js +0 -18
  32. package/admin/src/pages/Providers/reducer.js +0 -54
  33. package/admin/src/pages/Providers/utils/api.js +0 -26
  34. package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
  35. package/admin/src/pages/Roles/CreatePage.js +0 -185
  36. package/admin/src/pages/Roles/EditPage.js +0 -197
  37. package/admin/src/pages/Roles/ProtectedCreatePage.js +0 -15
  38. package/admin/src/pages/Roles/ProtectedEditPage.js +0 -15
  39. package/admin/src/pages/Roles/ProtectedListPage.js +0 -17
  40. package/admin/src/utils/getRequestURL.js +0 -5
@@ -1,6 +1,6 @@
1
1
  import React, { useReducer } from 'react';
2
2
 
3
- import { Accordion, AccordionContent, AccordionToggle, Box, Flex } from '@strapi/design-system';
3
+ import { Accordion, AccordionContent, AccordionToggle, Flex } from '@strapi/design-system';
4
4
  import { useIntl } from 'react-intl';
5
5
 
6
6
  import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
@@ -44,9 +44,7 @@ const Permissions = () => {
44
44
  variant={index % 2 ? 'primary' : 'secondary'}
45
45
  />
46
46
  <AccordionContent>
47
- <Box>
48
- <PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />
49
- </Box>
47
+ <PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />
50
48
  </AccordionContent>
51
49
  </Accordion>
52
50
  ))}
@@ -9,7 +9,6 @@ import { prefixPluginTranslations } from '@strapi/helper-plugin';
9
9
  import pluginPkg from '../../package.json';
10
10
 
11
11
  import { PERMISSIONS } from './constants';
12
- import pluginId from './pluginId';
13
12
  import getTrad from './utils/getTrad';
14
13
 
15
14
  const name = pluginPkg.strapi.name;
@@ -19,7 +18,7 @@ export default {
19
18
  // Create the plugin's settings section
20
19
  app.createSettingSection(
21
20
  {
22
- id: pluginId,
21
+ id: 'users-permissions',
23
22
  intlLabel: {
24
23
  id: getTrad('Settings.section-label'),
25
24
  defaultMessage: 'Users & Permissions plugin',
@@ -32,7 +31,7 @@ export default {
32
31
  defaultMessage: 'Roles',
33
32
  },
34
33
  id: 'roles',
35
- to: `/settings/${pluginId}/roles`,
34
+ to: `/settings/users-permissions/roles`,
36
35
  async Component() {
37
36
  const component = await import(
38
37
  /* webpackChunkName: "users-roles-settings-page" */ './pages/Roles'
@@ -48,7 +47,7 @@ export default {
48
47
  defaultMessage: 'Providers',
49
48
  },
50
49
  id: 'providers',
51
- to: `/settings/${pluginId}/providers`,
50
+ to: `/settings/users-permissions/providers`,
52
51
  async Component() {
53
52
  const component = await import(
54
53
  /* webpackChunkName: "users-providers-settings-page" */ './pages/Providers'
@@ -64,7 +63,7 @@ export default {
64
63
  defaultMessage: 'Email templates',
65
64
  },
66
65
  id: 'email-templates',
67
- to: `/settings/${pluginId}/email-templates`,
66
+ to: `/settings/users-permissions/email-templates`,
68
67
  async Component() {
69
68
  const component = await import(
70
69
  /* webpackChunkName: "users-email-settings-page" */ './pages/EmailTemplates'
@@ -80,7 +79,7 @@ export default {
80
79
  defaultMessage: 'Advanced Settings',
81
80
  },
82
81
  id: 'advanced-settings',
83
- to: `/settings/${pluginId}/advanced-settings`,
82
+ to: `/settings/users-permissions/advanced-settings`,
84
83
  async Component() {
85
84
  const component = await import(
86
85
  /* webpackChunkName: "users-advanced-settings-page" */ './pages/AdvancedSettings'
@@ -94,7 +93,7 @@ export default {
94
93
  );
95
94
 
96
95
  app.registerPlugin({
97
- id: pluginId,
96
+ id: 'users-permissions',
98
97
  name,
99
98
  });
100
99
  },
@@ -107,7 +106,7 @@ export default {
107
106
  )
108
107
  .then(({ default: data }) => {
109
108
  return {
110
- data: prefixPluginTranslations(data, pluginId),
109
+ data: prefixPluginTranslations(data, 'users-permissions'),
111
110
  locale,
112
111
  };
113
112
  })
@@ -1,4 +1,4 @@
1
- import React, { useMemo } from 'react';
1
+ import React from 'react';
2
2
 
3
3
  import {
4
4
  Box,
@@ -20,6 +20,8 @@ import {
20
20
  GenericInput,
21
21
  LoadingIndicatorPage,
22
22
  SettingsPageTitle,
23
+ useAPIErrorHandler,
24
+ useFetchClient,
23
25
  useFocusWhenNavigate,
24
26
  useNotification,
25
27
  useOverlayBlocker,
@@ -33,7 +35,6 @@ import { useMutation, useQuery, useQueryClient } from 'react-query';
33
35
  import { PERMISSIONS } from '../../constants';
34
36
  import { getTrad } from '../../utils';
35
37
 
36
- import { fetchData, putAdvancedSettings } from './utils/api';
37
38
  import layout from './utils/layout';
38
39
  import schema from './utils/schema';
39
40
 
@@ -49,36 +50,47 @@ const AdvancedSettingsPage = () => {
49
50
  const { lockApp, unlockApp } = useOverlayBlocker();
50
51
  const { notifyStatus } = useNotifyAT();
51
52
  const queryClient = useQueryClient();
53
+ const { get, put } = useFetchClient();
54
+ const { formatAPIError } = useAPIErrorHandler();
55
+
52
56
  useFocusWhenNavigate();
53
57
 
54
- const updatePermissions = useMemo(() => ({ update: PERMISSIONS.updateAdvancedSettings }), []);
55
58
  const {
56
59
  isLoading: isLoadingForPermissions,
57
60
  allowedActions: { canUpdate },
58
- } = useRBAC(updatePermissions);
59
-
60
- const { status: isLoadingData, data } = useQuery('advanced', () => fetchData(), {
61
- onSuccess() {
62
- notifyStatus(
63
- formatMessage({
64
- id: getTrad('Form.advancedSettings.data.loaded'),
65
- defaultMessage: 'Advanced settings data has been loaded',
66
- })
67
- );
68
- },
69
- onError() {
70
- toggleNotification({
71
- type: 'warning',
72
- message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
73
- });
61
+ } = useRBAC({ update: PERMISSIONS.updateAdvancedSettings });
62
+
63
+ const { isLoading: isLoadingData, data } = useQuery(
64
+ ['users-permissions', 'advanced'],
65
+ async () => {
66
+ const { data } = await get('/users-permissions/advanced');
67
+
68
+ return data;
74
69
  },
75
- });
70
+ {
71
+ onSuccess() {
72
+ notifyStatus(
73
+ formatMessage({
74
+ id: getTrad('Form.advancedSettings.data.loaded'),
75
+ defaultMessage: 'Advanced settings data has been loaded',
76
+ })
77
+ );
78
+ },
79
+ onError() {
80
+ toggleNotification({
81
+ type: 'warning',
82
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
83
+ });
84
+ },
85
+ }
86
+ );
76
87
 
77
- const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
88
+ const isLoading = isLoadingForPermissions || isLoadingData;
78
89
 
79
- const submitMutation = useMutation((body) => putAdvancedSettings(body), {
90
+ const submitMutation = useMutation((body) => put('/users-permissions/advanced', body), {
80
91
  async onSuccess() {
81
- await queryClient.invalidateQueries('advanced');
92
+ await queryClient.invalidateQueries(['users-permissions', 'advanced']);
93
+
82
94
  toggleNotification({
83
95
  type: 'success',
84
96
  message: { id: getTrad('notification.success.saved'), defaultMessage: 'Saved' },
@@ -86,11 +98,12 @@ const AdvancedSettingsPage = () => {
86
98
 
87
99
  unlockApp();
88
100
  },
89
- onError() {
101
+ onError(error) {
90
102
  toggleNotification({
91
103
  type: 'warning',
92
- message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
104
+ message: formatAPIError(error),
93
105
  });
106
+
94
107
  unlockApp();
95
108
  },
96
109
  refetchActive: true,
@@ -101,9 +114,12 @@ const AdvancedSettingsPage = () => {
101
114
  const handleSubmit = async (body) => {
102
115
  lockApp();
103
116
 
104
- const urlConfirmation = body.email_confirmation ? body.email_confirmation_redirection : '';
105
-
106
- await submitMutation.mutateAsync({ ...body, email_confirmation_redirection: urlConfirmation });
117
+ submitMutation.mutate({
118
+ ...body,
119
+ email_confirmation_redirection: body.email_confirmation
120
+ ? body.email_confirmation_redirection
121
+ : '',
122
+ });
107
123
  };
108
124
 
109
125
  if (isLoading) {
@@ -143,7 +159,7 @@ const AdvancedSettingsPage = () => {
143
159
  validationSchema={schema}
144
160
  enableReinitialize
145
161
  >
146
- {({ errors, values, handleChange, isSubmitting }) => {
162
+ {({ errors, values, handleChange, isSubmitting, dirty }) => {
147
163
  return (
148
164
  <Form>
149
165
  <HeaderLayout
@@ -155,7 +171,7 @@ const AdvancedSettingsPage = () => {
155
171
  <Button
156
172
  loading={isSubmitting}
157
173
  type="submit"
158
- disabled={!canUpdate}
174
+ disabled={canUpdate ? !dirty : !canUpdate}
159
175
  startIcon={<Check />}
160
176
  size="S"
161
177
  >
@@ -1,10 +1,12 @@
1
- import React, { useMemo, useRef, useState } from 'react';
1
+ import * as React from 'react';
2
2
 
3
3
  import { ContentLayout, HeaderLayout, Main, useNotifyAT } from '@strapi/design-system';
4
4
  import {
5
5
  CheckPagePermissions,
6
6
  LoadingIndicatorPage,
7
7
  SettingsPageTitle,
8
+ useAPIErrorHandler,
9
+ useFetchClient,
8
10
  useFocusWhenNavigate,
9
11
  useNotification,
10
12
  useOverlayBlocker,
@@ -19,7 +21,6 @@ import { getTrad } from '../../utils';
19
21
 
20
22
  import EmailForm from './components/EmailForm';
21
23
  import EmailTable from './components/EmailTable';
22
- import { fetchData, putEmailTemplate } from './utils/api';
23
24
 
24
25
  const ProtectedEmailTemplatesPage = () => (
25
26
  <CheckPagePermissions permissions={PERMISSIONS.readEmailTemplates}>
@@ -33,40 +34,46 @@ const EmailTemplatesPage = () => {
33
34
  const { notifyStatus } = useNotifyAT();
34
35
  const toggleNotification = useNotification();
35
36
  const { lockApp, unlockApp } = useOverlayBlocker();
36
- const trackUsageRef = useRef(trackUsage);
37
37
  const queryClient = useQueryClient();
38
- useFocusWhenNavigate();
38
+ const { get, put } = useFetchClient();
39
+ const { formatAPIError } = useAPIErrorHandler();
39
40
 
40
- const [isModalOpen, setIsModalOpen] = useState(false);
41
- const [templateToEdit, setTemplateToEdit] = useState(null);
41
+ useFocusWhenNavigate();
42
42
 
43
- const updatePermissions = useMemo(() => {
44
- return { update: PERMISSIONS.updateEmailTemplates };
45
- }, []);
43
+ const [isModalOpen, setIsModalOpen] = React.useState(false);
44
+ const [templateToEdit, setTemplateToEdit] = React.useState(null);
46
45
 
47
46
  const {
48
47
  isLoading: isLoadingForPermissions,
49
48
  allowedActions: { canUpdate },
50
- } = useRBAC(updatePermissions);
51
-
52
- const { status: isLoadingData, data } = useQuery('email-templates', () => fetchData(), {
53
- onSuccess() {
54
- notifyStatus(
55
- formatMessage({
56
- id: getTrad('Email.template.data.loaded'),
57
- defaultMessage: 'Email templates has been loaded',
58
- })
59
- );
60
- },
61
- onError() {
62
- toggleNotification({
63
- type: 'warning',
64
- message: { id: 'notification.error', defaultMessage: 'An error occured' },
65
- });
49
+ } = useRBAC({ update: PERMISSIONS.updateEmailTemplates });
50
+
51
+ const { isLoading: isLoadingData, data } = useQuery(
52
+ ['users-permissions', 'email-templates'],
53
+ async () => {
54
+ const { data } = await get('/users-permissions/email-templates');
55
+
56
+ return data;
66
57
  },
67
- });
58
+ {
59
+ onSuccess() {
60
+ notifyStatus(
61
+ formatMessage({
62
+ id: getTrad('Email.template.data.loaded'),
63
+ defaultMessage: 'Email templates has been loaded',
64
+ })
65
+ );
66
+ },
67
+ onError(error) {
68
+ toggleNotification({
69
+ type: 'warning',
70
+ message: formatAPIError(error),
71
+ });
72
+ },
73
+ }
74
+ );
68
75
 
69
- const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
76
+ const isLoading = isLoadingForPermissions || isLoadingData;
70
77
 
71
78
  const handleToggle = () => {
72
79
  setIsModalOpen((prev) => !prev);
@@ -77,34 +84,38 @@ const EmailTemplatesPage = () => {
77
84
  handleToggle();
78
85
  };
79
86
 
80
- const submitMutation = useMutation((body) => putEmailTemplate({ 'email-templates': body }), {
81
- async onSuccess() {
82
- await queryClient.invalidateQueries('email-templates');
83
-
84
- toggleNotification({
85
- type: 'success',
86
- message: { id: 'notification.success.saved', defaultMessage: 'Saved' },
87
- });
88
-
89
- trackUsageRef.current('didEditEmailTemplates');
90
-
91
- unlockApp();
92
- handleToggle();
93
- },
94
- onError() {
95
- toggleNotification({
96
- type: 'warning',
97
- message: { id: 'notification.error', defaultMessage: 'An error occured' },
98
- });
99
- unlockApp();
100
- },
101
- refetchActive: true,
102
- });
103
- const { isLoading: isSubmittingForm } = submitMutation;
87
+ const submitMutation = useMutation(
88
+ (body) => put('/users-permissions/email-templates', { 'email-templates': body }),
89
+ {
90
+ async onSuccess() {
91
+ await queryClient.invalidateQueries(['users-permissions', 'email-templates']);
92
+
93
+ toggleNotification({
94
+ type: 'success',
95
+ message: { id: 'notification.success.saved', defaultMessage: 'Saved' },
96
+ });
97
+
98
+ trackUsage('didEditEmailTemplates');
99
+
100
+ unlockApp();
101
+ handleToggle();
102
+ },
103
+ onError(error) {
104
+ toggleNotification({
105
+ type: 'warning',
106
+ message: formatAPIError(error),
107
+ });
108
+
109
+ unlockApp();
110
+ },
111
+ refetchActive: true,
112
+ }
113
+ );
104
114
 
105
115
  const handleSubmit = (body) => {
106
116
  lockApp();
107
- trackUsageRef.current('willEditEmailTemplates');
117
+
118
+ trackUsage('willEditEmailTemplates');
108
119
 
109
120
  const editedTemplates = { ...data, [templateToEdit]: body };
110
121
  submitMutation.mutate(editedTemplates);
@@ -133,7 +144,7 @@ const EmailTemplatesPage = () => {
133
144
  }
134
145
 
135
146
  return (
136
- <Main aria-busy={isSubmittingForm}>
147
+ <Main aria-busy={submitMutation.isLoading}>
137
148
  <SettingsPageTitle
138
149
  name={formatMessage({
139
150
  id: getTrad('HeaderNav.link.emailTemplates'),
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useRef, useState } from 'react';
1
+ import * as React from 'react';
2
2
 
3
3
  import {
4
4
  ContentLayout,
@@ -13,7 +13,6 @@ import {
13
13
  Thead,
14
14
  Tr,
15
15
  Typography,
16
- useNotifyAT,
17
16
  VisuallyHidden,
18
17
  } from '@strapi/design-system';
19
18
  import {
@@ -22,6 +21,9 @@ import {
22
21
  onRowClick,
23
22
  SettingsPageTitle,
24
23
  stopPropagation,
24
+ useAPIErrorHandler,
25
+ useCollator,
26
+ useFetchClient,
25
27
  useFocusWhenNavigate,
26
28
  useNotification,
27
29
  useOverlayBlocker,
@@ -29,7 +31,6 @@ import {
29
31
  useTracking,
30
32
  } from '@strapi/helper-plugin';
31
33
  import { Pencil } from '@strapi/icons';
32
- import has from 'lodash/has';
33
34
  import upperFirst from 'lodash/upperFirst';
34
35
  import { useIntl } from 'react-intl';
35
36
  import { useMutation, useQuery, useQueryClient } from 'react-query';
@@ -38,94 +39,94 @@ import FormModal from '../../components/FormModal';
38
39
  import { PERMISSIONS } from '../../constants';
39
40
  import { getTrad } from '../../utils';
40
41
 
41
- import { fetchData, putProvider } from './utils/api';
42
- import createProvidersArray from './utils/createProvidersArray';
43
42
  import forms from './utils/forms';
44
43
 
45
44
  export const ProvidersPage = () => {
46
- const { formatMessage } = useIntl();
47
- useFocusWhenNavigate();
48
- const { notifyStatus } = useNotifyAT();
45
+ const { formatMessage, locale } = useIntl();
49
46
  const queryClient = useQueryClient();
50
47
  const { trackUsage } = useTracking();
51
- const trackUsageRef = useRef(trackUsage);
52
- const [isOpen, setIsOpen] = useState(false);
53
- const [isSubmiting, setIsSubmiting] = useState(false);
54
- const [providerToEditName, setProviderToEditName] = useState(null);
48
+ const [isOpen, setIsOpen] = React.useState(false);
49
+ const [providerToEditName, setProviderToEditName] = React.useState(null);
55
50
  const toggleNotification = useNotification();
56
51
  const { lockApp, unlockApp } = useOverlayBlocker();
52
+ const { get, put } = useFetchClient();
53
+ const { formatAPIError } = useAPIErrorHandler();
54
+ const formatter = useCollator(locale, {
55
+ sensitivity: 'base',
56
+ });
57
57
 
58
- const updatePermissions = useMemo(() => {
59
- return { update: PERMISSIONS.updateProviders };
60
- }, []);
58
+ useFocusWhenNavigate();
61
59
 
62
60
  const {
63
- isLoading: isLoadingForPermissions,
61
+ isLoading: isLoadingPermissions,
64
62
  allowedActions: { canUpdate },
65
- } = useRBAC(updatePermissions);
63
+ } = useRBAC({ update: PERMISSIONS.updateProviders });
66
64
 
67
- const {
68
- isLoading: isLoadingForData,
69
- data: modifiedData,
70
- isFetching,
71
- } = useQuery('get-providers', () => fetchData(toggleNotification), {
72
- onSuccess() {
73
- notifyStatus(
74
- formatMessage({
75
- id: getTrad('Providers.data.loaded'),
76
- defaultMessage: 'Providers have been loaded',
77
- })
78
- );
79
- },
80
- initialData: {},
81
- });
65
+ const { isLoading: isLoadingData, data } = useQuery(
66
+ ['users-permissions', 'get-providers'],
67
+ async () => {
68
+ const { data } = await get('/users-permissions/providers');
82
69
 
83
- const isLoading = isLoadingForData || isFetching;
70
+ return data;
71
+ },
72
+ {
73
+ initialData: {},
74
+ }
75
+ );
84
76
 
85
- const submitMutation = useMutation(putProvider, {
77
+ const submitMutation = useMutation((body) => put('/users-permissions/providers', body), {
86
78
  async onSuccess() {
87
- await queryClient.invalidateQueries('get-providers');
79
+ await queryClient.invalidateQueries(['users-permissions', 'providers']);
80
+
88
81
  toggleNotification({
89
- type: 'info',
82
+ type: 'success',
90
83
  message: { id: getTrad('notification.success.submit') },
91
84
  });
92
85
 
93
- trackUsageRef.current('didEditAuthenticationProvider');
94
- setIsSubmiting(false);
86
+ trackUsage('didEditAuthenticationProvider');
87
+
95
88
  handleToggleModal();
96
89
  unlockApp();
97
90
  },
98
- onError() {
91
+ onError(error) {
99
92
  toggleNotification({
100
93
  type: 'warning',
101
- message: { id: 'notification.error' },
94
+ message: formatAPIError(error),
102
95
  });
96
+
103
97
  unlockApp();
104
- setIsSubmiting(false);
105
98
  },
106
99
  refetchActive: false,
107
100
  });
108
101
 
109
- const providers = useMemo(() => createProvidersArray(modifiedData), [modifiedData]);
102
+ const providers = Object.entries(data)
103
+ .reduce((acc, [name, provider]) => {
104
+ const { icon, enabled, subdomain } = provider;
105
+
106
+ acc.push({
107
+ name,
108
+ icon: icon === 'envelope' ? ['fas', 'envelope'] : ['fab', icon],
109
+ enabled,
110
+ subdomain,
111
+ });
112
+
113
+ return acc;
114
+ }, [])
115
+ .sort((a, b) => formatter.compare(a.name, b.name));
110
116
 
111
- const rowCount = providers.length;
117
+ const isLoading = isLoadingData || isLoadingPermissions;
112
118
 
113
- const isProviderWithSubdomain = useMemo(() => {
119
+ const isProviderWithSubdomain = React.useMemo(() => {
114
120
  if (!providerToEditName) {
115
121
  return false;
116
122
  }
117
123
 
118
124
  const providerToEdit = providers.find((obj) => obj.name === providerToEditName);
119
125
 
120
- return has(providerToEdit, 'subdomain');
126
+ return !!providerToEdit?.subdomain;
121
127
  }, [providers, providerToEditName]);
122
128
 
123
- const pageTitle = formatMessage({
124
- id: getTrad('HeaderNav.link.providers'),
125
- defaultMessage: 'Providers',
126
- });
127
-
128
- const layoutToRender = useMemo(() => {
129
+ const layoutToRender = React.useMemo(() => {
129
130
  if (providerToEditName === 'email') {
130
131
  return forms.email;
131
132
  }
@@ -149,20 +150,21 @@ export const ProvidersPage = () => {
149
150
  };
150
151
 
151
152
  const handleSubmit = async (values) => {
152
- setIsSubmiting(true);
153
-
154
153
  lockApp();
155
154
 
156
- trackUsageRef.current('willEditAuthenticationProvider');
155
+ trackUsage('willEditAuthenticationProvider');
157
156
 
158
- const body = { ...modifiedData, [providerToEditName]: values };
159
-
160
- submitMutation.mutate({ providers: body });
157
+ submitMutation.mutate({ providers: { ...data, [providerToEditName]: values } });
161
158
  };
162
159
 
163
160
  return (
164
161
  <Layout>
165
- <SettingsPageTitle name={pageTitle} />
162
+ <SettingsPageTitle
163
+ name={formatMessage({
164
+ id: getTrad('HeaderNav.link.providers'),
165
+ defaultMessage: 'Providers',
166
+ })}
167
+ />
166
168
  <Main>
167
169
  <HeaderLayout
168
170
  title={formatMessage({
@@ -170,11 +172,11 @@ export const ProvidersPage = () => {
170
172
  defaultMessage: 'Providers',
171
173
  })}
172
174
  />
173
- {isLoading || isLoadingForPermissions ? (
175
+ {isLoading ? (
174
176
  <LoadingIndicatorPage />
175
177
  ) : (
176
178
  <ContentLayout>
177
- <Table colCount={3} rowCount={rowCount + 1}>
179
+ <Table colCount={3} rowCount={providers.length + 1}>
178
180
  <Thead>
179
181
  <Tr>
180
182
  <Th>
@@ -247,9 +249,9 @@ export const ProvidersPage = () => {
247
249
  )}
248
250
  </Main>
249
251
  <FormModal
250
- initialData={modifiedData[providerToEditName]}
252
+ initialData={data[providerToEditName]}
251
253
  isOpen={isOpen}
252
- isSubmiting={isSubmiting}
254
+ isSubmiting={submitMutation.isLoading}
253
255
  layout={layoutToRender}
254
256
  headerBreadcrumbs={[
255
257
  formatMessage({
@@ -3,8 +3,7 @@ import { useEffect } from 'react';
3
3
  import { useNotification, useFetchClient, useAPIErrorHandler } from '@strapi/helper-plugin';
4
4
  import { useQueries } from 'react-query';
5
5
 
6
- import pluginId from '../pluginId';
7
- import { cleanPermissions, getTrad } from '../utils';
6
+ import { cleanPermissions, getTrad } from '../../../utils';
8
7
 
9
8
  export const usePlugins = () => {
10
9
  const toggleNotification = useNotification();
@@ -21,19 +20,23 @@ export const usePlugins = () => {
21
20
  { data: routes, isLoading: isLoadingRoutes, error: routesError, refetch: refetchRoutes },
22
21
  ] = useQueries([
23
22
  {
24
- queryKey: [pluginId, 'permissions'],
23
+ queryKey: ['users-permissions', 'permissions'],
25
24
  async queryFn() {
26
- const res = await get(`/${pluginId}/permissions`);
25
+ const {
26
+ data: { permissions },
27
+ } = await get(`/users-permissions/permissions`);
27
28
 
28
- return res.data.permissions;
29
+ return permissions;
29
30
  },
30
31
  },
31
32
  {
32
- queryKey: [pluginId, 'routes'],
33
+ queryKey: ['users-permissions', 'routes'],
33
34
  async queryFn() {
34
- const res = await get(`/${pluginId}/routes`);
35
+ const {
36
+ data: { routes },
37
+ } = await get(`/users-permissions/routes`);
35
38
 
36
- return res.data.routes;
39
+ return routes;
37
40
  },
38
41
  },
39
42
  ]);
@@ -63,8 +66,12 @@ export const usePlugins = () => {
63
66
  const isLoading = isLoadingPermissions || isLoadingRoutes;
64
67
 
65
68
  return {
69
+ // TODO: these return values need to be memoized, otherwise
70
+ // they will create infinite rendering loops when used as
71
+ // effect dependencies
66
72
  permissions: permissions ? cleanPermissions(permissions) : {},
67
73
  routes: routes ?? {},
74
+
68
75
  getData: refetchQueries,
69
76
  isLoading,
70
77
  };