@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.
Files changed (63) hide show
  1. package/admin/src/components/BoundRoute/index.js +5 -3
  2. package/admin/src/components/FormModal/Input/index.js +6 -3
  3. package/admin/src/components/FormModal/index.js +13 -10
  4. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +1 -1
  5. package/admin/src/components/Permissions/PermissionRow/SubCategory.js +26 -5
  6. package/admin/src/components/Permissions/PermissionRow/index.js +4 -2
  7. package/admin/src/components/Permissions/index.js +6 -5
  8. package/admin/src/components/Policies/index.js +3 -2
  9. package/admin/src/components/UsersPermissions/index.js +8 -5
  10. package/admin/src/{permissions.js → constants.js} +1 -3
  11. package/admin/src/contexts/UsersPermissionsContext/index.js +1 -0
  12. package/admin/src/index.js +14 -13
  13. package/admin/src/pages/AdvancedSettings/index.js +68 -52
  14. package/admin/src/pages/AdvancedSettings/utils/schema.js +1 -1
  15. package/admin/src/pages/EmailTemplates/components/EmailForm.js +14 -13
  16. package/admin/src/pages/EmailTemplates/components/EmailTable.js +9 -7
  17. package/admin/src/pages/EmailTemplates/index.js +77 -63
  18. package/admin/src/pages/EmailTemplates/utils/schema.js +1 -1
  19. package/admin/src/pages/Providers/index.js +91 -86
  20. package/admin/src/pages/Providers/utils/forms.js +1 -1
  21. package/admin/src/pages/Roles/{CreatePage/utils/schema.js → constants.js} +2 -4
  22. package/admin/src/pages/Roles/hooks/usePlugins.js +78 -0
  23. package/admin/src/pages/Roles/index.js +17 -11
  24. package/admin/src/pages/Roles/pages/CreatePage.js +190 -0
  25. package/admin/src/pages/Roles/pages/EditPage.js +211 -0
  26. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/components/TableBody.js +46 -15
  27. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/index.js +67 -49
  28. package/admin/src/pages/Roles/{ListPage → pages/ListPage}/utils/api.js +3 -4
  29. package/admin/src/translations/ru.json +50 -26
  30. package/admin/src/translations/zh-Hans.json +80 -80
  31. package/admin/src/utils/index.js +1 -2
  32. package/documentation/content-api.yaml +23 -15
  33. package/jest.config.front.js +2 -0
  34. package/package.json +23 -27
  35. package/server/bootstrap/index.js +35 -0
  36. package/server/controllers/auth.js +46 -7
  37. package/server/controllers/user.js +12 -1
  38. package/server/middlewares/rateLimit.js +41 -21
  39. package/server/register.js +7 -1
  40. package/server/services/providers-registry.js +1 -1
  41. package/admin/src/hooks/index.js +0 -5
  42. package/admin/src/hooks/useFetchRole/index.js +0 -64
  43. package/admin/src/hooks/useFetchRole/reducer.js +0 -31
  44. package/admin/src/hooks/useForm/index.js +0 -70
  45. package/admin/src/hooks/useForm/reducer.js +0 -40
  46. package/admin/src/hooks/usePlugins/index.js +0 -67
  47. package/admin/src/hooks/usePlugins/init.js +0 -5
  48. package/admin/src/hooks/usePlugins/reducer.js +0 -34
  49. package/admin/src/hooks/useRolesList/index.js +0 -63
  50. package/admin/src/hooks/useRolesList/init.js +0 -5
  51. package/admin/src/hooks/useRolesList/reducer.js +0 -31
  52. package/admin/src/pages/AdvancedSettings/utils/api.js +0 -17
  53. package/admin/src/pages/EmailTemplates/utils/api.js +0 -17
  54. package/admin/src/pages/Providers/reducer.js +0 -54
  55. package/admin/src/pages/Providers/utils/api.js +0 -25
  56. package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
  57. package/admin/src/pages/Roles/CreatePage/index.js +0 -182
  58. package/admin/src/pages/Roles/EditPage/index.js +0 -194
  59. package/admin/src/pages/Roles/EditPage/utils/schema.js +0 -9
  60. package/admin/src/pages/Roles/ProtectedCreatePage/index.js +0 -12
  61. package/admin/src/pages/Roles/ProtectedEditPage/index.js +0 -12
  62. package/admin/src/pages/Roles/ProtectedListPage/index.js +0 -15
  63. 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
- import PropTypes from 'prop-types';
3
- import { IconButton, Typography, Flex, Tbody, Tr, Td } from '@strapi/design-system';
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 { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
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
- import pluginId from '../../../../pluginId';
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/${pluginId}/roles/${id}`);
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
- {`${role.nb_users} ${formatMessage({
41
- id: 'global.users',
42
- defaultMessage: 'users',
43
- }).toLowerCase()}`}
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
- <IconButton
50
- onClick={() => handleClickEdit(role.id)}
51
- noBorder
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, { useMemo, useState } from 'react';
1
+ import React, { useState } from 'react';
2
+
2
3
  import {
3
- Button,
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
- useTracking,
20
- SettingsPageTitle,
18
+ CheckPagePermissions,
21
19
  CheckPermissions,
22
- useNotification,
23
- useRBAC,
24
- NoPermissions,
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
- EmptyStateLayout,
30
- ConfirmDialog,
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 { useHistory } from 'react-router-dom';
34
- import { useMutation, useQuery, useQueryClient } from 'react-query';
35
- import matchSorter from 'match-sorter';
36
-
37
- import { fetchData, deleteData } from './utils/api';
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 RoleListPage = () => {
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(updatePermissions);
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 isLoading = isLoadingForData || isFetching;
77
+ const { includes } = useFilter(locale, {
78
+ sensitivity: 'base',
79
+ });
82
80
 
83
- const handleNewRoleClick = () => {
84
- trackUsage('willCreateRole');
85
- push(`/settings/${pluginId}/roles/new`);
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 queryClient.invalidateQueries('get-roles');
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 = matchSorter(roles || [], _q, { keys: ['name', 'description'] });
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={permissions.createRole}>
142
- <Button onClick={handleNewRoleClick} startIcon={<Plus />} size="S">
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
- </Button>
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={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 default RoleListPage;
236
+ export const ProtectedRolesListPage = () => {
237
+ return (
238
+ <CheckPagePermissions permissions={PERMISSIONS.accessRoles}>
239
+ <RolesListPage />
240
+ </CheckPagePermissions>
241
+ );
242
+ };