@strapi/plugin-users-permissions 4.0.0-next.7 → 4.0.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.
Files changed (180) hide show
  1. package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
  2. package/admin/src/components/BoundRoute/index.js +40 -24
  3. package/admin/src/components/FormModal/Input/index.js +121 -0
  4. package/admin/src/components/FormModal/index.js +123 -0
  5. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +19 -26
  6. package/admin/src/components/Permissions/PermissionRow/SubCategory.js +118 -0
  7. package/admin/src/components/Permissions/PermissionRow/index.js +9 -48
  8. package/admin/src/components/Permissions/index.js +36 -24
  9. package/admin/src/components/Permissions/init.js +1 -6
  10. package/admin/src/components/Policies/index.js +46 -47
  11. package/admin/src/components/UsersPermissions/index.js +29 -26
  12. package/admin/src/components/UsersPermissions/init.js +1 -2
  13. package/admin/src/hooks/useFetchRole/index.js +17 -7
  14. package/admin/src/hooks/useForm/index.js +3 -29
  15. package/admin/src/hooks/useForm/reducer.js +2 -21
  16. package/admin/src/hooks/usePlugins/index.js +12 -21
  17. package/admin/src/hooks/usePlugins/reducer.js +0 -3
  18. package/admin/src/index.js +29 -34
  19. package/admin/src/pages/AdvancedSettings/index.js +210 -193
  20. package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
  21. package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
  22. package/admin/src/pages/AdvancedSettings/utils/schema.js +21 -0
  23. package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
  24. package/admin/src/pages/EmailTemplates/components/EmailTable.js +116 -0
  25. package/admin/src/pages/EmailTemplates/index.js +125 -198
  26. package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
  27. package/admin/src/pages/Providers/index.js +208 -216
  28. package/admin/src/pages/Providers/utils/api.js +21 -0
  29. package/admin/src/pages/Providers/utils/forms.js +168 -126
  30. package/admin/src/pages/Roles/CreatePage/index.js +155 -147
  31. package/admin/src/pages/Roles/EditPage/index.js +162 -134
  32. package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
  33. package/admin/src/pages/Roles/ListPage/index.js +176 -156
  34. package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
  35. package/admin/src/pages/Roles/index.js +14 -8
  36. package/admin/src/translations/ar.json +0 -8
  37. package/admin/src/translations/cs.json +0 -8
  38. package/admin/src/translations/de.json +0 -8
  39. package/admin/src/translations/dk.json +0 -8
  40. package/admin/src/translations/en.json +33 -12
  41. package/admin/src/translations/es.json +0 -8
  42. package/admin/src/translations/fr.json +0 -8
  43. package/admin/src/translations/id.json +0 -8
  44. package/admin/src/translations/it.json +0 -8
  45. package/admin/src/translations/ja.json +0 -8
  46. package/admin/src/translations/ko.json +93 -54
  47. package/admin/src/translations/ms.json +0 -8
  48. package/admin/src/translations/nl.json +0 -8
  49. package/admin/src/translations/pl.json +0 -8
  50. package/admin/src/translations/pt-BR.json +0 -8
  51. package/admin/src/translations/pt.json +0 -8
  52. package/admin/src/translations/ru.json +0 -8
  53. package/admin/src/translations/sk.json +0 -8
  54. package/admin/src/translations/sv.json +0 -8
  55. package/admin/src/translations/th.json +0 -8
  56. package/admin/src/translations/tr.json +0 -8
  57. package/admin/src/translations/uk.json +0 -8
  58. package/admin/src/translations/vi.json +0 -8
  59. package/admin/src/translations/zh-Hans.json +5 -14
  60. package/admin/src/translations/zh.json +0 -8
  61. package/admin/src/utils/axiosInstance.js +36 -0
  62. package/admin/src/utils/formatPluginName.js +26 -0
  63. package/admin/src/utils/index.js +1 -0
  64. package/documentation/1.0.0/overrides/users-permissions-Role.json +6 -6
  65. package/documentation/1.0.0/overrides/users-permissions-User.json +7 -7
  66. package/jest.config.front.js +10 -0
  67. package/package.json +35 -32
  68. package/server/bootstrap/index.js +20 -25
  69. package/server/config.js +3 -3
  70. package/server/content-types/index.js +3 -3
  71. package/server/content-types/permission/index.js +30 -3
  72. package/server/content-types/role/index.js +47 -3
  73. package/server/content-types/user/index.js +65 -4
  74. package/server/controllers/auth.js +85 -237
  75. package/server/controllers/content-manager-user.js +183 -0
  76. package/server/controllers/index.js +12 -6
  77. package/server/controllers/permissions.js +26 -0
  78. package/server/controllers/role.js +77 -0
  79. package/server/controllers/settings.js +85 -0
  80. package/server/controllers/user.js +119 -45
  81. package/server/controllers/validation/auth.js +29 -0
  82. package/server/controllers/validation/user.js +38 -0
  83. package/server/graphql/index.js +44 -0
  84. package/server/graphql/mutations/auth/email-confirmation.js +39 -0
  85. package/server/graphql/mutations/auth/forgot-password.js +38 -0
  86. package/server/graphql/mutations/auth/login.js +38 -0
  87. package/server/graphql/mutations/auth/register.js +39 -0
  88. package/server/graphql/mutations/auth/reset-password.js +41 -0
  89. package/server/graphql/mutations/crud/role/create-role.js +37 -0
  90. package/server/graphql/mutations/crud/role/delete-role.js +28 -0
  91. package/server/graphql/mutations/crud/role/update-role.js +38 -0
  92. package/server/graphql/mutations/crud/user/create-user.js +48 -0
  93. package/server/graphql/mutations/crud/user/delete-user.js +42 -0
  94. package/server/graphql/mutations/crud/user/update-user.js +49 -0
  95. package/server/graphql/mutations/index.js +42 -0
  96. package/server/graphql/queries/index.js +13 -0
  97. package/server/graphql/queries/me.js +17 -0
  98. package/server/graphql/resolvers-configs.js +37 -0
  99. package/server/graphql/types/create-role-payload.js +11 -0
  100. package/server/graphql/types/delete-role-payload.js +11 -0
  101. package/server/graphql/types/index.js +21 -0
  102. package/server/graphql/types/login-input.js +13 -0
  103. package/server/graphql/types/login-payload.js +12 -0
  104. package/server/graphql/types/me-role.js +14 -0
  105. package/server/graphql/types/me.js +16 -0
  106. package/server/graphql/types/password-payload.js +11 -0
  107. package/server/graphql/types/register-input.js +13 -0
  108. package/server/graphql/types/update-role-payload.js +11 -0
  109. package/server/graphql/utils.js +27 -0
  110. package/server/index.js +21 -0
  111. package/server/middlewares/index.js +2 -2
  112. package/server/{policies → middlewares}/rateLimit.js +3 -7
  113. package/server/register.js +11 -0
  114. package/server/routes/admin/index.js +10 -0
  115. package/server/routes/admin/permissions.js +20 -0
  116. package/server/routes/admin/role.js +79 -0
  117. package/server/routes/admin/settings.js +95 -0
  118. package/server/routes/content-api/auth.js +73 -0
  119. package/server/routes/content-api/index.js +11 -0
  120. package/server/routes/content-api/permissions.js +9 -0
  121. package/server/routes/content-api/role.js +29 -0
  122. package/server/routes/content-api/user.js +61 -0
  123. package/server/routes/index.js +4 -3
  124. package/server/services/index.js +10 -8
  125. package/server/services/jwt.js +9 -17
  126. package/server/services/providers.js +32 -33
  127. package/server/services/role.js +177 -0
  128. package/server/services/user.js +9 -15
  129. package/server/services/users-permissions.js +140 -338
  130. package/server/strategies/users-permissions.js +123 -0
  131. package/server/utils/index.d.ts +2 -0
  132. package/strapi-admin.js +3 -0
  133. package/strapi-server.js +1 -19
  134. package/admin/src/assets/images/logo.svg +0 -1
  135. package/admin/src/components/BaselineAlignement/index.js +0 -33
  136. package/admin/src/components/Bloc/index.js +0 -10
  137. package/admin/src/components/BoundRoute/Components.js +0 -78
  138. package/admin/src/components/ContainerFluid/index.js +0 -13
  139. package/admin/src/components/FormBloc/index.js +0 -61
  140. package/admin/src/components/IntlInput/index.js +0 -38
  141. package/admin/src/components/ListBaselineAlignment/index.js +0 -8
  142. package/admin/src/components/ListRow/Components.js +0 -74
  143. package/admin/src/components/ListRow/index.js +0 -35
  144. package/admin/src/components/ModalForm/Wrapper.js +0 -12
  145. package/admin/src/components/ModalForm/index.js +0 -59
  146. package/admin/src/components/Permissions/ListWrapper.js +0 -9
  147. package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +0 -7
  148. package/admin/src/components/Permissions/PermissionRow/RowStyle.js +0 -28
  149. package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +0 -13
  150. package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +0 -8
  151. package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +0 -26
  152. package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +0 -116
  153. package/admin/src/components/Policies/Components.js +0 -26
  154. package/admin/src/components/PrefixedIcon/index.js +0 -27
  155. package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +0 -7
  156. package/admin/src/components/Roles/EmptyRole/index.js +0 -27
  157. package/admin/src/components/Roles/RoleListWrapper/index.js +0 -17
  158. package/admin/src/components/Roles/RoleRow/RoleDescription.js +0 -9
  159. package/admin/src/components/Roles/RoleRow/index.js +0 -45
  160. package/admin/src/components/Roles/index.js +0 -3
  161. package/admin/src/components/SizedInput/index.js +0 -24
  162. package/admin/src/pages/AdvancedSettings/reducer.js +0 -65
  163. package/admin/src/pages/AdvancedSettings/utils/form.js +0 -52
  164. package/admin/src/pages/EmailTemplates/CustomTextInput.js +0 -105
  165. package/admin/src/pages/EmailTemplates/Wrapper.js +0 -36
  166. package/admin/src/pages/EmailTemplates/reducer.js +0 -58
  167. package/admin/src/pages/EmailTemplates/utils/forms.js +0 -81
  168. package/admin/src/pages/Roles/ListPage/BaselineAlignment.js +0 -8
  169. package/server/content-types/permission/schema.json +0 -48
  170. package/server/content-types/role/schema.json +0 -46
  171. package/server/content-types/user/schema.json +0 -66
  172. package/server/controllers/user/admin.js +0 -230
  173. package/server/controllers/user/api.js +0 -174
  174. package/server/controllers/users-permissions.js +0 -271
  175. package/server/middlewares/users-permissions.js +0 -36
  176. package/server/policies/index.js +0 -11
  177. package/server/policies/isAuthenticated.js +0 -9
  178. package/server/policies/permissions.js +0 -94
  179. package/server/routes/routes.json +0 -381
  180. package/server/schema.graphql.js +0 -317
@@ -0,0 +1,41 @@
1
+ const getMethodColor = verb => {
2
+ switch (verb) {
3
+ case 'POST': {
4
+ return {
5
+ text: 'success600',
6
+ border: 'success200',
7
+ background: 'success100',
8
+ };
9
+ }
10
+ case 'GET': {
11
+ return {
12
+ text: 'secondary600',
13
+ border: 'secondary200',
14
+ background: 'secondary100',
15
+ };
16
+ }
17
+ case 'PUT': {
18
+ return {
19
+ text: 'warning600',
20
+ border: 'warning200',
21
+ background: 'warning100',
22
+ };
23
+ }
24
+ case 'DELETE': {
25
+ return {
26
+ text: 'danger600',
27
+ border: 'danger200',
28
+ background: 'danger100',
29
+ };
30
+ }
31
+ default: {
32
+ return {
33
+ text: 'neutral600',
34
+ border: 'neutral200',
35
+ background: 'neutral100',
36
+ };
37
+ }
38
+ }
39
+ };
40
+
41
+ export default getMethodColor;
@@ -1,39 +1,55 @@
1
- /**
2
- *
3
- * BoundRoute
4
- *
5
- */
6
-
7
1
  import React from 'react';
8
- import { get, includes, map, tail, toLower } from 'lodash';
9
- import { FormattedMessage } from 'react-intl';
2
+ import styled from 'styled-components';
3
+ import { Stack } from '@strapi/design-system/Stack';
4
+ import { Box } from '@strapi/design-system/Box';
5
+ import { Typography } from '@strapi/design-system/Typography';
6
+ import map from 'lodash/map';
7
+ import tail from 'lodash/tail';
8
+ import { useIntl } from 'react-intl';
10
9
  import PropTypes from 'prop-types';
11
- import { Header, Path, Verb, Wrapper } from './Components';
10
+ import getMethodColor from './getMethodColor';
11
+
12
+ const MethodBox = styled(Box)`
13
+ margin: -1px;
14
+ border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};
15
+ `;
12
16
 
13
17
  function BoundRoute({ route }) {
14
- const title = get(route, 'handler');
15
- const formattedRoute = get(route, 'path') ? tail(get(route, 'path').split('/')) : [];
18
+ const { formatMessage } = useIntl();
19
+
20
+ const { method, handler: title, path } = route;
21
+ const formattedRoute = path ? tail(path.split('/')) : [];
16
22
  const [controller = '', action = ''] = title ? title.split('.') : [];
23
+ const colors = getMethodColor(route.method);
17
24
 
18
25
  return (
19
- <div className="col-md-12">
20
- <Header>
21
- <FormattedMessage id="users-permissions.BoundRoute.title" />
26
+ <Stack size={2}>
27
+ <Typography variant="delta" as="h3">
28
+ {formatMessage({
29
+ id: 'users-permissions.BoundRoute.title',
30
+ defaultMessage: 'Bound route to',
31
+ })}
22
32
  &nbsp;
23
33
  <span>{controller}</span>
24
- <span>.{action} </span>
25
- </Header>
26
- <Wrapper>
27
- <Verb className={toLower(get(route, 'method'))}>{get(route, 'method')}</Verb>
28
- <Path>
34
+ <Typography variant="delta" textColor="primary600">
35
+ .{action}
36
+ </Typography>
37
+ </Typography>
38
+ <Stack horizontal hasRadius background="neutral0" borderColor="neutral200" size={0}>
39
+ <MethodBox background={colors.background} borderColor={colors.border} padding={2}>
40
+ <Typography fontWeight="bold" textColor={colors.text}>
41
+ {method}
42
+ </Typography>
43
+ </MethodBox>
44
+ <Box paddingLeft={2} paddingRight={2}>
29
45
  {map(formattedRoute, value => (
30
- <span key={value} style={includes(value, ':') ? { color: '#787E8F' } : {}}>
46
+ <Typography key={value} textColor={value.includes(':') ? 'neutral600' : 'neutral900'}>
31
47
  /{value}
32
- </span>
48
+ </Typography>
33
49
  ))}
34
- </Path>
35
- </Wrapper>
36
- </div>
50
+ </Box>
51
+ </Stack>
52
+ </Stack>
37
53
  );
38
54
  }
39
55
 
@@ -0,0 +1,121 @@
1
+ /**
2
+ *
3
+ * Input
4
+ *
5
+ */
6
+
7
+ import React from 'react';
8
+ import { useIntl } from 'react-intl';
9
+ import { ToggleInput } from '@strapi/design-system/ToggleInput';
10
+ import { TextInput } from '@strapi/design-system/TextInput';
11
+ import PropTypes from 'prop-types';
12
+
13
+ const Input = ({
14
+ description,
15
+ disabled,
16
+ intlLabel,
17
+ error,
18
+ name,
19
+ onChange,
20
+ placeholder,
21
+ providerToEditName,
22
+ type,
23
+ value,
24
+ }) => {
25
+ const { formatMessage } = useIntl();
26
+ const inputValue =
27
+ name === 'noName' ? `${strapi.backendURL}/connect/${providerToEditName}/callback` : value;
28
+
29
+ const label = formatMessage(
30
+ { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
31
+ { ...intlLabel.values }
32
+ );
33
+ const hint = description
34
+ ? formatMessage(
35
+ { id: description.id, defaultMessage: description.defaultMessage },
36
+ { ...description.values }
37
+ )
38
+ : '';
39
+
40
+ if (type === 'bool') {
41
+ return (
42
+ <ToggleInput
43
+ aria-label={name}
44
+ checked={value}
45
+ disabled={disabled}
46
+ hint={hint}
47
+ label={label}
48
+ name={name}
49
+ offLabel={formatMessage({
50
+ id: 'app.components.ToggleCheckbox.off-label',
51
+ defaultMessage: 'Off',
52
+ })}
53
+ onLabel={formatMessage({
54
+ id: 'app.components.ToggleCheckbox.on-label',
55
+ defaultMessage: 'On',
56
+ })}
57
+ onChange={e => {
58
+ onChange({ target: { name, value: e.target.checked } });
59
+ }}
60
+ />
61
+ );
62
+ }
63
+
64
+ const formattedPlaceholder = placeholder
65
+ ? formatMessage(
66
+ { id: placeholder.id, defaultMessage: placeholder.defaultMessage },
67
+ { ...placeholder.values }
68
+ )
69
+ : '';
70
+
71
+ const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
72
+
73
+ return (
74
+ <TextInput
75
+ aria-label={name}
76
+ disabled={disabled}
77
+ error={errorMessage}
78
+ label={label}
79
+ name={name}
80
+ onChange={onChange}
81
+ placeholder={formattedPlaceholder}
82
+ type={type}
83
+ value={inputValue}
84
+ />
85
+ );
86
+ };
87
+
88
+ Input.defaultProps = {
89
+ description: null,
90
+ disabled: false,
91
+ error: '',
92
+ placeholder: null,
93
+ value: '',
94
+ };
95
+
96
+ Input.propTypes = {
97
+ description: PropTypes.shape({
98
+ id: PropTypes.string.isRequired,
99
+ defaultMessage: PropTypes.string.isRequired,
100
+ values: PropTypes.object,
101
+ }),
102
+ disabled: PropTypes.bool,
103
+ error: PropTypes.string,
104
+ intlLabel: PropTypes.shape({
105
+ id: PropTypes.string.isRequired,
106
+ defaultMessage: PropTypes.string.isRequired,
107
+ values: PropTypes.object,
108
+ }).isRequired,
109
+ name: PropTypes.string.isRequired,
110
+ onChange: PropTypes.func.isRequired,
111
+ placeholder: PropTypes.shape({
112
+ id: PropTypes.string.isRequired,
113
+ defaultMessage: PropTypes.string.isRequired,
114
+ values: PropTypes.object,
115
+ }),
116
+ providerToEditName: PropTypes.string.isRequired,
117
+ type: PropTypes.string.isRequired,
118
+ value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
119
+ };
120
+
121
+ export default Input;
@@ -0,0 +1,123 @@
1
+ /**
2
+ *
3
+ * FormModal
4
+ *
5
+ */
6
+
7
+ import React from 'react';
8
+ import { useIntl } from 'react-intl';
9
+ import { Button } from '@strapi/design-system/Button';
10
+ import { Stack } from '@strapi/design-system/Stack';
11
+ import { Breadcrumbs, Crumb } from '@strapi/design-system/Breadcrumbs';
12
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
13
+ import {
14
+ ModalLayout,
15
+ ModalHeader,
16
+ ModalFooter,
17
+ ModalBody,
18
+ } from '@strapi/design-system/ModalLayout';
19
+ import PropTypes from 'prop-types';
20
+ import { Formik } from 'formik';
21
+ import { Form } from '@strapi/helper-plugin';
22
+ import Input from './Input';
23
+
24
+ const FormModal = ({
25
+ headerBreadcrumbs,
26
+ initialData,
27
+ isSubmiting,
28
+ layout,
29
+ isOpen,
30
+ onSubmit,
31
+ onToggle,
32
+ providerToEditName,
33
+ }) => {
34
+ const { formatMessage } = useIntl();
35
+
36
+ if (!isOpen) {
37
+ return null;
38
+ }
39
+
40
+ return (
41
+ <ModalLayout onClose={onToggle} labelledBy="title">
42
+ <ModalHeader>
43
+ <Breadcrumbs label={headerBreadcrumbs.join(', ')}>
44
+ {headerBreadcrumbs.map(crumb => (
45
+ <Crumb key={crumb}>{crumb}</Crumb>
46
+ ))}
47
+ </Breadcrumbs>
48
+ </ModalHeader>
49
+ <Formik
50
+ onSubmit={values => onSubmit(values)}
51
+ initialValues={initialData}
52
+ validationSchema={layout.schema}
53
+ validateOnChange={false}
54
+ >
55
+ {({ errors, handleChange, values }) => {
56
+ return (
57
+ <Form>
58
+ <ModalBody>
59
+ <Stack size={1}>
60
+ <Grid gap={5}>
61
+ {layout.form.map(row => {
62
+ return row.map(input => {
63
+ return (
64
+ <GridItem key={input.name} col={input.size} xs={12}>
65
+ <Input
66
+ {...input}
67
+ error={errors[input.name]}
68
+ onChange={handleChange}
69
+ value={values[input.name]}
70
+ providerToEditName={providerToEditName}
71
+ />
72
+ </GridItem>
73
+ );
74
+ });
75
+ })}
76
+ </Grid>
77
+ </Stack>
78
+ </ModalBody>
79
+ <ModalFooter
80
+ startActions={
81
+ <Button variant="tertiary" onClick={onToggle} type="button">
82
+ {formatMessage({
83
+ id: 'app.components.Button.cancel',
84
+ defaultMessage: 'Cancel',
85
+ })}
86
+ </Button>
87
+ }
88
+ endActions={
89
+ <>
90
+ <Button type="submit" loading={isSubmiting}>
91
+ {formatMessage({ id: 'app.components.Button.save', defaultMessage: 'Save' })}
92
+ </Button>
93
+ </>
94
+ }
95
+ />
96
+ </Form>
97
+ );
98
+ }}
99
+ </Formik>
100
+ </ModalLayout>
101
+ );
102
+ };
103
+
104
+ FormModal.defaultProps = {
105
+ initialData: null,
106
+ providerToEditName: null,
107
+ };
108
+
109
+ FormModal.propTypes = {
110
+ headerBreadcrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
111
+ initialData: PropTypes.object,
112
+ layout: PropTypes.shape({
113
+ form: PropTypes.arrayOf(PropTypes.array),
114
+ schema: PropTypes.object,
115
+ }).isRequired,
116
+ isOpen: PropTypes.bool.isRequired,
117
+ isSubmiting: PropTypes.bool.isRequired,
118
+ onSubmit: PropTypes.func.isRequired,
119
+ onToggle: PropTypes.func.isRequired,
120
+ providerToEditName: PropTypes.string,
121
+ };
122
+
123
+ export default FormModal;
@@ -1,37 +1,30 @@
1
- /* eslint-disable indent */
2
- import styled from 'styled-components';
3
- import PolicyWrapper from './SubCategory/PolicyWrapper';
1
+ import styled, { css } from 'styled-components';
2
+ import { Box } from '@strapi/design-system/Box';
4
3
 
5
- const CheckboxWrapper = styled.div`
4
+ const activeCheckboxWrapperStyles = css`
5
+ background: ${props => props.theme.colors.primary100};
6
+ svg {
7
+ opacity: 1;
8
+ }
9
+ `;
10
+
11
+ const CheckboxWrapper = styled(Box)`
6
12
  display: flex;
7
13
  justify-content: space-between;
8
- min-width: 50%;
9
- padding: 0.9rem;
10
- height: 3.6rem;
11
- position: relative;
12
- ${PolicyWrapper} {
14
+ align-items: center;
15
+
16
+ svg {
13
17
  opacity: 0;
14
- > svg {
15
- align-self: center;
16
- font-size: 1.4rem;
17
- color: ${({ theme }) => theme.main.colors.greyDark};
18
+ path {
19
+ fill: ${props => props.theme.colors.primary600};
18
20
  }
19
- cursor: pointer;
20
21
  }
22
+
23
+ /* Show active style both on hover and when the action is selected */
24
+ ${props => props.isActive && activeCheckboxWrapperStyles}
21
25
  &:hover {
22
- ${PolicyWrapper} {
23
- opacity: 1;
24
- }
25
- background-color: ${({ theme }) => theme.main.colors.mediumGrey};
26
+ ${activeCheckboxWrapperStyles}
26
27
  }
27
- ${({ isActive, theme }) =>
28
- isActive &&
29
- `
30
- ${PolicyWrapper} {
31
- opacity: 1;
32
- }
33
- background-color: ${theme.main.colors.mediumGrey};
34
- `}
35
28
  `;
36
29
 
37
30
  export default CheckboxWrapper;
@@ -0,0 +1,118 @@
1
+ import React, { useCallback, useMemo } from 'react';
2
+ import { get } from 'lodash';
3
+ import styled from 'styled-components';
4
+ import PropTypes from 'prop-types';
5
+ import { Box } from '@strapi/design-system/Box';
6
+ import { Checkbox } from '@strapi/design-system/Checkbox';
7
+ import { Flex } from '@strapi/design-system/Flex';
8
+ import { Typography } from '@strapi/design-system/Typography';
9
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
10
+ import CogIcon from '@strapi/icons/Cog';
11
+ import { useIntl } from 'react-intl';
12
+ import CheckboxWrapper from './CheckboxWrapper';
13
+ import { useUsersPermissions } from '../../../contexts/UsersPermissionsContext';
14
+
15
+ const Border = styled.div`
16
+ flex: 1;
17
+ align-self: center;
18
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
19
+ `;
20
+
21
+ const SubCategory = ({ subCategory }) => {
22
+ const { formatMessage } = useIntl();
23
+ const {
24
+ onChange,
25
+ onChangeSelectAll,
26
+ onSelectedAction,
27
+ selectedAction,
28
+ modifiedData,
29
+ } = useUsersPermissions();
30
+
31
+ const currentScopedModifiedData = useMemo(() => {
32
+ return get(modifiedData, subCategory.name, {});
33
+ }, [modifiedData, subCategory]);
34
+
35
+ const hasAllActionsSelected = useMemo(() => {
36
+ return Object.values(currentScopedModifiedData).every(action => action.enabled === true);
37
+ }, [currentScopedModifiedData]);
38
+
39
+ const hasSomeActionsSelected = useMemo(() => {
40
+ return (
41
+ Object.values(currentScopedModifiedData).some(action => action.enabled === true) &&
42
+ !hasAllActionsSelected
43
+ );
44
+ }, [currentScopedModifiedData, hasAllActionsSelected]);
45
+
46
+ const handleChangeSelectAll = useCallback(
47
+ ({ target: { name } }) => {
48
+ onChangeSelectAll({ target: { name, value: !hasAllActionsSelected } });
49
+ },
50
+ [hasAllActionsSelected, onChangeSelectAll]
51
+ );
52
+
53
+ const isActionSelected = useCallback(
54
+ actionName => {
55
+ return selectedAction === actionName;
56
+ },
57
+ [selectedAction]
58
+ );
59
+
60
+ return (
61
+ <Box>
62
+ <Flex justifyContent="space-between" alignItems="center">
63
+ <Box paddingRight={4}>
64
+ <Typography variant="sigma" textColor="neutral600">
65
+ {subCategory.label}
66
+ </Typography>
67
+ </Box>
68
+ <Border />
69
+ <Box paddingLeft={4}>
70
+ <Checkbox
71
+ name={subCategory.name}
72
+ value={hasAllActionsSelected}
73
+ onValueChange={value =>
74
+ handleChangeSelectAll({ target: { name: subCategory.name, value } })}
75
+ indeterminate={hasSomeActionsSelected}
76
+ >
77
+ {formatMessage({ id: 'app.utils.select-all', defaultMessage: 'Select all' })}
78
+ </Checkbox>
79
+ </Box>
80
+ </Flex>
81
+ <Flex paddingTop={6} paddingBottom={6}>
82
+ <Grid gap={2} style={{ flex: 1 }}>
83
+ {subCategory.actions.map(action => {
84
+ const name = `${action.name}.enabled`;
85
+
86
+ return (
87
+ <GridItem col={6} key={action.name}>
88
+ <CheckboxWrapper isActive={isActionSelected(action.name)} padding={2} hasRadius>
89
+ <Checkbox
90
+ value={get(modifiedData, name, false)}
91
+ name={name}
92
+ onValueChange={value => onChange({ target: { name, value } })}
93
+ >
94
+ {action.label}
95
+ </Checkbox>
96
+ <button
97
+ type="button"
98
+ data-testid="action-cog"
99
+ onClick={() => onSelectedAction(action.name)}
100
+ style={{ display: 'inline-flex', alignItems: 'center' }}
101
+ >
102
+ <CogIcon />
103
+ </button>
104
+ </CheckboxWrapper>
105
+ </GridItem>
106
+ );
107
+ })}
108
+ </Grid>
109
+ </Flex>
110
+ </Box>
111
+ );
112
+ };
113
+
114
+ SubCategory.propTypes = {
115
+ subCategory: PropTypes.object.isRequired,
116
+ };
117
+
118
+ export default SubCategory;
@@ -1,24 +1,11 @@
1
1
  import React, { useMemo } from 'react';
2
- import { Flex, Text } from '@buffetjs/core';
3
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
2
  import PropTypes from 'prop-types';
5
- import { useIntl } from 'react-intl';
6
- import { sortBy } from 'lodash';
7
- import { PermissionsWrapper, RowContainer } from '@strapi/helper-plugin';
8
-
9
- import getTrad from '../../../utils/getTrad';
3
+ import sortBy from 'lodash/sortBy';
4
+ import { Box } from '@strapi/design-system/Box';
10
5
  import SubCategory from './SubCategory';
11
- import RowStyle from './RowStyle';
12
-
13
- const PermissionRow = ({ isOpen, isWhite, name, onOpenPlugin, permissions }) => {
14
- const { formatMessage } = useIntl();
15
6
 
7
+ const PermissionRow = ({ name, permissions }) => {
16
8
  const subCategories = useMemo(() => {
17
- // Avoid computing when not necesserary
18
- if (!isOpen) {
19
- return [];
20
- }
21
-
22
9
  return sortBy(
23
10
  Object.values(permissions.controllers).reduce((acc, curr, index) => {
24
11
  const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
@@ -47,45 +34,19 @@ const PermissionRow = ({ isOpen, isWhite, name, onOpenPlugin, permissions }) =>
47
34
  }, []),
48
35
  'label'
49
36
  );
50
- }, [isOpen, name, permissions]);
37
+ }, [name, permissions]);
51
38
 
52
39
  return (
53
- <RowContainer isWhite={isWhite}>
54
- <RowStyle isActive={isOpen} isWhite={isWhite} onClick={onOpenPlugin}>
55
- <Flex alignItems="center" justifyContent="space-between">
56
- <div>
57
- <Text color="grey" fontWeight="bold" fontSize="xs" textTransform="uppercase">
58
- {name}
59
- </Text>
60
- <Text lineHeight="22px" color="grey">
61
- {formatMessage({ id: getTrad('Plugin.permissions.plugins.description') }, { name })}
62
- </Text>
63
- </div>
64
- <div>
65
- <FontAwesomeIcon
66
- style={{ width: '11px' }}
67
- color="#9EA7B8"
68
- icon={isOpen ? 'chevron-up' : 'chevron-down'}
69
- />
70
- </div>
71
- </Flex>
72
- </RowStyle>
73
- {isOpen && (
74
- <PermissionsWrapper isWhite={isWhite}>
75
- {subCategories.map(subCategory => (
76
- <SubCategory key={subCategory.name} subCategory={subCategory} />
77
- ))}
78
- </PermissionsWrapper>
79
- )}
80
- </RowContainer>
40
+ <Box padding={6}>
41
+ {subCategories.map(subCategory => (
42
+ <SubCategory key={subCategory.name} subCategory={subCategory} />
43
+ ))}
44
+ </Box>
81
45
  );
82
46
  };
83
47
 
84
48
  PermissionRow.propTypes = {
85
- isOpen: PropTypes.bool.isRequired,
86
- isWhite: PropTypes.bool.isRequired,
87
49
  name: PropTypes.string.isRequired,
88
- onOpenPlugin: PropTypes.func.isRequired,
89
50
  permissions: PropTypes.object.isRequired,
90
51
  };
91
52