@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.
- package/admin/src/components/Permissions/index.js +2 -4
- package/admin/src/index.js +7 -8
- package/admin/src/pages/AdvancedSettings/index.js +46 -30
- package/admin/src/pages/EmailTemplates/index.js +64 -53
- package/admin/src/pages/Providers/index.js +64 -62
- package/admin/src/{hooks → pages/Roles/hooks}/usePlugins.js +15 -8
- package/admin/src/pages/Roles/index.js +10 -7
- package/admin/src/pages/Roles/pages/CreatePage.js +199 -0
- package/admin/src/pages/Roles/pages/EditPage.js +220 -0
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/components/TableBody.js +44 -14
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/index.js +29 -30
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/utils/api.js +2 -4
- package/admin/src/translations/zh-Hans.json +80 -80
- package/admin/src/utils/index.js +0 -1
- package/documentation/content-api.yaml +1 -1
- package/jest.config.front.js +1 -1
- package/package.json +11 -11
- package/server/bootstrap/index.js +36 -0
- package/server/controllers/auth.js +51 -14
- package/server/controllers/user.js +12 -1
- package/server/middlewares/rateLimit.js +41 -21
- package/admin/src/hooks/index.js +0 -5
- package/admin/src/hooks/useFetchRole/index.js +0 -67
- package/admin/src/hooks/useFetchRole/reducer.js +0 -31
- package/admin/src/hooks/useForm/index.js +0 -70
- package/admin/src/hooks/useForm/reducer.js +0 -40
- package/admin/src/hooks/useRolesList/index.js +0 -65
- package/admin/src/hooks/useRolesList/init.js +0 -5
- package/admin/src/hooks/useRolesList/reducer.js +0 -31
- package/admin/src/pages/AdvancedSettings/utils/api.js +0 -18
- package/admin/src/pages/EmailTemplates/utils/api.js +0 -18
- package/admin/src/pages/Providers/reducer.js +0 -54
- package/admin/src/pages/Providers/utils/api.js +0 -26
- package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
- package/admin/src/pages/Roles/CreatePage.js +0 -185
- package/admin/src/pages/Roles/EditPage.js +0 -197
- package/admin/src/pages/Roles/ProtectedCreatePage.js +0 -15
- package/admin/src/pages/Roles/ProtectedEditPage.js +0 -15
- package/admin/src/pages/Roles/ProtectedListPage.js +0 -17
- 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,
|
|
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
|
-
<
|
|
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
|
))}
|
package/admin/src/index.js
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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,
|
|
109
|
+
data: prefixPluginTranslations(data, 'users-permissions'),
|
|
111
110
|
locale,
|
|
112
111
|
};
|
|
113
112
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import 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(
|
|
59
|
-
|
|
60
|
-
const {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
88
|
+
const isLoading = isLoadingForPermissions || isLoadingData;
|
|
78
89
|
|
|
79
|
-
const submitMutation = useMutation((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:
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
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
|
-
|
|
38
|
+
const { get, put } = useFetchClient();
|
|
39
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
const [templateToEdit, setTemplateToEdit] = useState(null);
|
|
41
|
+
useFocusWhenNavigate();
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
|
|
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(
|
|
51
|
-
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
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={
|
|
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
|
|
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
|
|
52
|
-
const [
|
|
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
|
-
|
|
59
|
-
return { update: PERMISSIONS.updateProviders };
|
|
60
|
-
}, []);
|
|
58
|
+
useFocusWhenNavigate();
|
|
61
59
|
|
|
62
60
|
const {
|
|
63
|
-
isLoading:
|
|
61
|
+
isLoading: isLoadingPermissions,
|
|
64
62
|
allowedActions: { canUpdate },
|
|
65
|
-
} = useRBAC(
|
|
63
|
+
} = useRBAC({ update: PERMISSIONS.updateProviders });
|
|
66
64
|
|
|
67
|
-
const {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
70
|
+
return data;
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
initialData: {},
|
|
74
|
+
}
|
|
75
|
+
);
|
|
84
76
|
|
|
85
|
-
const submitMutation = useMutation(
|
|
77
|
+
const submitMutation = useMutation((body) => put('/users-permissions/providers', body), {
|
|
86
78
|
async onSuccess() {
|
|
87
|
-
await queryClient.invalidateQueries('
|
|
79
|
+
await queryClient.invalidateQueries(['users-permissions', 'providers']);
|
|
80
|
+
|
|
88
81
|
toggleNotification({
|
|
89
|
-
type: '
|
|
82
|
+
type: 'success',
|
|
90
83
|
message: { id: getTrad('notification.success.submit') },
|
|
91
84
|
});
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
126
|
+
return !!providerToEdit?.subdomain;
|
|
121
127
|
}, [providers, providerToEditName]);
|
|
122
128
|
|
|
123
|
-
const
|
|
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
|
-
|
|
155
|
+
trackUsage('willEditAuthenticationProvider');
|
|
157
156
|
|
|
158
|
-
|
|
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
|
|
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
|
|
175
|
+
{isLoading ? (
|
|
174
176
|
<LoadingIndicatorPage />
|
|
175
177
|
) : (
|
|
176
178
|
<ContentLayout>
|
|
177
|
-
<Table colCount={3} rowCount={
|
|
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={
|
|
252
|
+
initialData={data[providerToEditName]}
|
|
251
253
|
isOpen={isOpen}
|
|
252
|
-
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
|
|
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: [
|
|
23
|
+
queryKey: ['users-permissions', 'permissions'],
|
|
25
24
|
async queryFn() {
|
|
26
|
-
const
|
|
25
|
+
const {
|
|
26
|
+
data: { permissions },
|
|
27
|
+
} = await get(`/users-permissions/permissions`);
|
|
27
28
|
|
|
28
|
-
return
|
|
29
|
+
return permissions;
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
{
|
|
32
|
-
queryKey: [
|
|
33
|
+
queryKey: ['users-permissions', 'routes'],
|
|
33
34
|
async queryFn() {
|
|
34
|
-
const
|
|
35
|
+
const {
|
|
36
|
+
data: { routes },
|
|
37
|
+
} = await get(`/users-permissions/routes`);
|
|
35
38
|
|
|
36
|
-
return
|
|
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
|
};
|