@strapi/plugin-users-permissions 0.0.0-next.dff425769af4d4d006725a10c395f59637403653 → 0.0.0-next.e037a7b2d1f48b7bd8bcd0d9400ca0f9ded8a982
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/BoundRoute/index.js +5 -3
- package/admin/src/components/FormModal/Input/index.js +6 -3
- package/admin/src/components/FormModal/index.js +13 -10
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +1 -1
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +26 -5
- package/admin/src/components/Permissions/PermissionRow/index.js +4 -2
- package/admin/src/components/Permissions/index.js +6 -5
- package/admin/src/components/Policies/index.js +3 -2
- package/admin/src/components/UsersPermissions/index.js +8 -5
- package/admin/src/{permissions.js → constants.js} +1 -3
- package/admin/src/contexts/UsersPermissionsContext/index.js +1 -0
- package/admin/src/index.js +14 -13
- package/admin/src/pages/AdvancedSettings/index.js +68 -52
- package/admin/src/pages/AdvancedSettings/utils/schema.js +1 -1
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +14 -13
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +9 -7
- package/admin/src/pages/EmailTemplates/index.js +77 -63
- package/admin/src/pages/EmailTemplates/utils/schema.js +1 -1
- package/admin/src/pages/Providers/index.js +91 -86
- package/admin/src/pages/Providers/utils/forms.js +1 -1
- package/admin/src/pages/Roles/{CreatePage/utils/schema.js → constants.js} +2 -4
- package/admin/src/pages/Roles/hooks/usePlugins.js +78 -0
- package/admin/src/pages/Roles/index.js +17 -11
- package/admin/src/pages/Roles/pages/CreatePage.js +190 -0
- package/admin/src/pages/Roles/pages/EditPage.js +211 -0
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/components/TableBody.js +46 -15
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/index.js +67 -49
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/utils/api.js +3 -4
- package/admin/src/translations/ru.json +50 -26
- package/admin/src/translations/zh-Hans.json +80 -80
- package/admin/src/utils/index.js +1 -2
- package/documentation/content-api.yaml +23 -15
- package/jest.config.front.js +2 -0
- package/package.json +23 -27
- package/server/bootstrap/index.js +35 -0
- package/server/controllers/auth.js +46 -7
- package/server/controllers/user.js +12 -1
- package/server/middlewares/rateLimit.js +41 -21
- package/server/register.js +7 -1
- package/server/services/providers-registry.js +1 -1
- package/admin/src/hooks/index.js +0 -5
- package/admin/src/hooks/useFetchRole/index.js +0 -64
- 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/usePlugins/index.js +0 -67
- package/admin/src/hooks/usePlugins/init.js +0 -5
- package/admin/src/hooks/usePlugins/reducer.js +0 -34
- package/admin/src/hooks/useRolesList/index.js +0 -63
- 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 -17
- package/admin/src/pages/EmailTemplates/utils/api.js +0 -17
- package/admin/src/pages/Providers/reducer.js +0 -54
- package/admin/src/pages/Providers/utils/api.js +0 -25
- package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
- package/admin/src/pages/Roles/CreatePage/index.js +0 -182
- package/admin/src/pages/Roles/EditPage/index.js +0 -194
- package/admin/src/pages/Roles/EditPage/utils/schema.js +0 -9
- package/admin/src/pages/Roles/ProtectedCreatePage/index.js +0 -12
- package/admin/src/pages/Roles/ProtectedEditPage/index.js +0 -12
- package/admin/src/pages/Roles/ProtectedListPage/index.js +0 -15
- package/admin/src/utils/getRequestURL.js +0 -5
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
ContentLayout,
|
|
6
|
+
Flex,
|
|
7
|
+
Grid,
|
|
8
|
+
GridItem,
|
|
9
|
+
HeaderLayout,
|
|
10
|
+
Main,
|
|
11
|
+
Textarea,
|
|
12
|
+
TextInput,
|
|
13
|
+
Typography,
|
|
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
|
+
import { Check } from '@strapi/icons';
|
|
25
|
+
import { Formik } from 'formik';
|
|
26
|
+
import { useIntl } from 'react-intl';
|
|
27
|
+
import { useMutation } from 'react-query';
|
|
28
|
+
import { useHistory } from 'react-router-dom';
|
|
29
|
+
|
|
30
|
+
import UsersPermissions from '../../../components/UsersPermissions';
|
|
31
|
+
import { PERMISSIONS } from '../../../constants';
|
|
32
|
+
import getTrad from '../../../utils/getTrad';
|
|
33
|
+
import { createRoleSchema } from '../constants';
|
|
34
|
+
import { usePlugins } from '../hooks/usePlugins';
|
|
35
|
+
|
|
36
|
+
export const CreatePage = () => {
|
|
37
|
+
const { formatMessage } = useIntl();
|
|
38
|
+
const toggleNotification = useNotification();
|
|
39
|
+
const { goBack } = useHistory();
|
|
40
|
+
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
41
|
+
const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
|
|
42
|
+
const { trackUsage } = useTracking();
|
|
43
|
+
const permissionsRef = React.useRef();
|
|
44
|
+
const { post } = useFetchClient();
|
|
45
|
+
const mutation = useMutation((body) => post(`/users-permissions/roles`, body), {
|
|
46
|
+
onError() {
|
|
47
|
+
toggleNotification({
|
|
48
|
+
type: 'warning',
|
|
49
|
+
message: {
|
|
50
|
+
id: 'notification.error',
|
|
51
|
+
defaultMessage: 'An error occurred',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
onSuccess() {
|
|
57
|
+
trackUsage('didCreateRole');
|
|
58
|
+
|
|
59
|
+
toggleNotification({
|
|
60
|
+
type: 'success',
|
|
61
|
+
message: {
|
|
62
|
+
id: getTrad('Settings.roles.created'),
|
|
63
|
+
defaultMessage: 'Role created',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Forcing redirecting since we don't have the id in the response
|
|
68
|
+
goBack();
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const handleCreateRoleSubmit = async (data) => {
|
|
73
|
+
lockApp();
|
|
74
|
+
|
|
75
|
+
// TODO: refactor. Child -> parent component communication is evil;
|
|
76
|
+
// We should either move the provider one level up or move the state
|
|
77
|
+
// straight into redux.
|
|
78
|
+
const permissions = permissionsRef.current.getPermissions();
|
|
79
|
+
|
|
80
|
+
await mutation.mutate({ ...data, ...permissions, users: [] });
|
|
81
|
+
|
|
82
|
+
unlockApp();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Main>
|
|
87
|
+
{/* TODO: This needs to be translated */}
|
|
88
|
+
<SettingsPageTitle name="Roles" />
|
|
89
|
+
<Formik
|
|
90
|
+
enableReinitialize
|
|
91
|
+
initialValues={{ name: '', description: '' }}
|
|
92
|
+
onSubmit={handleCreateRoleSubmit}
|
|
93
|
+
validationSchema={createRoleSchema}
|
|
94
|
+
>
|
|
95
|
+
{({ handleSubmit, values, handleChange, errors }) => (
|
|
96
|
+
<Form noValidate onSubmit={handleSubmit}>
|
|
97
|
+
<HeaderLayout
|
|
98
|
+
primaryAction={
|
|
99
|
+
!isLoadingPlugins && (
|
|
100
|
+
<Button type="submit" loading={mutation.isLoading} startIcon={<Check />}>
|
|
101
|
+
{formatMessage({
|
|
102
|
+
id: 'global.save',
|
|
103
|
+
defaultMessage: 'Save',
|
|
104
|
+
})}
|
|
105
|
+
</Button>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
title={formatMessage({
|
|
109
|
+
id: 'Settings.roles.create.title',
|
|
110
|
+
defaultMessage: 'Create a role',
|
|
111
|
+
})}
|
|
112
|
+
subtitle={formatMessage({
|
|
113
|
+
id: 'Settings.roles.create.description',
|
|
114
|
+
defaultMessage: 'Define the rights given to the role',
|
|
115
|
+
})}
|
|
116
|
+
/>
|
|
117
|
+
<ContentLayout>
|
|
118
|
+
<Flex
|
|
119
|
+
background="neutral0"
|
|
120
|
+
direction="column"
|
|
121
|
+
alignItems="stretch"
|
|
122
|
+
gap={7}
|
|
123
|
+
hasRadius
|
|
124
|
+
paddingTop={6}
|
|
125
|
+
paddingBottom={6}
|
|
126
|
+
paddingLeft={7}
|
|
127
|
+
paddingRight={7}
|
|
128
|
+
shadow="filterShadow"
|
|
129
|
+
>
|
|
130
|
+
<Flex direction="column" alignItems="stretch">
|
|
131
|
+
<Typography variant="delta" as="h2">
|
|
132
|
+
{formatMessage({
|
|
133
|
+
id: getTrad('EditPage.form.roles'),
|
|
134
|
+
defaultMessage: 'Role details',
|
|
135
|
+
})}
|
|
136
|
+
</Typography>
|
|
137
|
+
|
|
138
|
+
<Grid gap={4}>
|
|
139
|
+
<GridItem col={6}>
|
|
140
|
+
<TextInput
|
|
141
|
+
name="name"
|
|
142
|
+
value={values.name || ''}
|
|
143
|
+
onChange={handleChange}
|
|
144
|
+
label={formatMessage({
|
|
145
|
+
id: 'global.name',
|
|
146
|
+
defaultMessage: 'Name',
|
|
147
|
+
})}
|
|
148
|
+
error={errors?.name ? formatMessage({ id: errors.name }) : false}
|
|
149
|
+
required
|
|
150
|
+
/>
|
|
151
|
+
</GridItem>
|
|
152
|
+
<GridItem col={6}>
|
|
153
|
+
<Textarea
|
|
154
|
+
id="description"
|
|
155
|
+
value={values.description || ''}
|
|
156
|
+
onChange={handleChange}
|
|
157
|
+
label={formatMessage({
|
|
158
|
+
id: 'global.description',
|
|
159
|
+
defaultMessage: 'Description',
|
|
160
|
+
})}
|
|
161
|
+
error={
|
|
162
|
+
errors?.description ? formatMessage({ id: errors.description }) : false
|
|
163
|
+
}
|
|
164
|
+
required
|
|
165
|
+
/>
|
|
166
|
+
</GridItem>
|
|
167
|
+
</Grid>
|
|
168
|
+
</Flex>
|
|
169
|
+
|
|
170
|
+
{!isLoadingPlugins && (
|
|
171
|
+
<UsersPermissions
|
|
172
|
+
ref={permissionsRef}
|
|
173
|
+
permissions={permissions}
|
|
174
|
+
routes={routes}
|
|
175
|
+
/>
|
|
176
|
+
)}
|
|
177
|
+
</Flex>
|
|
178
|
+
</ContentLayout>
|
|
179
|
+
</Form>
|
|
180
|
+
)}
|
|
181
|
+
</Formik>
|
|
182
|
+
</Main>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const ProtectedRolesCreatePage = () => (
|
|
187
|
+
<CheckPagePermissions permissions={PERMISSIONS.createRole}>
|
|
188
|
+
<CreatePage />
|
|
189
|
+
</CheckPagePermissions>
|
|
190
|
+
);
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ContentLayout,
|
|
5
|
+
HeaderLayout,
|
|
6
|
+
Main,
|
|
7
|
+
Button,
|
|
8
|
+
Flex,
|
|
9
|
+
TextInput,
|
|
10
|
+
Textarea,
|
|
11
|
+
Typography,
|
|
12
|
+
GridItem,
|
|
13
|
+
Grid,
|
|
14
|
+
} from '@strapi/design-system';
|
|
15
|
+
import {
|
|
16
|
+
CheckPagePermissions,
|
|
17
|
+
useOverlayBlocker,
|
|
18
|
+
SettingsPageTitle,
|
|
19
|
+
LoadingIndicatorPage,
|
|
20
|
+
Form,
|
|
21
|
+
useAPIErrorHandler,
|
|
22
|
+
useFetchClient,
|
|
23
|
+
useNotification,
|
|
24
|
+
Link,
|
|
25
|
+
} from '@strapi/helper-plugin';
|
|
26
|
+
import { ArrowLeft, Check } from '@strapi/icons';
|
|
27
|
+
import { Formik } from 'formik';
|
|
28
|
+
import { useIntl } from 'react-intl';
|
|
29
|
+
import { useQuery, useMutation } from 'react-query';
|
|
30
|
+
import { useRouteMatch } from 'react-router-dom';
|
|
31
|
+
|
|
32
|
+
import UsersPermissions from '../../../components/UsersPermissions';
|
|
33
|
+
import { PERMISSIONS } from '../../../constants';
|
|
34
|
+
import getTrad from '../../../utils/getTrad';
|
|
35
|
+
import { createRoleSchema } from '../constants';
|
|
36
|
+
import { usePlugins } from '../hooks/usePlugins';
|
|
37
|
+
|
|
38
|
+
export const EditPage = () => {
|
|
39
|
+
const { formatMessage } = useIntl();
|
|
40
|
+
const toggleNotification = useNotification();
|
|
41
|
+
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
42
|
+
const {
|
|
43
|
+
params: { id },
|
|
44
|
+
} = useRouteMatch(`/settings/users-permissions/roles/:id`);
|
|
45
|
+
const { get } = useFetchClient();
|
|
46
|
+
const { isLoading: isLoadingPlugins, routes } = usePlugins();
|
|
47
|
+
const {
|
|
48
|
+
data: role,
|
|
49
|
+
isLoading: isLoadingRole,
|
|
50
|
+
refetch: refetchRole,
|
|
51
|
+
} = useQuery(['users-permissions', 'role', id], async () => {
|
|
52
|
+
// TODO: why doesn't this endpoint follow the admin API conventions?
|
|
53
|
+
const {
|
|
54
|
+
data: { role },
|
|
55
|
+
} = await get(`/users-permissions/roles/${id}`);
|
|
56
|
+
|
|
57
|
+
return role;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const permissionsRef = React.useRef();
|
|
61
|
+
const { put } = useFetchClient();
|
|
62
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
63
|
+
const mutation = useMutation((body) => put(`/users-permissions/roles/${id}`, body), {
|
|
64
|
+
onError(error) {
|
|
65
|
+
toggleNotification({
|
|
66
|
+
type: 'warning',
|
|
67
|
+
message: formatAPIError(error),
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
async onSuccess() {
|
|
72
|
+
toggleNotification({
|
|
73
|
+
type: 'success',
|
|
74
|
+
message: {
|
|
75
|
+
id: getTrad('Settings.roles.created'),
|
|
76
|
+
defaultMessage: 'Role edited',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await refetchRole();
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const handleEditRoleSubmit = async (data) => {
|
|
85
|
+
// Set loading state
|
|
86
|
+
lockApp();
|
|
87
|
+
|
|
88
|
+
const permissions = permissionsRef.current.getPermissions();
|
|
89
|
+
|
|
90
|
+
await mutation.mutate({ ...data, ...permissions, users: [] });
|
|
91
|
+
|
|
92
|
+
unlockApp();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (isLoadingRole) {
|
|
96
|
+
return <LoadingIndicatorPage />;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Main>
|
|
101
|
+
{/* TODO: this needs to be translated */}
|
|
102
|
+
<SettingsPageTitle name="Roles" />
|
|
103
|
+
<Formik
|
|
104
|
+
enableReinitialize
|
|
105
|
+
initialValues={{ name: role.name, description: role.description }}
|
|
106
|
+
onSubmit={handleEditRoleSubmit}
|
|
107
|
+
validationSchema={createRoleSchema}
|
|
108
|
+
>
|
|
109
|
+
{({ handleSubmit, values, handleChange, errors }) => (
|
|
110
|
+
<Form noValidate onSubmit={handleSubmit}>
|
|
111
|
+
<HeaderLayout
|
|
112
|
+
primaryAction={
|
|
113
|
+
!isLoadingPlugins && (
|
|
114
|
+
<Button
|
|
115
|
+
disabled={role.code === 'strapi-super-admin'}
|
|
116
|
+
type="submit"
|
|
117
|
+
loading={mutation.isLoading}
|
|
118
|
+
startIcon={<Check />}
|
|
119
|
+
>
|
|
120
|
+
{formatMessage({
|
|
121
|
+
id: 'global.save',
|
|
122
|
+
defaultMessage: 'Save',
|
|
123
|
+
})}
|
|
124
|
+
</Button>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
title={role.name}
|
|
128
|
+
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
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
<ContentLayout>
|
|
139
|
+
<Flex
|
|
140
|
+
background="neutral0"
|
|
141
|
+
direction="column"
|
|
142
|
+
alignItems="stretch"
|
|
143
|
+
gap={7}
|
|
144
|
+
hasRadius
|
|
145
|
+
paddingTop={6}
|
|
146
|
+
paddingBottom={6}
|
|
147
|
+
paddingLeft={7}
|
|
148
|
+
paddingRight={7}
|
|
149
|
+
shadow="filterShadow"
|
|
150
|
+
>
|
|
151
|
+
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
152
|
+
<Typography variant="delta" as="h2">
|
|
153
|
+
{formatMessage({
|
|
154
|
+
id: getTrad('EditPage.form.roles'),
|
|
155
|
+
defaultMessage: 'Role details',
|
|
156
|
+
})}
|
|
157
|
+
</Typography>
|
|
158
|
+
|
|
159
|
+
<Grid gap={4}>
|
|
160
|
+
<GridItem col={6}>
|
|
161
|
+
<TextInput
|
|
162
|
+
name="name"
|
|
163
|
+
value={values.name || ''}
|
|
164
|
+
onChange={handleChange}
|
|
165
|
+
label={formatMessage({
|
|
166
|
+
id: 'global.name',
|
|
167
|
+
defaultMessage: 'Name',
|
|
168
|
+
})}
|
|
169
|
+
error={errors?.name ? formatMessage({ id: errors.name }) : false}
|
|
170
|
+
required
|
|
171
|
+
/>
|
|
172
|
+
</GridItem>
|
|
173
|
+
<GridItem col={6}>
|
|
174
|
+
<Textarea
|
|
175
|
+
id="description"
|
|
176
|
+
value={values.description || ''}
|
|
177
|
+
onChange={handleChange}
|
|
178
|
+
label={formatMessage({
|
|
179
|
+
id: 'global.description',
|
|
180
|
+
defaultMessage: 'Description',
|
|
181
|
+
})}
|
|
182
|
+
error={
|
|
183
|
+
errors?.description ? formatMessage({ id: errors.description }) : false
|
|
184
|
+
}
|
|
185
|
+
required
|
|
186
|
+
/>
|
|
187
|
+
</GridItem>
|
|
188
|
+
</Grid>
|
|
189
|
+
</Flex>
|
|
190
|
+
|
|
191
|
+
{!isLoadingPlugins && (
|
|
192
|
+
<UsersPermissions
|
|
193
|
+
ref={permissionsRef}
|
|
194
|
+
permissions={role.permissions}
|
|
195
|
+
routes={routes}
|
|
196
|
+
/>
|
|
197
|
+
)}
|
|
198
|
+
</Flex>
|
|
199
|
+
</ContentLayout>
|
|
200
|
+
</Form>
|
|
201
|
+
)}
|
|
202
|
+
</Formik>
|
|
203
|
+
</Main>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const ProtectedRolesEditPage = () => (
|
|
208
|
+
<CheckPagePermissions permissions={PERMISSIONS.updateRole}>
|
|
209
|
+
<EditPage />
|
|
210
|
+
</CheckPagePermissions>
|
|
211
|
+
);
|
|
@@ -1,12 +1,39 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
import {
|
|
2
|
+
|
|
3
|
+
import { Flex, IconButton, Link, Tbody, Td, Tr, Typography } from '@strapi/design-system';
|
|
4
|
+
import { CheckPermissions, onRowClick, pxToRem, stopPropagation } from '@strapi/helper-plugin';
|
|
4
5
|
import { Pencil, Trash } from '@strapi/icons';
|
|
5
|
-
import
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
6
7
|
import { useIntl } from 'react-intl';
|
|
7
8
|
import { useHistory } from 'react-router-dom';
|
|
9
|
+
import styled from 'styled-components';
|
|
10
|
+
|
|
11
|
+
const EditLink = styled(Link)`
|
|
12
|
+
align-items: center;
|
|
13
|
+
height: ${pxToRem(32)};
|
|
14
|
+
display: flex;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
padding: ${({ theme }) => `${theme.spaces[2]}}`};
|
|
17
|
+
width: ${pxToRem(32)};
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
svg {
|
|
20
|
+
height: ${pxToRem(12)};
|
|
21
|
+
width: ${pxToRem(12)};
|
|
22
|
+
|
|
23
|
+
path {
|
|
24
|
+
fill: ${({ theme }) => theme.colors.neutral500};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&:hover,
|
|
29
|
+
&:focus {
|
|
30
|
+
svg {
|
|
31
|
+
path {
|
|
32
|
+
fill: ${({ theme }) => theme.colors.neutral800};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
10
37
|
|
|
11
38
|
const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
|
|
12
39
|
const { formatMessage } = useIntl();
|
|
@@ -22,7 +49,7 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
22
49
|
};
|
|
23
50
|
|
|
24
51
|
const handleClickEdit = (id) => {
|
|
25
|
-
push(`/settings
|
|
52
|
+
push(`/settings/users-permissions/roles/${id}`);
|
|
26
53
|
};
|
|
27
54
|
|
|
28
55
|
return (
|
|
@@ -37,25 +64,29 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
37
64
|
</Td>
|
|
38
65
|
<Td width="30%">
|
|
39
66
|
<Typography>
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
{formatMessage(
|
|
68
|
+
{
|
|
69
|
+
id: 'Roles.RoleRow.user-count',
|
|
70
|
+
defaultMessage: '{number, plural, =0 {# user} one {# user} other {# users}}',
|
|
71
|
+
},
|
|
72
|
+
{ number: role.nb_users }
|
|
73
|
+
)}
|
|
44
74
|
</Typography>
|
|
45
75
|
</Td>
|
|
46
76
|
<Td>
|
|
47
77
|
<Flex justifyContent="end" {...stopPropagation}>
|
|
48
78
|
<CheckPermissions permissions={permissions.updateRole}>
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
icon={<Pencil />}
|
|
53
|
-
label={formatMessage(
|
|
79
|
+
<EditLink
|
|
80
|
+
to={`/settings/users-permissions/roles/${role.id}`}
|
|
81
|
+
aria-label={formatMessage(
|
|
54
82
|
{ id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
|
|
55
83
|
{ target: `${role.name}` }
|
|
56
84
|
)}
|
|
57
|
-
|
|
85
|
+
>
|
|
86
|
+
<Pencil />
|
|
87
|
+
</EditLink>
|
|
58
88
|
</CheckPermissions>
|
|
89
|
+
|
|
59
90
|
{checkCanDeleteRole(role) && (
|
|
60
91
|
<CheckPermissions permissions={permissions.deleteRole}>
|
|
61
92
|
<IconButton
|
|
@@ -1,49 +1,50 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
+
ActionLayout,
|
|
5
|
+
ContentLayout,
|
|
4
6
|
HeaderLayout,
|
|
5
7
|
Layout,
|
|
6
|
-
ContentLayout,
|
|
7
|
-
ActionLayout,
|
|
8
8
|
Main,
|
|
9
9
|
Table,
|
|
10
|
-
Tr,
|
|
11
|
-
Thead,
|
|
12
10
|
Th,
|
|
11
|
+
Thead,
|
|
12
|
+
Tr,
|
|
13
13
|
Typography,
|
|
14
14
|
useNotifyAT,
|
|
15
15
|
VisuallyHidden,
|
|
16
16
|
} from '@strapi/design-system';
|
|
17
|
-
import { Plus } from '@strapi/icons';
|
|
18
17
|
import {
|
|
19
|
-
|
|
20
|
-
SettingsPageTitle,
|
|
18
|
+
CheckPagePermissions,
|
|
21
19
|
CheckPermissions,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
ConfirmDialog,
|
|
21
|
+
EmptyStateLayout,
|
|
22
|
+
LinkButton,
|
|
25
23
|
LoadingIndicatorPage,
|
|
24
|
+
NoPermissions,
|
|
26
25
|
SearchURLQuery,
|
|
26
|
+
SettingsPageTitle,
|
|
27
|
+
useCollator,
|
|
28
|
+
useFilter,
|
|
27
29
|
useFocusWhenNavigate,
|
|
30
|
+
useNotification,
|
|
28
31
|
useQueryParams,
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
useRBAC,
|
|
33
|
+
useTracking,
|
|
31
34
|
} from '@strapi/helper-plugin';
|
|
35
|
+
import { Plus } from '@strapi/icons';
|
|
32
36
|
import { useIntl } from 'react-intl';
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
import
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import { getTrad } from '../../../utils';
|
|
39
|
-
import pluginId from '../../../pluginId';
|
|
40
|
-
import permissions from '../../../permissions';
|
|
37
|
+
import { useMutation, useQuery } from 'react-query';
|
|
38
|
+
|
|
39
|
+
import { PERMISSIONS } from '../../../../constants';
|
|
40
|
+
import { getTrad } from '../../../../utils';
|
|
41
|
+
|
|
41
42
|
import TableBody from './components/TableBody';
|
|
43
|
+
import { deleteData, fetchData } from './utils/api';
|
|
42
44
|
|
|
43
|
-
const
|
|
45
|
+
export const RolesListPage = () => {
|
|
44
46
|
const { trackUsage } = useTracking();
|
|
45
|
-
const { formatMessage } = useIntl();
|
|
46
|
-
const { push } = useHistory();
|
|
47
|
+
const { formatMessage, locale } = useIntl();
|
|
47
48
|
const toggleNotification = useNotification();
|
|
48
49
|
const { notifyStatus } = useNotifyAT();
|
|
49
50
|
const [{ query }] = useQueryParams();
|
|
@@ -53,37 +54,38 @@ const RoleListPage = () => {
|
|
|
53
54
|
const [roleToDelete, setRoleToDelete] = useState();
|
|
54
55
|
useFocusWhenNavigate();
|
|
55
56
|
|
|
56
|
-
const queryClient = useQueryClient();
|
|
57
|
-
|
|
58
|
-
const updatePermissions = useMemo(() => {
|
|
59
|
-
return {
|
|
60
|
-
create: permissions.createRole,
|
|
61
|
-
read: permissions.readRoles,
|
|
62
|
-
update: permissions.updateRole,
|
|
63
|
-
delete: permissions.deleteRole,
|
|
64
|
-
};
|
|
65
|
-
}, []);
|
|
66
|
-
|
|
67
57
|
const {
|
|
68
58
|
isLoading: isLoadingForPermissions,
|
|
69
59
|
allowedActions: { canRead, canDelete },
|
|
70
|
-
} = useRBAC(
|
|
60
|
+
} = useRBAC({
|
|
61
|
+
create: PERMISSIONS.createRole,
|
|
62
|
+
read: PERMISSIONS.readRoles,
|
|
63
|
+
update: PERMISSIONS.updateRole,
|
|
64
|
+
delete: PERMISSIONS.deleteRole,
|
|
65
|
+
});
|
|
71
66
|
|
|
72
67
|
const {
|
|
73
68
|
isLoading: isLoadingForData,
|
|
74
69
|
data: { roles },
|
|
75
70
|
isFetching,
|
|
71
|
+
refetch,
|
|
76
72
|
} = useQuery('get-roles', () => fetchData(toggleNotification, notifyStatus), {
|
|
77
73
|
initialData: {},
|
|
78
74
|
enabled: canRead,
|
|
79
75
|
});
|
|
80
76
|
|
|
81
|
-
const
|
|
77
|
+
const { includes } = useFilter(locale, {
|
|
78
|
+
sensitivity: 'base',
|
|
79
|
+
});
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
/**
|
|
82
|
+
* @type {Intl.Collator}
|
|
83
|
+
*/
|
|
84
|
+
const formatter = useCollator(locale, {
|
|
85
|
+
sensitivity: 'base',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const isLoading = isLoadingForData || isFetching;
|
|
87
89
|
|
|
88
90
|
const handleShowConfirmDelete = () => {
|
|
89
91
|
setShowConfirmDelete(!showConfirmDelete);
|
|
@@ -107,7 +109,7 @@ const RoleListPage = () => {
|
|
|
107
109
|
|
|
108
110
|
const deleteMutation = useMutation((id) => deleteData(id, toggleNotification), {
|
|
109
111
|
async onSuccess() {
|
|
110
|
-
await
|
|
112
|
+
await refetch();
|
|
111
113
|
},
|
|
112
114
|
});
|
|
113
115
|
|
|
@@ -118,7 +120,12 @@ const RoleListPage = () => {
|
|
|
118
120
|
setIsConfirmButtonLoading(false);
|
|
119
121
|
};
|
|
120
122
|
|
|
121
|
-
const sortedRoles =
|
|
123
|
+
const sortedRoles = (roles || [])
|
|
124
|
+
.filter((role) => includes(role.name, _q) || includes(role.description, _q))
|
|
125
|
+
.sort(
|
|
126
|
+
(a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
|
|
127
|
+
);
|
|
128
|
+
|
|
122
129
|
const emptyContent = _q && !sortedRoles.length ? 'search' : 'roles';
|
|
123
130
|
|
|
124
131
|
const colCount = 4;
|
|
@@ -138,13 +145,18 @@ const RoleListPage = () => {
|
|
|
138
145
|
defaultMessage: 'List of roles',
|
|
139
146
|
})}
|
|
140
147
|
primaryAction={
|
|
141
|
-
<CheckPermissions permissions={
|
|
142
|
-
<
|
|
148
|
+
<CheckPermissions permissions={PERMISSIONS.createRole}>
|
|
149
|
+
<LinkButton
|
|
150
|
+
to="/settings/users-permissions/roles/new"
|
|
151
|
+
onClick={() => trackUsage('willCreateRole')}
|
|
152
|
+
startIcon={<Plus />}
|
|
153
|
+
size="S"
|
|
154
|
+
>
|
|
143
155
|
{formatMessage({
|
|
144
156
|
id: getTrad('List.button.roles'),
|
|
145
157
|
defaultMessage: 'Add new role',
|
|
146
158
|
})}
|
|
147
|
-
</
|
|
159
|
+
</LinkButton>
|
|
148
160
|
</CheckPermissions>
|
|
149
161
|
}
|
|
150
162
|
/>
|
|
@@ -201,7 +213,7 @@ const RoleListPage = () => {
|
|
|
201
213
|
<TableBody
|
|
202
214
|
sortedRoles={sortedRoles}
|
|
203
215
|
canDelete={canDelete}
|
|
204
|
-
permissions={
|
|
216
|
+
permissions={PERMISSIONS}
|
|
205
217
|
setRoleToDelete={setRoleToDelete}
|
|
206
218
|
onDelete={[showConfirmDelete, setShowConfirmDelete]}
|
|
207
219
|
/>
|
|
@@ -221,4 +233,10 @@ const RoleListPage = () => {
|
|
|
221
233
|
);
|
|
222
234
|
};
|
|
223
235
|
|
|
224
|
-
export
|
|
236
|
+
export const ProtectedRolesListPage = () => {
|
|
237
|
+
return (
|
|
238
|
+
<CheckPagePermissions permissions={PERMISSIONS.accessRoles}>
|
|
239
|
+
<RolesListPage />
|
|
240
|
+
</CheckPagePermissions>
|
|
241
|
+
);
|
|
242
|
+
};
|