@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
|
@@ -4,23 +4,26 @@ import { AnErrorOccurred, CheckPagePermissions } from '@strapi/helper-plugin';
|
|
|
4
4
|
import { Route, Switch } from 'react-router-dom';
|
|
5
5
|
|
|
6
6
|
import { PERMISSIONS } from '../../constants';
|
|
7
|
-
import pluginId from '../../pluginId';
|
|
8
7
|
|
|
9
|
-
import ProtectedRolesCreatePage from './
|
|
10
|
-
import ProtectedRolesEditPage from './
|
|
11
|
-
import ProtectedRolesListPage from './
|
|
8
|
+
import { ProtectedRolesCreatePage } from './pages/CreatePage';
|
|
9
|
+
import { ProtectedRolesEditPage } from './pages/EditPage';
|
|
10
|
+
import { ProtectedRolesListPage } from './pages/ListPage';
|
|
12
11
|
|
|
13
12
|
const Roles = () => {
|
|
14
13
|
return (
|
|
15
14
|
<CheckPagePermissions permissions={PERMISSIONS.accessRoles}>
|
|
16
15
|
<Switch>
|
|
17
16
|
<Route
|
|
18
|
-
path=
|
|
17
|
+
path="/settings/users-permissions/roles/new"
|
|
19
18
|
component={ProtectedRolesCreatePage}
|
|
20
19
|
exact
|
|
21
20
|
/>
|
|
22
|
-
<Route
|
|
23
|
-
|
|
21
|
+
<Route
|
|
22
|
+
path="/settings/users-permissions/roles/:id"
|
|
23
|
+
component={ProtectedRolesEditPage}
|
|
24
|
+
exact
|
|
25
|
+
/>
|
|
26
|
+
<Route path="/settings/users-permissions/roles" component={ProtectedRolesListPage} exact />
|
|
24
27
|
<Route path="" component={AnErrorOccurred} />
|
|
25
28
|
</Switch>
|
|
26
29
|
</CheckPagePermissions>
|
|
@@ -0,0 +1,199 @@
|
|
|
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={
|
|
149
|
+
errors?.name
|
|
150
|
+
? formatMessage({ id: errors.name, defaultMessage: 'Name is required' })
|
|
151
|
+
: false
|
|
152
|
+
}
|
|
153
|
+
required
|
|
154
|
+
/>
|
|
155
|
+
</GridItem>
|
|
156
|
+
<GridItem col={6}>
|
|
157
|
+
<Textarea
|
|
158
|
+
id="description"
|
|
159
|
+
value={values.description || ''}
|
|
160
|
+
onChange={handleChange}
|
|
161
|
+
label={formatMessage({
|
|
162
|
+
id: 'global.description',
|
|
163
|
+
defaultMessage: 'Description',
|
|
164
|
+
})}
|
|
165
|
+
error={
|
|
166
|
+
errors?.description
|
|
167
|
+
? formatMessage({
|
|
168
|
+
id: errors.description,
|
|
169
|
+
defaultMessage: 'Description is required',
|
|
170
|
+
})
|
|
171
|
+
: false
|
|
172
|
+
}
|
|
173
|
+
required
|
|
174
|
+
/>
|
|
175
|
+
</GridItem>
|
|
176
|
+
</Grid>
|
|
177
|
+
</Flex>
|
|
178
|
+
|
|
179
|
+
{!isLoadingPlugins && (
|
|
180
|
+
<UsersPermissions
|
|
181
|
+
ref={permissionsRef}
|
|
182
|
+
permissions={permissions}
|
|
183
|
+
routes={routes}
|
|
184
|
+
/>
|
|
185
|
+
)}
|
|
186
|
+
</Flex>
|
|
187
|
+
</ContentLayout>
|
|
188
|
+
</Form>
|
|
189
|
+
)}
|
|
190
|
+
</Formik>
|
|
191
|
+
</Main>
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const ProtectedRolesCreatePage = () => (
|
|
196
|
+
<CheckPagePermissions permissions={PERMISSIONS.createRole}>
|
|
197
|
+
<CreatePage />
|
|
198
|
+
</CheckPagePermissions>
|
|
199
|
+
);
|
|
@@ -0,0 +1,220 @@
|
|
|
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={
|
|
170
|
+
errors?.name
|
|
171
|
+
? formatMessage({ id: errors.name, defaultMessage: 'Name is required' })
|
|
172
|
+
: false
|
|
173
|
+
}
|
|
174
|
+
required
|
|
175
|
+
/>
|
|
176
|
+
</GridItem>
|
|
177
|
+
<GridItem col={6}>
|
|
178
|
+
<Textarea
|
|
179
|
+
id="description"
|
|
180
|
+
value={values.description || ''}
|
|
181
|
+
onChange={handleChange}
|
|
182
|
+
label={formatMessage({
|
|
183
|
+
id: 'global.description',
|
|
184
|
+
defaultMessage: 'Description',
|
|
185
|
+
})}
|
|
186
|
+
error={
|
|
187
|
+
errors?.description
|
|
188
|
+
? formatMessage({
|
|
189
|
+
id: errors.description,
|
|
190
|
+
defaultMessage: 'Description is required',
|
|
191
|
+
})
|
|
192
|
+
: false
|
|
193
|
+
}
|
|
194
|
+
required
|
|
195
|
+
/>
|
|
196
|
+
</GridItem>
|
|
197
|
+
</Grid>
|
|
198
|
+
</Flex>
|
|
199
|
+
|
|
200
|
+
{!isLoadingPlugins && (
|
|
201
|
+
<UsersPermissions
|
|
202
|
+
ref={permissionsRef}
|
|
203
|
+
permissions={role.permissions}
|
|
204
|
+
routes={routes}
|
|
205
|
+
/>
|
|
206
|
+
)}
|
|
207
|
+
</Flex>
|
|
208
|
+
</ContentLayout>
|
|
209
|
+
</Form>
|
|
210
|
+
)}
|
|
211
|
+
</Formik>
|
|
212
|
+
</Main>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export const ProtectedRolesEditPage = () => (
|
|
217
|
+
<CheckPagePermissions permissions={PERMISSIONS.updateRole}>
|
|
218
|
+
<EditPage />
|
|
219
|
+
</CheckPagePermissions>
|
|
220
|
+
);
|
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import { Flex, IconButton, Tbody, Td, Tr, Typography } from '@strapi/design-system';
|
|
4
|
-
import { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
|
|
3
|
+
import { Flex, IconButton, Link, Tbody, Td, Tr, Typography } from '@strapi/design-system';
|
|
4
|
+
import { CheckPermissions, onRowClick, pxToRem, stopPropagation } from '@strapi/helper-plugin';
|
|
5
5
|
import { Pencil, Trash } from '@strapi/icons';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import { useIntl } from 'react-intl';
|
|
8
8
|
import { useHistory } from 'react-router-dom';
|
|
9
|
+
import styled from 'styled-components';
|
|
9
10
|
|
|
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)};
|
|
18
|
+
|
|
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
|
+
`;
|
|
11
37
|
|
|
12
38
|
const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
|
|
13
39
|
const { formatMessage } = useIntl();
|
|
@@ -23,7 +49,7 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
23
49
|
};
|
|
24
50
|
|
|
25
51
|
const handleClickEdit = (id) => {
|
|
26
|
-
push(`/settings
|
|
52
|
+
push(`/settings/users-permissions/roles/${id}`);
|
|
27
53
|
};
|
|
28
54
|
|
|
29
55
|
return (
|
|
@@ -38,25 +64,29 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
38
64
|
</Td>
|
|
39
65
|
<Td width="30%">
|
|
40
66
|
<Typography>
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
+
)}
|
|
45
74
|
</Typography>
|
|
46
75
|
</Td>
|
|
47
76
|
<Td>
|
|
48
77
|
<Flex justifyContent="end" {...stopPropagation}>
|
|
49
78
|
<CheckPermissions permissions={permissions.updateRole}>
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
icon={<Pencil />}
|
|
54
|
-
label={formatMessage(
|
|
79
|
+
<EditLink
|
|
80
|
+
to={`/settings/users-permissions/roles/${role.id}`}
|
|
81
|
+
aria-label={formatMessage(
|
|
55
82
|
{ id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
|
|
56
83
|
{ target: `${role.name}` }
|
|
57
84
|
)}
|
|
58
|
-
|
|
85
|
+
>
|
|
86
|
+
<Pencil />
|
|
87
|
+
</EditLink>
|
|
59
88
|
</CheckPermissions>
|
|
89
|
+
|
|
60
90
|
{checkCanDeleteRole(role) && (
|
|
61
91
|
<CheckPermissions permissions={permissions.deleteRole}>
|
|
62
92
|
<IconButton
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ActionLayout,
|
|
5
|
-
Button,
|
|
6
5
|
ContentLayout,
|
|
7
6
|
HeaderLayout,
|
|
8
7
|
Layout,
|
|
@@ -16,9 +15,11 @@ import {
|
|
|
16
15
|
VisuallyHidden,
|
|
17
16
|
} from '@strapi/design-system';
|
|
18
17
|
import {
|
|
18
|
+
CheckPagePermissions,
|
|
19
19
|
CheckPermissions,
|
|
20
20
|
ConfirmDialog,
|
|
21
21
|
EmptyStateLayout,
|
|
22
|
+
LinkButton,
|
|
22
23
|
LoadingIndicatorPage,
|
|
23
24
|
NoPermissions,
|
|
24
25
|
SearchURLQuery,
|
|
@@ -33,20 +34,17 @@ import {
|
|
|
33
34
|
} from '@strapi/helper-plugin';
|
|
34
35
|
import { Plus } from '@strapi/icons';
|
|
35
36
|
import { useIntl } from 'react-intl';
|
|
36
|
-
import { useMutation, useQuery
|
|
37
|
-
import { useHistory } from 'react-router-dom';
|
|
37
|
+
import { useMutation, useQuery } from 'react-query';
|
|
38
38
|
|
|
39
|
-
import { PERMISSIONS } from '
|
|
40
|
-
import
|
|
41
|
-
import { getTrad } from '../../../utils';
|
|
39
|
+
import { PERMISSIONS } from '../../../../constants';
|
|
40
|
+
import { getTrad } from '../../../../utils';
|
|
42
41
|
|
|
43
42
|
import TableBody from './components/TableBody';
|
|
44
43
|
import { deleteData, fetchData } from './utils/api';
|
|
45
44
|
|
|
46
|
-
const
|
|
45
|
+
export const RolesListPage = () => {
|
|
47
46
|
const { trackUsage } = useTracking();
|
|
48
47
|
const { formatMessage, locale } = useIntl();
|
|
49
|
-
const { push } = useHistory();
|
|
50
48
|
const toggleNotification = useNotification();
|
|
51
49
|
const { notifyStatus } = useNotifyAT();
|
|
52
50
|
const [{ query }] = useQueryParams();
|
|
@@ -56,26 +54,21 @@ const RoleListPage = () => {
|
|
|
56
54
|
const [roleToDelete, setRoleToDelete] = useState();
|
|
57
55
|
useFocusWhenNavigate();
|
|
58
56
|
|
|
59
|
-
const queryClient = useQueryClient();
|
|
60
|
-
|
|
61
|
-
const updatePermissions = useMemo(() => {
|
|
62
|
-
return {
|
|
63
|
-
create: PERMISSIONS.createRole,
|
|
64
|
-
read: PERMISSIONS.readRoles,
|
|
65
|
-
update: PERMISSIONS.updateRole,
|
|
66
|
-
delete: PERMISSIONS.deleteRole,
|
|
67
|
-
};
|
|
68
|
-
}, []);
|
|
69
|
-
|
|
70
57
|
const {
|
|
71
58
|
isLoading: isLoadingForPermissions,
|
|
72
59
|
allowedActions: { canRead, canDelete },
|
|
73
|
-
} = useRBAC(
|
|
60
|
+
} = useRBAC({
|
|
61
|
+
create: PERMISSIONS.createRole,
|
|
62
|
+
read: PERMISSIONS.readRoles,
|
|
63
|
+
update: PERMISSIONS.updateRole,
|
|
64
|
+
delete: PERMISSIONS.deleteRole,
|
|
65
|
+
});
|
|
74
66
|
|
|
75
67
|
const {
|
|
76
68
|
isLoading: isLoadingForData,
|
|
77
69
|
data: { roles },
|
|
78
70
|
isFetching,
|
|
71
|
+
refetch,
|
|
79
72
|
} = useQuery('get-roles', () => fetchData(toggleNotification, notifyStatus), {
|
|
80
73
|
initialData: {},
|
|
81
74
|
enabled: canRead,
|
|
@@ -94,11 +87,6 @@ const RoleListPage = () => {
|
|
|
94
87
|
|
|
95
88
|
const isLoading = isLoadingForData || isFetching;
|
|
96
89
|
|
|
97
|
-
const handleNewRoleClick = () => {
|
|
98
|
-
trackUsage('willCreateRole');
|
|
99
|
-
push(`/settings/${pluginId}/roles/new`);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
90
|
const handleShowConfirmDelete = () => {
|
|
103
91
|
setShowConfirmDelete(!showConfirmDelete);
|
|
104
92
|
};
|
|
@@ -121,7 +109,7 @@ const RoleListPage = () => {
|
|
|
121
109
|
|
|
122
110
|
const deleteMutation = useMutation((id) => deleteData(id, toggleNotification), {
|
|
123
111
|
async onSuccess() {
|
|
124
|
-
await
|
|
112
|
+
await refetch();
|
|
125
113
|
},
|
|
126
114
|
});
|
|
127
115
|
|
|
@@ -158,12 +146,17 @@ const RoleListPage = () => {
|
|
|
158
146
|
})}
|
|
159
147
|
primaryAction={
|
|
160
148
|
<CheckPermissions permissions={PERMISSIONS.createRole}>
|
|
161
|
-
<
|
|
149
|
+
<LinkButton
|
|
150
|
+
to="/settings/users-permissions/roles/new"
|
|
151
|
+
onClick={() => trackUsage('willCreateRole')}
|
|
152
|
+
startIcon={<Plus />}
|
|
153
|
+
size="S"
|
|
154
|
+
>
|
|
162
155
|
{formatMessage({
|
|
163
156
|
id: getTrad('List.button.roles'),
|
|
164
157
|
defaultMessage: 'Add new role',
|
|
165
158
|
})}
|
|
166
|
-
</
|
|
159
|
+
</LinkButton>
|
|
167
160
|
</CheckPermissions>
|
|
168
161
|
}
|
|
169
162
|
/>
|
|
@@ -240,4 +233,10 @@ const RoleListPage = () => {
|
|
|
240
233
|
);
|
|
241
234
|
};
|
|
242
235
|
|
|
243
|
-
export
|
|
236
|
+
export const ProtectedRolesListPage = () => {
|
|
237
|
+
return (
|
|
238
|
+
<CheckPagePermissions permissions={PERMISSIONS.accessRoles}>
|
|
239
|
+
<RolesListPage />
|
|
240
|
+
</CheckPagePermissions>
|
|
241
|
+
);
|
|
242
|
+
};
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { getFetchClient } from '@strapi/helper-plugin';
|
|
2
2
|
|
|
3
|
-
import { getRequestURL } from '../../../../utils';
|
|
4
|
-
|
|
5
3
|
export const fetchData = async (toggleNotification, notifyStatus) => {
|
|
6
4
|
try {
|
|
7
5
|
const { get } = getFetchClient();
|
|
8
|
-
const { data } = await get(
|
|
6
|
+
const { data } = await get('/users-permissions/roles');
|
|
9
7
|
notifyStatus('The roles have loaded successfully');
|
|
10
8
|
|
|
11
9
|
return data;
|
|
@@ -22,7 +20,7 @@ export const fetchData = async (toggleNotification, notifyStatus) => {
|
|
|
22
20
|
export const deleteData = async (id, toggleNotification) => {
|
|
23
21
|
try {
|
|
24
22
|
const { del } = getFetchClient();
|
|
25
|
-
await del(
|
|
23
|
+
await del(`/users-permissions/roles/${id}`);
|
|
26
24
|
} catch (error) {
|
|
27
25
|
toggleNotification({
|
|
28
26
|
type: 'warning',
|