@strapi/plugin-users-permissions 4.12.6 → 4.12.7

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 (32) hide show
  1. package/admin/src/components/Permissions/index.js +4 -2
  2. package/admin/src/hooks/index.js +5 -0
  3. package/admin/src/hooks/useFetchRole/index.js +67 -0
  4. package/admin/src/hooks/useFetchRole/reducer.js +31 -0
  5. package/admin/src/hooks/useForm/index.js +68 -0
  6. package/admin/src/hooks/useForm/reducer.js +40 -0
  7. package/admin/src/{pages/Roles/hooks → hooks}/usePlugins.js +8 -15
  8. package/admin/src/hooks/useRolesList/index.js +65 -0
  9. package/admin/src/hooks/useRolesList/init.js +5 -0
  10. package/admin/src/hooks/useRolesList/reducer.js +31 -0
  11. package/admin/src/index.js +8 -7
  12. package/admin/src/pages/AdvancedSettings/index.js +24 -41
  13. package/admin/src/pages/AdvancedSettings/utils/api.js +16 -0
  14. package/admin/src/pages/EmailTemplates/index.js +47 -62
  15. package/admin/src/pages/EmailTemplates/utils/api.js +16 -0
  16. package/admin/src/pages/Providers/index.js +58 -64
  17. package/admin/src/pages/Providers/reducer.js +54 -0
  18. package/admin/src/pages/Providers/utils/api.js +24 -0
  19. package/admin/src/pages/Providers/utils/createProvidersArray.js +21 -0
  20. package/admin/src/pages/Roles/CreatePage.js +185 -0
  21. package/admin/src/pages/Roles/EditPage.js +197 -0
  22. package/admin/src/pages/Roles/{pages/ListPage → ListPage}/components/TableBody.js +11 -41
  23. package/admin/src/pages/Roles/{pages/ListPage → ListPage}/index.js +15 -19
  24. package/admin/src/pages/Roles/ProtectedCreatePage.js +15 -0
  25. package/admin/src/pages/Roles/ProtectedEditPage.js +15 -0
  26. package/admin/src/pages/Roles/ProtectedListPage.js +17 -0
  27. package/admin/src/pages/Roles/index.js +7 -10
  28. package/jest.config.front.js +1 -1
  29. package/package.json +4 -4
  30. package/admin/src/pages/Roles/pages/CreatePage.js +0 -190
  31. package/admin/src/pages/Roles/pages/EditPage.js +0 -211
  32. /package/admin/src/pages/Roles/{pages/ListPage → ListPage}/utils/api.js +0 -0
@@ -1,6 +1,6 @@
1
1
  import React, { useReducer } from 'react';
2
2
 
3
- import { Accordion, AccordionContent, AccordionToggle, Flex } from '@strapi/design-system';
3
+ import { Accordion, AccordionContent, AccordionToggle, Box, Flex } from '@strapi/design-system';
4
4
  import { useIntl } from 'react-intl';
5
5
 
6
6
  import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
@@ -44,7 +44,9 @@ const Permissions = () => {
44
44
  variant={index % 2 ? 'primary' : 'secondary'}
45
45
  />
46
46
  <AccordionContent>
47
- <PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />
47
+ <Box>
48
+ <PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />
49
+ </Box>
48
50
  </AccordionContent>
49
51
  </Accordion>
50
52
  ))}
@@ -0,0 +1,5 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export { default as useForm } from './useForm';
3
+ export { default as useRolesList } from './useRolesList';
4
+ export * from './usePlugins';
5
+ export { default as useFetchRole } from './useFetchRole';
@@ -0,0 +1,67 @@
1
+ import { useCallback, useEffect, useReducer, useRef } from 'react';
2
+
3
+ import { useFetchClient, useNotification } from '@strapi/helper-plugin';
4
+
5
+ import pluginId from '../../pluginId';
6
+
7
+ import reducer, { initialState } from './reducer';
8
+
9
+ const useFetchRole = (id) => {
10
+ const [state, dispatch] = useReducer(reducer, initialState);
11
+ const toggleNotification = useNotification();
12
+ const isMounted = useRef(null);
13
+ const { get } = useFetchClient();
14
+
15
+ useEffect(() => {
16
+ isMounted.current = true;
17
+
18
+ if (id) {
19
+ fetchRole(id);
20
+ } else {
21
+ dispatch({
22
+ type: 'GET_DATA_SUCCEEDED',
23
+ role: {},
24
+ });
25
+ }
26
+
27
+ return () => (isMounted.current = false);
28
+ // eslint-disable-next-line react-hooks/exhaustive-deps
29
+ }, [id]);
30
+
31
+ const fetchRole = async (roleId) => {
32
+ try {
33
+ const {
34
+ data: { role },
35
+ } = await get(`/${pluginId}/roles/${roleId}`);
36
+
37
+ // Prevent updating state on an unmounted component
38
+ if (isMounted.current) {
39
+ dispatch({
40
+ type: 'GET_DATA_SUCCEEDED',
41
+ role,
42
+ });
43
+ }
44
+ } catch (err) {
45
+ console.error(err);
46
+
47
+ dispatch({
48
+ type: 'GET_DATA_ERROR',
49
+ });
50
+ toggleNotification({
51
+ type: 'warning',
52
+ message: { id: 'notification.error' },
53
+ });
54
+ }
55
+ };
56
+
57
+ const handleSubmitSucceeded = useCallback((data) => {
58
+ dispatch({
59
+ type: 'ON_SUBMIT_SUCCEEDED',
60
+ ...data,
61
+ });
62
+ }, []);
63
+
64
+ return { ...state, onSubmitSucceeded: handleSubmitSucceeded };
65
+ };
66
+
67
+ export default useFetchRole;
@@ -0,0 +1,31 @@
1
+ /* eslint-disable consistent-return */
2
+ import produce from 'immer';
3
+
4
+ export const initialState = {
5
+ role: {},
6
+ isLoading: true,
7
+ };
8
+
9
+ const reducer = (state, action) =>
10
+ produce(state, (draftState) => {
11
+ switch (action.type) {
12
+ case 'GET_DATA_SUCCEEDED': {
13
+ draftState.role = action.role;
14
+ draftState.isLoading = false;
15
+ break;
16
+ }
17
+ case 'GET_DATA_ERROR': {
18
+ draftState.isLoading = false;
19
+ break;
20
+ }
21
+ case 'ON_SUBMIT_SUCCEEDED': {
22
+ draftState.role.name = action.name;
23
+ draftState.role.description = action.description;
24
+ break;
25
+ }
26
+ default:
27
+ return draftState;
28
+ }
29
+ });
30
+
31
+ export default reducer;
@@ -0,0 +1,68 @@
1
+ import { useCallback, useEffect, useReducer, useRef } from 'react';
2
+
3
+ import { useFetchClient, useNotification, useRBAC } from '@strapi/helper-plugin';
4
+
5
+ import reducer, { initialState } from './reducer';
6
+
7
+ const useUserForm = (endPoint, permissions) => {
8
+ const { isLoading: isLoadingForPermissions, allowedActions } = useRBAC(permissions);
9
+ const [{ isLoading, modifiedData }, dispatch] = useReducer(reducer, initialState);
10
+ const toggleNotification = useNotification();
11
+ const isMounted = useRef(true);
12
+
13
+ const { get } = useFetchClient();
14
+
15
+ useEffect(() => {
16
+ const getData = async () => {
17
+ try {
18
+ dispatch({
19
+ type: 'GET_DATA',
20
+ });
21
+
22
+ const { data } = await get(`/users-permissions/${endPoint}`);
23
+
24
+ dispatch({
25
+ type: 'GET_DATA_SUCCEEDED',
26
+ data,
27
+ });
28
+ } catch (err) {
29
+ // The user aborted the request
30
+ if (isMounted.current) {
31
+ dispatch({
32
+ type: 'GET_DATA_ERROR',
33
+ });
34
+ console.error(err);
35
+ toggleNotification({
36
+ type: 'warning',
37
+ message: { id: 'notification.error' },
38
+ });
39
+ }
40
+ }
41
+ };
42
+
43
+ if (!isLoadingForPermissions) {
44
+ getData();
45
+ }
46
+
47
+ return () => {
48
+ isMounted.current = false;
49
+ };
50
+ }, [isLoadingForPermissions, endPoint, get, toggleNotification]);
51
+
52
+ const dispatchSubmitSucceeded = useCallback((data) => {
53
+ dispatch({
54
+ type: 'ON_SUBMIT_SUCCEEDED',
55
+ data,
56
+ });
57
+ }, []);
58
+
59
+ return {
60
+ allowedActions,
61
+ dispatchSubmitSucceeded,
62
+ isLoading,
63
+ isLoadingForPermissions,
64
+ modifiedData,
65
+ };
66
+ };
67
+
68
+ export default useUserForm;
@@ -0,0 +1,40 @@
1
+ import produce from 'immer';
2
+
3
+ const initialState = {
4
+ isLoading: true,
5
+ modifiedData: {},
6
+ };
7
+
8
+ const reducer = (state, action) =>
9
+ // eslint-disable-next-line consistent-return
10
+ produce(state, (draftState) => {
11
+ switch (action.type) {
12
+ case 'GET_DATA': {
13
+ draftState.isLoading = true;
14
+ draftState.modifiedData = {};
15
+
16
+ break;
17
+ }
18
+ case 'GET_DATA_SUCCEEDED': {
19
+ draftState.isLoading = false;
20
+ draftState.modifiedData = action.data;
21
+
22
+ break;
23
+ }
24
+ case 'GET_DATA_ERROR': {
25
+ draftState.isLoading = true;
26
+ break;
27
+ }
28
+ case 'ON_SUBMIT_SUCCEEDED': {
29
+ draftState.modifiedData = action.data;
30
+
31
+ break;
32
+ }
33
+ default: {
34
+ return draftState;
35
+ }
36
+ }
37
+ });
38
+
39
+ export default reducer;
40
+ export { initialState };
@@ -3,7 +3,8 @@ 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 { cleanPermissions, getTrad } from '../../../utils';
6
+ import pluginId from '../pluginId';
7
+ import { cleanPermissions, getTrad } from '../utils';
7
8
 
8
9
  export const usePlugins = () => {
9
10
  const toggleNotification = useNotification();
@@ -20,23 +21,19 @@ export const usePlugins = () => {
20
21
  { data: routes, isLoading: isLoadingRoutes, error: routesError, refetch: refetchRoutes },
21
22
  ] = useQueries([
22
23
  {
23
- queryKey: ['users-permissions', 'permissions'],
24
+ queryKey: [pluginId, 'permissions'],
24
25
  async queryFn() {
25
- const {
26
- data: { permissions },
27
- } = await get(`/users-permissions/permissions`);
26
+ const res = await get(`/${pluginId}/permissions`);
28
27
 
29
- return permissions;
28
+ return res.data.permissions;
30
29
  },
31
30
  },
32
31
  {
33
- queryKey: ['users-permissions', 'routes'],
32
+ queryKey: [pluginId, 'routes'],
34
33
  async queryFn() {
35
- const {
36
- data: { routes },
37
- } = await get(`/users-permissions/routes`);
34
+ const res = await get(`/${pluginId}/routes`);
38
35
 
39
- return routes;
36
+ return res.data.routes;
40
37
  },
41
38
  },
42
39
  ]);
@@ -66,12 +63,8 @@ export const usePlugins = () => {
66
63
  const isLoading = isLoadingPermissions || isLoadingRoutes;
67
64
 
68
65
  return {
69
- // TODO: these return values need to be memoized, otherwise
70
- // they will create infinite rendering loops when used as
71
- // effect dependencies
72
66
  permissions: permissions ? cleanPermissions(permissions) : {},
73
67
  routes: routes ?? {},
74
-
75
68
  getData: refetchQueries,
76
69
  isLoading,
77
70
  };
@@ -0,0 +1,65 @@
1
+ import { useCallback, useEffect, useReducer, useRef } from 'react';
2
+
3
+ import { useFetchClient, useNotification } from '@strapi/helper-plugin';
4
+ import get from 'lodash/get';
5
+
6
+ import pluginId from '../../pluginId';
7
+
8
+ import init from './init';
9
+ import reducer, { initialState } from './reducer';
10
+
11
+ const useRolesList = (shouldFetchData = true) => {
12
+ const [{ roles, isLoading }, dispatch] = useReducer(reducer, initialState, () =>
13
+ init(initialState, shouldFetchData)
14
+ );
15
+ const toggleNotification = useNotification();
16
+
17
+ const isMounted = useRef(true);
18
+ const fetchClient = useFetchClient();
19
+
20
+ const fetchRolesList = useCallback(async () => {
21
+ try {
22
+ dispatch({
23
+ type: 'GET_DATA',
24
+ });
25
+
26
+ const {
27
+ data: { roles },
28
+ } = await fetchClient.get(`/${pluginId}/roles`);
29
+
30
+ dispatch({
31
+ type: 'GET_DATA_SUCCEEDED',
32
+ data: roles,
33
+ });
34
+ } catch (err) {
35
+ const message = get(err, ['response', 'payload', 'message'], 'An error occured');
36
+
37
+ if (isMounted.current) {
38
+ dispatch({
39
+ type: 'GET_DATA_ERROR',
40
+ });
41
+
42
+ if (message !== 'Forbidden') {
43
+ toggleNotification({
44
+ type: 'warning',
45
+ message,
46
+ });
47
+ }
48
+ }
49
+ }
50
+ }, [fetchClient, toggleNotification]);
51
+
52
+ useEffect(() => {
53
+ if (shouldFetchData) {
54
+ fetchRolesList();
55
+ }
56
+
57
+ return () => {
58
+ isMounted.current = false;
59
+ };
60
+ }, [shouldFetchData, fetchRolesList]);
61
+
62
+ return { roles, isLoading, getData: fetchRolesList };
63
+ };
64
+
65
+ export default useRolesList;
@@ -0,0 +1,5 @@
1
+ const init = (initialState, shouldFetchData) => {
2
+ return { ...initialState, isLoading: shouldFetchData };
3
+ };
4
+
5
+ export default init;
@@ -0,0 +1,31 @@
1
+ /* eslint-disable consistent-return */
2
+ import produce from 'immer';
3
+
4
+ export const initialState = {
5
+ roles: [],
6
+ isLoading: true,
7
+ };
8
+
9
+ const reducer = (state, action) =>
10
+ produce(state, (draftState) => {
11
+ switch (action.type) {
12
+ case 'GET_DATA': {
13
+ draftState.isLoading = true;
14
+ draftState.roles = [];
15
+ break;
16
+ }
17
+ case 'GET_DATA_SUCCEEDED': {
18
+ draftState.roles = action.data;
19
+ draftState.isLoading = false;
20
+ break;
21
+ }
22
+ case 'GET_DATA_ERROR': {
23
+ draftState.isLoading = false;
24
+ break;
25
+ }
26
+ default:
27
+ return draftState;
28
+ }
29
+ });
30
+
31
+ export default reducer;
@@ -9,6 +9,7 @@ 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';
12
13
  import getTrad from './utils/getTrad';
13
14
 
14
15
  const name = pluginPkg.strapi.name;
@@ -18,7 +19,7 @@ export default {
18
19
  // Create the plugin's settings section
19
20
  app.createSettingSection(
20
21
  {
21
- id: 'users-permissions',
22
+ id: pluginId,
22
23
  intlLabel: {
23
24
  id: getTrad('Settings.section-label'),
24
25
  defaultMessage: 'Users & Permissions plugin',
@@ -31,7 +32,7 @@ export default {
31
32
  defaultMessage: 'Roles',
32
33
  },
33
34
  id: 'roles',
34
- to: `/settings/users-permissions/roles`,
35
+ to: `/settings/${pluginId}/roles`,
35
36
  async Component() {
36
37
  const component = await import(
37
38
  /* webpackChunkName: "users-roles-settings-page" */ './pages/Roles'
@@ -47,7 +48,7 @@ export default {
47
48
  defaultMessage: 'Providers',
48
49
  },
49
50
  id: 'providers',
50
- to: `/settings/users-permissions/providers`,
51
+ to: `/settings/${pluginId}/providers`,
51
52
  async Component() {
52
53
  const component = await import(
53
54
  /* webpackChunkName: "users-providers-settings-page" */ './pages/Providers'
@@ -63,7 +64,7 @@ export default {
63
64
  defaultMessage: 'Email templates',
64
65
  },
65
66
  id: 'email-templates',
66
- to: `/settings/users-permissions/email-templates`,
67
+ to: `/settings/${pluginId}/email-templates`,
67
68
  async Component() {
68
69
  const component = await import(
69
70
  /* webpackChunkName: "users-email-settings-page" */ './pages/EmailTemplates'
@@ -79,7 +80,7 @@ export default {
79
80
  defaultMessage: 'Advanced Settings',
80
81
  },
81
82
  id: 'advanced-settings',
82
- to: `/settings/users-permissions/advanced-settings`,
83
+ to: `/settings/${pluginId}/advanced-settings`,
83
84
  async Component() {
84
85
  const component = await import(
85
86
  /* webpackChunkName: "users-advanced-settings-page" */ './pages/AdvancedSettings'
@@ -93,7 +94,7 @@ export default {
93
94
  );
94
95
 
95
96
  app.registerPlugin({
96
- id: 'users-permissions',
97
+ id: pluginId,
97
98
  name,
98
99
  });
99
100
  },
@@ -106,7 +107,7 @@ export default {
106
107
  )
107
108
  .then(({ default: data }) => {
108
109
  return {
109
- data: prefixPluginTranslations(data, 'users-permissions'),
110
+ data: prefixPluginTranslations(data, pluginId),
110
111
  locale,
111
112
  };
112
113
  })
@@ -20,8 +20,6 @@ import {
20
20
  GenericInput,
21
21
  LoadingIndicatorPage,
22
22
  SettingsPageTitle,
23
- useAPIErrorHandler,
24
- useFetchClient,
25
23
  useFocusWhenNavigate,
26
24
  useNotification,
27
25
  useOverlayBlocker,
@@ -35,6 +33,7 @@ import { useMutation, useQuery, useQueryClient } from 'react-query';
35
33
  import { PERMISSIONS } from '../../constants';
36
34
  import { getTrad } from '../../utils';
37
35
 
36
+ import { fetchData, putAdvancedSettings } from './utils/api';
38
37
  import layout from './utils/layout';
39
38
  import schema from './utils/schema';
40
39
 
@@ -50,9 +49,6 @@ const AdvancedSettingsPage = () => {
50
49
  const { lockApp, unlockApp } = useOverlayBlocker();
51
50
  const { notifyStatus } = useNotifyAT();
52
51
  const queryClient = useQueryClient();
53
- const { get, put } = useFetchClient();
54
- const { formatAPIError } = useAPIErrorHandler();
55
-
56
52
  useFocusWhenNavigate();
57
53
 
58
54
  const {
@@ -60,37 +56,28 @@ const AdvancedSettingsPage = () => {
60
56
  allowedActions: { canUpdate },
61
57
  } = useRBAC({ update: PERMISSIONS.updateAdvancedSettings });
62
58
 
63
- const { isLoading: isLoadingData, data } = useQuery(
64
- ['users-permissions', 'advanced'],
65
- async () => {
66
- const { data } = await get('/users-permissions/advanced');
67
-
68
- return data;
59
+ const { status: isLoadingData, data } = useQuery('advanced', () => fetchData(), {
60
+ onSuccess() {
61
+ notifyStatus(
62
+ formatMessage({
63
+ id: getTrad('Form.advancedSettings.data.loaded'),
64
+ defaultMessage: 'Advanced settings data has been loaded',
65
+ })
66
+ );
69
67
  },
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
- );
68
+ onError() {
69
+ toggleNotification({
70
+ type: 'warning',
71
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
72
+ });
73
+ },
74
+ });
87
75
 
88
- const isLoading = isLoadingForPermissions || isLoadingData;
76
+ const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
89
77
 
90
- const submitMutation = useMutation((body) => put('/users-permissions/advanced', body), {
78
+ const submitMutation = useMutation((body) => putAdvancedSettings(body), {
91
79
  async onSuccess() {
92
- await queryClient.invalidateQueries(['users-permissions', 'advanced']);
93
-
80
+ await queryClient.invalidateQueries('advanced');
94
81
  toggleNotification({
95
82
  type: 'success',
96
83
  message: { id: getTrad('notification.success.saved'), defaultMessage: 'Saved' },
@@ -98,12 +85,11 @@ const AdvancedSettingsPage = () => {
98
85
 
99
86
  unlockApp();
100
87
  },
101
- onError(error) {
88
+ onError() {
102
89
  toggleNotification({
103
90
  type: 'warning',
104
- message: formatAPIError(error),
91
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
105
92
  });
106
-
107
93
  unlockApp();
108
94
  },
109
95
  refetchActive: true,
@@ -114,12 +100,9 @@ const AdvancedSettingsPage = () => {
114
100
  const handleSubmit = async (body) => {
115
101
  lockApp();
116
102
 
117
- submitMutation.mutate({
118
- ...body,
119
- email_confirmation_redirection: body.email_confirmation
120
- ? body.email_confirmation_redirection
121
- : '',
122
- });
103
+ const urlConfirmation = body.email_confirmation ? body.email_confirmation_redirection : '';
104
+
105
+ await submitMutation.mutateAsync({ ...body, email_confirmation_redirection: urlConfirmation });
123
106
  };
124
107
 
125
108
  if (isLoading) {
@@ -0,0 +1,16 @@
1
+ import { getFetchClient } from '@strapi/helper-plugin';
2
+
3
+ const fetchData = async () => {
4
+ const { get } = getFetchClient();
5
+ const { data } = await get('/users-permissions/advanced');
6
+
7
+ return data;
8
+ };
9
+
10
+ const putAdvancedSettings = (body) => {
11
+ const { put } = getFetchClient();
12
+
13
+ return put('/users-permissions/advanced', body);
14
+ };
15
+
16
+ export { fetchData, putAdvancedSettings };