From b9ffe9de460bf8ae7ad480f63d3d3dc22f578bdf Mon Sep 17 00:00:00 2001 From: soupette Date: Fri, 22 Nov 2019 15:57:00 +0100 Subject: [PATCH] Handle edit relation --- .../api/like/models/Like.settings.json | 10 +- .../containers/DataManagerProvider/index.js | 15 +- .../containers/DataManagerProvider/reducer.js | 164 +++++++++++++++++- .../admin/src/containers/FormModal/index.js | 8 +- .../admin/src/containers/FormModal/reducer.js | 9 + 5 files changed, 197 insertions(+), 9 deletions(-) diff --git a/examples/getstarted/api/like/models/Like.settings.json b/examples/getstarted/api/like/models/Like.settings.json index f83298ddca..8be0a41644 100755 --- a/examples/getstarted/api/like/models/Like.settings.json +++ b/examples/getstarted/api/like/models/Like.settings.json @@ -18,6 +18,14 @@ "review": { "model": "review", "via": "likes" + }, + "like_left": { + "collection": "like", + "via": "like_right" + }, + "like_right": { + "model": "like", + "via": "like_left" } } -} \ No newline at end of file +} diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/index.js index d33b8f2b01..e9ff467aac 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/index.js @@ -73,12 +73,21 @@ const DataManagerProvider = ({ children }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoading, pathname]); - const addAttribute = (attributeToSet, forTarget, targetUid) => { + const addAttribute = ( + attributeToSet, + forTarget, + targetUid, + isEditing = false, + initialAttribute + ) => { + const actionType = isEditing ? 'EDIT_ATTRIBUTE' : 'ADD_ATTRIBUTE'; + dispatch({ - type: 'ADD_ATTRIBUTE', + type: actionType, attributeToSet, forTarget, targetUid, + initialAttribute, }); }; @@ -138,7 +147,7 @@ const DataManagerProvider = ({ children }) => { return ; } - console.log({ modifiedData, contentTypes }); + console.log({ modifiedData: modifiedData.contentType }); return ( { + if (originalNature === 'manyToOne') { + return 'oneToMany'; + } else if (originalNature === 'oneToMany') { + return 'manyToOne'; + } else { + return originalNature; + } +}; + const reducer = (state, action) => { switch (action.type) { case 'ADD_ATTRIBUTE': { @@ -49,13 +60,14 @@ const reducer = (state, action) => { target === currentUid ) { const oppositeAttribute = { - nature, + nature: getOppositeNature(nature), target, - type, unique: rest.unique, required: rest.required, dominant: nature === 'manyToMany' ? !rest.dominant : null, targetAttribute: name, + columnName: rest.targetColumnName, + targetColumnName: rest.columnName, }; return obj.update(rest.targetAttribute, () => { @@ -67,6 +79,150 @@ const reducer = (state, action) => { } ); } + case 'EDIT_ATTRIBUTE': { + const { + attributeToSet: { name, ...rest }, + forTarget, + targetUid, + initialAttribute, + } = action; + const initialAttributeName = get(initialAttribute, ['name'], ''); + const pathToDataToEdit = ['component', 'contentType'].includes(forTarget) + ? [forTarget] + : [forTarget, targetUid]; + + return state.updateIn( + ['modifiedData', ...pathToDataToEdit, 'schema'], + obj => { + let oppositeAttributeNameToRemove = null; + let oppositeAttributeNameToUpdate = null; + let oppositeAttributeNameToCreateBecauseOfNatureChange = null; + let oppositeAttributeToCreate = null; + + const newObj = OrderedMap( + obj + .get('attributes') + .keySeq() + .reduce((acc, current) => { + const isEditingCurrentAttribute = + current === initialAttributeName; + + if (isEditingCurrentAttribute) { + const currentUid = state.getIn([ + 'modifiedData', + ...pathToDataToEdit, + 'uid', + ]); + const isEditingRelation = has(initialAttribute, 'nature'); + const didChangeTargetRelation = + initialAttribute.target !== rest.target; + const didCreateInternalRelation = rest.target === currentUid; + const nature = rest.nature; + const initialNature = initialAttribute.nature; + const hadInternalRelation = + initialAttribute.target === currentUid; + const didChangeRelationNature = + initialAttribute.nature !== nature; + const shouldRemoveOppositeAttributeBecauseOfTargetChange = + didChangeTargetRelation && + !didCreateInternalRelation && + hadInternalRelation && + isEditingRelation; + const shouldRemoveOppositeAttributeBecauseOfNatureChange = + didChangeRelationNature && + hadInternalRelation && + ['oneWay', 'manyWay'].includes(nature) && + isEditingRelation; + const shouldUpdateOppositeAttributeBecauseOfNatureChange = + !ONE_SIDE_RELATIONS.includes(initialNature) && + !ONE_SIDE_RELATIONS.includes(nature) && + hadInternalRelation && + didCreateInternalRelation && + isEditingRelation; + const shouldCreateOppositeAttributeBecauseOfNatureChange = + ONE_SIDE_RELATIONS.includes(initialNature) && + !ONE_SIDE_RELATIONS.includes(nature) && + hadInternalRelation && + didCreateInternalRelation && + isEditingRelation; + + // Update the opposite attribute name so it is removed at the end of the loop + if ( + shouldRemoveOppositeAttributeBecauseOfTargetChange || + shouldRemoveOppositeAttributeBecauseOfNatureChange + ) { + oppositeAttributeNameToRemove = + initialAttribute.targetAttribute; + } + + // Set the opposite attribute that will be updated when the loop attribute matches the name + if ( + shouldUpdateOppositeAttributeBecauseOfNatureChange || + shouldCreateOppositeAttributeBecauseOfNatureChange + ) { + oppositeAttributeNameToUpdate = + initialAttribute.targetAttribute; + oppositeAttributeNameToCreateBecauseOfNatureChange = + rest.targetAttribute; + + oppositeAttributeToCreate = { + nature: getOppositeNature(rest.nature), + target: rest.target, + unique: rest.unique, + required: rest.required, + dominant: + rest.nature === 'manyToMany' ? !rest.dominant : null, + targetAttribute: name, + columnName: rest.targetColumnName, + targetColumnName: rest.columnName, + }; + + // First update the current attribute with the value + acc[name] = fromJS(rest); + + // Then (if needed) create the opposite attribute the case is changing the relation from + // We do it here so keep the order of the attributes + // oneWay || manyWay to something another relation + if (shouldCreateOppositeAttributeBecauseOfNatureChange) { + acc[ + oppositeAttributeNameToCreateBecauseOfNatureChange + ] = fromJS(oppositeAttributeToCreate); + + oppositeAttributeToCreate = null; + oppositeAttributeNameToCreateBecauseOfNatureChange = null; + } + + return acc; + } + + acc[name] = fromJS(rest); + } else if (current === oppositeAttributeNameToUpdate) { + acc[ + oppositeAttributeNameToCreateBecauseOfNatureChange + ] = fromJS(oppositeAttributeToCreate); + } else { + acc[current] = obj.getIn(['attributes', current]); + } + + return acc; + }, {}) + ); + + let updatedObj; + + // Remove the opposite attribute + if (oppositeAttributeNameToRemove !== null) { + console.log('ppppp'); + updatedObj = newObj.remove(oppositeAttributeNameToRemove); + } else { + updatedObj = newObj; + } + + return obj.set('attributes', updatedObj); + } + ); + } + case 'GET_DATA_SUCCEEDED': return state .update('components', () => fromJS(action.components)) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js index 990bdf9778..05a37d5680 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js @@ -285,7 +285,13 @@ const FormModal = () => { search: nextSearch, }); } else if (state.modalType === 'attribute') { - addAttribute(modifiedData, state.forTarget, state.targetUid); + addAttribute( + modifiedData, + state.forTarget, + state.targetUid, + state.actionType === 'edit', + initialData + ); push({ search: nextSearch }); } else { console.log('Do something with component later'); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/reducer.js index 7ada2a6551..b5fd30d9bd 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/reducer.js @@ -47,6 +47,13 @@ const reducer = (state, action) => { : oldValue, shouldPluralizeTargetAttribute(value) ); + }) + .update('targetColumnName', oldValue => { + if (['oneWay', 'manyWay'].includes(value)) { + return null; + } + + return oldValue; }); } @@ -110,6 +117,8 @@ const reducer = (state, action) => { unique: false, required: false, dominant: null, + columnName: null, + targetColumnName: null, }; } else { dataToSet = { type: attributeType, default: null };