@strapi/plugin-users-permissions 4.20.5 → 5.0.0-alpha.1
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/FormModal/index.jsx +1 -2
- package/admin/src/components/Permissions/reducer.js +1 -1
- package/admin/src/components/UsersPermissions/reducer.js +1 -1
- package/admin/src/index.js +15 -32
- package/admin/src/pages/AdvancedSettings/index.jsx +72 -112
- package/admin/src/pages/AdvancedSettings/utils/layout.js +20 -35
- package/admin/src/pages/AdvancedSettings/utils/schema.js +5 -2
- package/admin/src/pages/EmailTemplates/components/EmailForm.jsx +47 -74
- package/admin/src/pages/EmailTemplates/components/EmailTable.jsx +4 -5
- package/admin/src/pages/EmailTemplates/index.jsx +25 -55
- package/admin/src/pages/EmailTemplates/utils/schema.js +18 -6
- package/admin/src/pages/Providers/index.jsx +91 -108
- package/admin/src/pages/Providers/utils/forms.js +11 -11
- package/admin/src/pages/Roles/constants.js +3 -3
- package/admin/src/pages/Roles/hooks/usePlugins.js +4 -4
- package/admin/src/pages/Roles/index.jsx +9 -18
- package/admin/src/pages/Roles/pages/CreatePage.jsx +20 -28
- package/admin/src/pages/Roles/pages/EditPage.jsx +25 -37
- package/admin/src/pages/Roles/pages/ListPage/components/TableBody.jsx +23 -28
- package/admin/src/pages/Roles/pages/ListPage/index.jsx +73 -42
- package/admin/src/translations/en.json +1 -1
- package/admin/src/utils/prefixPluginTranslations.js +13 -0
- package/dist/_chunks/EditViewPage-kgrZ8rEg-6k5dfk_x.js +84412 -0
- package/dist/_chunks/EditViewPage-kgrZ8rEg-6k5dfk_x.js.map +1 -0
- package/dist/_chunks/EditViewPage-kgrZ8rEg-GlayP0Uq.mjs +84382 -0
- package/dist/_chunks/EditViewPage-kgrZ8rEg-GlayP0Uq.mjs.map +1 -0
- package/dist/_chunks/Helmet-d9JljxUo.js +1010 -0
- package/dist/_chunks/Helmet-d9JljxUo.js.map +1 -0
- package/dist/_chunks/Helmet-kyJ1Zklj.mjs +1008 -0
- package/dist/_chunks/Helmet-kyJ1Zklj.mjs.map +1 -0
- package/dist/_chunks/ListViewPage-BNB0ptO7-TUQO_9Hj.js +1617 -0
- package/dist/_chunks/ListViewPage-BNB0ptO7-TUQO_9Hj.js.map +1 -0
- package/dist/_chunks/ListViewPage-BNB0ptO7-t1ra9JlI.mjs +1594 -0
- package/dist/_chunks/ListViewPage-BNB0ptO7-t1ra9JlI.mjs.map +1 -0
- package/dist/_chunks/ReviewWorkflowsColumn-56Z6l-FH-3Dq1lGu9.js +33 -0
- package/dist/_chunks/ReviewWorkflowsColumn-56Z6l-FH-3Dq1lGu9.js.map +1 -0
- package/dist/_chunks/ReviewWorkflowsColumn-56Z6l-FH-mpkuW-HV.mjs +33 -0
- package/dist/_chunks/ReviewWorkflowsColumn-56Z6l-FH-mpkuW-HV.mjs.map +1 -0
- package/dist/_chunks/constants-evLWZCaJ-0QLv9QPI.mjs +190 -0
- package/dist/_chunks/constants-evLWZCaJ-0QLv9QPI.mjs.map +1 -0
- package/dist/_chunks/constants-evLWZCaJ-dGs71EWl.js +209 -0
- package/dist/_chunks/constants-evLWZCaJ-dGs71EWl.js.map +1 -0
- package/dist/_chunks/{en-m608rMZx.js → en-TaNIVnDO.js} +2 -2
- package/dist/_chunks/en-TaNIVnDO.js.map +1 -0
- package/dist/_chunks/{en-CE3wEy_c.mjs → en-jvJ-d-Qq.mjs} +2 -2
- package/dist/_chunks/en-jvJ-d-Qq.mjs.map +1 -0
- package/dist/_chunks/{index-XqdaO5WZ.js → index-6E51D69B.js} +149 -149
- package/dist/_chunks/index-6E51D69B.js.map +1 -0
- package/dist/_chunks/index-BGIcvvEB.mjs +260 -0
- package/dist/_chunks/index-BGIcvvEB.mjs.map +1 -0
- package/dist/_chunks/{index-6Kdo3KXv.js → index-Bg2Rf_5y.js} +112 -154
- package/dist/_chunks/index-Bg2Rf_5y.js.map +1 -0
- package/dist/_chunks/index-LpFmy25n.js +279 -0
- package/dist/_chunks/index-LpFmy25n.js.map +1 -0
- package/dist/_chunks/{index-a9oKDd3C.mjs → index-R05CeNXG.mjs} +106 -148
- package/dist/_chunks/index-R05CeNXG.mjs.map +1 -0
- package/dist/_chunks/index-YFPS5vYF-ZGkR3L1g.js +16558 -0
- package/dist/_chunks/index-YFPS5vYF-ZGkR3L1g.js.map +1 -0
- package/dist/_chunks/index-YFPS5vYF-cugkJcLS.mjs +16533 -0
- package/dist/_chunks/index-YFPS5vYF-cugkJcLS.mjs.map +1 -0
- package/dist/_chunks/{index-ethhTEkj.mjs → index-aEKi1Qb9.mjs} +39 -36
- package/dist/_chunks/index-aEKi1Qb9.mjs.map +1 -0
- package/dist/_chunks/{index-rryiT0-Z.mjs → index-hG66XSuA.mjs} +131 -130
- package/dist/_chunks/index-hG66XSuA.mjs.map +1 -0
- package/dist/_chunks/{index-iNtwnT3f.mjs → index-xt3l4qU9.mjs} +35 -35
- package/dist/_chunks/index-xt3l4qU9.mjs.map +1 -0
- package/dist/_chunks/{index-O9AAUvyy.js → index-yKMi8hKt.js} +36 -36
- package/dist/_chunks/index-yKMi8hKt.js.map +1 -0
- package/dist/_chunks/{index-1uupZmu0.js → index-ylhaoJtw.js} +43 -40
- package/dist/_chunks/index-ylhaoJtw.js.map +1 -0
- package/dist/_chunks/useSyncRbac-83vFRiaG-YY4KQcAU.js +57 -0
- package/dist/_chunks/useSyncRbac-83vFRiaG-YY4KQcAU.js.map +1 -0
- package/dist/_chunks/useSyncRbac-83vFRiaG-ov11t-T1.mjs +39 -0
- package/dist/_chunks/useSyncRbac-83vFRiaG-ov11t-T1.mjs.map +1 -0
- package/dist/admin/index.js +1 -2
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +1 -2
- package/dist/admin/index.mjs.map +1 -1
- package/dist/style.css +84 -0
- package/package.json +13 -13
- package/server/bootstrap/grant-config.js +9 -0
- package/server/bootstrap/index.js +2 -39
- package/server/content-types/user/index.js +0 -1
- package/server/controllers/auth.js +24 -53
- package/server/controllers/content-manager-user.js +24 -28
- package/server/controllers/role.js +1 -1
- package/server/controllers/user.js +5 -5
- package/server/middlewares/rateLimit.js +1 -1
- package/server/register.js +1 -1
- package/server/services/jwt.js +3 -3
- package/server/services/permission.js +3 -7
- package/server/services/providers-registry.js +15 -0
- package/server/services/providers.js +10 -5
- package/server/services/role.js +15 -13
- package/server/services/user.js +28 -14
- package/server/services/users-permissions.js +12 -10
- package/server/utils/sanitize/sanitizers.js +2 -2
- package/admin/src/pages/Roles/pages/ListPage/utils/api.js +0 -30
- package/dist/_chunks/en-CE3wEy_c.mjs.map +0 -1
- package/dist/_chunks/en-m608rMZx.js.map +0 -1
- package/dist/_chunks/index-1uupZmu0.js.map +0 -1
- package/dist/_chunks/index-6Kdo3KXv.js.map +0 -1
- package/dist/_chunks/index-O9AAUvyy.js.map +0 -1
- package/dist/_chunks/index-Un-J-cxQ.js +0 -320
- package/dist/_chunks/index-Un-J-cxQ.js.map +0 -1
- package/dist/_chunks/index-X0yw_GgN.mjs +0 -301
- package/dist/_chunks/index-X0yw_GgN.mjs.map +0 -1
- package/dist/_chunks/index-XqdaO5WZ.js.map +0 -1
- package/dist/_chunks/index-a9oKDd3C.mjs.map +0 -1
- package/dist/_chunks/index-ethhTEkj.mjs.map +0 -1
- package/dist/_chunks/index-iNtwnT3f.mjs.map +0 -1
- package/dist/_chunks/index-rryiT0-Z.mjs.map +0 -1
|
@@ -12,20 +12,13 @@ import {
|
|
|
12
12
|
TextInput,
|
|
13
13
|
Typography,
|
|
14
14
|
} from '@strapi/design-system';
|
|
15
|
-
import {
|
|
16
|
-
CheckPagePermissions,
|
|
17
|
-
Form,
|
|
18
|
-
SettingsPageTitle,
|
|
19
|
-
useFetchClient,
|
|
20
|
-
useNotification,
|
|
21
|
-
useOverlayBlocker,
|
|
22
|
-
useTracking,
|
|
23
|
-
} from '@strapi/helper-plugin';
|
|
24
15
|
import { Check } from '@strapi/icons';
|
|
25
|
-
import {
|
|
16
|
+
import { Page, useTracking, useNotification, useFetchClient } from '@strapi/strapi/admin';
|
|
17
|
+
import { Formik, Form } from 'formik';
|
|
18
|
+
import { Helmet } from 'react-helmet';
|
|
26
19
|
import { useIntl } from 'react-intl';
|
|
27
20
|
import { useMutation } from 'react-query';
|
|
28
|
-
import {
|
|
21
|
+
import { useNavigate } from 'react-router-dom';
|
|
29
22
|
|
|
30
23
|
import UsersPermissions from '../../../components/UsersPermissions';
|
|
31
24
|
import { PERMISSIONS } from '../../../constants';
|
|
@@ -35,9 +28,8 @@ import { usePlugins } from '../hooks/usePlugins';
|
|
|
35
28
|
|
|
36
29
|
export const CreatePage = () => {
|
|
37
30
|
const { formatMessage } = useIntl();
|
|
38
|
-
const toggleNotification = useNotification();
|
|
39
|
-
const
|
|
40
|
-
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
31
|
+
const { toggleNotification } = useNotification();
|
|
32
|
+
const navigate = useNavigate();
|
|
41
33
|
const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
|
|
42
34
|
const { trackUsage } = useTracking();
|
|
43
35
|
const permissionsRef = React.useRef();
|
|
@@ -45,11 +37,11 @@ export const CreatePage = () => {
|
|
|
45
37
|
const mutation = useMutation((body) => post(`/users-permissions/roles`, body), {
|
|
46
38
|
onError() {
|
|
47
39
|
toggleNotification({
|
|
48
|
-
type: '
|
|
49
|
-
message: {
|
|
40
|
+
type: 'danger',
|
|
41
|
+
message: formatMessage({
|
|
50
42
|
id: 'notification.error',
|
|
51
43
|
defaultMessage: 'An error occurred',
|
|
52
|
-
},
|
|
44
|
+
}),
|
|
53
45
|
});
|
|
54
46
|
},
|
|
55
47
|
|
|
@@ -58,34 +50,34 @@ export const CreatePage = () => {
|
|
|
58
50
|
|
|
59
51
|
toggleNotification({
|
|
60
52
|
type: 'success',
|
|
61
|
-
message: {
|
|
53
|
+
message: formatMessage({
|
|
62
54
|
id: getTrad('Settings.roles.created'),
|
|
63
55
|
defaultMessage: 'Role created',
|
|
64
|
-
},
|
|
56
|
+
}),
|
|
65
57
|
});
|
|
66
58
|
|
|
67
59
|
// Forcing redirecting since we don't have the id in the response
|
|
68
|
-
|
|
60
|
+
navigate(-1);
|
|
69
61
|
},
|
|
70
62
|
});
|
|
71
63
|
|
|
72
64
|
const handleCreateRoleSubmit = async (data) => {
|
|
73
|
-
lockApp();
|
|
74
|
-
|
|
75
65
|
// TODO: refactor. Child -> parent component communication is evil;
|
|
76
66
|
// We should either move the provider one level up or move the state
|
|
77
67
|
// straight into redux.
|
|
78
68
|
const permissions = permissionsRef.current.getPermissions();
|
|
79
69
|
|
|
80
70
|
await mutation.mutate({ ...data, ...permissions, users: [] });
|
|
81
|
-
|
|
82
|
-
unlockApp();
|
|
83
71
|
};
|
|
84
72
|
|
|
85
73
|
return (
|
|
86
74
|
<Main>
|
|
87
|
-
|
|
88
|
-
|
|
75
|
+
<Helmet
|
|
76
|
+
title={formatMessage(
|
|
77
|
+
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
|
|
78
|
+
{ name: 'Roles' }
|
|
79
|
+
)}
|
|
80
|
+
/>
|
|
89
81
|
<Formik
|
|
90
82
|
enableReinitialize
|
|
91
83
|
initialValues={{ name: '', description: '' }}
|
|
@@ -193,7 +185,7 @@ export const CreatePage = () => {
|
|
|
193
185
|
};
|
|
194
186
|
|
|
195
187
|
export const ProtectedRolesCreatePage = () => (
|
|
196
|
-
<
|
|
188
|
+
<Page.Protect permissions={PERMISSIONS.createRole}>
|
|
197
189
|
<CreatePage />
|
|
198
|
-
</
|
|
190
|
+
</Page.Protect>
|
|
199
191
|
);
|
|
@@ -12,22 +12,19 @@ import {
|
|
|
12
12
|
GridItem,
|
|
13
13
|
Grid,
|
|
14
14
|
} from '@strapi/design-system';
|
|
15
|
+
import { Check } from '@strapi/icons';
|
|
15
16
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
SettingsPageTitle,
|
|
19
|
-
LoadingIndicatorPage,
|
|
20
|
-
Form,
|
|
17
|
+
Page,
|
|
18
|
+
BackButton,
|
|
21
19
|
useAPIErrorHandler,
|
|
22
|
-
useFetchClient,
|
|
23
20
|
useNotification,
|
|
24
|
-
|
|
25
|
-
} from '@strapi/
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
21
|
+
useFetchClient,
|
|
22
|
+
} from '@strapi/strapi/admin';
|
|
23
|
+
import { Formik, Form } from 'formik';
|
|
24
|
+
import { Helmet } from 'react-helmet';
|
|
28
25
|
import { useIntl } from 'react-intl';
|
|
29
26
|
import { useQuery, useMutation } from 'react-query';
|
|
30
|
-
import {
|
|
27
|
+
import { useMatch } from 'react-router-dom';
|
|
31
28
|
|
|
32
29
|
import UsersPermissions from '../../../components/UsersPermissions';
|
|
33
30
|
import { PERMISSIONS } from '../../../constants';
|
|
@@ -37,11 +34,10 @@ import { usePlugins } from '../hooks/usePlugins';
|
|
|
37
34
|
|
|
38
35
|
export const EditPage = () => {
|
|
39
36
|
const { formatMessage } = useIntl();
|
|
40
|
-
const toggleNotification = useNotification();
|
|
41
|
-
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
37
|
+
const { toggleNotification } = useNotification();
|
|
42
38
|
const {
|
|
43
39
|
params: { id },
|
|
44
|
-
} =
|
|
40
|
+
} = useMatch(`/settings/users-permissions/roles/:id`);
|
|
45
41
|
const { get } = useFetchClient();
|
|
46
42
|
const { isLoading: isLoadingPlugins, routes } = usePlugins();
|
|
47
43
|
const {
|
|
@@ -63,7 +59,7 @@ export const EditPage = () => {
|
|
|
63
59
|
const mutation = useMutation((body) => put(`/users-permissions/roles/${id}`, body), {
|
|
64
60
|
onError(error) {
|
|
65
61
|
toggleNotification({
|
|
66
|
-
type: '
|
|
62
|
+
type: 'danger',
|
|
67
63
|
message: formatAPIError(error),
|
|
68
64
|
});
|
|
69
65
|
},
|
|
@@ -71,10 +67,10 @@ export const EditPage = () => {
|
|
|
71
67
|
async onSuccess() {
|
|
72
68
|
toggleNotification({
|
|
73
69
|
type: 'success',
|
|
74
|
-
message: {
|
|
70
|
+
message: formatMessage({
|
|
75
71
|
id: getTrad('Settings.roles.created'),
|
|
76
72
|
defaultMessage: 'Role edited',
|
|
77
|
-
},
|
|
73
|
+
}),
|
|
78
74
|
});
|
|
79
75
|
|
|
80
76
|
await refetchRole();
|
|
@@ -82,24 +78,23 @@ export const EditPage = () => {
|
|
|
82
78
|
});
|
|
83
79
|
|
|
84
80
|
const handleEditRoleSubmit = async (data) => {
|
|
85
|
-
// Set loading state
|
|
86
|
-
lockApp();
|
|
87
|
-
|
|
88
81
|
const permissions = permissionsRef.current.getPermissions();
|
|
89
82
|
|
|
90
83
|
await mutation.mutate({ ...data, ...permissions, users: [] });
|
|
91
|
-
|
|
92
|
-
unlockApp();
|
|
93
84
|
};
|
|
94
85
|
|
|
95
86
|
if (isLoadingRole) {
|
|
96
|
-
return <
|
|
87
|
+
return <Page.Loading />;
|
|
97
88
|
}
|
|
98
89
|
|
|
99
90
|
return (
|
|
100
91
|
<Main>
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
<Helmet
|
|
93
|
+
title={formatMessage(
|
|
94
|
+
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
|
|
95
|
+
{ name: 'Roles' }
|
|
96
|
+
)}
|
|
97
|
+
/>
|
|
103
98
|
<Formik
|
|
104
99
|
enableReinitialize
|
|
105
100
|
initialValues={{ name: role.name, description: role.description }}
|
|
@@ -110,7 +105,7 @@ export const EditPage = () => {
|
|
|
110
105
|
<Form noValidate onSubmit={handleSubmit}>
|
|
111
106
|
<HeaderLayout
|
|
112
107
|
primaryAction={
|
|
113
|
-
!isLoadingPlugins
|
|
108
|
+
!isLoadingPlugins ? (
|
|
114
109
|
<Button
|
|
115
110
|
disabled={role.code === 'strapi-super-admin'}
|
|
116
111
|
type="submit"
|
|
@@ -122,18 +117,11 @@ export const EditPage = () => {
|
|
|
122
117
|
defaultMessage: 'Save',
|
|
123
118
|
})}
|
|
124
119
|
</Button>
|
|
125
|
-
)
|
|
120
|
+
) : null
|
|
126
121
|
}
|
|
127
122
|
title={role.name}
|
|
128
123
|
subtitle={role.description}
|
|
129
|
-
navigationAction={
|
|
130
|
-
<Link startIcon={<ArrowLeft />} to="/settings/users-permissions/roles">
|
|
131
|
-
{formatMessage({
|
|
132
|
-
id: 'global.back',
|
|
133
|
-
defaultMessage: 'Back',
|
|
134
|
-
})}
|
|
135
|
-
</Link>
|
|
136
|
-
}
|
|
124
|
+
navigationAction={<BackButton />}
|
|
137
125
|
/>
|
|
138
126
|
<ContentLayout>
|
|
139
127
|
<Flex
|
|
@@ -214,7 +202,7 @@ export const EditPage = () => {
|
|
|
214
202
|
};
|
|
215
203
|
|
|
216
204
|
export const ProtectedRolesEditPage = () => (
|
|
217
|
-
<
|
|
205
|
+
<Page.Protect permissions={PERMISSIONS.updateRole}>
|
|
218
206
|
<EditPage />
|
|
219
|
-
</
|
|
207
|
+
</Page.Protect>
|
|
220
208
|
);
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
import { Flex, IconButton, Link, Tbody, Td, Tr, Typography } from '@strapi/design-system';
|
|
4
|
-
import { CheckPermissions, onRowClick, pxToRem, stopPropagation } from '@strapi/helper-plugin';
|
|
5
4
|
import { Pencil, Trash } from '@strapi/icons';
|
|
6
5
|
import PropTypes from 'prop-types';
|
|
7
6
|
import { useIntl } from 'react-intl';
|
|
8
|
-
import {
|
|
7
|
+
import { useNavigate } from 'react-router-dom';
|
|
9
8
|
import styled from 'styled-components';
|
|
10
9
|
|
|
11
10
|
const EditLink = styled(Link)`
|
|
12
11
|
align-items: center;
|
|
13
|
-
height: ${
|
|
12
|
+
height: ${32 / 16}rem;
|
|
14
13
|
display: flex;
|
|
15
14
|
justify-content: center;
|
|
16
15
|
padding: ${({ theme }) => `${theme.spaces[2]}}`};
|
|
17
|
-
width: ${
|
|
16
|
+
width: ${32 / 16}rem;
|
|
18
17
|
|
|
19
18
|
svg {
|
|
20
|
-
height: ${
|
|
21
|
-
width: ${
|
|
19
|
+
height: ${12 / 16}rem;
|
|
20
|
+
width: ${12 / 16}rem;
|
|
22
21
|
|
|
23
22
|
path {
|
|
24
23
|
fill: ${({ theme }) => theme.colors.neutral500};
|
|
@@ -35,9 +34,9 @@ const EditLink = styled(Link)`
|
|
|
35
34
|
}
|
|
36
35
|
`;
|
|
37
36
|
|
|
38
|
-
const TableBody = ({ sortedRoles, canDelete,
|
|
37
|
+
const TableBody = ({ sortedRoles, canDelete, canUpdate, setRoleToDelete, onDelete }) => {
|
|
39
38
|
const { formatMessage } = useIntl();
|
|
40
|
-
const
|
|
39
|
+
const navigate = useNavigate();
|
|
41
40
|
const [showConfirmDelete, setShowConfirmDelete] = onDelete;
|
|
42
41
|
|
|
43
42
|
const checkCanDeleteRole = (role) =>
|
|
@@ -48,14 +47,10 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
48
47
|
setShowConfirmDelete(!showConfirmDelete);
|
|
49
48
|
};
|
|
50
49
|
|
|
51
|
-
const handleClickEdit = (id) => {
|
|
52
|
-
push(`/settings/users-permissions/roles/${id}`);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
50
|
return (
|
|
56
51
|
<Tbody>
|
|
57
52
|
{sortedRoles?.map((role) => (
|
|
58
|
-
<Tr key={role.name} {
|
|
53
|
+
<Tr key={role.name} onClick={() => navigate(role.id.toString())}>
|
|
59
54
|
<Td width="20%">
|
|
60
55
|
<Typography>{role.name}</Typography>
|
|
61
56
|
</Td>
|
|
@@ -74,10 +69,10 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
74
69
|
</Typography>
|
|
75
70
|
</Td>
|
|
76
71
|
<Td>
|
|
77
|
-
<Flex justifyContent="end" {
|
|
78
|
-
|
|
72
|
+
<Flex justifyContent="end" onClick={(e) => e.stopPropagation()}>
|
|
73
|
+
{canUpdate ? (
|
|
79
74
|
<EditLink
|
|
80
|
-
to={
|
|
75
|
+
to={role.id.toString()}
|
|
81
76
|
aria-label={formatMessage(
|
|
82
77
|
{ id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
|
|
83
78
|
{ target: `${role.name}` }
|
|
@@ -85,20 +80,18 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
85
80
|
>
|
|
86
81
|
<Pencil />
|
|
87
82
|
</EditLink>
|
|
88
|
-
|
|
83
|
+
) : null}
|
|
89
84
|
|
|
90
85
|
{checkCanDeleteRole(role) && (
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
/>
|
|
101
|
-
</CheckPermissions>
|
|
86
|
+
<IconButton
|
|
87
|
+
onClick={() => handleClickDelete(role.id.toString())}
|
|
88
|
+
noBorder
|
|
89
|
+
icon={<Trash />}
|
|
90
|
+
label={formatMessage(
|
|
91
|
+
{ id: 'global.delete-target', defaultMessage: 'Delete {target}' },
|
|
92
|
+
{ target: `${role.name}` }
|
|
93
|
+
)}
|
|
94
|
+
/>
|
|
102
95
|
)}
|
|
103
96
|
</Flex>
|
|
104
97
|
</Td>
|
|
@@ -112,6 +105,7 @@ export default TableBody;
|
|
|
112
105
|
|
|
113
106
|
TableBody.defaultProps = {
|
|
114
107
|
canDelete: false,
|
|
108
|
+
canUpdate: false,
|
|
115
109
|
};
|
|
116
110
|
|
|
117
111
|
TableBody.propTypes = {
|
|
@@ -120,4 +114,5 @@ TableBody.propTypes = {
|
|
|
120
114
|
setRoleToDelete: PropTypes.func.isRequired,
|
|
121
115
|
sortedRoles: PropTypes.array.isRequired,
|
|
122
116
|
canDelete: PropTypes.bool,
|
|
117
|
+
canUpdate: PropTypes.bool,
|
|
123
118
|
};
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
ContentLayout,
|
|
6
6
|
HeaderLayout,
|
|
7
7
|
Layout,
|
|
8
|
-
Main,
|
|
9
8
|
Table,
|
|
10
9
|
Th,
|
|
11
10
|
Thead,
|
|
@@ -13,50 +12,47 @@ import {
|
|
|
13
12
|
Typography,
|
|
14
13
|
useNotifyAT,
|
|
15
14
|
VisuallyHidden,
|
|
16
|
-
} from '@strapi/design-system';
|
|
17
|
-
import {
|
|
18
|
-
CheckPagePermissions,
|
|
19
|
-
CheckPermissions,
|
|
20
|
-
ConfirmDialog,
|
|
21
15
|
EmptyStateLayout,
|
|
22
|
-
LinkButton,
|
|
23
|
-
LoadingIndicatorPage,
|
|
24
|
-
NoPermissions,
|
|
25
|
-
SearchURLQuery,
|
|
26
|
-
SettingsPageTitle,
|
|
27
16
|
useCollator,
|
|
28
17
|
useFilter,
|
|
29
|
-
|
|
18
|
+
} from '@strapi/design-system';
|
|
19
|
+
import { LinkButton } from '@strapi/design-system/v2';
|
|
20
|
+
import { useRBAC } from '@strapi/helper-plugin';
|
|
21
|
+
import { Plus } from '@strapi/icons';
|
|
22
|
+
import {
|
|
23
|
+
ConfirmDialog,
|
|
24
|
+
useTracking,
|
|
25
|
+
Page,
|
|
26
|
+
SearchInput,
|
|
27
|
+
BackButton,
|
|
30
28
|
useNotification,
|
|
31
29
|
useQueryParams,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} from '
|
|
35
|
-
import { Plus } from '@strapi/icons';
|
|
30
|
+
useFetchClient,
|
|
31
|
+
} from '@strapi/strapi/admin';
|
|
32
|
+
import { Helmet } from 'react-helmet';
|
|
36
33
|
import { useIntl } from 'react-intl';
|
|
37
34
|
import { useMutation, useQuery } from 'react-query';
|
|
35
|
+
import { NavLink } from 'react-router-dom';
|
|
38
36
|
|
|
39
37
|
import { PERMISSIONS } from '../../../../constants';
|
|
40
38
|
import { getTrad } from '../../../../utils';
|
|
41
39
|
|
|
42
40
|
import TableBody from './components/TableBody';
|
|
43
|
-
import { deleteData, fetchData } from './utils/api';
|
|
44
41
|
|
|
45
42
|
export const RolesListPage = () => {
|
|
46
43
|
const { trackUsage } = useTracking();
|
|
47
44
|
const { formatMessage, locale } = useIntl();
|
|
48
|
-
const toggleNotification = useNotification();
|
|
45
|
+
const { toggleNotification } = useNotification();
|
|
49
46
|
const { notifyStatus } = useNotifyAT();
|
|
50
47
|
const [{ query }] = useQueryParams();
|
|
51
48
|
const _q = query?._q || '';
|
|
52
49
|
const [showConfirmDelete, setShowConfirmDelete] = useState(false);
|
|
53
|
-
const [isConfirmButtonLoading, setIsConfirmButtonLoading] = useState(false);
|
|
54
50
|
const [roleToDelete, setRoleToDelete] = useState();
|
|
55
|
-
|
|
51
|
+
const { del, get } = useFetchClient();
|
|
56
52
|
|
|
57
53
|
const {
|
|
58
54
|
isLoading: isLoadingForPermissions,
|
|
59
|
-
allowedActions: { canRead, canDelete },
|
|
55
|
+
allowedActions: { canRead, canDelete, canCreate, canUpdate },
|
|
60
56
|
} = useRBAC({
|
|
61
57
|
create: PERMISSIONS.createRole,
|
|
62
58
|
read: PERMISSIONS.readRoles,
|
|
@@ -69,12 +65,12 @@ export const RolesListPage = () => {
|
|
|
69
65
|
data: { roles },
|
|
70
66
|
isFetching,
|
|
71
67
|
refetch,
|
|
72
|
-
} = useQuery('get-roles', () => fetchData(toggleNotification, notifyStatus), {
|
|
68
|
+
} = useQuery('get-roles', () => fetchData(toggleNotification, formatMessage, notifyStatus), {
|
|
73
69
|
initialData: {},
|
|
74
70
|
enabled: canRead,
|
|
75
71
|
});
|
|
76
72
|
|
|
77
|
-
const {
|
|
73
|
+
const { contains } = useFilter(locale, {
|
|
78
74
|
sensitivity: 'base',
|
|
79
75
|
});
|
|
80
76
|
|
|
@@ -85,12 +81,39 @@ export const RolesListPage = () => {
|
|
|
85
81
|
sensitivity: 'base',
|
|
86
82
|
});
|
|
87
83
|
|
|
88
|
-
const isLoading = isLoadingForData || isFetching;
|
|
84
|
+
const isLoading = isLoadingForData || isFetching || isLoadingForPermissions;
|
|
89
85
|
|
|
90
86
|
const handleShowConfirmDelete = () => {
|
|
91
87
|
setShowConfirmDelete(!showConfirmDelete);
|
|
92
88
|
};
|
|
93
89
|
|
|
90
|
+
const deleteData = async (id, formatMessage, toggleNotification) => {
|
|
91
|
+
try {
|
|
92
|
+
await del(`/users-permissions/roles/${id}`);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
toggleNotification({
|
|
95
|
+
type: 'danger',
|
|
96
|
+
message: formatMessage({ id: 'notification.error', defaultMessage: 'An error occured' }),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const fetchData = async (toggleNotification, formatMessage, notifyStatus) => {
|
|
102
|
+
try {
|
|
103
|
+
const { data } = await get('/users-permissions/roles');
|
|
104
|
+
notifyStatus('The roles have loaded successfully');
|
|
105
|
+
|
|
106
|
+
return data;
|
|
107
|
+
} catch (err) {
|
|
108
|
+
toggleNotification({
|
|
109
|
+
type: 'danger',
|
|
110
|
+
message: formatMessage({ id: 'notification.error' }),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
throw new Error(err);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
94
117
|
const emptyLayout = {
|
|
95
118
|
roles: {
|
|
96
119
|
id: getTrad('Roles.empty'),
|
|
@@ -107,21 +130,19 @@ export const RolesListPage = () => {
|
|
|
107
130
|
defaultMessage: 'Roles',
|
|
108
131
|
});
|
|
109
132
|
|
|
110
|
-
const deleteMutation = useMutation((id) => deleteData(id, toggleNotification), {
|
|
133
|
+
const deleteMutation = useMutation((id) => deleteData(id, formatMessage, toggleNotification), {
|
|
111
134
|
async onSuccess() {
|
|
112
135
|
await refetch();
|
|
113
136
|
},
|
|
114
137
|
});
|
|
115
138
|
|
|
116
139
|
const handleConfirmDelete = async () => {
|
|
117
|
-
setIsConfirmButtonLoading(true);
|
|
118
140
|
await deleteMutation.mutateAsync(roleToDelete);
|
|
119
141
|
setShowConfirmDelete(!showConfirmDelete);
|
|
120
|
-
setIsConfirmButtonLoading(false);
|
|
121
142
|
};
|
|
122
143
|
|
|
123
144
|
const sortedRoles = (roles || [])
|
|
124
|
-
.filter((role) =>
|
|
145
|
+
.filter((role) => contains(role.name, _q) || contains(role.description, _q))
|
|
125
146
|
.sort(
|
|
126
147
|
(a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
|
|
127
148
|
);
|
|
@@ -131,10 +152,19 @@ export const RolesListPage = () => {
|
|
|
131
152
|
const colCount = 4;
|
|
132
153
|
const rowCount = (roles?.length || 0) + 1;
|
|
133
154
|
|
|
155
|
+
if (isLoading) {
|
|
156
|
+
return <Page.Loading />;
|
|
157
|
+
}
|
|
158
|
+
|
|
134
159
|
return (
|
|
135
160
|
<Layout>
|
|
136
|
-
<
|
|
137
|
-
|
|
161
|
+
<Helmet
|
|
162
|
+
title={formatMessage(
|
|
163
|
+
{ id: 'Settings.PageTitle', defaultMessage: 'Settings - {name}' },
|
|
164
|
+
{ name: pageTitle }
|
|
165
|
+
)}
|
|
166
|
+
/>
|
|
167
|
+
<Page.Main>
|
|
138
168
|
<HeaderLayout
|
|
139
169
|
title={formatMessage({
|
|
140
170
|
id: 'global.roles',
|
|
@@ -145,9 +175,10 @@ export const RolesListPage = () => {
|
|
|
145
175
|
defaultMessage: 'List of roles',
|
|
146
176
|
})}
|
|
147
177
|
primaryAction={
|
|
148
|
-
|
|
178
|
+
canCreate ? (
|
|
149
179
|
<LinkButton
|
|
150
|
-
to="
|
|
180
|
+
to="new"
|
|
181
|
+
as={NavLink}
|
|
151
182
|
onClick={() => trackUsage('willCreateRole')}
|
|
152
183
|
startIcon={<Plus />}
|
|
153
184
|
size="S"
|
|
@@ -157,13 +188,14 @@ export const RolesListPage = () => {
|
|
|
157
188
|
defaultMessage: 'Add new role',
|
|
158
189
|
})}
|
|
159
190
|
</LinkButton>
|
|
160
|
-
|
|
191
|
+
) : null
|
|
161
192
|
}
|
|
193
|
+
navigationAction={<BackButton />}
|
|
162
194
|
/>
|
|
163
195
|
|
|
164
196
|
<ActionLayout
|
|
165
197
|
startActions={
|
|
166
|
-
<
|
|
198
|
+
<SearchInput
|
|
167
199
|
label={formatMessage({
|
|
168
200
|
id: 'app.component.search.label',
|
|
169
201
|
defaultMessage: 'Search',
|
|
@@ -173,8 +205,7 @@ export const RolesListPage = () => {
|
|
|
173
205
|
/>
|
|
174
206
|
|
|
175
207
|
<ContentLayout>
|
|
176
|
-
{!canRead && <NoPermissions />}
|
|
177
|
-
{(isLoading || isLoadingForPermissions) && <LoadingIndicatorPage />}
|
|
208
|
+
{!canRead && <Page.NoPermissions />}
|
|
178
209
|
{canRead && sortedRoles && sortedRoles?.length ? (
|
|
179
210
|
<Table colCount={colCount} rowCount={rowCount}>
|
|
180
211
|
<Thead>
|
|
@@ -213,30 +244,30 @@ export const RolesListPage = () => {
|
|
|
213
244
|
<TableBody
|
|
214
245
|
sortedRoles={sortedRoles}
|
|
215
246
|
canDelete={canDelete}
|
|
247
|
+
canUpdate={canUpdate}
|
|
216
248
|
permissions={PERMISSIONS}
|
|
217
249
|
setRoleToDelete={setRoleToDelete}
|
|
218
250
|
onDelete={[showConfirmDelete, setShowConfirmDelete]}
|
|
219
251
|
/>
|
|
220
252
|
</Table>
|
|
221
253
|
) : (
|
|
222
|
-
<EmptyStateLayout content={emptyLayout[emptyContent]} />
|
|
254
|
+
<EmptyStateLayout content={formatMessage(emptyLayout[emptyContent])} />
|
|
223
255
|
)}
|
|
224
256
|
</ContentLayout>
|
|
225
257
|
<ConfirmDialog
|
|
226
|
-
isConfirmButtonLoading={isConfirmButtonLoading}
|
|
227
258
|
onConfirm={handleConfirmDelete}
|
|
228
|
-
|
|
259
|
+
onClose={handleShowConfirmDelete}
|
|
229
260
|
isOpen={showConfirmDelete}
|
|
230
261
|
/>
|
|
231
|
-
</Main>
|
|
262
|
+
</Page.Main>
|
|
232
263
|
</Layout>
|
|
233
264
|
);
|
|
234
265
|
};
|
|
235
266
|
|
|
236
267
|
export const ProtectedRolesListPage = () => {
|
|
237
268
|
return (
|
|
238
|
-
<
|
|
269
|
+
<Page.Protect permissions={PERMISSIONS.accessRoles}>
|
|
239
270
|
<RolesListPage />
|
|
240
|
-
</
|
|
271
|
+
</Page.Protect>
|
|
241
272
|
);
|
|
242
273
|
};
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"Settings.roles.deleted": "Role deleted",
|
|
61
61
|
"Settings.roles.edited": "Role edited",
|
|
62
62
|
"Settings.section-label": "Users & Permissions plugin",
|
|
63
|
-
"components.Input.error.validation.email": "This is
|
|
63
|
+
"components.Input.error.validation.email": "This is not a valid email",
|
|
64
64
|
"components.Input.error.validation.json": "This doesn't match the JSON format",
|
|
65
65
|
"components.Input.error.validation.max": "The value is too high.",
|
|
66
66
|
"components.Input.error.validation.maxLength": "The value is too long.",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const prefixPluginTranslations = (trad, pluginId) => {
|
|
2
|
+
if (!pluginId) {
|
|
3
|
+
throw new TypeError("pluginId can't be empty");
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return Object.keys(trad).reduce((acc, current) => {
|
|
7
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
|
8
|
+
|
|
9
|
+
return acc;
|
|
10
|
+
}, {});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { prefixPluginTranslations };
|