@akemona-org/strapi-plugin-users-permissions 3.7.0
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/LICENSE +22 -0
- package/README.md +19 -0
- package/admin/src/assets/images/logo.svg +1 -0
- package/admin/src/components/BaselineAlignement/index.js +33 -0
- package/admin/src/components/Bloc/index.js +10 -0
- package/admin/src/components/BoundRoute/Components.js +78 -0
- package/admin/src/components/BoundRoute/index.js +56 -0
- package/admin/src/components/ContainerFluid/index.js +13 -0
- package/admin/src/components/FormBloc/index.js +61 -0
- package/admin/src/components/IntlInput/index.js +38 -0
- package/admin/src/components/ListBaselineAlignment/index.js +8 -0
- package/admin/src/components/ListRow/Components.js +74 -0
- package/admin/src/components/ListRow/index.js +35 -0
- package/admin/src/components/ModalForm/Wrapper.js +12 -0
- package/admin/src/components/ModalForm/index.js +59 -0
- package/admin/src/components/Permissions/ListWrapper.js +9 -0
- package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +7 -0
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +37 -0
- package/admin/src/components/Permissions/PermissionRow/RowStyle.js +28 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +13 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +8 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +26 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +116 -0
- package/admin/src/components/Permissions/PermissionRow/index.js +92 -0
- package/admin/src/components/Permissions/index.js +44 -0
- package/admin/src/components/Permissions/init.js +14 -0
- package/admin/src/components/Permissions/reducer.js +27 -0
- package/admin/src/components/Policies/Components.js +26 -0
- package/admin/src/components/Policies/index.js +61 -0
- package/admin/src/components/PrefixedIcon/index.js +27 -0
- package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +7 -0
- package/admin/src/components/Roles/EmptyRole/index.js +27 -0
- package/admin/src/components/Roles/RoleListWrapper/index.js +17 -0
- package/admin/src/components/Roles/RoleRow/RoleDescription.js +9 -0
- package/admin/src/components/Roles/RoleRow/index.js +45 -0
- package/admin/src/components/Roles/index.js +3 -0
- package/admin/src/components/SizedInput/index.js +24 -0
- package/admin/src/components/UsersPermissions/index.js +91 -0
- package/admin/src/components/UsersPermissions/init.js +11 -0
- package/admin/src/components/UsersPermissions/reducer.js +60 -0
- package/admin/src/containers/AdvancedSettings/index.js +218 -0
- package/admin/src/containers/AdvancedSettings/reducer.js +65 -0
- package/admin/src/containers/AdvancedSettings/utils/form.js +52 -0
- package/admin/src/containers/EmailTemplates/CustomTextInput.js +105 -0
- package/admin/src/containers/EmailTemplates/Wrapper.js +36 -0
- package/admin/src/containers/EmailTemplates/index.js +222 -0
- package/admin/src/containers/EmailTemplates/reducer.js +58 -0
- package/admin/src/containers/EmailTemplates/utils/forms.js +81 -0
- package/admin/src/containers/EmailTemplates/utils/schema.js +25 -0
- package/admin/src/containers/Providers/index.js +283 -0
- package/admin/src/containers/Providers/reducer.js +54 -0
- package/admin/src/containers/Providers/utils/createProvidersArray.js +21 -0
- package/admin/src/containers/Providers/utils/forms.js +205 -0
- package/admin/src/containers/Roles/CreatePage/index.js +167 -0
- package/admin/src/containers/Roles/CreatePage/utils/schema.js +9 -0
- package/admin/src/containers/Roles/EditPage/index.js +161 -0
- package/admin/src/containers/Roles/EditPage/utils/schema.js +9 -0
- package/admin/src/containers/Roles/ListPage/BaselineAlignment.js +8 -0
- package/admin/src/containers/Roles/ListPage/index.js +188 -0
- package/admin/src/containers/Roles/ProtectedCreatePage/index.js +12 -0
- package/admin/src/containers/Roles/ProtectedEditPage/index.js +12 -0
- package/admin/src/containers/Roles/ProtectedListPage/index.js +15 -0
- package/admin/src/containers/Roles/index.js +35 -0
- package/admin/src/contexts/EditPage/index.js +26 -0
- package/admin/src/contexts/HomePage/index.js +27 -0
- package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
- package/admin/src/hooks/index.js +5 -0
- package/admin/src/hooks/useFetchRole/index.js +55 -0
- package/admin/src/hooks/useFetchRole/reducer.js +31 -0
- package/admin/src/hooks/useForm/index.js +96 -0
- package/admin/src/hooks/useForm/reducer.js +59 -0
- package/admin/src/hooks/usePlugins/index.js +73 -0
- package/admin/src/hooks/usePlugins/init.js +5 -0
- package/admin/src/hooks/usePlugins/reducer.js +37 -0
- package/admin/src/hooks/useRolesList/index.js +62 -0
- package/admin/src/hooks/useRolesList/init.js +5 -0
- package/admin/src/hooks/useRolesList/reducer.js +31 -0
- package/admin/src/index.js +109 -0
- package/admin/src/permissions.js +33 -0
- package/admin/src/pluginId.js +5 -0
- package/admin/src/translations/ar.json +49 -0
- package/admin/src/translations/cs.json +55 -0
- package/admin/src/translations/de.json +68 -0
- package/admin/src/translations/dk.json +116 -0
- package/admin/src/translations/en.json +104 -0
- package/admin/src/translations/es.json +70 -0
- package/admin/src/translations/fr.json +55 -0
- package/admin/src/translations/id.json +69 -0
- package/admin/src/translations/index.js +55 -0
- package/admin/src/translations/it.json +68 -0
- package/admin/src/translations/ja.json +53 -0
- package/admin/src/translations/ko.json +55 -0
- package/admin/src/translations/ms.json +54 -0
- package/admin/src/translations/nl.json +53 -0
- package/admin/src/translations/pl.json +55 -0
- package/admin/src/translations/pt-BR.json +49 -0
- package/admin/src/translations/pt.json +53 -0
- package/admin/src/translations/ru.json +68 -0
- package/admin/src/translations/sk.json +57 -0
- package/admin/src/translations/sv.json +68 -0
- package/admin/src/translations/th.json +66 -0
- package/admin/src/translations/tr.json +53 -0
- package/admin/src/translations/uk.json +54 -0
- package/admin/src/translations/vi.json +55 -0
- package/admin/src/translations/zh-Hans.json +104 -0
- package/admin/src/translations/zh.json +53 -0
- package/admin/src/utils/cleanPermissions.js +25 -0
- package/admin/src/utils/formatPolicies.js +8 -0
- package/admin/src/utils/getRequestURL.js +5 -0
- package/admin/src/utils/getTrad.js +5 -0
- package/admin/src/utils/index.js +4 -0
- package/config/functions/bootstrap.js +234 -0
- package/config/layout.js +10 -0
- package/config/policies/isAuthenticated.js +9 -0
- package/config/policies/permissions.js +93 -0
- package/config/policies/rateLimit.js +33 -0
- package/config/request.json +6 -0
- package/config/routes.json +397 -0
- package/config/schema.graphql.js +280 -0
- package/config/security.json +5 -0
- package/config/users-permissions-actions.js +80 -0
- package/controllers/Auth.js +612 -0
- package/controllers/User.js +125 -0
- package/controllers/UsersPermissions.js +291 -0
- package/controllers/user/admin.js +224 -0
- package/controllers/user/api.js +173 -0
- package/controllers/validation/email-template.js +40 -0
- package/documentation/1.0.0/overrides/users-permissions-Role.json +281 -0
- package/documentation/1.0.0/overrides/users-permissions-User.json +325 -0
- package/middlewares/users-permissions/defaults.json +5 -0
- package/middlewares/users-permissions/index.js +40 -0
- package/models/Permission.js +7 -0
- package/models/Permission.settings.json +43 -0
- package/models/Role.js +7 -0
- package/models/Role.settings.json +42 -0
- package/models/User.config.js +15 -0
- package/models/User.js +7 -0
- package/models/User.settings.json +62 -0
- package/package.json +70 -0
- package/services/Jwt.js +65 -0
- package/services/Providers.js +596 -0
- package/services/User.js +167 -0
- package/services/UsersPermissions.js +416 -0
|
@@ -0,0 +1,116 @@
|
|
|
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 { Flex, Padded, Text, Checkbox } from '@buffetjs/core';
|
|
6
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
7
|
+
import { useIntl } from 'react-intl';
|
|
8
|
+
import CheckboxWrapper from '../CheckboxWrapper';
|
|
9
|
+
import BaselineAlignment from '../BaselineAlignment';
|
|
10
|
+
import SubCategoryWrapper from './SubCategoryWrapper';
|
|
11
|
+
import { useUsersPermissions } from '../../../../contexts/UsersPermissionsContext';
|
|
12
|
+
import PolicyWrapper from './PolicyWrapper';
|
|
13
|
+
|
|
14
|
+
const Border = styled.div`
|
|
15
|
+
flex: 1;
|
|
16
|
+
align-self: center;
|
|
17
|
+
border-top: 1px solid #f6f6f6;
|
|
18
|
+
padding: 0px 10px;
|
|
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
|
+
<SubCategoryWrapper>
|
|
62
|
+
<Flex justifyContent="space-between" alignItems="center">
|
|
63
|
+
<Padded right size="sm">
|
|
64
|
+
<Text
|
|
65
|
+
lineHeight="18px"
|
|
66
|
+
color="#919bae"
|
|
67
|
+
fontWeight="bold"
|
|
68
|
+
fontSize="xs"
|
|
69
|
+
textTransform="uppercase"
|
|
70
|
+
>
|
|
71
|
+
{subCategory.label}
|
|
72
|
+
</Text>
|
|
73
|
+
</Padded>
|
|
74
|
+
<Border />
|
|
75
|
+
<Padded left size="sm">
|
|
76
|
+
<BaselineAlignment />
|
|
77
|
+
<Checkbox
|
|
78
|
+
name={subCategory.name}
|
|
79
|
+
message={formatMessage({ id: 'app.utils.select-all' })}
|
|
80
|
+
onChange={handleChangeSelectAll}
|
|
81
|
+
someChecked={hasSomeActionsSelected}
|
|
82
|
+
value={hasAllActionsSelected}
|
|
83
|
+
/>
|
|
84
|
+
</Padded>
|
|
85
|
+
</Flex>
|
|
86
|
+
<BaselineAlignment />
|
|
87
|
+
<Padded top size="xs">
|
|
88
|
+
<Flex flexWrap="wrap">
|
|
89
|
+
{subCategory.actions.map(action => {
|
|
90
|
+
const name = `${action.name}.enabled`;
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<CheckboxWrapper isActive={isActionSelected(action.name)} key={action.name}>
|
|
94
|
+
<Checkbox
|
|
95
|
+
value={get(modifiedData, name, false)}
|
|
96
|
+
name={name}
|
|
97
|
+
message={action.label}
|
|
98
|
+
onChange={onChange}
|
|
99
|
+
/>
|
|
100
|
+
<PolicyWrapper onClick={() => onSelectedAction(action.name)}>
|
|
101
|
+
<FontAwesomeIcon icon="cog" />
|
|
102
|
+
</PolicyWrapper>
|
|
103
|
+
</CheckboxWrapper>
|
|
104
|
+
);
|
|
105
|
+
})}
|
|
106
|
+
</Flex>
|
|
107
|
+
</Padded>
|
|
108
|
+
</SubCategoryWrapper>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
SubCategory.propTypes = {
|
|
113
|
+
subCategory: PropTypes.object.isRequired,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export default SubCategory;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Flex, Text } from '@buffetjs/core';
|
|
3
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
4
|
+
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';
|
|
10
|
+
import SubCategory from './SubCategory';
|
|
11
|
+
import RowStyle from './RowStyle';
|
|
12
|
+
|
|
13
|
+
const PermissionRow = ({ isOpen, isWhite, name, onOpenPlugin, permissions }) => {
|
|
14
|
+
const { formatMessage } = useIntl();
|
|
15
|
+
|
|
16
|
+
const subCategories = useMemo(() => {
|
|
17
|
+
// Avoid computing when not necesserary
|
|
18
|
+
if (!isOpen) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return sortBy(
|
|
23
|
+
Object.values(permissions.controllers).reduce((acc, curr, index) => {
|
|
24
|
+
const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
|
|
25
|
+
const actions = sortBy(
|
|
26
|
+
Object.keys(curr).reduce((acc, current) => {
|
|
27
|
+
return [
|
|
28
|
+
...acc,
|
|
29
|
+
{
|
|
30
|
+
...curr[current],
|
|
31
|
+
label: current,
|
|
32
|
+
name: `${currentName}.${current}`,
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
}, []),
|
|
36
|
+
'label'
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return [
|
|
40
|
+
...acc,
|
|
41
|
+
{
|
|
42
|
+
actions,
|
|
43
|
+
label: Object.keys(permissions.controllers)[index],
|
|
44
|
+
name: currentName,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}, []),
|
|
48
|
+
'label'
|
|
49
|
+
);
|
|
50
|
+
}, [isOpen, name, permissions]);
|
|
51
|
+
|
|
52
|
+
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>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
PermissionRow.propTypes = {
|
|
85
|
+
isOpen: PropTypes.bool.isRequired,
|
|
86
|
+
isWhite: PropTypes.bool.isRequired,
|
|
87
|
+
name: PropTypes.string.isRequired,
|
|
88
|
+
onOpenPlugin: PropTypes.func.isRequired,
|
|
89
|
+
permissions: PropTypes.object.isRequired,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default PermissionRow;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { memo, useCallback, useReducer } from 'react';
|
|
2
|
+
import { Padded } from '@buffetjs/core';
|
|
3
|
+
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
|
|
4
|
+
import ListWrapper from './ListWrapper';
|
|
5
|
+
import PermissionRow from './PermissionRow';
|
|
6
|
+
import init from './init';
|
|
7
|
+
import { initialState, reducer } from './reducer';
|
|
8
|
+
|
|
9
|
+
const Permissions = () => {
|
|
10
|
+
const { modifiedData } = useUsersPermissions();
|
|
11
|
+
const [{ collapses }, dispatch] = useReducer(reducer, initialState, state =>
|
|
12
|
+
init(state, modifiedData)
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const handleOpenPlugin = useCallback(index => {
|
|
16
|
+
dispatch({
|
|
17
|
+
type: 'TOGGLE_COLLAPSE',
|
|
18
|
+
index,
|
|
19
|
+
});
|
|
20
|
+
}, []);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<ListWrapper>
|
|
24
|
+
<Padded left right size="sm">
|
|
25
|
+
{collapses.map((_, index) => {
|
|
26
|
+
const { isOpen, name } = collapses[index];
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<PermissionRow
|
|
30
|
+
key={name}
|
|
31
|
+
isOpen={isOpen}
|
|
32
|
+
isWhite={index % 2 === 1}
|
|
33
|
+
name={name}
|
|
34
|
+
onOpenPlugin={() => handleOpenPlugin(index)}
|
|
35
|
+
permissions={modifiedData[name]}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
})}
|
|
39
|
+
</Padded>
|
|
40
|
+
</ListWrapper>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default memo(Permissions);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const init = (initialState, permissions) => {
|
|
2
|
+
const collapses = Object.keys(permissions)
|
|
3
|
+
.sort()
|
|
4
|
+
.reduce((acc, current, index) => {
|
|
5
|
+
return acc.concat({
|
|
6
|
+
name: current,
|
|
7
|
+
isOpen: index === 0,
|
|
8
|
+
});
|
|
9
|
+
}, []);
|
|
10
|
+
|
|
11
|
+
return { ...initialState, collapses };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default init;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import produce from 'immer';
|
|
2
|
+
|
|
3
|
+
const initialState = {
|
|
4
|
+
collapses: [],
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const reducer = (state, action) =>
|
|
8
|
+
// eslint-disable-next-line consistent-return
|
|
9
|
+
produce(state, draftState => {
|
|
10
|
+
switch (action.type) {
|
|
11
|
+
case 'TOGGLE_COLLAPSE': {
|
|
12
|
+
draftState.collapses = state.collapses.map((collapse, index) => {
|
|
13
|
+
if (index === action.index) {
|
|
14
|
+
return { ...collapse, isOpen: !collapse.isOpen };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return { ...collapse, isOpen: false };
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
default:
|
|
23
|
+
return draftState;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export { initialState, reducer };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { themePropTypes } from 'strapi-helper-plugin';
|
|
3
|
+
|
|
4
|
+
const Wrapper = styled.div`
|
|
5
|
+
min-height: 100%;
|
|
6
|
+
background-color: #f6f6f6;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
const Header = styled.div`
|
|
10
|
+
margin-bottom: 1.1rem;
|
|
11
|
+
padding-top: 1.1rem;
|
|
12
|
+
font-size: 18px;
|
|
13
|
+
font-weight: ${({ theme }) => theme.main.fontWeights.bold};
|
|
14
|
+
line-height: 3.6rem;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const Sticky = styled.div`
|
|
18
|
+
position: sticky;
|
|
19
|
+
top: 70px;
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
Header.propTypes = {
|
|
23
|
+
...themePropTypes,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { Header, Wrapper, Sticky };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { FormattedMessage } from 'react-intl';
|
|
3
|
+
import { Col } from 'reactstrap';
|
|
4
|
+
import { get, isEmpty, takeRight, toLower, without } from 'lodash';
|
|
5
|
+
import { getTrad } from '../../utils';
|
|
6
|
+
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
|
|
7
|
+
import BoundRoute from '../BoundRoute';
|
|
8
|
+
import SizedInput from '../SizedInput';
|
|
9
|
+
import { Header, Wrapper, Sticky } from './Components';
|
|
10
|
+
|
|
11
|
+
const Policies = () => {
|
|
12
|
+
const { modifiedData, selectedAction, routes, policies, onChange } = useUsersPermissions();
|
|
13
|
+
const baseTitle = 'users-permissions.Policies.header';
|
|
14
|
+
const title = !selectedAction ? 'hint' : 'title';
|
|
15
|
+
const path = without(selectedAction.split('.'), 'controllers');
|
|
16
|
+
const controllerRoutes = get(routes, path[0]);
|
|
17
|
+
const displayedRoutes = isEmpty(controllerRoutes)
|
|
18
|
+
? []
|
|
19
|
+
: controllerRoutes.filter(o => toLower(o.handler) === toLower(takeRight(path, 2).join('.')));
|
|
20
|
+
|
|
21
|
+
const inputName = `${selectedAction}.policy`;
|
|
22
|
+
|
|
23
|
+
const value = useMemo(() => {
|
|
24
|
+
return get(modifiedData, inputName, '');
|
|
25
|
+
}, [inputName, modifiedData]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Wrapper className="col-md-5">
|
|
29
|
+
<Sticky className="container-fluid">
|
|
30
|
+
<div className="row">
|
|
31
|
+
<Header className="col-md-12">
|
|
32
|
+
<FormattedMessage id={`${baseTitle}.${title}`} />
|
|
33
|
+
</Header>
|
|
34
|
+
{selectedAction && (
|
|
35
|
+
<>
|
|
36
|
+
<SizedInput
|
|
37
|
+
type="select"
|
|
38
|
+
name={inputName}
|
|
39
|
+
onChange={onChange}
|
|
40
|
+
label={getTrad('Policies.InputSelect.label')}
|
|
41
|
+
options={policies}
|
|
42
|
+
value={value}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<div className="row">
|
|
46
|
+
<Col size={{ xs: 12 }}>
|
|
47
|
+
{displayedRoutes.map((route, key) => (
|
|
48
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
49
|
+
<BoundRoute key={key} route={route} />
|
|
50
|
+
))}
|
|
51
|
+
</Col>
|
|
52
|
+
</div>
|
|
53
|
+
</>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
56
|
+
</Sticky>
|
|
57
|
+
</Wrapper>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default Policies;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Flex, Padded, Text } from '@buffetjs/core';
|
|
3
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
4
|
+
import { upperFirst } from 'lodash';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
|
|
7
|
+
const PrefixedIcon = ({ icon, name }) => {
|
|
8
|
+
return (
|
|
9
|
+
<Flex>
|
|
10
|
+
<div>
|
|
11
|
+
<FontAwesomeIcon icon={icon} />
|
|
12
|
+
</div>
|
|
13
|
+
<Padded left size="md">
|
|
14
|
+
<Text fontWeight="semiBold" lineHeight="18px">
|
|
15
|
+
{upperFirst(name)}
|
|
16
|
+
</Text>
|
|
17
|
+
</Padded>
|
|
18
|
+
</Flex>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
PrefixedIcon.propTypes = {
|
|
23
|
+
icon: PropTypes.array.isRequired,
|
|
24
|
+
name: PropTypes.string.isRequired,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default PrefixedIcon;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Flex, Padded, Text } from '@buffetjs/core';
|
|
3
|
+
import { useIntl } from 'react-intl';
|
|
4
|
+
|
|
5
|
+
import BaselineAlignment from './BaselineAlignment';
|
|
6
|
+
|
|
7
|
+
const EmptyRole = () => {
|
|
8
|
+
const { formatMessage } = useIntl();
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<BaselineAlignment />
|
|
13
|
+
<Padded top bottom size="md">
|
|
14
|
+
<Flex justifyContent="center">
|
|
15
|
+
<Text fontSize="lg" fontWeight="bold">
|
|
16
|
+
{formatMessage({
|
|
17
|
+
id: 'Roles.components.List.empty',
|
|
18
|
+
defaultMessage: 'There is no role',
|
|
19
|
+
})}
|
|
20
|
+
</Text>
|
|
21
|
+
</Flex>
|
|
22
|
+
</Padded>
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default EmptyRole;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
|
|
3
|
+
const RoleListWrapper = styled.div`
|
|
4
|
+
border-radius: 2px;
|
|
5
|
+
box-shadow: 0 2px 4px #e3e9f3;
|
|
6
|
+
background: white;
|
|
7
|
+
|
|
8
|
+
> div,
|
|
9
|
+
> div > div:last-of-type {
|
|
10
|
+
box-shadow: none;
|
|
11
|
+
border-radius: 2px;
|
|
12
|
+
border-bottom-left-radius: 0;
|
|
13
|
+
border-bottom-right-radius: 0;
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export default RoleListWrapper;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { CustomRow } from '@buffetjs/styles';
|
|
4
|
+
import { IconLinks, Text } from '@buffetjs/core';
|
|
5
|
+
import { useIntl } from 'react-intl';
|
|
6
|
+
|
|
7
|
+
import RoleDescription from './RoleDescription';
|
|
8
|
+
|
|
9
|
+
const RoleRow = ({ role, onClick, links }) => {
|
|
10
|
+
const { formatMessage } = useIntl();
|
|
11
|
+
const number = role.nb_users;
|
|
12
|
+
const text = formatMessage(
|
|
13
|
+
{ id: `Roles.RoleRow.user-count.${number > 1 ? 'plural' : 'singular'}` },
|
|
14
|
+
{ number }
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<CustomRow onClick={onClick}>
|
|
19
|
+
<td>
|
|
20
|
+
<Text fontWeight="semiBold">{role.name}</Text>
|
|
21
|
+
</td>
|
|
22
|
+
<td>
|
|
23
|
+
<RoleDescription>{role.description}</RoleDescription>
|
|
24
|
+
</td>
|
|
25
|
+
<td>
|
|
26
|
+
<Text>{text}</Text>
|
|
27
|
+
</td>
|
|
28
|
+
<td>
|
|
29
|
+
<IconLinks links={links} />
|
|
30
|
+
</td>
|
|
31
|
+
</CustomRow>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
RoleRow.defaultProps = {
|
|
36
|
+
onClick: null,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
RoleRow.propTypes = {
|
|
40
|
+
links: PropTypes.array.isRequired,
|
|
41
|
+
onClick: PropTypes.func,
|
|
42
|
+
role: PropTypes.object.isRequired,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default RoleRow;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Col } from 'reactstrap';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import IntlInput from '../IntlInput';
|
|
5
|
+
|
|
6
|
+
const SizedInput = ({ size, ...rest }) => {
|
|
7
|
+
return (
|
|
8
|
+
<Col {...size}>
|
|
9
|
+
<IntlInput {...rest} />
|
|
10
|
+
</Col>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
SizedInput.defaultProps = {
|
|
15
|
+
size: {
|
|
16
|
+
xs: '12',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
SizedInput.propTypes = {
|
|
21
|
+
size: PropTypes.object,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default SizedInput;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { memo, useReducer, useCallback, forwardRef, useImperativeHandle } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Padded, Flex } from '@buffetjs/core';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
|
|
6
|
+
import FormCard from '../FormBloc';
|
|
7
|
+
import getTrad from '../../utils/getTrad';
|
|
8
|
+
import Policies from '../Policies';
|
|
9
|
+
import Permissions from '../Permissions';
|
|
10
|
+
import reducer, { initialState } from './reducer';
|
|
11
|
+
import { UsersPermissionsProvider } from '../../contexts/UsersPermissionsContext';
|
|
12
|
+
import init from './init';
|
|
13
|
+
|
|
14
|
+
const UsersPermissions = forwardRef(({ permissions, routes, policies }, ref) => {
|
|
15
|
+
const { formatMessage } = useIntl();
|
|
16
|
+
const [state, dispatch] = useReducer(reducer, initialState, state =>
|
|
17
|
+
init(state, permissions, routes, policies)
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
useImperativeHandle(ref, () => ({
|
|
21
|
+
getPermissions: () => {
|
|
22
|
+
return {
|
|
23
|
+
permissions: state.modifiedData,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
resetForm: () => {
|
|
27
|
+
dispatch({ type: 'ON_RESET' });
|
|
28
|
+
},
|
|
29
|
+
setFormAfterSubmit: () => {
|
|
30
|
+
dispatch({ type: 'ON_SUBMIT_SUCCEEDED' });
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
const handleChange = useCallback(({ target: { name, value } }) => {
|
|
35
|
+
dispatch({
|
|
36
|
+
type: 'ON_CHANGE',
|
|
37
|
+
keys: name.split('.'),
|
|
38
|
+
value: value === 'empty__string_value' ? '' : value,
|
|
39
|
+
});
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
const handleChangeSelectAll = useCallback(({ target: { name, value } }) => {
|
|
43
|
+
dispatch({
|
|
44
|
+
type: 'ON_CHANGE_SELECT_ALL',
|
|
45
|
+
keys: name.split('.'),
|
|
46
|
+
value,
|
|
47
|
+
});
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
const handleSelectedAction = useCallback(actionToSelect => {
|
|
51
|
+
dispatch({
|
|
52
|
+
type: 'SELECT_ACTION',
|
|
53
|
+
actionToSelect,
|
|
54
|
+
});
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
const providerValue = {
|
|
58
|
+
...state,
|
|
59
|
+
onChange: handleChange,
|
|
60
|
+
onChangeSelectAll: handleChangeSelectAll,
|
|
61
|
+
onSelectedAction: handleSelectedAction,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<UsersPermissionsProvider value={providerValue}>
|
|
66
|
+
<Flex>
|
|
67
|
+
<FormCard
|
|
68
|
+
title={formatMessage({
|
|
69
|
+
id: getTrad('Plugins.header.title'),
|
|
70
|
+
})}
|
|
71
|
+
subtitle={formatMessage({
|
|
72
|
+
id: getTrad('Plugins.header.description'),
|
|
73
|
+
})}
|
|
74
|
+
>
|
|
75
|
+
<Padded left right size="xs">
|
|
76
|
+
<Permissions />
|
|
77
|
+
</Padded>
|
|
78
|
+
</FormCard>
|
|
79
|
+
<Policies />
|
|
80
|
+
</Flex>
|
|
81
|
+
</UsersPermissionsProvider>
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
UsersPermissions.propTypes = {
|
|
86
|
+
permissions: PropTypes.object.isRequired,
|
|
87
|
+
routes: PropTypes.object.isRequired,
|
|
88
|
+
policies: PropTypes.array.isRequired,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default memo(UsersPermissions);
|