Add logic to set the correct leaf when in edition

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2021-02-19 17:34:52 +01:00
parent b256776fbb
commit d6e70a737d
5 changed files with 98 additions and 30 deletions

View File

@ -10,9 +10,9 @@ import formatPermissionsToAPI from './utils/formatPermissionsToAPI';
import init from './init';
import reducer, { initialState } from './reducer';
const Permissions = forwardRef(({ layout, isFormDisabled }, ref) => {
const Permissions = forwardRef(({ layout, isFormDisabled, permissions }, ref) => {
const [{ layouts, modifiedData }, dispatch] = useReducer(reducer, initialState, () =>
init(layout)
init(layout, permissions)
);
useImperativeHandle(ref, () => {
@ -112,11 +112,13 @@ const Permissions = forwardRef(({ layout, isFormDisabled }, ref) => {
});
Permissions.defaultProps = {
permissions: [],
layout,
};
Permissions.propTypes = {
layout: PropTypes.object,
isFormDisabled: PropTypes.bool.isRequired,
permissions: PropTypes.array,
};
export default memo(Permissions);

View File

@ -2,7 +2,7 @@ import createDefaultCTFormFromLayout from './utils/createDefaultCTFormFromLayout
import createDefaultPluginsFormFromLayout from './utils/createDefaultPluginsFormFromLayout';
import formatLayoutForSettingsAndPlugins from './utils/formatLayoutForSettingsAndPlugins';
const init = layout => {
const init = (layout, permissions) => {
const {
conditions,
sections: { collectionTypes, singleTypes, plugins, settings },
@ -17,7 +17,8 @@ const init = layout => {
collectionTypes: createDefaultCTFormFromLayout(
collectionTypes,
collectionTypes.actions || [],
conditions
conditions,
permissions
),
singleTypes: createDefaultCTFormFromLayout(singleTypes, singleTypes.actions || [], conditions),
plugins: createDefaultPluginsFormFromLayout(layouts.plugins, conditions),

View File

@ -1,13 +1,13 @@
import { merge, isEmpty, set } from 'lodash';
import { merge, get, isEmpty, set } from 'lodash';
/**
* Creates the default condition form: { [conditionId]: false }
* @param {object} conditions.id Id of the condition
* @returns {object}
*/
const createDefaultConditionsForm = conditions =>
const createDefaultConditionsForm = (conditions, initialConditions = []) =>
conditions.reduce((acc, current) => {
acc[current.id] = false;
acc[current.id] = initialConditions.indexOf(current.id) !== -1;
return acc;
}, {});
@ -16,16 +16,26 @@ const createDefaultConditionsForm = conditions =>
* Create the default form a property (fields, locales) with all the values
* set to false
* @param {object} property.children ex: {children: [{value: 'foo',}]}
* @param {array<string>} The found property values retrieved from the role associated permissions
* @returns {object} ex: { foo: false }
*
*/
const createDefaultPropertyForms = ({ children }) => {
const createDefaultPropertyForms = ({ children }, propertyValues, prefix = '') => {
return children.reduce((acc, current) => {
if (current.children) {
return { ...acc, [current.value]: createDefaultPropertyForms(current) };
return {
...acc,
[current.value]: createDefaultPropertyForms(
current,
propertyValues,
`${prefix}${current.value}.`
),
};
}
acc[current.value] = false;
const hasProperty = propertyValues.indexOf(`${prefix}${current.value}`) !== -1;
acc[current.value] = hasProperty;
return acc;
}, {});
@ -43,12 +53,16 @@ const createDefaultPropertyForms = ({ children }) => {
* }
* @returns {object} In this case it will return { fields: { name: false } }
*/
const createDefaultPropertiesForm = (propertiesArray, ctLayout) => {
const createDefaultPropertiesForm = (propertiesArray, ctLayout, matchingPermission) => {
return propertiesArray.reduce((acc, currentPropertyName) => {
const foundProperty = ctLayout.properties.find(({ value }) => value === currentPropertyName);
if (foundProperty) {
const propertyForm = createDefaultPropertyForms(foundProperty);
const matchingPermissionPropertyValues = get(matchingPermission, foundProperty.value, []);
const propertyForm = createDefaultPropertyForms(
foundProperty,
matchingPermissionPropertyValues
);
acc[currentPropertyName] = propertyForm;
}
@ -89,7 +103,12 @@ const findLayouts = (allLayouts, subjects) => {
* }
* }
*/
const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray) => {
const createDefaultCTFormFromLayout = (
{ subjects },
actionArray,
conditionArray,
initialPermissions = []
) => {
return actionArray.reduce((defaultForm, current) => {
const actionSubjects = current.subjects;
@ -105,17 +124,26 @@ const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray
// The object has the following shape: { [ctUID]: { [actionId]: { [property]: { enabled: false } } } }
const contentTypesActions = Object.keys(subjectLayouts).reduce((acc, currentCTUID) => {
const { actionId, applyToProperties } = current;
const conditionsForm = createDefaultConditionsForm(conditionArray);
const matchingPermission = findMatchingPermission(initialPermissions, actionId, currentCTUID);
const conditionsForm = createDefaultConditionsForm(
conditionArray,
get(matchingPermission, 'conditions', [])
);
if (isEmpty(applyToProperties)) {
set(acc, [currentCTUID, actionId], { enabled: false, conditions: conditionsForm });
set(acc, [currentCTUID, actionId], {
enabled: matchingPermission !== undefined,
conditions: conditionsForm,
});
return acc;
}
const propertiesForm = createDefaultPropertiesForm(
applyToProperties,
subjectLayouts[currentCTUID]
subjectLayouts[currentCTUID],
matchingPermission
);
set(acc, [currentCTUID, actionId], { ...propertiesForm, conditions: conditionsForm });
@ -127,6 +155,9 @@ const createDefaultCTFormFromLayout = ({ subjects }, actionArray, conditionArray
}, {});
};
const findMatchingPermission = (permissions, action, subject) =>
permissions.find(perm => perm.action === action && perm.subject === subject);
export default createDefaultCTFormFromLayout;
export {
createDefaultConditionsForm,

View File

@ -20,7 +20,7 @@ const conditions = [
describe('ADMIN | COMPONENTS | Permissions | utils', () => {
describe('createConditionForm', () => {
it('should return an object with all the values set to false', () => {
it('should return an object with all the leafs set to false', () => {
const expected = {
'admin::is-creator': false,
'admin::has-same-role-as-creator': false,
@ -28,10 +28,21 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
expect(createDefaultConditionsForm(conditions)).toEqual(expected);
});
it('should return an object with the leafs set to true when the initial conditions contains the condition', () => {
const expected = {
'admin::is-creator': false,
'admin::has-same-role-as-creator': true,
};
expect(
createDefaultConditionsForm(conditions, ['test', 'admin::has-same-role-as-creator'])
).toEqual(expected);
});
});
describe('createDefaultPropertyForms,', () => {
it('should return an object with keys corresponding to the property value and all the values set to false', () => {
it('should return an object with keys corresponding to the property value and all the leafs set to false', () => {
const data = {
children: [
{
@ -47,10 +58,10 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
bar: false,
};
expect(createDefaultPropertyForms(data)).toEqual(expected);
expect(createDefaultPropertyForms(data, [])).toEqual(expected);
});
it('should create the default form for a complex object', () => {
it('should create the default form for a complex object when the second argument is not an empty array', () => {
const data = {
children: [
{
@ -74,17 +85,18 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
},
],
};
const propertyValues = ['foo', 'bar.foo.bar'];
const expected = {
foo: false,
foo: true,
bar: {
name: false,
foo: {
bar: false,
bar: true,
},
},
};
expect(createDefaultPropertyForms(data)).toEqual(expected);
expect(createDefaultPropertyForms(data, propertyValues)).toEqual(expected);
});
});
@ -286,6 +298,7 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
],
},
];
const actions = [
{
label: 'Create',
@ -312,12 +325,12 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
fields: {
postal_coder: false,
categories: false,
cover: false,
cover: true,
images: false,
city: false,
},
conditions: {
'admin::is-creator': false,
'admin::is-creator': true,
'admin::has-same-role-as-creator': false,
},
},
@ -336,10 +349,10 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
f2: false,
services: { name: false, media: false, closing: { name: { test: false } } },
dz: false,
relation: false,
relation: true,
},
locales: {
en: false,
en: true,
fr: false,
},
conditions: {
@ -360,7 +373,25 @@ describe('ADMIN | COMPONENTS | Permissions | utils', () => {
},
};
expect(createDefaultCTFormFromLayout({ subjects }, actions, conditions)).toEqual(expected);
const permissions = [
{
action: 'content-manager.explorer.create',
subject: 'restaurant',
fields: ['relation'],
locales: ['en'],
},
{
action: 'content-manager.explorer.create',
subject: 'address',
fields: ['cover'],
locales: ['fr'],
conditions: ['admin::is-creator'],
},
];
expect(createDefaultCTFormFromLayout({ subjects }, actions, conditions, permissions)).toEqual(
expected
);
});
});

View File

@ -36,7 +36,6 @@ const EditPage = () => {
isLoading: isRoleLoading,
onSubmitSucceeded,
} = useFetchRole(id);
console.log({ rolePermissions });
/* eslint-disable indent */
const headerActions = (handleSubmit, handleReset) =>
@ -177,7 +176,11 @@ const EditPage = () => {
/>
{!isLayoutLoading && !isRoleLoading && (
<Padded top bottom size="md">
<Permissions isFormDisabled={isFormDisabled} ref={permissionsRef} />
<Permissions
isFormDisabled={isFormDisabled}
permissions={rolePermissions}
ref={permissionsRef}
/>
</Padded>
)}
</ContainerFluid>