mirror of
https://github.com/strapi/strapi.git
synced 2025-12-28 07:33:17 +00:00
Fix PR review 2
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
parent
c75a0fe8fe
commit
342e0a9a86
@ -1,4 +1,5 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "menus",
|
||||
"info": {
|
||||
"name": "menu",
|
||||
@ -14,8 +15,8 @@
|
||||
"type": "text"
|
||||
},
|
||||
"menusections": {
|
||||
"collection": "menusection",
|
||||
"via": "menu"
|
||||
"via": "menu",
|
||||
"collection": "menusection"
|
||||
},
|
||||
"restaurant": {
|
||||
"via": "menu",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "menusections",
|
||||
"info": {
|
||||
"name": "menusection",
|
||||
@ -21,7 +22,8 @@
|
||||
"dishes": {
|
||||
"component": "default.dish",
|
||||
"type": "component",
|
||||
"repeatable": true
|
||||
"repeatable": true,
|
||||
"required": true
|
||||
},
|
||||
"menu": {
|
||||
"model": "menu",
|
||||
|
||||
18
examples/getstarted/components/default/comp1.json
Normal file
18
examples/getstarted/components/default/comp1.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"collectionName": "components_default_comp1_s",
|
||||
"info": {
|
||||
"name": "comp1",
|
||||
"icon": "arrow-alt-circle-up"
|
||||
},
|
||||
"options": {},
|
||||
"attributes": {
|
||||
"comp2": {
|
||||
"type": "component",
|
||||
"repeatable": false,
|
||||
"component": "default.comp2"
|
||||
},
|
||||
"dazdza": {
|
||||
"type": "decimal"
|
||||
}
|
||||
}
|
||||
}
|
||||
19
examples/getstarted/components/default/comp2.json
Normal file
19
examples/getstarted/components/default/comp2.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"collectionName": "components_default_comp2_s",
|
||||
"info": {
|
||||
"name": "comp2",
|
||||
"icon": "ambulance"
|
||||
},
|
||||
"options": {},
|
||||
"attributes": {
|
||||
"azd": {
|
||||
"type": "string"
|
||||
},
|
||||
"dzadaz": {
|
||||
"type": "datetime"
|
||||
},
|
||||
"dazdz": {
|
||||
"type": "biginteger"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import {
|
||||
contentManagerPermissionPrefix,
|
||||
ATTRIBUTES_PERMISSIONS_ACTIONS,
|
||||
getAttributesByModel,
|
||||
getAttributePermissionsSizeByContentTypeAction,
|
||||
getNumberOfRecursivePermissionsByAction,
|
||||
} from '../../../../../../../src/components/Roles/Permissions/utils';
|
||||
import CollapseLabel from '../../../../../../../src/components/Roles/Permissions/ContentTypes/CollapseLabel';
|
||||
@ -53,11 +54,11 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
|
||||
const attributeActions = get(
|
||||
permissions,
|
||||
[contentTypeUid, attributePermissionName, 'actions'],
|
||||
[contentTypeUid, 'attributes', attributePermissionName, 'actions'],
|
||||
[]
|
||||
);
|
||||
|
||||
const getRecursiveAttributes = useCallback(() => {
|
||||
const recursiveAttributes = useMemo(() => {
|
||||
const component = components.find(component => component.uid === attribute.component);
|
||||
|
||||
return [
|
||||
@ -66,6 +67,13 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
];
|
||||
}, [attribute, attributePermissionName, components]);
|
||||
|
||||
const getContentTypePermissions = useCallback(
|
||||
action => {
|
||||
return getAttributePermissionsSizeByContentTypeAction(permissions, contentTypeUid, action);
|
||||
},
|
||||
[contentTypeUid, permissions]
|
||||
);
|
||||
|
||||
const getRecursiveAttributesPermissions = action => {
|
||||
const number = getNumberOfRecursivePermissionsByAction(
|
||||
contentTypeUid,
|
||||
@ -84,12 +92,20 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
// If the current attribute is a component,
|
||||
// we need select all the component attributes.
|
||||
// Otherwhise, we just need to select the current attribute
|
||||
|
||||
if (isCollapsable) {
|
||||
const shouldEnable = !allRecursiveChecked(action);
|
||||
const hasContentTypeAction =
|
||||
(!shouldEnable &&
|
||||
getContentTypePermissions(action) === getRecursiveAttributesPermissions(action)) ||
|
||||
(shouldEnable && getContentTypePermissions(action) === 0);
|
||||
|
||||
onAttributesSelect({
|
||||
action,
|
||||
subject: contentTypeUid,
|
||||
attributes: getRecursiveAttributes(),
|
||||
attributes: recursiveAttributes,
|
||||
shouldEnable: !allRecursiveChecked(action),
|
||||
hasContentTypeAction,
|
||||
});
|
||||
} else {
|
||||
onAttributePermissionSelect({
|
||||
@ -130,16 +146,14 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
const recursivePermissions = getRecursiveAttributesPermissions(action);
|
||||
|
||||
return (
|
||||
isCollapsable &&
|
||||
recursivePermissions > 0 &&
|
||||
recursivePermissions < getRecursiveAttributes().length
|
||||
isCollapsable && recursivePermissions > 0 && recursivePermissions < recursiveAttributes.length
|
||||
);
|
||||
};
|
||||
|
||||
const allRecursiveChecked = action => {
|
||||
const recursivePermissions = getRecursiveAttributesPermissions(action);
|
||||
|
||||
return isCollapsable && recursivePermissions === getRecursiveAttributes().length;
|
||||
return isCollapsable && recursivePermissions === recursiveAttributes.length;
|
||||
};
|
||||
|
||||
return (
|
||||
@ -149,7 +163,7 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
<Flex style={{ flex: 1 }}>
|
||||
<RowStyle
|
||||
isActive={isActive}
|
||||
isRequired={attribute.required}
|
||||
isRequired={attribute.required && !isCollapsable}
|
||||
isCollapsable={attribute.component}
|
||||
level={recursiveLevel}
|
||||
>
|
||||
@ -176,8 +190,8 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
<PermissionWrapper>
|
||||
{ATTRIBUTES_PERMISSIONS_ACTIONS.map(action => (
|
||||
<PermissionCheckbox
|
||||
disabled={attribute.required && !isCollapsable}
|
||||
key={`${attribute.attributeName}-${action}`}
|
||||
disabled={attribute.required}
|
||||
onChange={() => handleCheck(`${contentManagerPermissionPrefix}.${action}`)}
|
||||
someChecked={someChecked(`${contentManagerPermissionPrefix}.${action}`)}
|
||||
value={allRecursiveChecked(action) || checkPermission(action)}
|
||||
|
||||
@ -8,6 +8,7 @@ import { getAttributesToDisplay } from '../../../../../../../src/utils';
|
||||
import {
|
||||
contentManagerPermissionPrefix,
|
||||
getNumberOfRecursivePermissionsByAction,
|
||||
getAttributePermissionsSizeByContentTypeAction,
|
||||
getAttributesByModel,
|
||||
getRecursivePermissions,
|
||||
ATTRIBUTES_PERMISSIONS_ACTIONS,
|
||||
@ -36,7 +37,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
const isActive = collapsePath[1] === attribute.attributeName;
|
||||
const attributeActions = get(
|
||||
permissions,
|
||||
[contentType.uid, attribute.attributeName, 'actions'],
|
||||
[contentType.uid, 'attributes', attribute.attributeName, 'actions'],
|
||||
[]
|
||||
);
|
||||
|
||||
@ -44,7 +45,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
return getRecursivePermissions(contentType.uid, attribute.attributeName, permissions);
|
||||
}, [contentType, permissions, attribute]);
|
||||
|
||||
const getRecursiveAttributes = useCallback(() => {
|
||||
const recursiveAttributes = useMemo(() => {
|
||||
const component = components.find(component => component.uid === attribute.component);
|
||||
|
||||
return [...getAttributesByModel(component, components, attribute.attributeName), attribute];
|
||||
@ -52,8 +53,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
|
||||
const hasAllActions = useMemo(() => {
|
||||
return (
|
||||
recursivePermissions ===
|
||||
ATTRIBUTES_PERMISSIONS_ACTIONS.length * getRecursiveAttributes().length
|
||||
recursivePermissions === ATTRIBUTES_PERMISSIONS_ACTIONS.length * recursiveAttributes.length
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [permissions]);
|
||||
@ -61,21 +61,22 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
const hasSomeActions = useMemo(() => {
|
||||
return (
|
||||
recursivePermissions > 0 &&
|
||||
recursivePermissions < ATTRIBUTES_PERMISSIONS_ACTIONS.length * getRecursiveAttributes().length
|
||||
recursivePermissions < ATTRIBUTES_PERMISSIONS_ACTIONS.length * recursiveAttributes.length
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [permissions]);
|
||||
|
||||
const handleCheckAllAction = () => {
|
||||
if (isCollapsable) {
|
||||
const attributesToAdd = getRecursiveAttributes();
|
||||
const allActionsSize = attributesToAdd.length * ATTRIBUTES_PERMISSIONS_ACTIONS.length;
|
||||
const attributes = recursiveAttributes;
|
||||
const allActionsSize = attributes.length * ATTRIBUTES_PERMISSIONS_ACTIONS.length;
|
||||
const shouldEnable = recursivePermissions >= 0 && recursivePermissions < allActionsSize;
|
||||
|
||||
onAllContentTypeActions({
|
||||
subject: contentType.uid,
|
||||
attributes: attributesToAdd,
|
||||
shouldEnable: recursivePermissions >= 0 && recursivePermissions < allActionsSize,
|
||||
addContentTypeActions: false,
|
||||
attributes,
|
||||
shouldEnable,
|
||||
shouldSetAllContentTypes: false,
|
||||
});
|
||||
} else {
|
||||
onAllAttributeActionsSelect({
|
||||
@ -88,7 +89,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
const getRecursiveAttributesPermissions = useCallback(
|
||||
action => {
|
||||
return getNumberOfRecursivePermissionsByAction(
|
||||
collapsePath[0],
|
||||
contentType.uid,
|
||||
action,
|
||||
attribute.attributeName,
|
||||
permissions
|
||||
@ -98,6 +99,13 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
[attribute, permissions]
|
||||
);
|
||||
|
||||
const getContentTypePermissions = useCallback(
|
||||
action => {
|
||||
return getAttributePermissionsSizeByContentTypeAction(permissions, contentType.uid, action);
|
||||
},
|
||||
[contentType, permissions]
|
||||
);
|
||||
|
||||
const checkPermission = useCallback(
|
||||
action => {
|
||||
return attributeActions.findIndex(permAction => permAction === action) !== -1;
|
||||
@ -109,11 +117,18 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
const handleCheck = useCallback(
|
||||
action => {
|
||||
if (isCollapsable) {
|
||||
const shouldEnable = !allRecursiveChecked(action);
|
||||
const hasContentTypeAction =
|
||||
(!shouldEnable &&
|
||||
getContentTypePermissions(action) === getRecursiveAttributesPermissions(action)) ||
|
||||
(shouldEnable && getContentTypePermissions(action) === 0);
|
||||
|
||||
onAttributesSelect({
|
||||
action,
|
||||
subject: collapsePath[0],
|
||||
attributes: getRecursiveAttributes(),
|
||||
shouldEnable: !allRecursiveChecked(action),
|
||||
subject: contentType.uid,
|
||||
attributes: recursiveAttributes,
|
||||
shouldEnable,
|
||||
hasContentTypeAction,
|
||||
});
|
||||
} else {
|
||||
onAttributePermissionSelect({
|
||||
@ -142,20 +157,20 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
return (
|
||||
isCollapsable &&
|
||||
getRecursiveAttributesPermissions(action) > 0 &&
|
||||
getRecursiveAttributesPermissions(action) < getRecursiveAttributes().length
|
||||
getRecursiveAttributesPermissions(action) < recursiveAttributes.length
|
||||
);
|
||||
};
|
||||
|
||||
const allRecursiveChecked = action => {
|
||||
return (
|
||||
isCollapsable && getRecursiveAttributesPermissions(action) === getRecursiveAttributes().length
|
||||
isCollapsable && getRecursiveAttributesPermissions(action) === recursiveAttributes.length
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AttributeRowWrapper
|
||||
isRequired={attribute.required}
|
||||
isRequired={attribute.required && !isCollapsable}
|
||||
isActive={isActive}
|
||||
isCollapsable={isCollapsable}
|
||||
alignItems="center"
|
||||
@ -164,7 +179,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
<Padded left size="sm" />
|
||||
<PermissionName width="15rem">
|
||||
<Checkbox
|
||||
disabled={attribute.required}
|
||||
disabled={attribute.required && !isCollapsable}
|
||||
name={attribute.attributeName}
|
||||
value={hasAllActions}
|
||||
someChecked={hasSomeActions}
|
||||
@ -194,7 +209,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
{ATTRIBUTES_PERMISSIONS_ACTIONS.map(action => (
|
||||
<PermissionCheckbox
|
||||
key={action}
|
||||
disabled={attribute.required}
|
||||
disabled={attribute.required && !isCollapsable}
|
||||
value={
|
||||
allRecursiveChecked(`${contentManagerPermissionPrefix}.${action}`) ||
|
||||
checkPermission(`${contentManagerPermissionPrefix}.${action}`)
|
||||
|
||||
@ -33,9 +33,11 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
} = usePermissionsContext();
|
||||
const isActive = collapsePath[0] === contentType.uid;
|
||||
|
||||
const contentTypeActions = Object.values(
|
||||
get(permissions, [contentType.uid, 'contentTypeActions'], {})
|
||||
).filter(action => !!action);
|
||||
const contentTypeActions = useMemo(() => {
|
||||
return Object.values(get(permissions, [contentType.uid, 'contentTypeActions'], {})).filter(
|
||||
action => !!action
|
||||
);
|
||||
}, [contentType, permissions]);
|
||||
|
||||
// Number of all actions in the current content type.
|
||||
const allCurrentActionsSize = useMemo(() => {
|
||||
@ -94,7 +96,7 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
subject: contentType.uid,
|
||||
attributes,
|
||||
shouldEnable: !hasAllAttributeByAction(action) || !hasContentTypeAction(action),
|
||||
contentTypeAction: true,
|
||||
hasContentTypeAction: true,
|
||||
});
|
||||
};
|
||||
|
||||
@ -112,7 +114,7 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
subject: contentType.uid,
|
||||
attributes: getAttributesByModel(contentType, components),
|
||||
shouldEnable: allCurrentActionsSize < allActionsSize,
|
||||
addContentTypeActions: true,
|
||||
shouldSetAllContentTypes: true,
|
||||
});
|
||||
};
|
||||
|
||||
@ -127,7 +129,8 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
name={contentType.name}
|
||||
someChecked={
|
||||
contentTypeActions.length > 0 &&
|
||||
contentTypeActions.length < contentTypesPermissionsLayout.length > 0
|
||||
allCurrentActionsSize > 0 &&
|
||||
allCurrentActionsSize < allActionsSize
|
||||
}
|
||||
value={allCurrentActionsSize === allActionsSize}
|
||||
/>
|
||||
|
||||
@ -47,12 +47,10 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
|
||||
const attributeActions = get(
|
||||
permissions,
|
||||
[contentTypeUid, attributePermissionName, 'actions'],
|
||||
[contentTypeUid, 'attributes', attributePermissionName, 'actions'],
|
||||
[]
|
||||
);
|
||||
|
||||
// Get the recursive component attributes
|
||||
// ans add the current attribute as it is a permission too.
|
||||
const getRecursiveAttributes = useCallback(() => {
|
||||
const component = components.find(component => component.uid === attribute.component);
|
||||
|
||||
@ -62,7 +60,7 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
];
|
||||
}, [attribute, attributePermissionName, components]);
|
||||
|
||||
const countRecursivePermissions = action => {
|
||||
const getRecursiveAttributesPermissions = action => {
|
||||
const number = getNumberOfRecursivePermissionsByAction(
|
||||
contentTypeUid,
|
||||
action,
|
||||
@ -99,7 +97,7 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
};
|
||||
|
||||
const someChecked = action => {
|
||||
const recursivePermissions = countRecursivePermissions(action);
|
||||
const recursivePermissions = getRecursiveAttributesPermissions(action);
|
||||
|
||||
return (
|
||||
isCollapsable &&
|
||||
@ -109,7 +107,7 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
};
|
||||
|
||||
const allRecursiveChecked = action => {
|
||||
const recursivePermissions = countRecursivePermissions(action);
|
||||
const recursivePermissions = getRecursiveAttributesPermissions(action);
|
||||
|
||||
return isCollapsable && recursivePermissions === getRecursiveAttributes().length;
|
||||
};
|
||||
@ -121,7 +119,7 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
<Flex style={{ flex: 1 }}>
|
||||
<RowStyle
|
||||
isActive={isActive}
|
||||
isRequired={attribute.required}
|
||||
isRequired={attribute.required && !isCollapsable}
|
||||
isCollapsable={attribute.component}
|
||||
level={recursiveLevel}
|
||||
>
|
||||
@ -145,11 +143,12 @@ const ComponentAttributeRow = ({ attribute, index, numberOfAttributes, recursive
|
||||
<Chevron icon={isActive ? 'caret-up' : 'caret-down'} />
|
||||
</CollapseLabel>
|
||||
</RowStyle>
|
||||
<PermissionWrapper>
|
||||
<PermissionWrapper disabled>
|
||||
{ATTRIBUTES_PERMISSIONS_ACTIONS.map(action => (
|
||||
<PermissionCheckbox
|
||||
key={`${attribute.attributeName}-${action}`}
|
||||
disabled
|
||||
key={`${attribute.attributeName}-${action}`}
|
||||
// onChange={() => handleCheck(`${contentManagerPermissionPrefix}.${action}`)}
|
||||
someChecked={someChecked(`${contentManagerPermissionPrefix}.${action}`)}
|
||||
value={allRecursiveChecked(action) || checkPermission(action)}
|
||||
name={`${attribute.attributeName}-${action}`}
|
||||
|
||||
@ -9,7 +9,6 @@ import {
|
||||
contentManagerPermissionPrefix,
|
||||
getNumberOfRecursivePermissionsByAction,
|
||||
getAttributesByModel,
|
||||
getAllAttributesActionsSize,
|
||||
getRecursivePermissions,
|
||||
ATTRIBUTES_PERMISSIONS_ACTIONS,
|
||||
} from '../../../utils';
|
||||
@ -35,7 +34,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
const isActive = collapsePath[1] === attribute.attributeName;
|
||||
const attributeActions = get(
|
||||
permissions,
|
||||
[contentType.uid, attribute.attributeName, 'actions'],
|
||||
[contentType.uid, 'attributes', attribute.attributeName, 'actions'],
|
||||
[]
|
||||
);
|
||||
|
||||
@ -67,16 +66,14 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
|
||||
const handleCheckAllAction = () => {
|
||||
if (isCollapsable) {
|
||||
const allCurrentActionsSize = getAllAttributesActionsSize(contentType.uid, permissions);
|
||||
const attributeToAdd = getRecursiveAttributes();
|
||||
|
||||
const allActionsSize = attributeToAdd.length * ATTRIBUTES_PERMISSIONS_ACTIONS.length;
|
||||
const attributesToAdd = getRecursiveAttributes();
|
||||
const allActionsSize = attributesToAdd.length * ATTRIBUTES_PERMISSIONS_ACTIONS.length;
|
||||
|
||||
onAllContentTypeActions({
|
||||
subject: contentType.uid,
|
||||
attributes: attributeToAdd,
|
||||
shouldEnable: allCurrentActionsSize >= 0 && allCurrentActionsSize < allActionsSize,
|
||||
addContentTypeActions: false,
|
||||
attributes: attributesToAdd,
|
||||
shouldEnable: recursivePermissions >= 0 && recursivePermissions < allActionsSize,
|
||||
shouldSetAllContentTypes: false,
|
||||
});
|
||||
} else {
|
||||
onAllAttributeActionsSelect({
|
||||
@ -135,7 +132,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
return (
|
||||
<>
|
||||
<AttributeRowWrapper
|
||||
isRequired={attribute.required}
|
||||
isRequired={attribute.required && !isCollapsable}
|
||||
isActive={isActive}
|
||||
isCollapsable={isCollapsable}
|
||||
alignItems="center"
|
||||
@ -144,7 +141,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
<Padded left size="sm" />
|
||||
<PermissionName width="15rem">
|
||||
<Checkbox
|
||||
disabled={attribute.required}
|
||||
disabled={attribute.required && !isCollapsable}
|
||||
name={attribute.attributeName}
|
||||
value={hasAllActions}
|
||||
someChecked={hasSomeActions}
|
||||
@ -170,7 +167,7 @@ const AttributeRow = ({ attribute, contentType }) => {
|
||||
<Chevron icon={isActive ? 'caret-up' : 'caret-down'} />
|
||||
</CollapseLabel>
|
||||
</PermissionName>
|
||||
<PermissionWrapper>
|
||||
<PermissionWrapper disabled>
|
||||
{ATTRIBUTES_PERMISSIONS_ACTIONS.map(action => (
|
||||
<PermissionCheckbox
|
||||
key={action}
|
||||
|
||||
@ -3,6 +3,16 @@ import { Flex } from '@buffetjs/core';
|
||||
|
||||
const PermissionWrapper = styled(Flex)`
|
||||
flex: 1;
|
||||
${({ isDisabled, theme }) =>
|
||||
isDisabled &&
|
||||
`
|
||||
input[type='checkbox'] {
|
||||
&:after {
|
||||
color: ${theme.main.colors.grey};
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
export default PermissionWrapper;
|
||||
|
||||
@ -30,15 +30,14 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
} = usePermissionsContext();
|
||||
const isActive = collapsePath[0] === contentType.uid;
|
||||
|
||||
// Number of all actions in the current content type
|
||||
const contentTypeActions = Object.values(
|
||||
get(permissions, [contentType.uid, 'contentTypeActions'], {})
|
||||
).filter(action => !!action);
|
||||
|
||||
// Number of all actions in the current content type.
|
||||
const allCurrentActionsSize = useMemo(() => {
|
||||
return (
|
||||
getAllAttributesActionsSize(contentType.uid, permissions) +
|
||||
Object.values(get(permissions, [contentType.uid, 'contentTypeActions'], {})).filter(
|
||||
action => !!action
|
||||
).length
|
||||
);
|
||||
}, [contentType, permissions]);
|
||||
return getAllAttributesActionsSize(contentType.uid, permissions) + contentTypeActions.length;
|
||||
}, [contentType, contentTypeActions, permissions]);
|
||||
|
||||
// Attributes to display : Liste of attributes of in the content type without timestamps and id
|
||||
// Used to display the first level of attributes.
|
||||
@ -46,42 +45,37 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
return getAttributesToDisplay(contentType);
|
||||
}, [contentType]);
|
||||
|
||||
// The number of all recursive attributes.
|
||||
// All recursive attributes.
|
||||
// Used to recursively set the global content type action
|
||||
const attributesSizes = useMemo(() => {
|
||||
return getAttributesByModel(contentType, components).length;
|
||||
const attributes = useMemo(() => {
|
||||
return getAttributesByModel(contentType, components);
|
||||
}, [contentType, components]);
|
||||
|
||||
const allActionsSize =
|
||||
attributes.length * ATTRIBUTES_PERMISSIONS_ACTIONS.length +
|
||||
contentTypesPermissionsLayout.length;
|
||||
|
||||
const hasContentTypeAction = useCallback(
|
||||
action => get(permissions, [contentType.uid, 'contentTypeActions', action], false),
|
||||
[permissions, contentType]
|
||||
);
|
||||
|
||||
const hasAllAttributeByAction = useCallback(
|
||||
action =>
|
||||
getAttributePermissionsSizeByContentTypeAction(permissions, contentType.uid, action) ===
|
||||
attributesSizes,
|
||||
[permissions, contentType, attributesSizes]
|
||||
);
|
||||
|
||||
// Check if an attribute have the passed action
|
||||
// Used to set the someChecked props of an action checkbox
|
||||
const hasSomeAttributeByAction = useCallback(
|
||||
action =>
|
||||
getAttributePermissionsSizeByContentTypeAction(permissions, contentType.uid, action) > 0 &&
|
||||
getAttributePermissionsSizeByContentTypeAction(permissions, contentType.uid, action) <
|
||||
attributesSizes,
|
||||
[permissions, contentType.uid, attributesSizes]
|
||||
attributes.length &&
|
||||
hasContentTypeAction(action),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[permissions, contentType, attributes]
|
||||
);
|
||||
|
||||
const handleToggleAttributes = () => {
|
||||
onCollapse(0, contentType.uid);
|
||||
};
|
||||
|
||||
const allActionsSize =
|
||||
attributesSizes * ATTRIBUTES_PERMISSIONS_ACTIONS.length -
|
||||
(ATTRIBUTES_PERMISSIONS_ACTIONS.length - contentTypesPermissionsLayout.length);
|
||||
|
||||
// Check/Uncheck all the actions for all
|
||||
// attributes of the current content type
|
||||
const handleAllContentTypeActions = () => {
|
||||
@ -89,7 +83,7 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
subject: contentType.uid,
|
||||
attributes: getAttributesByModel(contentType, components),
|
||||
shouldEnable: allCurrentActionsSize < allActionsSize,
|
||||
addContentTypeActions: true,
|
||||
shouldSetAllContentTypes: true,
|
||||
});
|
||||
};
|
||||
|
||||
@ -102,7 +96,11 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
<Checkbox
|
||||
onChange={handleAllContentTypeActions}
|
||||
name={contentType.name}
|
||||
someChecked={allCurrentActionsSize > 0 && allCurrentActionsSize < allActionsSize}
|
||||
someChecked={
|
||||
contentTypeActions.length > 0 &&
|
||||
allCurrentActionsSize > 0 &&
|
||||
allCurrentActionsSize < allActionsSize
|
||||
}
|
||||
value={allCurrentActionsSize === allActionsSize}
|
||||
/>
|
||||
<CollapseLabel
|
||||
@ -124,21 +122,21 @@ const ContentTypeRow = ({ index, contentType, contentTypesPermissionsLayout }) =
|
||||
<Chevron icon={isActive ? 'chevron-up' : 'chevron-down'} />
|
||||
</CollapseLabel>
|
||||
</PermissionName>
|
||||
<PermissionWrapper>
|
||||
<PermissionWrapper disabled>
|
||||
{contentTypesPermissionsLayout.map(permissionLayout =>
|
||||
!isAttributeAction(permissionLayout.action) ? (
|
||||
<PermissionCheckbox
|
||||
key={permissionLayout.action}
|
||||
disabled
|
||||
key={permissionLayout.action}
|
||||
value={hasContentTypeAction(permissionLayout.action)}
|
||||
hasConditions={false}
|
||||
name={`${contentType.name}-${permissionLayout.action}`}
|
||||
/>
|
||||
) : (
|
||||
<PermissionCheckbox
|
||||
disabeld
|
||||
key={permissionLayout.action}
|
||||
disabled
|
||||
value={hasAllAttributeByAction(permissionLayout.action)}
|
||||
value={hasContentTypeAction(permissionLayout.action)}
|
||||
someChecked={hasSomeAttributeByAction(permissionLayout.action)}
|
||||
hasConditions={false}
|
||||
name={`${contentType.name}-${permissionLayout.action}`}
|
||||
|
||||
@ -19,11 +19,10 @@ const PermissionCheckbox = styled(Checkbox)`
|
||||
}
|
||||
`}
|
||||
${({ disabled, theme }) =>
|
||||
disabled &&
|
||||
`
|
||||
input[type='checkbox'] {
|
||||
&:after {
|
||||
color: ${theme.main.colors.grey};
|
||||
color: ${!disabled ? theme.main.colors.mediumBlue : theme.main.colors.grey};
|
||||
}
|
||||
}
|
||||
`}
|
||||
|
||||
@ -26,7 +26,7 @@ const PermissionsHeader = ({ allAttributes, contentTypes }) => {
|
||||
attributes: allAttributes,
|
||||
action,
|
||||
shouldEnable: !hasAllActions(action),
|
||||
contentTypeAction: true,
|
||||
hasContentTypeAction: true,
|
||||
});
|
||||
} else {
|
||||
onGlobalPermissionsActionSelect({
|
||||
|
||||
@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Padded } from '@buffetjs/core';
|
||||
import ContentTypeRow from 'ee_else_ce/components/Roles/Permissions/ContentTypes/ContentTypesRow';
|
||||
// import ContentTypeRow from './ContentTypesRow';
|
||||
|
||||
import Wrapper from './Wrapper';
|
||||
import PermissionsHeader from './PermissionsHeader';
|
||||
|
||||
@ -53,14 +53,14 @@ const Permissions = forwardRef(({ permissionsLayout, rolePermissions }, ref) =>
|
||||
attributes,
|
||||
action,
|
||||
shouldEnable,
|
||||
contentTypeAction,
|
||||
hasContentTypeAction,
|
||||
}) => {
|
||||
dispatch({
|
||||
type: 'SET_ATTRIBUTES_PERMISSIONS',
|
||||
attributes,
|
||||
action,
|
||||
shouldEnable,
|
||||
contentTypeAction,
|
||||
hasContentTypeAction,
|
||||
});
|
||||
};
|
||||
|
||||
@ -69,15 +69,15 @@ const Permissions = forwardRef(({ permissionsLayout, rolePermissions }, ref) =>
|
||||
action,
|
||||
attributes,
|
||||
shouldEnable,
|
||||
contentTypeAction,
|
||||
hasContentTypeAction,
|
||||
}) => {
|
||||
dispatch({
|
||||
type: 'CONTENT_TYPE_ATTRIBUTES_ACTION_SELECT',
|
||||
type: 'ON_ATTRIBUTES_SELECT',
|
||||
subject,
|
||||
action,
|
||||
attributes,
|
||||
shouldEnable,
|
||||
contentTypeAction,
|
||||
hasContentTypeAction,
|
||||
});
|
||||
};
|
||||
|
||||
@ -93,14 +93,14 @@ const Permissions = forwardRef(({ permissionsLayout, rolePermissions }, ref) =>
|
||||
subject,
|
||||
attributes,
|
||||
shouldEnable,
|
||||
addContentTypeActions,
|
||||
shouldSetAllContentTypes,
|
||||
}) => {
|
||||
dispatch({
|
||||
type: 'ALL_CONTENT_TYPE_PERMISSIONS_SELECT',
|
||||
subject,
|
||||
attributes,
|
||||
shouldEnable,
|
||||
addContentTypeActions,
|
||||
shouldSetAllContentTypes,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
/* eslint-disable indent */
|
||||
/* eslint-disable consistent-return */
|
||||
import produce from 'immer';
|
||||
import { get } from 'lodash';
|
||||
import { get, set } from 'lodash';
|
||||
|
||||
import { staticAttributeActions } from './utils';
|
||||
import { staticAttributeActions, getAttributePermissionsSizeByContentTypeAction } from './utils';
|
||||
import generateContentTypeActions from './utils/generateContentTypeActions';
|
||||
|
||||
export const initialState = {
|
||||
collapsePath: [],
|
||||
@ -26,12 +27,12 @@ const reducer = (state, action) =>
|
||||
}
|
||||
// This reducer action is used to enable/disable all actions for the payload attributes
|
||||
case 'SET_ATTRIBUTES_PERMISSIONS': {
|
||||
const { attributes, action: permissionAction, contentTypeAction, shouldEnable } = action;
|
||||
const { attributes, action: permissionAction, hasContentTypeAction, shouldEnable } = action;
|
||||
|
||||
const actionsToSet = (contentTypeUid, attribute) => {
|
||||
const setActions = (contentTypeUid, attribute) => {
|
||||
const attributeActions = get(
|
||||
state.permissions,
|
||||
[contentTypeUid, attribute.attributeName, 'actions'],
|
||||
[contentTypeUid, 'attributes', attribute.attributeName, 'actions'],
|
||||
[]
|
||||
);
|
||||
|
||||
@ -54,11 +55,14 @@ const reducer = (state, action) =>
|
||||
...acc,
|
||||
[current.contentTypeUid]: {
|
||||
...acc[current.contentTypeUid],
|
||||
[current.attributeName]: {
|
||||
...get(state.permissions, [current.contentTypeUid, current], {}),
|
||||
actions: actionsToSet(current.contentTypeUid, current),
|
||||
attributes: {
|
||||
...get(acc, [current.contentTypeUid, 'attributes'], {}),
|
||||
[current.attributeName]: {
|
||||
...get(state.permissions, [current.contentTypeUid, 'attributes', current], {}),
|
||||
actions: setActions(current.contentTypeUid, current),
|
||||
},
|
||||
},
|
||||
contentTypeActions: contentTypeAction
|
||||
contentTypeActions: hasContentTypeAction
|
||||
? {
|
||||
...get(state.permissions, [current.contentTypeUid, 'contentTypeActions'], {}),
|
||||
[permissionAction]: shouldEnable,
|
||||
@ -75,71 +79,129 @@ const reducer = (state, action) =>
|
||||
case 'ALL_ATTRIBUTE_ACTIONS_SELECT': {
|
||||
const { subject, attribute } = action;
|
||||
const isAll =
|
||||
get(state.permissions, [subject, attribute, 'actions'], []).length ===
|
||||
get(state.permissions, [subject, 'attributes', attribute, 'actions'], []).length ===
|
||||
staticAttributeActions.length;
|
||||
|
||||
let attributesToSet = {};
|
||||
|
||||
if (isAll) {
|
||||
draftState.permissions[subject][attribute].actions = [];
|
||||
set(attributesToSet, [attribute, 'actions'], []);
|
||||
} else {
|
||||
draftState.permissions = {
|
||||
...draftState.permissions,
|
||||
[subject]: {
|
||||
...draftState.permissions[subject],
|
||||
[attribute]: {
|
||||
actions: staticAttributeActions,
|
||||
},
|
||||
},
|
||||
};
|
||||
set(attributesToSet, [attribute, 'actions'], staticAttributeActions);
|
||||
}
|
||||
|
||||
const subjectPermissions = {
|
||||
...get(state.permissions, [subject, 'attributes'], {}),
|
||||
...attributesToSet,
|
||||
};
|
||||
|
||||
const existingContentTypeActions = get(
|
||||
state.permissions,
|
||||
[subject, 'contentTypeActions'],
|
||||
{}
|
||||
);
|
||||
const permissionsLayout = get(state.permissionsLayout, ['sections', 'contentTypes'], []);
|
||||
|
||||
draftState.permissions[subject] = {
|
||||
attributes: subjectPermissions,
|
||||
contentTypeActions: generateContentTypeActions(
|
||||
subjectPermissions,
|
||||
existingContentTypeActions,
|
||||
permissionsLayout
|
||||
),
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
// This reducer action is used to enable/disable a single attribute action
|
||||
case 'ATTRIBUTE_PERMISSION_SELECT': {
|
||||
const { subject, action: permissionAction, attribute } = action;
|
||||
const attributeActions = get(state.permissions, [subject, attribute, 'actions'], []);
|
||||
const attributeActions = get(
|
||||
state.permissions,
|
||||
[subject, 'attributes', attribute, 'actions'],
|
||||
[]
|
||||
);
|
||||
const subjectActions = getAttributePermissionsSizeByContentTypeAction(
|
||||
state.permissions,
|
||||
subject,
|
||||
permissionAction
|
||||
);
|
||||
const hasContentTypeAction = get(
|
||||
state.permissions,
|
||||
[subject, 'contentTypeActions', permissionAction],
|
||||
false
|
||||
);
|
||||
|
||||
const isExist = attributeActions.includes(permissionAction);
|
||||
|
||||
if (!isExist) {
|
||||
if (attributeActions.length > 0) {
|
||||
draftState.permissions[subject][attribute].actions.push(permissionAction);
|
||||
draftState.permissions[subject].attributes[attribute].actions.push(permissionAction);
|
||||
} else {
|
||||
draftState.permissions[subject] = {
|
||||
...get(state.permissions, [subject], {}),
|
||||
[attribute]: {
|
||||
...get(state.permissions, [subject, attribute], {}),
|
||||
actions: [permissionAction],
|
||||
attributes: {
|
||||
...get(state.permissions, [subject, 'attributes'], {}),
|
||||
[attribute]: {
|
||||
...get(state.permissions, [subject, 'attributes', attribute], {}),
|
||||
actions: [permissionAction],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
} else {
|
||||
draftState.permissions[subject][attribute].actions = get(
|
||||
draftState.permissions[subject].attributes[attribute].actions = get(
|
||||
state.permissions,
|
||||
[subject, attribute, 'actions'],
|
||||
[subject, 'attributes', attribute, 'actions'],
|
||||
[]
|
||||
).filter(action => action !== permissionAction);
|
||||
}
|
||||
|
||||
const willRemoveLastAction = subjectActions === 1 && isExist;
|
||||
|
||||
if (!hasContentTypeAction && !isExist) {
|
||||
draftState.permissions[subject].contentTypeActions = {
|
||||
...get(state.permissions, [subject, 'contentTypeActions'], {}),
|
||||
[permissionAction]: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (hasContentTypeAction && willRemoveLastAction) {
|
||||
draftState.permissions[subject].contentTypeActions = {
|
||||
...get(state.permissions, [subject, 'contentTypeActions'], {}),
|
||||
[permissionAction]: false,
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// This reducer action is used to enable/disable
|
||||
// the content type attributes permissions for an action
|
||||
case 'CONTENT_TYPE_ATTRIBUTES_ACTION_SELECT': {
|
||||
case 'ON_ATTRIBUTES_SELECT': {
|
||||
const {
|
||||
attributes,
|
||||
subject,
|
||||
contentTypeAction,
|
||||
hasContentTypeAction,
|
||||
action: permissionAction,
|
||||
shouldEnable,
|
||||
} = action;
|
||||
const existingContentTypeAction = get(
|
||||
state.permissions,
|
||||
[subject, 'contentTypeActions', permissionAction],
|
||||
false
|
||||
);
|
||||
let attributesPermissions = attributes.reduce((acc, attribute) => {
|
||||
return {
|
||||
...acc,
|
||||
[attribute.attributeName]: {
|
||||
...get(state.permissions, [subject, attribute.attributeName], {}),
|
||||
...get(state.permissions, [subject, 'attributes', attribute.attributeName], {}),
|
||||
actions: Array.from(
|
||||
new Set([
|
||||
...get(state.permissions, [subject, attribute.attributeName, 'actions'], []),
|
||||
...get(
|
||||
state.permissions,
|
||||
[subject, 'attributes', attribute.attributeName, 'actions'],
|
||||
[]
|
||||
),
|
||||
permissionAction,
|
||||
])
|
||||
),
|
||||
@ -154,11 +216,11 @@ const reducer = (state, action) =>
|
||||
return {
|
||||
...acc,
|
||||
[attribute.attributeName]: {
|
||||
...get(state.permissions, [subject, attribute.attributeName], {}),
|
||||
...get(state.permissions, [subject, 'attributes', attribute.attributeName], {}),
|
||||
actions: [
|
||||
...get(
|
||||
state.permissions,
|
||||
[subject, attribute.attributeName, 'actions'],
|
||||
[subject, 'attributes', attribute.attributeName, 'actions'],
|
||||
[]
|
||||
).filter(action => action !== permissionAction),
|
||||
],
|
||||
@ -169,8 +231,11 @@ const reducer = (state, action) =>
|
||||
|
||||
draftState.permissions[subject] = {
|
||||
...state.permissions[subject],
|
||||
...attributesPermissions,
|
||||
...(contentTypeAction
|
||||
attributes: {
|
||||
...get(state.permissions, [subject, 'attributes'], {}),
|
||||
...attributesPermissions,
|
||||
},
|
||||
...(hasContentTypeAction || !existingContentTypeAction
|
||||
? {
|
||||
contentTypeActions: {
|
||||
...get(state.permissions, [subject, 'contentTypeActions'], {}),
|
||||
@ -211,31 +276,48 @@ const reducer = (state, action) =>
|
||||
// This reducer action is used to enable/disable all
|
||||
// content type attributes actions recursively
|
||||
case 'ALL_CONTENT_TYPE_PERMISSIONS_SELECT': {
|
||||
const { subject, attributes, shouldEnable } = action;
|
||||
const { subject, attributes, shouldEnable, shouldSetAllContentTypes } = action;
|
||||
const staticActionsName = get(
|
||||
state.permissionsLayout,
|
||||
['sections', 'contentTypes'],
|
||||
[]
|
||||
).map(contentTypeAction => contentTypeAction.action);
|
||||
let permissionsToSet = attributes.reduce((acc, attribute) => {
|
||||
|
||||
let attributesActions = attributes.reduce((acc, attribute) => {
|
||||
return {
|
||||
...get(state.permissions, [subject, 'attributes'], {}),
|
||||
...acc,
|
||||
[attribute.attributeName]: {
|
||||
...get(state.permissions, [subject, attribute.attributeName], {}),
|
||||
...get(state.permissions, [subject, 'attributes', attribute.attributeName], {}),
|
||||
actions: !attribute.required && !shouldEnable ? [] : staticAttributeActions,
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
const contentTypeActions = staticActionsName.reduce((acc, current) => {
|
||||
const contentTypeLayoutAction = staticActionsName.reduce((acc, current) => {
|
||||
return {
|
||||
...acc,
|
||||
[current]: shouldEnable,
|
||||
};
|
||||
}, {});
|
||||
|
||||
const existingContentTypeActions = get(
|
||||
state.permissions,
|
||||
[subject, 'contentTypeActions'],
|
||||
{}
|
||||
);
|
||||
const permissionsLayout = get(state.permissionsLayout, ['sections', 'contentTypes'], []);
|
||||
|
||||
const contentTypeActions = shouldSetAllContentTypes
|
||||
? contentTypeLayoutAction
|
||||
: generateContentTypeActions(
|
||||
attributesActions,
|
||||
existingContentTypeActions,
|
||||
permissionsLayout
|
||||
);
|
||||
|
||||
draftState.permissions[subject] = {
|
||||
...get(state.permissions, [subject]),
|
||||
...permissionsToSet,
|
||||
...get(state.permissions, [subject], {}),
|
||||
attributes: attributesActions,
|
||||
contentTypeActions,
|
||||
};
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,31 @@
|
||||
import { staticAttributeActions } from './permissonsConstantsActions';
|
||||
|
||||
const generateContentTypeActions = (subjectPermissions, existingContentTypeActions) => {
|
||||
const additionalActions = Object.entries(existingContentTypeActions).reduce((acc, current) => {
|
||||
if (current[1] && !staticAttributeActions.includes(current[0])) {
|
||||
return { ...acc, [current[0]]: current[1] };
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const actions = Array.from(
|
||||
new Set(
|
||||
Object.values(subjectPermissions).reduce((acc, current) => {
|
||||
return [...acc, ...current.actions];
|
||||
}, [])
|
||||
)
|
||||
);
|
||||
|
||||
const generatedContentTypeActions = actions.reduce(
|
||||
(acc, current) => ({
|
||||
...acc,
|
||||
[current]: true,
|
||||
}),
|
||||
{}
|
||||
);
|
||||
|
||||
return { ...generatedContentTypeActions, ...additionalActions };
|
||||
};
|
||||
|
||||
export default generateContentTypeActions;
|
||||
@ -1,9 +1,12 @@
|
||||
import { get } from 'lodash';
|
||||
|
||||
const getAllAttributesActionsSize = (contentTypeUid, permissions) => {
|
||||
return Object.entries(get(permissions, [contentTypeUid], {})).reduce((acc, current) => {
|
||||
return acc + get(current[1], ['actions'], []).length;
|
||||
}, 0);
|
||||
return Object.entries(get(permissions, [contentTypeUid, 'attributes'], {})).reduce(
|
||||
(acc, current) => {
|
||||
return acc + get(current[1], ['actions'], []).length;
|
||||
},
|
||||
0
|
||||
);
|
||||
};
|
||||
|
||||
export default getAllAttributesActionsSize;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { get } from 'lodash';
|
||||
|
||||
const getAttributePermissionsSizeByContentTypeAction = (permissions, subject, action) => {
|
||||
const permissionsOccurencesByAction = Object.values(get(permissions, [subject], {})).filter(
|
||||
attribute => {
|
||||
return get(attribute, 'actions', []).findIndex(permAction => permAction === action) !== -1;
|
||||
}
|
||||
);
|
||||
const permissionsOccurencesByAction = Object.values(
|
||||
get(permissions, [subject, 'attributes'], {})
|
||||
).filter(attribute => {
|
||||
return get(attribute, 'actions', []).findIndex(permAction => permAction === action) !== -1;
|
||||
});
|
||||
|
||||
return permissionsOccurencesByAction.length;
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@ import { get } from 'lodash';
|
||||
|
||||
const getContentTypesActionsSize = (contentTypes, permissions, action) => {
|
||||
const count = contentTypes.reduce((acc, current) => {
|
||||
if (get(permissions, [current.uid, 'contentTypeActions', action], null)) {
|
||||
if (get(permissions, [current.uid, 'contentTypeActions', action], false)) {
|
||||
return acc + 1;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { get } from 'lodash';
|
||||
|
||||
const getNumberOfRecursivePermissionsByAction = (subject, action, attributeName, permissions) => {
|
||||
return Object.entries(get(permissions, [subject], {})).reduce((acc, current) => {
|
||||
return Object.entries(get(permissions, [subject, 'attributes'], {})).reduce((acc, current) => {
|
||||
if (current[0].startsWith(attributeName) && current[1].actions.includes(action)) {
|
||||
return acc + 1;
|
||||
}
|
||||
|
||||
@ -2,15 +2,14 @@ import { get } from 'lodash';
|
||||
|
||||
const getPermissionsCountByAction = (contentTypes, permissions, action) => {
|
||||
const count = contentTypes.reduce((contentTypeAcc, currentContentType) => {
|
||||
const attributeCount = Object.values(get(permissions, [currentContentType.uid], [])).reduce(
|
||||
(attributeAcc, currentAttribute) => {
|
||||
return (
|
||||
attributeAcc +
|
||||
get(currentAttribute, 'actions', []).filter(permAction => permAction === action).length
|
||||
);
|
||||
},
|
||||
0
|
||||
);
|
||||
const attributeCount = Object.values(
|
||||
get(permissions, [currentContentType.uid, 'attributes'], [])
|
||||
).reduce((attributeAcc, currentAttribute) => {
|
||||
return (
|
||||
attributeAcc +
|
||||
get(currentAttribute, 'actions', []).filter(permAction => permAction === action).length
|
||||
);
|
||||
}, 0);
|
||||
|
||||
return contentTypeAcc + attributeCount;
|
||||
}, 0);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { get } from 'lodash';
|
||||
|
||||
const getRecursivePermissions = (subject, attributeName, permissions) => {
|
||||
return Object.entries(get(permissions, [subject], {})).reduce((acc, current) => {
|
||||
return Object.entries(get(permissions, [subject, 'attributes'], {})).reduce((acc, current) => {
|
||||
if (current[0].startsWith(attributeName)) {
|
||||
return acc + current[1].actions.length;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { get } from 'lodash';
|
||||
|
||||
const getRecursivePermissionsBySubject = (subject, permissions) => {
|
||||
return Object.entries(get(permissions, [subject], {})).reduce((acc, current) => {
|
||||
return Object.entries(get(permissions, [subject, 'attributes'], {})).reduce((acc, current) => {
|
||||
if (current[1].actions.length > 0) {
|
||||
return acc + current[1].actions.length;
|
||||
}
|
||||
|
||||
@ -3,46 +3,50 @@ export const permissions = {
|
||||
contentTypeActions: {
|
||||
'plugins::content-manager.explorer.delete': true,
|
||||
},
|
||||
city: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
cover: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
closing_period: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
'closing_period.start_date': {
|
||||
actions: ['plugins::content-manager.explorer.create'],
|
||||
},
|
||||
'closing_period.dish.description': {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
attributes: {
|
||||
city: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
cover: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
closing_period: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
'closing_period.start_date': {
|
||||
actions: ['plugins::content-manager.explorer.create'],
|
||||
},
|
||||
'closing_period.dish.description': {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
'application::places.places': {
|
||||
like: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
country: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
attributes: {
|
||||
like: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
country: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
import generateContentTypeActions from '../generateContentTypeActions';
|
||||
|
||||
describe('ADMIN | COMPONENTS | ROLE | UTILS | getAttributesByModel', () => {
|
||||
it('should return all attributes of a contentType with nested attributes', () => {
|
||||
const subjectPermissions = {
|
||||
field1: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.read',
|
||||
],
|
||||
},
|
||||
field2: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
field3: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
};
|
||||
const existingContentTypeActions = {
|
||||
'plugins::content-manager.explorer.delete': true,
|
||||
'plugins::content-manager.explorer.publish': false,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
'plugins::content-manager.explorer.create': true,
|
||||
'plugins::content-manager.explorer.read': true,
|
||||
'plugins::content-manager.explorer.delete': true,
|
||||
};
|
||||
|
||||
expect(generateContentTypeActions(subjectPermissions, existingContentTypeActions)).toEqual(
|
||||
expected
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -15,9 +15,6 @@ const useFetchRole = id => {
|
||||
|
||||
const fetchRole = async roleId => {
|
||||
try {
|
||||
// const requestURL = `/admin/roles/${roleId}`;
|
||||
|
||||
// const { data } = await request(requestURL, { method: 'GET' });
|
||||
const [{ data: role }, { data: permissions }] = await Promise.all(
|
||||
[`roles/${roleId}`, `roles/${roleId}/permissions`].map(endPoint =>
|
||||
request(`/admin/${endPoint}`, { method: 'GET' })
|
||||
|
||||
@ -6,9 +6,9 @@ const formatPermissionsFromApi = data => {
|
||||
return {
|
||||
...acc,
|
||||
[field]: {
|
||||
...get(permissionsAcc, [permission.subject, field], {}),
|
||||
...get(permissionsAcc, [permission.subject, 'attributes', field], {}),
|
||||
actions: [
|
||||
...get(permissionsAcc, [permission.subject, field, 'actions'], []),
|
||||
...get(permissionsAcc, [permission.subject, 'attributes', field, 'actions'], []),
|
||||
permission.action,
|
||||
],
|
||||
},
|
||||
@ -21,7 +21,10 @@ const formatPermissionsFromApi = data => {
|
||||
...acc,
|
||||
[current.subject]: {
|
||||
...acc[current.subject],
|
||||
...getFieldsPermissions(acc, current),
|
||||
attributes: {
|
||||
...get(acc, [current.subject, 'attributes'], {}),
|
||||
...getFieldsPermissions(acc, current),
|
||||
},
|
||||
contentTypeActions: {
|
||||
...get(acc, [current.subject, 'contentTypeActions'], {}),
|
||||
[current.action]: true,
|
||||
|
||||
@ -1,40 +1,19 @@
|
||||
const existingActions = permissions => {
|
||||
return Array.from(
|
||||
new Set(
|
||||
Object.entries(permissions).reduce((acc, current) => {
|
||||
const actionsPermission = permission =>
|
||||
permission.reduce((accAction, currentAction) => {
|
||||
let actionsToReturn = accAction;
|
||||
|
||||
if (currentAction.actions) {
|
||||
actionsToReturn = [...actionsToReturn, ...currentAction.actions];
|
||||
}
|
||||
|
||||
if (typeof currentAction === 'object' && !currentAction.actions) {
|
||||
actionsToReturn = [...actionsToReturn, ...Object.keys(currentAction)];
|
||||
}
|
||||
|
||||
return actionsToReturn;
|
||||
}, []);
|
||||
|
||||
return [...acc, ...actionsPermission(Object.values(current[1]))];
|
||||
}, [])
|
||||
)
|
||||
);
|
||||
};
|
||||
import getExistingActions from './getExistingActions';
|
||||
|
||||
const formatPermissionsToApi = permissions => {
|
||||
const existingActions = getExistingActions(permissions);
|
||||
|
||||
return Object.entries(permissions).reduce((acc, current) => {
|
||||
const formatPermission = permission =>
|
||||
existingActions(permissions).reduce((actionAcc, currentAction) => {
|
||||
existingActions.reduce((actionAcc, currentAction) => {
|
||||
if (permission[1].contentTypeActions && permission[1].contentTypeActions[currentAction]) {
|
||||
const hasAction =
|
||||
Object.values(permission[1]).findIndex(
|
||||
Object.values(permission[1].attributes).findIndex(
|
||||
item => item.actions && item.actions.includes(currentAction)
|
||||
) !== -1;
|
||||
const hasContentTypeAction =
|
||||
permission[1].contentTypeActions && permission[1].contentTypeActions[currentAction];
|
||||
const fields = Object.entries(permission[1])
|
||||
const fields = Object.entries(permission[1].attributes)
|
||||
.map(item => {
|
||||
if (item[1].actions && item[1].actions.includes(currentAction)) {
|
||||
return item[0];
|
||||
|
||||
32
packages/strapi-admin/admin/src/utils/getExistingActions.js
Normal file
32
packages/strapi-admin/admin/src/utils/getExistingActions.js
Normal file
@ -0,0 +1,32 @@
|
||||
const getExistingActions = permissions => {
|
||||
return Array.from(
|
||||
new Set(
|
||||
Object.entries(permissions).reduce((acc, current) => {
|
||||
const getActionsPermission = permission =>
|
||||
permission.reduce((accAction, currentAction) => {
|
||||
let actionsToReturn = accAction;
|
||||
|
||||
if (currentAction.actions) {
|
||||
actionsToReturn = [...actionsToReturn, ...currentAction.actions];
|
||||
}
|
||||
|
||||
if (typeof currentAction === 'object' && !currentAction.actions) {
|
||||
actionsToReturn = [...actionsToReturn, ...Object.keys(currentAction)];
|
||||
}
|
||||
|
||||
return actionsToReturn;
|
||||
}, []);
|
||||
|
||||
return [
|
||||
...acc,
|
||||
...getActionsPermission([
|
||||
...Object.values(current[1].attributes),
|
||||
current[1].contentTypeActions,
|
||||
]),
|
||||
];
|
||||
}, [])
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default getExistingActions;
|
||||
@ -8,3 +8,4 @@ export { default as sortLinks } from './sortLinks';
|
||||
export { default as fakePermissionsData } from './fakePermissionsData';
|
||||
export { default as formatPermissionsFromApi } from './formatPermissionsFromApi';
|
||||
export { default as formatPermissionsToApi } from './formatPermissionsToApi';
|
||||
export { default as getExistingActions } from './getExistingActions';
|
||||
|
||||
55
packages/strapi-admin/admin/src/utils/tests/data.js
Normal file
55
packages/strapi-admin/admin/src/utils/tests/data.js
Normal file
@ -0,0 +1,55 @@
|
||||
const data = {
|
||||
'plugins::users-permissions.user': {
|
||||
contentTypeActions: {
|
||||
'plugins::content-manager.explorer.read': false,
|
||||
'plugins::content-manager.explorer.update': true,
|
||||
'plugins::content-manager.explorer.create': true,
|
||||
},
|
||||
attributes: {
|
||||
email: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
firstname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
lastname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
'role.data.name': {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
roles: {
|
||||
actions: ['plugins::content-manager.explorer.create'],
|
||||
},
|
||||
},
|
||||
},
|
||||
'application::category.category': {
|
||||
contentTypeActions: {
|
||||
'plugins::content-manager.explorer.delete': true,
|
||||
'plugins::content-manager.explorer.read': true,
|
||||
'plugins::content-manager.explorer.update': false,
|
||||
},
|
||||
attributes: {
|
||||
name: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
addresses: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
postal_code: {
|
||||
actions: ['plugins::content-manager.explorer.update'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default data;
|
||||
@ -44,26 +44,28 @@ describe('ADMIN | utils | formatPermissionsFromApi', () => {
|
||||
'plugins::content-manager.explorer.create': true,
|
||||
'plugins::content-manager.explorer.update': true,
|
||||
},
|
||||
email: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
firstname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
lastname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
roles: {
|
||||
actions: ['plugins::content-manager.explorer.create'],
|
||||
attributes: {
|
||||
email: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
firstname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
lastname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
roles: {
|
||||
actions: ['plugins::content-manager.explorer.create'],
|
||||
},
|
||||
},
|
||||
},
|
||||
'application::category.category': {
|
||||
@ -71,11 +73,13 @@ describe('ADMIN | utils | formatPermissionsFromApi', () => {
|
||||
'plugins::content-manager.explorer.read': true,
|
||||
'plugins::content-manager.explorer.delete': true,
|
||||
},
|
||||
name: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
addresses: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
attributes: {
|
||||
name: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
addresses: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,71 +1,22 @@
|
||||
import formatPermissionsToApi from '../formatPermissionsToApi';
|
||||
|
||||
const data = {
|
||||
'plugins::users-permissions.user': {
|
||||
contentTypeActions: {
|
||||
'plugins::content-manager.explorer.read': false,
|
||||
'plugins::content-manager.explorer.update': true,
|
||||
'plugins::content-manager.explorer.create': true,
|
||||
},
|
||||
email: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
firstname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
lastname: {
|
||||
actions: [
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
],
|
||||
},
|
||||
'role.data.name': {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
roles: {
|
||||
actions: ['plugins::content-manager.explorer.create'],
|
||||
},
|
||||
},
|
||||
'application::category.category': {
|
||||
contentTypeActions: {
|
||||
'plugins::content-manager.explorer.delete': true,
|
||||
'plugins::content-manager.explorer.read': true,
|
||||
'plugins::content-manager.explorer.update': false,
|
||||
},
|
||||
name: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
addresses: {
|
||||
actions: ['plugins::content-manager.explorer.read'],
|
||||
},
|
||||
postal_code: {
|
||||
actions: ['plugins::content-manager.explorer.update'],
|
||||
},
|
||||
},
|
||||
};
|
||||
import data from './data';
|
||||
|
||||
describe('ADMIN | utils | formatPermissionsToApi', () => {
|
||||
it('should format permissions to fit the api format', () => {
|
||||
const formattedPermissions = formatPermissionsToApi(data);
|
||||
const expected = [
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.update',
|
||||
conditions: [],
|
||||
fields: ['email', 'firstname', 'lastname'],
|
||||
subject: 'plugins::users-permissions.user',
|
||||
},
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.create',
|
||||
conditions: [],
|
||||
fields: ['email', 'firstname', 'lastname', 'roles'],
|
||||
subject: 'plugins::users-permissions.user',
|
||||
},
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.update',
|
||||
conditions: [],
|
||||
fields: ['email', 'firstname', 'lastname'],
|
||||
subject: 'plugins::users-permissions.user',
|
||||
},
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.read',
|
||||
conditions: [],
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
import getExistingActions from '../getExistingActions';
|
||||
import data from './data';
|
||||
|
||||
describe('ADMIN | utils | getExistingActions', () => {
|
||||
it('should return the existing actions', () => {
|
||||
const existingActions = getExistingActions(data);
|
||||
|
||||
expect(existingActions).toEqual([
|
||||
'plugins::content-manager.explorer.create',
|
||||
'plugins::content-manager.explorer.update',
|
||||
'plugins::content-manager.explorer.read',
|
||||
'plugins::content-manager.explorer.delete',
|
||||
]);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user