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 552d8d7685..250297a5d6 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 @@ -246,6 +246,8 @@ const DataManagerProvider = ({ allIcons, children }) => { }); }; + // console.log('mod', modifiedData); + return ( { + const componentUIDsToReturn = Object.keys(allComponents).filter(compoUid => { + const currentCompo = get(allComponents, compoUid, {}); + const initialCompo = get(initialComponents, compoUid, {}); + const hasComponentBeenCreated = get(currentCompo, ['isTemporary'], false); + const hasComponentBeenModified = !isEqual(currentCompo, initialCompo); + + return hasComponentBeenCreated || hasComponentBeenModified; + }); + + return makeUnique(componentUIDsToReturn); +}; + +const formatComponent = (component, mainDataUID, isCreatingData = false) => { + const formattedAttributes = formatAttributes( + get(component, 'schema.attributes', {}), + mainDataUID, + isCreatingData, + true + ); + + // Set tmpUID if the component has just been created + // Keep the uid if the component already exists + const compoUID = get(component, 'isTemporary', false) + ? { tmpUID: component.uid } + : { uid: component.uid }; + + const formattedComponent = Object.assign( + {}, + compoUID, + { category: component.category }, + // Omit the attributes since we want to format them + omit(component.schema, 'attributes'), + // Add the formatted attributes + { attributes: formattedAttributes } + ); + + return formattedComponent; +}; + +/** + * + * @param {Object} attributes + * @param {String} mainDataUID uid of the main data type + * @param {Boolean} isCreatingMainData + * @param {Boolean} isComponent + */ +const formatAttributes = ( + attributes, + mainDataUID, + isCreatingMainData, + isComponent +) => { + return Object.keys(attributes).reduce((acc, current) => { + const currentAttribute = get(attributes, current, {}); + const hasARelationWithMainDataUID = currentAttribute.target === mainDataUID; + + if (!hasARelationWithMainDataUID) { + acc[current] = currentAttribute; + } + + if (hasARelationWithMainDataUID) { + const currentTargetAttribute = get( + currentAttribute, + 'targetAttribute', + null + ); + + let target = currentTargetAttribute.target; + + if (isCreatingMainData) { + target = isComponent ? '__contentType__' : '__self__'; + } + + const formattedRelationAttribute = Object.assign({}, currentAttribute, { + target, + targetAttribute: + currentTargetAttribute === '-' ? null : currentTargetAttribute, + }); + + acc[current] = formattedRelationAttribute; + } + + return acc; + }, {}); +}; + +export { formatComponent, getCreatedAndModifiedComponents }; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/cleanData.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/cleanData.test.js new file mode 100644 index 0000000000..0969e1a7fb --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/cleanData.test.js @@ -0,0 +1,83 @@ +import { formatComponent, getCreatedAndModifiedComponents } from '../cleanData'; +import contentTypeData from './contentTypeData'; +import expectedData from './expectedFormattedContentTypeData'; + +describe('CleanData utils', () => { + describe('GetCreatedAndModifiedComponents', () => { + it('should return an empty array if there is no component', () => { + expect(getCreatedAndModifiedComponents({}, {})).toEqual([]); + }); + + it('should return an array containing the uid of the modified and created components', () => { + const { componentsToFormat } = expectedData; + const { + initialComponents, + rawData: { components }, + } = contentTypeData; + expect( + getCreatedAndModifiedComponents(components, initialComponents).sort() + ).toEqual(componentsToFormat.sort()); + }); + }); + + describe('FormatComponent', () => { + describe('Formatting created component', () => { + it('should remove the uid key if the component is new', () => { + const component = + contentTypeData.rawData.components['components.main-compo']; + + expect( + formatComponent( + component, + 'application::test-content-type.test-content-type', + true + ) + ).not.toHaveProperty('uid'); + }); + + it('should add a tempUID key if the component is new', () => { + const component = + contentTypeData.rawData.components['components.main-compo']; + + expect( + formatComponent( + component, + 'application::test-content-type.test-content-type', + true + ) + ).toHaveProperty('tmpUID'); + }); + + it('should format the component correctly', () => { + const component = + contentTypeData.rawData.components['components.main-compo']; + const expectedComponent = + expectedData.formattedComponents['components.main-compo']; + + expect( + formatComponent( + component, + 'application::test-content-type.test-content-type', + true + ) + ).toEqual(expectedComponent); + }); + }); + + describe('Formatting existing component', () => { + it('should format the component correctly', () => { + const component = contentTypeData.rawData.components['blog.quote']; + const expectedComponent = + expectedData.formattedComponents['blog.quote']; + + expect( + formatComponent( + component, + 'application::test-content-type.test-content-type', + true + ) + ).toEqual(expectedComponent); + }); + }); + }); +}); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/contentTypeData.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/contentTypeData.js index 9ff04b8d2f..400119a12a 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/contentTypeData.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/contentTypeData.js @@ -196,6 +196,11 @@ const data = { repeatable: true, component: 'default.metas', }, + quote: { + type: 'component', + repeatable: false, + component: 'blog.quote', + }, }, }, }, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/expectedFormattedContentTypeData.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/expectedFormattedContentTypeData.js index f6daaa3bee..3191868002 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/expectedFormattedContentTypeData.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/utils/tests/expectedFormattedContentTypeData.js @@ -54,13 +54,74 @@ const expectedData = { ], components: [ - expectedData.formattedComponents['components.main-compo'], - expectedData.formattedComponents['default.nested-compo'], - expectedData.formattedComponents['blog.quote'], + { + tmpUID: 'components.main-compo', + name: 'mainCompo', + icon: 'ad', + category: 'components', + attributes: { + name: { + type: 'string', + }, + testContentType: { + dominant: null, + columnName: null, + nature: 'oneWay', + targetAttribute: null, + target: '__contentType__', + unique: false, + targetColumnName: null, + required: false, + }, + subCompoField: { + type: 'component', + repeatable: false, + component: 'default.nested-compo', + }, + }, + }, + { + tmpUID: 'default.nested-compo', + name: 'nestedCompo', + icon: 'address-book', + category: 'default', + attributes: { + name: { + type: 'string', + }, + email: { + type: 'email', + default: null, + }, + }, + }, + { + uid: 'blog.quote', + category: 'blog', + name: 'quote', + description: '', + icon: 'anchor', + connection: 'default', + collectionName: 'components_quotes', + attributes: { + quote: { + type: 'string', + required: true, + }, + author: { + model: 'user', + plugin: 'users-permissions', + }, + link_to_biography: { + type: 'string', + required: true, + }, + }, + }, ], formattedComponents: { 'components.main-compo': { - tmpUId: 'components.main-compo', + tmpUID: 'components.main-compo', name: 'mainCompo', icon: 'ad', category: 'components', @@ -86,7 +147,7 @@ const expectedData = { }, }, 'default.nested-compo': { - tmpUId: 'default.nested-compo', + tmpUID: 'default.nested-compo', name: 'nestedCompo', icon: 'address-book', category: 'default', @@ -130,7 +191,7 @@ export default expectedData; // components: [ // { -// tmpUId: 'components.main-compo', +// tmpUID: 'components.main-compo', // name: 'mainCompo', // icon: 'ad', // category: 'components', @@ -156,7 +217,7 @@ export default expectedData; // }, // }, // { -// tmpUId: 'default.nested-compo', +// tmpUID: 'default.nested-compo', // name: 'nestedCompo', // icon: 'address-book', // category: 'default',