From 7a24e53192b2e404f4077e105ab919cc6020ecc3 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 7 Jan 2020 16:05:46 +0100 Subject: [PATCH 01/25] Improve makeUnique utils --- .../admin/src/utils/makeUnique.js | 3 +-- .../admin/src/utils/tests/makeUnique.test.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/utils/tests/makeUnique.test.js diff --git a/packages/strapi-plugin-content-type-builder/admin/src/utils/makeUnique.js b/packages/strapi-plugin-content-type-builder/admin/src/utils/makeUnique.js index 38f40a6d38..523f3f528f 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/utils/makeUnique.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/utils/makeUnique.js @@ -1,4 +1,3 @@ -const makeUnique = array => - array.filter((key, index) => array.indexOf(key) === index && key !== ''); +const makeUnique = array => [...new Set(array)]; export default makeUnique; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/utils/tests/makeUnique.test.js b/packages/strapi-plugin-content-type-builder/admin/src/utils/tests/makeUnique.test.js new file mode 100644 index 0000000000..6ae0971570 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/utils/tests/makeUnique.test.js @@ -0,0 +1,10 @@ +import makeUnique from '../makeUnique'; + +describe('CTB | utils | makeUnique', () => { + it('Should remove the duplicate elements', () => { + const data = ['a', 'b', 'c', 'aa', 'a', 'bb', 'b']; + const expected = ['a', 'b', 'c', 'aa', 'bb']; + + expect(makeUnique(data)).toEqual(expected); + }); +}); From 8c7e0f297afd4a8fd67ee6cbf4b4f468702ce8a2 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 7 Jan 2020 17:51:34 +0100 Subject: [PATCH 02/25] Add basics reducer tests --- .../containers/DataManagerProvider/index.js | 6 + .../containers/DataManagerProvider/reducer.js | 6 +- .../tests/reducer_basic_actions.test.js | 147 ++++++++++++++++++ 3 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js 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 6a193af67f..4867924037 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 @@ -86,7 +86,9 @@ const DataManagerProvider = ({ allIcons, children }) => { }); }) ); + const components = createDataObject(componentsArray); + const contentTypes = createDataObject(contentTypesArray); const orderedComponents = orderAllDataAttributesWithImmutable({ components, @@ -95,6 +97,8 @@ const DataManagerProvider = ({ allIcons, children }) => { components: contentTypes, }); + console.log(orderedContenTypes.get('components').toJS()); + dispatch({ type: 'GET_DATA_SUCCEEDED', components: orderedComponents.get('components'), @@ -372,6 +376,8 @@ const DataManagerProvider = ({ allIcons, children }) => { }); }; + console.log({ modifiedData }); + const sortedContentTypesList = sortBy( Object.keys(contentTypes) .map(uid => ({ diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index 634056bc7e..d103426c25 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -6,7 +6,7 @@ const initialState = fromJS({ components: {}, contentTypes: {}, initialComponents: {}, - intialContentTypes: {}, + initialContentTypes: {}, initialData: {}, modifiedData: {}, isLoading: true, @@ -358,7 +358,7 @@ const reducer = (state, action) => { ); } - case 'GET_DATA_SUCCEEDED': + case 'GET_DATA_SUCCEEDED': { return state .update('components', () => fromJS(action.components)) .update('initialComponents', () => fromJS(action.components)) @@ -366,7 +366,7 @@ const reducer = (state, action) => { .update('contentTypes', () => fromJS(action.contentTypes)) .update('isLoading', () => false); - + } case 'RELOAD_PLUGIN': return initialState; case 'REMOVE_FIELD_FROM_DISPLAYED_COMPONENT': { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js new file mode 100644 index 0000000000..3a7babf0c1 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js @@ -0,0 +1,147 @@ +import { fromJS } from 'immutable'; +import reducer, { initialState } from '../reducer'; + +describe('CTB | containers | reducer | basics actions ', () => { + it('Should return the initial state', () => { + expect(reducer(initialState, { type: 'TEST' })).toEqual(initialState); + }); + + describe('GET_DATA_SUCCEEDED', () => { + const components = { + 'default.test': { + uid: 'default.test', + category: 'default', + schema: { + attributes: {}, + }, + }, + }; + const contentTypes = { + 'application::test.test': { + uid: 'application::test.test', + schema: { + attributes: {}, + }, + }, + }; + const expected = initialState + .set('components', fromJS(components)) + .set('contentTypes', fromJS(contentTypes)) + .set('initialContentTypes', fromJS(contentTypes)) + .set('initialComponents', fromJS(components)) + .set('isLoading', false); + + expect( + reducer(initialState, { + type: 'GET_DATA_SUCCEEDED', + components, + contentTypes, + }) + ).toEqual(expected); + }); + + describe('RELOAD_PLUGIN', () => { + it('Should return the initial state constant', () => { + expect( + reducer(initialState.setIn(['components', 'foo'], {}), { + type: 'RELOAD_PLUGIN', + }) + ).toEqual(initialState); + }); + }); + + describe('SET_MODIFIED_DATA', () => { + it('Should set the modifiedData object correctly if the user did create a new type', () => { + const schemaToSet = fromJS({ + components: {}, + contentType: { + uid: 'test', + }, + }); + const expected = initialState + .set('modifiedData', schemaToSet) + .set('initialData', schemaToSet) + .set('isLoadingForDataToBeSet', false); + + expect( + reducer(initialState, { + type: 'SET_MODIFIED_DATA', + schemaToSet, + hasJustCreatedSchema: true, + }) + ).toEqual(expected); + }); + + it('Should set the modifiedData object correctly if the user did not create a new type', () => { + const schemaToSet = fromJS({ + components: {}, + contentType: { + uid: 'test', + }, + }); + const expected = initialState + .set('modifiedData', schemaToSet) + .set('initialData', schemaToSet) + .set('isLoadingForDataToBeSet', false); + + expect( + reducer(initialState, { + type: 'SET_MODIFIED_DATA', + schemaToSet, + hasJustCreatedSchema: false, + }) + ).toEqual(expected); + }); + }); + + describe('UPDATE_SCHEMA', () => { + it('Should update the modified data correctly if the schemaType is a content type', () => { + const data = { + name: 'test1', + collectionName: 'newTest', + }; + const state = fromJS({ + modifiedData: { + components: {}, + contentType: { + uid: 'test', + schema: { + name: 'test', + collectionName: 'test', + attributes: { + something: { + type: 'string', + }, + }, + }, + }, + }, + }); + const expected = fromJS({ + modifiedData: { + components: {}, + contentType: { + uid: 'test', + schema: { + name: 'test1', + collectionName: 'newTest', + attributes: { + something: { + type: 'string', + }, + }, + }, + }, + }, + }); + + expect( + reducer(state, { + type: 'UPDATE_SCHEMA', + data, + schemaType: 'contentType', + }) + ).toEqual(expected); + }); + }); +}); From 73214e7237491ea776cc755bddc110136d5d8ebf Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 8 Jan 2020 12:02:22 +0100 Subject: [PATCH 03/25] Add eslint rule --- .eslintrc.js | 8 ++++++++ .../admin/src/components/WrapperSelect/index.js | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 9b5ac0ed58..473cd181f4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -51,4 +51,12 @@ module.exports = { version: '16.5.2', }, }, + overrides: [ + { + files: ['packages/**/admin/src/**/**/*.js'], + rules: { + 'no-nested-ternary': ['error'], + }, + }, + ], }; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js index c8260498e6..12c060184f 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js @@ -2,8 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { SelectWrapper, SelectNav } from 'strapi-helper-plugin'; import { ErrorMessage } from '@buffetjs/styles'; -import CreatableSelect from '../CreatableSelect'; import ComponentSelect from '../ComponentSelect'; +import CreatableSelect from '../CreatableSelect'; +/*eslint-disable no-nested-ternary */ const WrapperSelect = ({ error, label, name, type, ...rest }) => { const styles = { From aa9d4e2d7a9bcdb8a803fdb42ebb9ca04cefa931 Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 8 Jan 2020 13:25:11 +0100 Subject: [PATCH 04/25] Add basics tests for reducer --- .../api/address/models/Address.settings.json | 6 + .../containers/DataManagerProvider/index.js | 4 +- .../tests/reducer_basic_actions.test.js | 630 ++++++++++++++++++ 3 files changed, 637 insertions(+), 3 deletions(-) diff --git a/examples/getstarted/api/address/models/Address.settings.json b/examples/getstarted/api/address/models/Address.settings.json index 270b48cb94..3d9b41b654 100755 --- a/examples/getstarted/api/address/models/Address.settings.json +++ b/examples/getstarted/api/address/models/Address.settings.json @@ -43,6 +43,12 @@ "full_name": { "type": "string", "required": true + }, + "dz": { + "type": "dynamiczone", + "components": [ + "default.openingtimes" + ] } } } 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 4867924037..22ee5d61aa 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 @@ -97,8 +97,6 @@ const DataManagerProvider = ({ allIcons, children }) => { components: contentTypes, }); - console.log(orderedContenTypes.get('components').toJS()); - dispatch({ type: 'GET_DATA_SUCCEEDED', components: orderedComponents.get('components'), @@ -376,7 +374,7 @@ const DataManagerProvider = ({ allIcons, children }) => { }); }; - console.log({ modifiedData }); + console.log({ modifiedData: reducerState.toJS() }); const sortedContentTypesList = sortBy( Object.keys(contentTypes) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js index 3a7babf0c1..8a99e08d81 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js @@ -6,6 +6,199 @@ describe('CTB | containers | reducer | basics actions ', () => { expect(reducer(initialState, { type: 'TEST' })).toEqual(initialState); }); + describe('ADD_CREATED_COMPONENT_TO_DYNAMIC_ZONE', () => { + it('should add the created component to the dynamic zone', () => { + const createdComponent = fromJS({ + uid: 'default.test', + category: 'default', + isTemporary: true, + schema: { + icon: 'book', + name: 'test', + collectionName: '', + attributes: {}, + }, + }); + const components = fromJS({ + 'default.test': createdComponent, + 'default.other': { + uid: 'default.other', + category: 'default', + + schema: { + icon: 'book', + name: 'test', + collectionName: '', + attributes: {}, + }, + }, + }); + const contentType = fromJS({ + uid: 'application::test', + schema: { + name: 'test', + attributes: { + dz: { + type: 'dynamiczone', + components: ['default.other'], + }, + }, + }, + }); + const state = initialState + .setIn(['components'], components) + .setIn(['modifiedData', 'components'], components) + + .setIn(['modifiedData', 'contentType'], contentType); + + const expected = state.setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + 'dz', + 'components', + ], + fromJS(['default.other', 'default.test']) + ); + + expect( + reducer(state, { + type: 'ADD_CREATED_COMPONENT_TO_DYNAMIC_ZONE', + dynamicZoneTarget: 'dz', + componentsToAdd: ['default.test'], + }) + ).toEqual(expected); + }); + }); + + describe('CANCEL_CHANGES', () => { + it('Should set the modifiedData and the components object with the initial ones', () => { + const state = fromJS({ + components: { + test: { + something: true, + }, + other: { + something: false, + }, + }, + initialComponents: { + test: { + something: false, + }, + other: { + something: false, + }, + }, + modifiedData: { + components: { + test: { + something: true, + }, + other: { + something: false, + }, + }, + contentType: { + uid: 'something', + name: 'test', + }, + }, + initialData: { + components: { + test: { + something: false, + }, + other: { + something: false, + }, + }, + contentType: { + uid: 'something', + name: 'something', + }, + }, + }); + + const expected = fromJS({ + components: { + test: { + something: false, + }, + other: { + something: false, + }, + }, + initialComponents: { + test: { + something: false, + }, + other: { + something: false, + }, + }, + modifiedData: { + components: { + test: { + something: false, + }, + other: { + something: false, + }, + }, + contentType: { + uid: 'something', + name: 'something', + }, + }, + initialData: { + components: { + test: { + something: false, + }, + other: { + something: false, + }, + }, + contentType: { + uid: 'something', + name: 'something', + }, + }, + }); + + expect(reducer(state, { type: 'CANCEL_CHANGES' })).toEqual(expected); + }); + }); + + describe('CREATE_SCHEMA', () => { + it('Should create a content type schema correctly', () => { + const uid = 'application::test'; + const data = { + collectionName: 'test', + name: 'test', + }; + const expected = initialState.setIn( + ['contentTypes', uid], + fromJS({ + uid, + isTemporary: true, + schema: { + collectionName: data.collectionName, + name: data.name, + attributes: {}, + }, + }) + ); + + expect( + reducer(initialState, { type: 'CREATE_SCHEMA', uid, data }) + ).toEqual(expected); + }); + }); + describe('GET_DATA_SUCCEEDED', () => { const components = { 'default.test': { @@ -50,6 +243,355 @@ describe('CTB | containers | reducer | basics actions ', () => { }); }); + describe('REMOVE_COMPONENT_FROM_DYNAMIC_ZONE', () => { + it('Should remove a component from a dynamic zone', () => { + const state = fromJS({ + components: { + 'default.openingtimes': { + uid: 'default.openingtimes', + category: 'default', + schema: { + icon: 'calendar', + name: 'openingtimes', + description: '', + connection: 'default', + collectionName: 'components_openingtimes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + 'default.dish': { + uid: 'default.dish', + category: 'default', + schema: { + icon: 'calendar', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + }, + modifiedData: { + components: { + 'default.dish': { + uid: 'default.dish', + category: 'default', + schema: { + icon: 'calendar', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + 'default.openingtimes': { + uid: 'default.openingtimes', + category: 'default', + schema: { + icon: 'calendar', + name: 'openingtimes', + description: '', + connection: 'default', + collectionName: 'components_openingtimes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + }, + contentType: { + uid: 'application::address.address', + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: 'addresses', + attributes: { + geolocation: { + type: 'json', + required: true, + }, + city: { + type: 'string', + required: true, + }, + postal_coder: { + type: 'string', + }, + category: { + model: 'category', + }, + cover: { + model: 'file', + via: 'related', + plugin: 'upload', + required: false, + }, + images: { + collection: 'file', + via: 'related', + plugin: 'upload', + required: false, + }, + full_name: { + type: 'string', + required: true, + }, + dz: { + type: 'dynamiczone', + components: ['default.openingtimes', 'default.dish'], + }, + otherDz: { + type: 'dynamiczone', + components: ['default.openingtimes', 'default.dish'], + }, + }, + }, + }, + }, + }); + + const expected = fromJS({ + components: { + 'default.openingtimes': { + uid: 'default.openingtimes', + category: 'default', + schema: { + icon: 'calendar', + name: 'openingtimes', + description: '', + connection: 'default', + collectionName: 'components_openingtimes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + 'default.dish': { + uid: 'default.dish', + category: 'default', + schema: { + icon: 'calendar', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + }, + modifiedData: { + components: { + 'default.dish': { + uid: 'default.dish', + category: 'default', + schema: { + icon: 'calendar', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + 'default.openingtimes': { + uid: 'default.openingtimes', + category: 'default', + schema: { + icon: 'calendar', + name: 'openingtimes', + description: '', + connection: 'default', + collectionName: 'components_openingtimes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + }, + contentType: { + uid: 'application::address.address', + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: 'addresses', + attributes: { + geolocation: { + type: 'json', + required: true, + }, + city: { + type: 'string', + required: true, + }, + postal_coder: { + type: 'string', + }, + category: { + model: 'category', + }, + cover: { + model: 'file', + via: 'related', + plugin: 'upload', + required: false, + }, + images: { + collection: 'file', + via: 'related', + plugin: 'upload', + required: false, + }, + full_name: { + type: 'string', + required: true, + }, + dz: { + type: 'dynamiczone', + components: ['default.openingtimes'], + }, + otherDz: { + type: 'dynamiczone', + components: ['default.openingtimes', 'default.dish'], + }, + }, + }, + }, + }, + }); + + expect( + reducer(state, { + type: 'REMOVE_COMPONENT_FROM_DYNAMIC_ZONE', + dzName: 'dz', + componentToRemoveIndex: 1, + }) + ).toEqual(expected); + }); + }); + + describe('REMOVE_FIELD_FROM_DISPLAYED_COMPONENT', () => { + it('Should remove the selected field', () => { + const state = fromJS({ + modifiedData: { + components: { + 'default.test': { + schema: { + attributes: { + text: { + type: 'text', + }, + other: { + type: 'string', + }, + last: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }); + + const expected = fromJS({ + modifiedData: { + components: { + 'default.test': { + schema: { + attributes: { + text: { + type: 'text', + }, + last: { + type: 'integer', + }, + }, + }, + }, + }, + }, + }); + + expect( + reducer(state, { + type: 'REMOVE_FIELD_FROM_DISPLAYED_COMPONENT', + componentUid: 'default.test', + attributeToRemoveName: 'other', + }) + ).toEqual(expected); + }); + }); + describe('SET_MODIFIED_DATA', () => { it('Should set the modifiedData object correctly if the user did create a new type', () => { const schemaToSet = fromJS({ @@ -143,5 +685,93 @@ describe('CTB | containers | reducer | basics actions ', () => { }) ).toEqual(expected); }); + + it('Should update the modified data correctly if the schemaType is a component', () => { + const data = { + name: 'newTest', + collectionName: 'newTest', + category: 'test', + icon: 'test', + }; + const state = fromJS({ + components: { + test: { + uid: 'test', + category: 'default', + schema: { + name: 'test', + icon: 'book', + collectionName: 'components_tests', + attributes: { + something: { + type: 'string', + }, + }, + }, + }, + }, + modifiedData: { + components: {}, + component: { + uid: 'test', + category: 'default', + schema: { + name: 'test', + icon: 'book', + collectionName: 'components_tests', + attributes: { + something: { + type: 'string', + }, + }, + }, + }, + }, + }); + const expected = fromJS({ + components: { + test: { + uid: 'test', + category: 'test', + schema: { + name: 'newTest', + icon: 'test', + collectionName: 'newTest', + attributes: { + something: { + type: 'string', + }, + }, + }, + }, + }, + modifiedData: { + components: {}, + component: { + uid: 'test', + category: 'test', + schema: { + name: 'newTest', + icon: 'test', + collectionName: 'newTest', + attributes: { + something: { + type: 'string', + }, + }, + }, + }, + }, + }); + + expect( + reducer(state, { + type: 'UPDATE_SCHEMA', + data, + schemaType: 'component', + uid: 'test', + }) + ).toEqual(expected); + }); }); }); From 8a570964c6989516b414255e6c92c4f412e92a87 Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 8 Jan 2020 16:42:01 +0100 Subject: [PATCH 05/25] Add tests for simple actions --- .../api/address/models/Address.settings.json | 6 - .../containers/DataManagerProvider/reducer.js | 3 +- .../DataManagerProvider/tests/data.js | 485 ++++++++++++++++++ .../tests/reducer_basic_actions.test.js | 168 ++++++ 4 files changed, 655 insertions(+), 7 deletions(-) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/data.js diff --git a/examples/getstarted/api/address/models/Address.settings.json b/examples/getstarted/api/address/models/Address.settings.json index 3d9b41b654..270b48cb94 100755 --- a/examples/getstarted/api/address/models/Address.settings.json +++ b/examples/getstarted/api/address/models/Address.settings.json @@ -43,12 +43,6 @@ "full_name": { "type": "string", "required": true - }, - "dz": { - "type": "dynamiczone", - "components": [ - "default.openingtimes" - ] } } } diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index 0b0e9fe06c..521fe847dd 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -15,6 +15,7 @@ const initialState = fromJS({ }); const ONE_SIDE_RELATIONS = ['oneWay', 'manyWay']; + const getOppositeNature = originalNature => { if (originalNature === 'manyToOne') { return 'oneToMany'; @@ -517,4 +518,4 @@ const reducer = (state, action) => { }; export default reducer; -export { initialState }; +export { addComponentsToState, initialState }; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/data.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/data.js new file mode 100644 index 0000000000..bd4699d657 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/data.js @@ -0,0 +1,485 @@ +const data = { + components: { + 'default.closingperiod': { + uid: 'default.closingperiod', + category: '', + schema: { + icon: 'angry', + name: 'closingperiod', + description: '', + connection: 'default', + collectionName: 'components_closingperiods', + attributes: { + label: { + type: 'string', + }, + start_date: { + type: 'date', + required: true, + }, + end_date: { + type: 'date', + required: true, + }, + media: { + type: 'media', + multiple: false, + required: false, + }, + dish: { + component: 'default.dish', + type: 'component', + }, + }, + }, + }, + 'default.dish': { + uid: 'default.dish', + category: 'default', + schema: { + icon: 'book', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: { + name: { + type: 'string', + required: true, + default: 'My super dish', + }, + description: { + type: 'text', + }, + price: { + type: 'float', + }, + picture: { + type: 'media', + multiple: false, + required: false, + }, + very_long_description: { + type: 'richtext', + }, + category: { + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }, + }, + }, + }, + 'default.openingtimes': { + uid: 'default.openingtimes', + category: 'default', + schema: { + icon: 'calendar', + name: 'openingtimes', + description: '', + connection: 'default', + collectionName: 'components_openingtimes', + attributes: { + label: { + type: 'string', + required: true, + default: 'something', + }, + time: { + type: 'string', + }, + }, + }, + }, + 'default.restaurantservice': { + uid: 'default.restaurantservice', + category: 'default', + schema: { + icon: 'strapi', + name: 'restaurantservice', + description: '', + connection: 'default', + collectionName: 'components_restaurantservices', + attributes: { + name: { + type: 'string', + required: true, + default: 'something', + }, + media: { + type: 'media', + multiple: false, + required: false, + }, + is_available: { + type: 'boolean', + required: true, + default: true, + }, + }, + }, + }, + }, + contentTypes: { + 'plugins::myplugin.test': { + uid: '', + plugin: 'myplugin', + schema: { + name: 'test', + description: '', + connection: 'default', + collectionName: 'myplugin_test', + attributes: { + type: { + type: 'string', + required: true, + unique: true, + configurable: true, + }, + }, + }, + }, + 'plugins::users-permissions.role': { + uid: 'plugins::users-permissions.role', + plugin: 'users-permissions', + schema: { + name: 'role', + description: '', + connection: 'default', + collectionName: '', + attributes: { + name: { + type: 'string', + minLength: 3, + required: true, + configurable: false, + }, + description: { type: 'string', configurable: false }, + type: { type: 'string', unique: true, configurable: false }, + permissions: { + nature: 'oneToMany', + target: 'plugins::users-permissions.permission', + plugin: 'users-permissions', + dominant: false, + targetAttribute: 'role', + configurable: false, + unique: false, + }, + users: { + nature: 'oneToMany', + target: 'plugins::users-permissions.user', + plugin: 'users-permissions', + dominant: false, + targetAttribute: 'role', + unique: false, + }, + }, + }, + }, + 'application::address.address': { + uid: 'application::address.address', + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: { + geolocation: { type: 'json', required: true }, + city: { type: 'string', required: true }, + postal_coder: { type: 'string' }, + category: { + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }, + cover: { type: 'media', multiple: false, required: false }, + images: { type: 'media', multiple: true, required: false }, + full_name: { type: 'string', required: true }, + }, + }, + }, + 'application::menusection.menusection': { + uid: 'application::menusection.menusection', + schema: { + name: 'menusection', + description: '', + connection: 'default', + collectionName: '', + attributes: { + name: { type: 'string', required: true, minLength: 6 }, + dishes: { + component: 'default.dish', + type: 'component', + repeatable: true, + }, + menu: { + nature: 'manyToOne', + target: 'application::menu.menu', + dominant: false, + targetAttribute: 'menusections', + unique: false, + }, + }, + }, + }, + 'application::country.country': { + uid: 'application::country.country', + schema: { + name: 'country', + description: '', + connection: 'default', + collectionName: '', + attributes: { + name: { type: 'string', required: true, minLength: 3 }, + code: { type: 'string', maxLength: 3, unique: true, minLength: 2 }, + }, + }, + }, + 'plugins::users-permissions.user': { + uid: 'plugins::users-permissions.user', + plugin: 'users-permissions', + schema: { + name: 'users', + description: '', + connection: 'default', + collectionName: '', + attributes: { + username: { + type: 'string', + minLength: 3, + unique: true, + configurable: false, + required: true, + }, + email: { + type: 'email', + minLength: 6, + configurable: false, + required: true, + }, + provider: { type: 'string', configurable: false }, + password: { + type: 'password', + minLength: 6, + configurable: false, + private: true, + }, + resetPasswordToken: { + type: 'string', + configurable: false, + private: true, + }, + confirmed: { type: 'boolean', default: false, configurable: false }, + blocked: { type: 'boolean', default: false, configurable: false }, + role: { + nature: 'manyToOne', + target: 'plugins::users-permissions.role', + plugin: 'users-permissions', + dominant: false, + targetAttribute: 'users', + configurable: false, + unique: false, + }, + picture: { type: 'media', multiple: false, required: false }, + }, + }, + }, + 'application::review.review': { + uid: 'application::review.review', + schema: { + name: 'review', + description: '', + connection: 'default', + collectionName: '', + attributes: { + comment: { type: 'text', required: true }, + rating: { type: 'integer', required: true, min: 1, max: 5 }, + likes: { + nature: 'oneToMany', + target: 'application::like.like', + dominant: false, + targetAttribute: 'review', + unique: false, + }, + author: { + nature: 'oneWay', + target: 'plugins::users-permissions.user', + plugin: 'users-permissions', + dominant: false, + unique: false, + }, + restaurant: { + nature: 'oneWay', + target: 'application::restaurant.restaurant', + dominant: false, + unique: false, + }, + }, + }, + }, + 'application::like.like': { + uid: 'application::like.like', + schema: { + name: 'like', + description: '', + connection: 'default', + collectionName: '', + attributes: { + author: { + nature: 'oneWay', + target: 'plugins::users-permissions.user', + plugin: 'users-permissions', + dominant: false, + unique: false, + }, + review: { + nature: 'manyToOne', + target: 'application::review.review', + dominant: false, + targetAttribute: 'likes', + unique: false, + }, + }, + }, + }, + 'application::category.category': { + uid: 'application::category.category', + schema: { + name: 'category', + description: '', + connection: 'default', + collectionName: '', + attributes: { + name: { type: 'string' }, + }, + }, + }, + 'plugins::users-permissions.permission': { + uid: 'plugins::users-permissions.permission', + plugin: 'users-permissions', + schema: { + name: 'permission', + description: '', + connection: 'default', + collectionName: '', + attributes: { + type: { type: 'string', required: true, configurable: false }, + controller: { type: 'string', required: true, configurable: false }, + action: { type: 'string', required: true, configurable: false }, + enabled: { type: 'boolean', required: true, configurable: false }, + policy: { type: 'string', configurable: false }, + role: { + nature: 'manyToOne', + target: 'plugins::users-permissions.role', + plugin: 'users-permissions', + dominant: false, + targetAttribute: 'permissions', + configurable: false, + unique: false, + }, + }, + }, + }, + 'application::menu.menu': { + uid: 'application::menu.menu', + schema: { + name: 'menu', + description: '', + connection: 'default', + collectionName: '', + attributes: { + description: { type: 'text' }, + menusections: { + nature: 'oneToMany', + target: 'application::menusection.menusection', + dominant: false, + targetAttribute: 'menu', + unique: false, + }, + restaurant: { + nature: 'oneToOne', + target: 'application::restaurant.restaurant', + dominant: false, + targetAttribute: 'menu', + unique: false, + }, + }, + }, + }, + 'application::restaurant.restaurant': { + uid: 'application::restaurant.restaurant', + schema: { + name: 'restaurant', + description: '', + connection: 'default', + collectionName: '', + attributes: { + price_range: { + enum: [ + 'very_cheap', + 'cheap', + 'average', + 'expensive', + 'very_expensive', + ], + type: 'enumeration', + }, + closing_period: { + component: 'default.closingperiod', + type: 'component', + }, + name: { maxLength: 50, required: true, minLength: 5, type: 'string' }, + address: { + nature: 'oneWay', + target: 'application::address.address', + dominant: false, + unique: false, + }, + cover: { type: 'media', multiple: false, required: false }, + images: { type: 'media', multiple: true, required: false }, + short_description: { type: 'text' }, + since: { type: 'date' }, + categories: { + nature: 'manyWay', + target: 'application::category.category', + dominant: false, + unique: false, + }, + description: { type: 'richtext', required: true }, + services: { + component: 'default.restaurantservice', + repeatable: true, + type: 'component', + }, + menu: { + nature: 'oneToOne', + target: 'application::menu.menu', + dominant: false, + targetAttribute: 'restaurant', + unique: false, + }, + opening_times: { + component: 'default.openingtimes', + type: 'component', + repeatable: true, + min: 1, + max: 10, + }, + dz: { + type: 'dynamiczone', + components: [ + 'default.closingperiod', + 'default.dish', + 'default.openingtimes', + 'default.restaurantservice', + ], + }, + }, + }, + }, + }, +}; + +export default data; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js index 8a99e08d81..45638021de 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js @@ -1,5 +1,7 @@ import { fromJS } from 'immutable'; +import { get } from 'lodash'; import reducer, { initialState } from '../reducer'; +import testData from './data'; describe('CTB | containers | reducer | basics actions ', () => { it('Should return the initial state', () => { @@ -173,6 +175,152 @@ describe('CTB | containers | reducer | basics actions ', () => { }); }); + describe('CHANGE_DYNAMIC_ZONE_COMPONENTS', () => { + it('Should add the component to the dz field and to the modifiedData.components if the added component is not already in the modifiedData.components', () => { + const componentUID = 'default.openingtimes'; + const component = get(testData, ['components', componentUID]); + const contentType = fromJS( + testData.contentTypes['application::address.address'] + ).setIn( + ['schema', 'attributes', 'dz'], + fromJS({ type: 'dynamiczone', components: ['default.openingtimes'] }) + ); + const state = initialState + .setIn(['components'], fromJS(testData.components)) + .setIn(['modifiedData', 'components', componentUID], fromJS(component)) + .setIn(['modifiedData', 'contentType'], contentType); + + const expected = state + .setIn( + ['modifiedData', 'components', 'default.dish'], + fromJS(get(testData, ['components', 'default.dish'])) + ) + .setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + 'dz', + 'components', + ], + fromJS([componentUID, 'default.dish']) + ); + + expect( + reducer(state, { + type: 'CHANGE_DYNAMIC_ZONE_COMPONENTS', + dynamicZoneTarget: 'dz', + newComponents: ['default.dish'], + }) + ).toEqual(expected); + }); + + it('Should add the component to the dz field and not to the modifiedData.components if the added component is already in the modifiedData.components', () => { + const componentUID = 'default.openingtimes'; + const component = get(testData, ['components', componentUID]); + const contentType = fromJS( + testData.contentTypes['application::address.address'] + ).setIn( + ['schema', 'attributes', 'dz'], + fromJS({ type: 'dynamiczone', components: ['default.openingtimes'] }) + ); + const state = initialState + .setIn(['components'], fromJS(testData.components)) + .setIn(['modifiedData', 'components', componentUID], fromJS(component)) + .setIn( + ['modifiedData', 'components', 'default.dish'], + fromJS(get(testData, ['components', 'default.dish'])) + ) + .setIn(['modifiedData', 'contentType'], contentType); + + const expected = state.setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + 'dz', + 'components', + ], + fromJS([componentUID, 'default.dish']) + ); + + expect( + reducer(state, { + type: 'CHANGE_DYNAMIC_ZONE_COMPONENTS', + dynamicZoneTarget: 'dz', + newComponents: ['default.dish'], + }) + ).toEqual(expected); + }); + }); + + describe('CREATE_COMPONENT_SCHEMA', () => { + it('Should add the created component schema to the components object when creating a component using the left menu link', () => { + const action = { + type: 'CREATE_COMPONENT_SCHEMA', + data: { name: 'new component', icon: 'arrow-alt-circle-down' }, + componentCategory: 'test', + schemaType: 'component', + uid: 'test.new-component', + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['components', fromJS(testData.components)]) + .setIn(['initialComponents', fromJS(testData.components)]); + + const expected = state.setIn( + ['components', action.uid], + fromJS({ + uid: action.uid, + isTemporary: true, + category: action.componentCategory, + schema: { + ...action.data, + attributes: {}, + }, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should add the created component schema to the components object, create the attribute and also add the created component to modifiedData.components when using the add attribute modal', () => { + const action = { + type: 'CREATE_COMPONENT_SCHEMA', + data: { name: 'new component', icon: 'arrow-alt-circle-down' }, + componentCategory: 'test', + schemaType: 'component', + uid: 'test.new-component', + shouldAddComponentToData: true, + }; + const compoToCreate = { + uid: action.uid, + isTemporary: true, + category: action.componentCategory, + schema: { + ...action.data, + attributes: {}, + }, + }; + + const state = initialState + .setIn(['components', fromJS(testData.components)]) + .setIn(['initialComponents', fromJS(testData.components)]); + + const expected = state + .setIn(['components', action.uid], fromJS(compoToCreate)) + .setIn( + ['modifiedData', 'components', action.uid], + fromJS(compoToCreate) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + describe('CREATE_SCHEMA', () => { it('Should create a content type schema correctly', () => { const uid = 'application::test'; @@ -199,6 +347,26 @@ describe('CTB | containers | reducer | basics actions ', () => { }); }); + describe('DELETE_NOT_SAVED_TYPE', () => { + it('Should reset the components and and contentTypes object', () => { + const state = initialState + .setIn(['components'], fromJS({ foo: {}, bar: {} })) + .setIn(['initialComponents'], fromJS({ foo: {} })) + .setIn(['contentTypes'], fromJS({ baz: {}, bat: {} })) + .setIn(['initialContentTypes'], fromJS({ baz: {} })); + + const expected = initialState + .setIn(['components'], fromJS({ foo: {} })) + .setIn(['initialComponents'], fromJS({ foo: {} })) + .setIn(['contentTypes'], fromJS({ baz: {} })) + .setIn(['initialContentTypes'], fromJS({ baz: {} })); + + expect(reducer(state, { type: 'DELETE_NOT_SAVED_TYPE' })).toEqual( + expected + ); + }); + }); + describe('GET_DATA_SUCCEEDED', () => { const components = { 'default.test': { From 60cd11624aa1d3cea0fc12a5b51b054314d89cec Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 8 Jan 2020 17:57:25 +0100 Subject: [PATCH 06/25] Add test for adding a common attribute --- .../reducer_add_attribute_action.test.js | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js new file mode 100644 index 0000000000..d4004332c9 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -0,0 +1,124 @@ +import { fromJS } from 'immutable'; +import { get } from 'lodash'; +import reducer, { initialState } from '../reducer'; +import testData from './data'; + +describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { + describe('Adding a common field that is not a relation', () => { + it('Should add a text field to a content type correctly', () => { + const state = initialState.setIn( + ['modifiedData', 'contentType'], + fromJS(get(testData, ['contentTypes', 'application::address.address'])) + ); + const action = { + type: 'ADD_ATTRIBUTE', + + attributeToSet: { + type: 'string', + name: 'name', + default: 'something', + private: true, + required: true, + unique: true, + maxLength: 3, + minLength: 1, + }, + forTarget: 'contentType', + targetUid: 'application::address.address', + initialAttribute: {}, + shouldAddComponentToData: false, + }; + + const expected = state.setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'name'], + fromJS({ + type: 'string', + default: 'something', + private: true, + required: true, + unique: true, + maxLength: 3, + minLength: 1, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should add a integer field to a component that is an attribute of a content type', () => { + const compoUID = 'default.dish'; + const compoSchema = fromJS(get(testData, ['components', compoUID])); + const state = initialState + .setIn( + ['modifiedData', 'contentType'], + fromJS( + get(testData, ['contentTypes', 'application::address.address']) + ).setIn( + ['schema', 'attributes', 'compo_field'], + fromJS({ + type: 'component', + component: compoUID, + }) + ) + ) + .setIn(['modifiedData', 'components', compoUID], compoSchema) + .setIn(['components', compoUID], compoSchema); + + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + name: 'test', + type: 'integer', + default: 2, + private: true, + required: true, + min: null, + }, + forTarget: 'components', + targetUid: 'default.dish', + initialAttribute: {}, + shouldAddComponentToData: false, + }; + + const expected = state.setIn( + [ + 'modifiedData', + 'components', + compoUID, + 'schema', + 'attributes', + 'test', + ], + fromJS({ + type: 'integer', + default: 2, + private: true, + required: true, + min: null, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('Adding a component field attribute', () => { + it('Should create the component attribute and add the component to the modifiedData.components if the component is not in the object', () => { + expect(true).toBe(true); + }); + + it('Should create the component attribute and not add the component to the modifiedData.components if the component is already in the object to keep the modifications', () => { + expect(true).toBe(true); + }); + + it('Should create the component correctly in case the component is created on the fly', () => { + expect(true).toBe(true); + }); + }); + + describe('Adding a dynamic zone', () => { + it('Should create the dynamiczone attribute correctly', () => { + expect(true).toBe(true); + }); + }); +}); From c577097994cfb5d2ec194ea39d0e304b3314bc83 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 14 Jan 2020 12:31:39 +0100 Subject: [PATCH 07/25] Add test for adding a compo and a dz --- .../containers/DataManagerProvider/reducer.js | 1 + .../reducer_add_attribute_action.test.js | 235 +++++++++++++++++- 2 files changed, 230 insertions(+), 6 deletions(-) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index c06604e9ee..338d33a9bb 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -75,6 +75,7 @@ const reducer = (state, action) => { forTarget, targetUid, } = action; + console.log(action); delete rest.createComponent; const pathToDataToEdit = ['component', 'contentType'].includes(forTarget) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js index d4004332c9..a76a55ac5e 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -104,21 +104,244 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { describe('Adding a component field attribute', () => { it('Should create the component attribute and add the component to the modifiedData.components if the component is not in the object', () => { - expect(true).toBe(true); + const contentTypeUID = 'application::address.address'; + const contentType = get(testData, ['contentTypes', contentTypeUID]); + const componentToAddUID = 'default.dish'; + + const state = initialState + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn(['modifiedData', 'contentType'], fromJS(contentType)) + .setIn(['modifiedData', 'components'], fromJS({})); + + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + type: 'component', + repeatable: true, + name: 'compoField', + component: componentToAddUID, + required: true, + max: 2, + min: 1, + }, + forTarget: 'contentType', + targetUid: 'application::address.address', + initialAttribute: {}, + shouldAddComponentToData: true, + }; + + const expected = state + .setIn( + ['modifiedData', 'components', componentToAddUID], + fromJS(testData.components[componentToAddUID]) + ) + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'compoField'], + fromJS({ + type: 'component', + repeatable: true, + + component: componentToAddUID, + required: true, + max: 2, + min: 1, + }) + ); + + expect(reducer(state, action)).toEqual(expected); }); - it('Should create the component attribute and not add the component to the modifiedData.components if the component is already in the object to keep the modifications', () => { - expect(true).toBe(true); + it('Should create the component attribute and add the component to the modifiedData.components and its nested components if none of the added components are in the object', () => { + const contentTypeUID = 'application::address.address'; + const contentType = get(testData, ['contentTypes', contentTypeUID]); + const componentToAddUID = 'default.closingperiod'; + + const state = initialState + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn(['modifiedData', 'contentType'], fromJS(contentType)) + .setIn(['modifiedData', 'components'], fromJS({})); + + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + type: 'component', + repeatable: true, + name: 'compoField', + component: componentToAddUID, + required: true, + max: 2, + min: 1, + }, + forTarget: 'contentType', + targetUid: 'application::address.address', + initialAttribute: {}, + shouldAddComponentToData: true, + }; + + const expected = state + .setIn( + ['modifiedData', 'components', componentToAddUID], + fromJS(testData.components[componentToAddUID]) + ) + .setIn( + ['modifiedData', 'components', 'default.dish'], + fromJS(testData.components['default.dish']) + ) + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'compoField'], + fromJS({ + type: 'component', + repeatable: true, + component: componentToAddUID, + required: true, + max: 2, + min: 1, + }) + ); + + expect(reducer(state, action)).toEqual(expected); }); - it('Should create the component correctly in case the component is created on the fly', () => { - expect(true).toBe(true); + it('Should create the component attribute and add the component to the modifiedData.components and only add the nested components that are not in components are in the object to keep previous the modifications', () => { + const contentTypeUID = 'application::address.address'; + const contentType = get(testData, ['contentTypes', contentTypeUID]); + const componentToAddUID = 'default.closingperiod'; + + const state = initialState + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn(['modifiedData', 'contentType'], fromJS(contentType)) + .setIn( + ['modifiedData', 'components', 'default.dish'], + fromJS(testData.components['default.dish']) + ); + + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + type: 'component', + repeatable: true, + name: 'compoField', + component: componentToAddUID, + required: true, + max: 2, + min: 1, + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: {}, + shouldAddComponentToData: true, + }; + + const expected = state + .setIn( + ['modifiedData', 'components', componentToAddUID], + fromJS(testData.components[componentToAddUID]) + ) + + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'compoField'], + fromJS({ + type: 'component', + repeatable: true, + component: componentToAddUID, + required: true, + max: 2, + min: 1, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should create the component correctly in case of creating the component on the fly', () => { + const componentToCreateUID = 'default.new-compo'; + const componentToCreate = { + uid: componentToCreateUID, + isTemporary: true, + category: 'default', + schema: { + name: 'newCompo', + icon: 'ad', + attributes: {}, + }, + }; + const contentTypeUID = 'application::address.address'; + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + name: 'newCompo', + type: 'component', + repeatable: false, + component: componentToCreateUID, + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: undefined, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['components', componentToCreateUID], fromJS(componentToCreate)) + .setIn( + ['modifiedData', 'components', componentToCreateUID], + fromJS(componentToCreate) + ) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + + const expected = state.setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'newCompo'], + fromJS({ + type: 'component', + repeatable: false, + component: componentToCreateUID, + }) + ); + + expect(reducer(state, action)).toEqual(expected); }); }); describe('Adding a dynamic zone', () => { it('Should create the dynamiczone attribute correctly', () => { - expect(true).toBe(true); + const contentTypeUID = 'application::address.address'; + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + type: 'dynamiczone', + components: [], + name: 'dz', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: {}, + shouldAddComponentToData: false, + }; + const state = initialState.setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + + const expected = state.setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'dz'], + fromJS({ + type: 'dynamiczone', + components: [], + }) + ); + + expect(reducer(state, action)).toEqual(expected); }); }); }); From 1e3c3d97361d3e15a41504a3c29146bc583342e3 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 14 Jan 2020 15:01:43 +0100 Subject: [PATCH 08/25] Add test for adding a relation with another ct --- .../reducer_add_attribute_action.test.js | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js index a76a55ac5e..a56dba16c2 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -344,4 +344,159 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { expect(reducer(state, action)).toEqual(expected); }); }); + + describe('Adding a relation with another content type', () => { + it('Should add the relation attribute correctly for a content type', () => { + const contentTypeUID = 'application::address.address'; + const targetContentTypeUID = 'application::category.category'; + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + name: 'categories', + nature: 'oneToMany', + targetAttribute: 'address', + target: targetContentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: {}, + shouldAddComponentToData: false, + }; + + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'categories'], + fromJS({ + nature: 'oneToMany', + targetAttribute: 'address', + target: targetContentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should add the relation attribute for a component', () => { + const componentUID = 'default.dish'; + const targetContentTypeUID = 'application::category.category'; + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + name: 'address', + nature: 'oneWay', + targetAttribute: '-', + target: targetContentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + forTarget: 'component', + targetUid: componentUID, + initialAttribute: {}, + shouldAddComponentToData: false, + }; + + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'component'], + fromJS(testData.components[componentUID]) + ) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'component', 'schema', 'attributes', 'address'], + fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: targetContentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should add the relation correctly for a component from the modifiedData.components object', () => { + const componentUID = 'default.dish'; + const targetContentTypeUID = 'application::category.category'; + const action = { + type: 'ADD_ATTRIBUTE', + attributeToSet: { + name: 'address', + nature: 'oneWay', + targetAttribute: '-', + target: targetContentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + forTarget: 'components', + targetUid: componentUID, + initialAttribute: {}, + shouldAddComponentToData: false, + }; + + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[targetContentTypeUID]) + ) + .setIn( + ['modifiedData', 'components', componentUID], + fromJS(testData.components[componentUID]) + ) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + [ + 'modifiedData', + 'components', + componentUID, + 'schema', + 'attributes', + 'address', + ], + fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: targetContentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); }); From 3db763340ced26a02df4e6a19178e5f09b96ff53 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 14 Jan 2020 15:30:14 +0100 Subject: [PATCH 09/25] Add tests for all relations --- .../containers/DataManagerProvider/reducer.js | 1 - .../reducer_add_attribute_action.test.js | 348 ++++++++++++++++++ 2 files changed, 348 insertions(+), 1 deletion(-) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index 338d33a9bb..c06604e9ee 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -75,7 +75,6 @@ const reducer = (state, action) => { forTarget, targetUid, } = action; - console.log(action); delete rest.createComponent; const pathToDataToEdit = ['component', 'contentType'].includes(forTarget) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js index a56dba16c2..fbe1eaa65a 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -499,4 +499,352 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { expect(reducer(state, action)).toEqual(expected); }); }); + + describe('Adding a relation with the same content type', () => { + it('Should not create an opposite attribute if the relation is oneWay', () => { + const contentTypeUID = 'application::address.address'; + const action = { + type: 'ADD_ATTRIBUTE', + forTarget: 'contentType', + targetUid: contentTypeUID, + attributeToSet: { + name: 'address', + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + shouldAddComponentToData: false, + }; + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + const expected = state.setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'address'], + fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should not create an opposite attribute if the relation is manyWay', () => { + const contentTypeUID = 'application::address.address'; + const action = { + type: 'ADD_ATTRIBUTE', + forTarget: 'contentType', + targetUid: contentTypeUID, + attributeToSet: { + name: 'address', + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + shouldAddComponentToData: false, + }; + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + const expected = state.setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', 'address'], + fromJS({ + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the oneToOne relation correctly and create the opposite attribute', () => { + const contentTypeUID = 'application::address.address'; + const name = 'address_left_side'; + const targetAttribute = 'address_right_side'; + const columnName = 'left_side'; + const targetColumnName = 'right_side'; + const attribute = { + nature: 'oneToOne', + targetAttribute, + target: contentTypeUID, + unique: false, + dominant: null, + columnName, + targetColumnName, + required: false, + }; + const action = { + type: 'ADD_ATTRIBUTE', + forTarget: 'contentType', + targetUid: contentTypeUID, + attributeToSet: { + name, + ...attribute, + }, + shouldAddComponentToData: false, + }; + const oppositeAttribute = { + nature: 'oneToOne', + target: contentTypeUID, + unique: false, + required: false, + targetAttribute: name, + dominant: null, + columnName: targetColumnName, + targetColumnName: columnName, + }; + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + + const expected = state + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', name], + fromJS(attribute) + ) + .setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + targetAttribute, + ], + fromJS(oppositeAttribute) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the oneToMany relation correctly and create the opposite attribute', () => { + const contentTypeUID = 'application::address.address'; + const name = 'address_left_side'; + const targetAttribute = 'address_right_side'; + const columnName = 'left_side'; + const targetColumnName = 'right_side'; + const attribute = { + nature: 'oneToMany', + targetAttribute, + target: contentTypeUID, + unique: false, + dominant: null, + columnName, + targetColumnName, + required: false, + }; + const action = { + type: 'ADD_ATTRIBUTE', + forTarget: 'contentType', + targetUid: contentTypeUID, + attributeToSet: { + name, + ...attribute, + }, + shouldAddComponentToData: false, + }; + const oppositeAttribute = { + nature: 'manyToOne', + target: contentTypeUID, + unique: false, + required: false, + targetAttribute: name, + dominant: null, + columnName: targetColumnName, + targetColumnName: columnName, + }; + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + + const expected = state + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', name], + fromJS(attribute) + ) + .setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + targetAttribute, + ], + fromJS(oppositeAttribute) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the manyToOne relation correctly and create the opposite attribute', () => { + const contentTypeUID = 'application::address.address'; + const name = 'address_left_side'; + const targetAttribute = 'address_right_side'; + const columnName = 'left_side'; + const targetColumnName = 'right_side'; + const attribute = { + nature: 'manyToOne', + targetAttribute, + target: contentTypeUID, + unique: false, + dominant: null, + columnName, + targetColumnName, + required: false, + }; + const action = { + type: 'ADD_ATTRIBUTE', + forTarget: 'contentType', + targetUid: contentTypeUID, + attributeToSet: { + name, + ...attribute, + }, + shouldAddComponentToData: false, + }; + const oppositeAttribute = { + nature: 'oneToMany', + target: contentTypeUID, + unique: false, + required: false, + targetAttribute: name, + dominant: null, + columnName: targetColumnName, + targetColumnName: columnName, + }; + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + + const expected = state + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', name], + fromJS(attribute) + ) + .setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + targetAttribute, + ], + fromJS(oppositeAttribute) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the manyToMany relation correctly and create the opposite attribute', () => { + const contentTypeUID = 'application::address.address'; + const name = 'address_left_side'; + const targetAttribute = 'address_right_side'; + const columnName = 'left_side'; + const targetColumnName = 'right_side'; + const attribute = { + nature: 'manyToMany', + targetAttribute, + target: contentTypeUID, + unique: false, + dominant: true, + columnName, + targetColumnName, + required: false, + }; + const action = { + type: 'ADD_ATTRIBUTE', + forTarget: 'contentType', + targetUid: contentTypeUID, + attributeToSet: { + name, + ...attribute, + }, + shouldAddComponentToData: false, + }; + const oppositeAttribute = { + nature: 'manyToMany', + target: contentTypeUID, + unique: false, + required: false, + targetAttribute: name, + dominant: false, + columnName: targetColumnName, + targetColumnName: columnName, + }; + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('components', fromJS(testData.components)) + .set('initialComponents', fromJS(testData.components)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ); + + const expected = state + .setIn( + ['modifiedData', 'contentType', 'schema', 'attributes', name], + fromJS(attribute) + ) + .setIn( + [ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + targetAttribute, + ], + fromJS(oppositeAttribute) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); }); From 1f85288c6368f2230354acef926c16600ae25d49 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 14 Jan 2020 16:01:27 +0100 Subject: [PATCH 10/25] Add tests for removing a field from a content type --- .../containers/DataManagerProvider/reducer.js | 2 +- .../reducer_add_attribute_action.test.js | 8 - .../tests/reducer_remove_field_action.test.js | 306 ++++++++++++++++++ 3 files changed, 307 insertions(+), 9 deletions(-) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index c06604e9ee..c8f331f696 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -112,7 +112,7 @@ const reducer = (state, action) => { nature: getOppositeNature(nature), target, unique: rest.unique, - required: rest.required, + // required: rest.required, dominant: nature === 'manyToMany' ? !rest.dominant : null, targetAttribute: name, columnName: rest.targetColumnName, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js index fbe1eaa65a..3d94cd6d93 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -601,7 +601,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { dominant: null, columnName, targetColumnName, - required: false, }; const action = { type: 'ADD_ATTRIBUTE', @@ -617,7 +616,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { nature: 'oneToOne', target: contentTypeUID, unique: false, - required: false, targetAttribute: name, dominant: null, columnName: targetColumnName, @@ -666,7 +664,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { dominant: null, columnName, targetColumnName, - required: false, }; const action = { type: 'ADD_ATTRIBUTE', @@ -682,7 +679,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { nature: 'manyToOne', target: contentTypeUID, unique: false, - required: false, targetAttribute: name, dominant: null, columnName: targetColumnName, @@ -731,7 +727,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { dominant: null, columnName, targetColumnName, - required: false, }; const action = { type: 'ADD_ATTRIBUTE', @@ -747,7 +742,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { nature: 'oneToMany', target: contentTypeUID, unique: false, - required: false, targetAttribute: name, dominant: null, columnName: targetColumnName, @@ -796,7 +790,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { dominant: true, columnName, targetColumnName, - required: false, }; const action = { type: 'ADD_ATTRIBUTE', @@ -812,7 +805,6 @@ describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { nature: 'manyToMany', target: contentTypeUID, unique: false, - required: false, targetAttribute: name, dominant: false, columnName: targetColumnName, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js new file mode 100644 index 0000000000..79b781cbf0 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js @@ -0,0 +1,306 @@ +import { fromJS } from 'immutable'; +import reducer, { initialState } from '../reducer'; +import testData from './data'; + +describe('CTB | containers | reducer | REMOVE_FIELD', () => { + describe('Removing a field that is not a relation', () => { + it('Should remove the attribute correctly from the content type', () => { + const contentTypeUID = 'application::address.address'; + const attributeToRemoveName = 'city'; + const action = { + type: 'REMOVE_FIELD', + mainDataKey: 'contentType', + attributeToRemoveName, + componentUid: '', + }; + + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.removeIn([ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + attributeToRemoveName, + ]); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('Removing a relation attribute with another content type', () => { + it('Should remove the attribute correctly if the relation is made with another content type', () => { + const contentTypeUID = 'application::menusection.menusection'; + const attributeToRemoveName = 'menu'; + const action = { + type: 'REMOVE_FIELD', + mainDataKey: 'contentType', + attributeToRemoveName, + componentUid: '', + }; + + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.removeIn([ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + attributeToRemoveName, + ]); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('Removing a relation attribute with another content type', () => { + it('Should remove the attribute correctly if the relation is made with another content type', () => { + const contentTypeUID = 'application::menusection.menusection'; + const attributeToRemoveName = 'menu'; + const action = { + type: 'REMOVE_FIELD', + mainDataKey: 'contentType', + attributeToRemoveName, + componentUid: '', + }; + + const state = initialState + .set('contentTypes', fromJS(testData.contentTypes)) + .set('initialContentTypes', fromJS(testData.contentTypes)) + .setIn( + ['modifiedData', 'contentType'], + fromJS(testData.contentTypes[contentTypeUID]) + ) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.removeIn([ + 'modifiedData', + 'contentType', + 'schema', + 'attributes', + attributeToRemoveName, + ]); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('Removing a relation attribute with the same content type', () => { + it('Should handle the removal of the one side (oneWay or manyWay) nature correctly', () => { + const contentTypeUID = 'application::dummy.dummy'; + const action = { + type: 'REMOVE_FIELD', + mainDataKey: 'contentType', + attributeToRemoveName: 'one_way_attr', + componentUid: '', + }; + const contentType = { + uid: contentTypeUID, + schema: { + name: 'dummy', + attributes: { + name: { type: 'string' }, + one_way_attr: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + many_way_attrs: { + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + one_to_many_left: { + nature: 'oneToMany', + targetAttribute: 'one_to_many_right', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + one_to_many_right: { + nature: 'manyToOne', + target: 'application::dummy.dummy', + unique: false, + dominant: null, + targetAttribute: 'one_to_many_left', + columnName: null, + targetColumnName: null, + }, + }, + }, + }; + + const expectedContentType = { + uid: contentTypeUID, + schema: { + name: 'dummy', + attributes: { + name: { type: 'string' }, + many_way_attrs: { + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + one_to_many_left: { + nature: 'oneToMany', + targetAttribute: 'one_to_many_right', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + one_to_many_right: { + nature: 'manyToOne', + target: 'application::dummy.dummy', + unique: false, + dominant: null, + targetAttribute: 'one_to_many_left', + columnName: null, + targetColumnName: null, + }, + }, + }, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], fromJS(contentType)) + .setIn(['modifiedData', 'contentType'], fromJS(contentType)); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + fromJS(expectedContentType) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the removal of the two sides (oneToOne, oneToMany, manyToOne, manyToMany) nature correctly', () => { + const contentTypeUID = 'application::dummy.dummy'; + const action = { + type: 'REMOVE_FIELD', + mainDataKey: 'contentType', + attributeToRemoveName: 'one_to_many_left', + componentUid: '', + }; + const contentType = { + uid: contentTypeUID, + schema: { + name: 'dummy', + attributes: { + name: { type: 'string' }, + one_way_attr: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + many_way_attrs: { + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + one_to_many_left: { + nature: 'oneToMany', + targetAttribute: 'one_to_many_right', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + one_to_many_right: { + nature: 'manyToOne', + target: 'application::dummy.dummy', + unique: false, + dominant: null, + targetAttribute: 'one_to_many_left', + columnName: null, + targetColumnName: null, + }, + }, + }, + }; + + const expectedContentType = { + uid: contentTypeUID, + schema: { + name: 'dummy', + attributes: { + name: { type: 'string' }, + one_way_attr: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + many_way_attrs: { + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }, + }, + }, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], fromJS(contentType)) + .setIn(['modifiedData', 'contentType'], fromJS(contentType)); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + fromJS(expectedContentType) + ); + + expect(reducer(state, action)).toEqual(expected); + expect( + reducer(state, { + ...action, + attributeToRemoveName: 'one_to_many_right', + }) + ).toEqual(expected); + }); + }); +}); From 7c7813a7871b24a1d73a7751823c87c3db096ce2 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 14 Jan 2020 17:14:46 +0100 Subject: [PATCH 11/25] Init relations tests --- .../containers/DataManagerProvider/reducer.js | 17 +- .../reducer_edit_attribute_action.test.js | 655 ++++++++++++++++++ 2 files changed, 664 insertions(+), 8 deletions(-) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index c8f331f696..58bd3a90cf 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -234,20 +234,21 @@ const reducer = (state, action) => { initialAttribute, } = action; let newState = state; + console.log(action); const initialAttributeName = get(initialAttribute, ['name'], ''); const pathToDataToEdit = ['component', 'contentType'].includes(forTarget) ? [forTarget] : [forTarget, targetUid]; - const isEditingComponentAttribute = rest.type === 'component'; + // const isEditingComponentAttribute = rest.type === 'component'; - if (isEditingComponentAttribute) { - newState = state.updateIn( - ['modifiedData', 'components', rest.component], - () => state.getIn(['components', rest.component]) - ); - } + // if (isEditingComponentAttribute) { + // newState = state.updateIn( + // ['modifiedData', 'components', rest.component], + // () => state.getIn(['components', rest.component]) + // ); + // } return newState.updateIn( ['modifiedData', ...pathToDataToEdit, 'schema'], @@ -332,7 +333,7 @@ const reducer = (state, action) => { nature: getOppositeNature(rest.nature), target: rest.target, unique: rest.unique, - required: rest.required, + // required: rest.required, dominant: rest.nature === 'manyToMany' ? !rest.dominant : null, targetAttribute: name, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js new file mode 100644 index 0000000000..c1a913066c --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js @@ -0,0 +1,655 @@ +import { fromJS, OrderedMap } from 'immutable'; +import reducer, { initialState } from '../reducer'; + +describe('CTB | containers | reducer | EDIT_ATTRIBUTE', () => { + describe('Editing a common attribute (string, integer, json, media, ...)', () => { + it('Should edit the attribute correctly and preserve the order of the attributes for a content type', () => { + const contentTypeUID = 'application::address.address'; + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + type: 'media', + multiple: true, + required: false, + name: 'covers', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + type: 'media', + multiple: false, + required: false, + name: 'cover', + }, + shouldAddComponentToData: false, + }; + + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + dishes: { + component: 'default.dish', + type: 'component', + repeatable: true, + }, + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ type: 'media', multiple: false, required: false }), + images: fromJS({ type: 'media', multiple: true, required: false }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + dishes: { + component: 'default.dish', + type: 'component', + repeatable: true, + }, + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + covers: fromJS({ type: 'media', multiple: true, required: false }), + images: fromJS({ type: 'media', multiple: true, required: false }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should edit the attribute correctly and preserve the order of the attributes for a component inside the content type view', () => { + const contentTypeUID = 'application::address.address'; + const componentUID = 'default.dish'; + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + type: 'text', + required: true, + name: 'test', + }, + forTarget: 'components', + targetUid: componentUID, + initialAttribute: { + type: 'text', + name: 'description', + }, + shouldAddComponentToData: false, + }; + + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + dishes: { + component: componentUID, + type: 'component', + repeatable: true, + }, + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ type: 'media', multiple: false, required: false }), + images: fromJS({ type: 'media', multiple: true, required: false }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const component = fromJS({ + uid: componentUID, + category: 'default', + schema: { + icon: 'book', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: OrderedMap({ + name: fromJS({ + type: 'string', + required: true, + default: 'My super dish', + }), + description: fromJS({ + type: 'text', + }), + price: fromJS({ + type: 'float', + }), + picture: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + very_long_description: fromJS({ + type: 'richtext', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + }), + }, + }); + + const expectedComponent = fromJS({ + uid: componentUID, + category: 'default', + schema: { + icon: 'book', + name: 'dish', + description: '', + connection: 'default', + collectionName: 'components_dishes', + attributes: OrderedMap({ + name: fromJS({ + type: 'string', + required: true, + default: 'My super dish', + }), + test: fromJS({ + type: 'text', + required: true, + }), + price: fromJS({ + type: 'float', + }), + picture: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + very_long_description: fromJS({ + type: 'richtext', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + }), + }, + }); + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components', componentUID], component) + .setIn(['components', componentUID], component); + + const expected = state.setIn( + ['modifiedData', 'components', componentUID], + expectedComponent + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('Editing a relation attribute', () => { + describe('Editing a relation with the same content type', () => { + describe('Changing the nature of the relation', () => { + it('Should handle changing the nature from a one side relation (oneWay or manyWay) to another one side relation correctly and preserve the order of the attributes', () => { + const contentTypeUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_ways: fromJS({ + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'manyWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'many_ways', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle changing the nature from a one side relation (oneWay or manyWay) to a many sides (oneToOne, ...) correctly and preserve the order of the attributes', () => { + const contentTypeUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'oneToOne', + targetAttribute: 'address', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + shouldAddComponentToData: false, + }; + + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneToOne', + targetAttribute: 'address', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + address: fromJS({ + nature: 'oneToOne', + targetAttribute: 'one_way', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: null, + targetColumnName: 'test', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle changing the nature from a many side relation to a one side relation correctly and preserve the order of the attributes', () => { + const contentTypeUID = 'application::address.address'; + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneToOne', + targetAttribute: 'address', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + shouldAddComponentToData: false, + }; + + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneToOne', + targetAttribute: 'address', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + address: fromJS({ + nature: 'oneToOne', + targetAttribute: 'one_way', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: null, + targetColumnName: 'test', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('Changing the target of the relation', () => { + it('Should handle the edition of the target correctly for a one way relation (oneWay, manyWay) with another content type and preserve the order of the attributes', () => { + expect(true).toBe(true); + }); + + it('Should remove the opposite attribute and keep the order of the attributes if the relation nature is not a one side', () => { + expect(true).toBe(true); + }); + }); + + describe('Editing the other informations of the relation', () => { + it('Should handle the edition of the name of the relation correctly for a one side relation', () => { + expect(true).toBe(true); + }); + + it('Should handle the edition of the other properties correctly by updating the opposite attribute in the other cases', () => { + expect(true).toBe(true); + }); + }); + }); + }); +}); From e13e8e242bc69fad8b050b2752c4a667d48ce00d Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 15 Jan 2020 11:55:34 +0100 Subject: [PATCH 12/25] Add tests for internal relations --- .../containers/DataManagerProvider/index.js | 3 - .../containers/DataManagerProvider/reducer.js | 10 - .../reducer_add_attribute_action.test.js | 2 +- .../tests/reducer_basic_actions.test.js | 2 +- .../reducer_edit_attribute_action.test.js | 913 +++++++++++++++++- .../tests/reducer_remove_field_action.test.js | 2 +- 6 files changed, 909 insertions(+), 23 deletions(-) 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 382964399a..1bcac8c515 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 @@ -88,7 +88,6 @@ const DataManagerProvider = ({ allIcons, children }) => { ); const components = createDataObject(componentsArray); - const contentTypes = createDataObject(contentTypesArray); const orderedComponents = orderAllDataAttributesWithImmutable({ components, @@ -374,8 +373,6 @@ const DataManagerProvider = ({ allIcons, children }) => { }); }; - console.log({ modifiedData: reducerState.toJS() }); - const sortedContentTypesList = sortBy( Object.keys(contentTypes) .map(uid => ({ diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js index 58bd3a90cf..13ed18318d 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/reducer.js @@ -234,22 +234,12 @@ const reducer = (state, action) => { initialAttribute, } = action; let newState = state; - console.log(action); const initialAttributeName = get(initialAttribute, ['name'], ''); const pathToDataToEdit = ['component', 'contentType'].includes(forTarget) ? [forTarget] : [forTarget, targetUid]; - // const isEditingComponentAttribute = rest.type === 'component'; - - // if (isEditingComponentAttribute) { - // newState = state.updateIn( - // ['modifiedData', 'components', rest.component], - // () => state.getIn(['components', rest.component]) - // ); - // } - return newState.updateIn( ['modifiedData', ...pathToDataToEdit, 'schema'], obj => { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js index 3d94cd6d93..a7878fa6ac 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -3,7 +3,7 @@ import { get } from 'lodash'; import reducer, { initialState } from '../reducer'; import testData from './data'; -describe('CTB | containers | reducer | ADD_ATTRIBUTE', () => { +describe('CTB | containers | DataManagerProvider | reducer | ADD_ATTRIBUTE', () => { describe('Adding a common field that is not a relation', () => { it('Should add a text field to a content type correctly', () => { const state = initialState.setIn( diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js index 45638021de..3a5fb76c29 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_basic_actions.test.js @@ -3,7 +3,7 @@ import { get } from 'lodash'; import reducer, { initialState } from '../reducer'; import testData from './data'; -describe('CTB | containers | reducer | basics actions ', () => { +describe('CTB | containers | DataManagerProvider | reducer | basics actions ', () => { it('Should return the initial state', () => { expect(reducer(initialState, { type: 'TEST' })).toEqual(initialState); }); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js index c1a913066c..c558294277 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_edit_attribute_action.test.js @@ -1,7 +1,7 @@ import { fromJS, OrderedMap } from 'immutable'; import reducer, { initialState } from '../reducer'; -describe('CTB | containers | reducer | EDIT_ATTRIBUTE', () => { +describe('CTB | containers | DataManagerProvider | reducer | EDIT_ATTRIBUTE', () => { describe('Editing a common attribute (string, integer, json, media, ...)', () => { it('Should edit the attribute correctly and preserve the order of the attributes for a content type', () => { const contentTypeUID = 'application::address.address'; @@ -633,23 +633,922 @@ describe('CTB | containers | reducer | EDIT_ATTRIBUTE', () => { describe('Changing the target of the relation', () => { it('Should handle the edition of the target correctly for a one way relation (oneWay, manyWay) with another content type and preserve the order of the attributes', () => { - expect(true).toBe(true); + const contentTypeUID = 'application::address.address'; + + const updatedTargetUID = 'application::category.category'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + address: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'oneWay', + targetAttribute: '-', + target: updatedTargetUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + name: 'one_way', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + name: 'address', + }, + shouldAddComponentToData: false, + }; + + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: updatedTargetUID, + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); }); it('Should remove the opposite attribute and keep the order of the attributes if the relation nature is not a one side', () => { - expect(true).toBe(true); + const contentTypeUID = 'application::address.address'; + + const updatedTargetUID = 'application::category.category'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_to_many_left: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: contentTypeUID, + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + }), + many_to_many_right: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_left', + target: contentTypeUID, + unique: false, + dominant: false, + columnName: null, + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_to_many_left: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: updatedTargetUID, + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: updatedTargetUID, + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + name: 'many_to_many_left', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: contentTypeUID, + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + name: 'many_to_many_left', + }, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); }); }); describe('Editing the other informations of the relation', () => { - it('Should handle the edition of the name of the relation correctly for a one side relation', () => { - expect(true).toBe(true); + it('Should handle the edition of the other properties correctly by updating the opposite attribute in the other cases', () => { + const contentTypeUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_to_many_left: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: contentTypeUID, + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + }), + many_to_many_right: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_left', + target: contentTypeUID, + unique: false, + dominant: false, + columnName: null, + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'manyToMany', + targetAttribute: 'many_to_many_right_updated', + target: contentTypeUID, + unique: true, + dominant: true, + columnName: 'left', + targetColumnName: 'right', + name: 'many_to_many_left', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: contentTypeUID, + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + name: 'many_to_many_left', + }, + shouldAddComponentToData: false, + }; + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_to_many_left: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_right_updated', + target: contentTypeUID, + unique: true, + dominant: true, + columnName: 'left', + targetColumnName: 'right', + }), + many_to_many_right_updated: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_left', + target: contentTypeUID, + unique: true, + dominant: false, + columnName: 'right', + targetColumnName: 'left', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); }); - it('Should handle the edition of the other properties correctly by updating the opposite attribute in the other cases', () => { - expect(true).toBe(true); + it('Should handle the edition of the name of the relation correctly for a one side relation', () => { + const contentTypeUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way_updated: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: 'updated', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: false, + dominant: null, + columnName: 'updated', + targetColumnName: null, + name: 'one_way_updated', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); }); }); }); + + describe('Editing a relation with another content type', () => { + it('Should not create an opposite attribute if the target is the same content type and the nature is a one side relation (oneWay, manyWay)', () => { + const contentTypeUID = 'application::category.category'; + const updatedTargetUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_way: fromJS({ + nature: 'oneWay', + targetAttribute: '-', + target: updatedTargetUID, + unique: false, + dominant: null, + columnName: 'test', + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'oneWay', + targetAttribute: '-', + target: updatedTargetUID, + unique: false, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneWay', + targetAttribute: '-', + target: updatedTargetUID, + unique: false, + dominant: null, + columnName: 'test', + targetColumnName: null, + name: 'one_way', + }, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should create an opposite attribute if the target is the same content type and the nature is not a one side relation (oneToOne, ...)', () => { + const originalTargetUID = 'application::category.category'; + + const contentTypeUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_to_many: fromJS({ + nature: 'oneToMany', + targetAttribute: 'many_to_one', + target: originalTargetUID, + unique: true, + dominant: null, + columnName: 'many_to_one', + targetColumnName: 'one_to_many', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + one_to_many: fromJS({ + nature: 'oneToMany', + targetAttribute: 'many_to_one', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'many_to_one', + targetColumnName: 'one_to_many', + }), + many_to_one: fromJS({ + nature: 'manyToOne', + targetAttribute: 'one_to_many', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'one_to_many', + targetColumnName: 'many_to_one', + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'oneToMany', + targetAttribute: 'many_to_one', + target: contentTypeUID, + unique: true, + dominant: null, + columnName: 'many_to_one', + targetColumnName: 'one_to_many', + name: 'one_to_many', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'oneToMany', + targetAttribute: 'many_to_one', + target: originalTargetUID, + unique: true, + dominant: null, + columnName: 'many_to_one', + targetColumnName: 'one_to_many', + name: 'one_to_many', + }, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should create an opposite attribute if the target is the same content type and the nature is manyToMany', () => { + const originalTargetUID = 'application::category.category'; + + const contentTypeUID = 'application::address.address'; + const contentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_to_many_left: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: originalTargetUID, + unique: true, + dominant: false, + columnName: null, + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + const expectedContentType = fromJS({ + uid: contentTypeUID, + schema: { + name: 'address', + description: '', + connection: 'default', + collectionName: '', + attributes: OrderedMap({ + geolocation: fromJS({ type: 'json', required: true }), + city: fromJS({ type: 'string', required: true }), + postal_code: fromJS({ type: 'string' }), + many_to_many_left: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: contentTypeUID, + unique: true, + dominant: false, + columnName: null, + targetColumnName: null, + }), + many_to_many_right: fromJS({ + nature: 'manyToMany', + targetAttribute: 'many_to_many_left', + target: contentTypeUID, + unique: true, + dominant: true, + columnName: null, + targetColumnName: null, + }), + category: fromJS({ + nature: 'oneWay', + target: 'application::category.category', + dominant: false, + unique: false, + }), + cover: fromJS({ + type: 'media', + multiple: false, + required: false, + }), + images: fromJS({ + type: 'media', + multiple: true, + required: false, + }), + full_name: fromJS({ type: 'string', required: true }), + }), + }, + }); + + const action = { + type: 'EDIT_ATTRIBUTE', + attributeToSet: { + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: contentTypeUID, + unique: true, + dominant: false, + columnName: null, + targetColumnName: null, + name: 'many_to_many_left', + }, + forTarget: 'contentType', + targetUid: contentTypeUID, + initialAttribute: { + nature: 'manyToMany', + targetAttribute: 'many_to_many_right', + target: originalTargetUID, + unique: true, + dominant: false, + columnName: null, + targetColumnName: null, + name: 'many_to_many_left', + }, + shouldAddComponentToData: false, + }; + + const state = initialState + .setIn(['contentTypes', contentTypeUID], contentType) + .setIn(['modifiedData', 'contentType'], contentType) + .setIn(['modifiedData', 'components'], fromJS({})); + + const expected = state.setIn( + ['modifiedData', 'contentType'], + expectedContentType + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); }); }); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js index 79b781cbf0..4d2daf9561 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js @@ -2,7 +2,7 @@ import { fromJS } from 'immutable'; import reducer, { initialState } from '../reducer'; import testData from './data'; -describe('CTB | containers | reducer | REMOVE_FIELD', () => { +describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () => { describe('Removing a field that is not a relation', () => { it('Should remove the attribute correctly from the content type', () => { const contentTypeUID = 'application::address.address'; From 16a6975af115bb8d6f8e89cdae5385c830e210cd Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 15 Jan 2020 12:35:26 +0100 Subject: [PATCH 13/25] Fix add compo to dz action --- .../restaurant/models/Restaurant.settings.json | 2 -- .../ComponentSelect/MultipleMenuList.js | 2 +- .../admin/src/containers/FormModal/reducer.js | 16 +++++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/getstarted/api/restaurant/models/Restaurant.settings.json b/examples/getstarted/api/restaurant/models/Restaurant.settings.json index b4f027a6cf..24b99755a4 100755 --- a/examples/getstarted/api/restaurant/models/Restaurant.settings.json +++ b/examples/getstarted/api/restaurant/models/Restaurant.settings.json @@ -81,8 +81,6 @@ "dz": { "type": "dynamiczone", "components": [ - "default.closingperiod", - "default.dish", "default.openingtimes", "default.restaurantservice" ] diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentSelect/MultipleMenuList.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentSelect/MultipleMenuList.js index 08852222fb..9dfbf68891 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentSelect/MultipleMenuList.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentSelect/MultipleMenuList.js @@ -138,7 +138,7 @@ const MultipleMenuList = ({ const handleChange = ({ target }) => { const dataTarget = { name, - components: target.name, + components: [target.name], shouldAddComponents: target.value, }; 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 9106b14eab..e4ba874edc 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 @@ -1,4 +1,4 @@ -import { fromJS } from 'immutable'; +import { fromJS, List } from 'immutable'; import pluralize from 'pluralize'; import { snakeCase } from 'lodash'; import makeUnique from '../../utils/makeUnique'; @@ -22,15 +22,17 @@ const reducer = (state, action) => { const { name, components, shouldAddComponents } = action; return state.updateIn(['modifiedData', name], list => { + let updatedList = list; + if (shouldAddComponents) { - return makeUnique(list.concat(components)); + updatedList = list.concat(components); } else { - return makeUnique( - list.filter(comp => { - return components.indexOf(comp) === -1; - }) - ); + updatedList = list.filter(comp => { + return components.indexOf(comp) === -1; + }); } + + return List(makeUnique(updatedList.toJS())); }); } case 'ON_CHANGE': From 451e1e6de88e1b6c570ea108cf859c982901630c Mon Sep 17 00:00:00 2001 From: soupette Date: Wed, 15 Jan 2020 14:47:54 +0100 Subject: [PATCH 14/25] Add tests for FormModal reducer --- .../FormModal/tests/reducer.test.js | 589 ++++++++++++++++++ 1 file changed, 589 insertions(+) create mode 100644 packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js new file mode 100644 index 0000000000..58fe79448e --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js @@ -0,0 +1,589 @@ +import { fromJS } from 'immutable'; +import reducer, { initialState } from '../reducer'; + +describe('CTB | containers | FormModal | reducer | actions', () => { + describe('ADD_COMPONENTS_TO_DYNAMIC_ZONE', () => { + it('Should add the components correctly', () => { + const action = { + type: 'ADD_COMPONENTS_TO_DYNAMIC_ZONE', + components: ['default.test', 'default.test2', 'default.test3'], + shouldAddComponents: true, + name: 'components', + }; + + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'dynamiczone', + name: 'dz', + components: ['default.test'], + }) + ); + const expected = state.setIn( + ['modifiedData'], + fromJS({ + type: 'dynamiczone', + name: 'dz', + components: ['default.test', 'default.test2', 'default.test3'], + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should remove the components correctly', () => { + const action = { + type: 'ADD_COMPONENTS_TO_DYNAMIC_ZONE', + components: ['default.test2', 'default.test3'], + shouldAddComponents: false, + name: 'components', + }; + + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'dynamiczone', + name: 'dz', + components: ['default.test', 'default.test2', 'default.test3'], + }) + ); + const expected = state.setIn( + ['modifiedData'], + fromJS({ + type: 'dynamiczone', + name: 'dz', + components: ['default.test'], + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('ON_CHANGE', () => { + it('Should update the modifiedData object correctly if it is not relation', () => { + const action = { + type: 'ON_CHANGE', + keys: ['name'], + value: 'test', + }; + const state = initialState.setIn(['modifiedData', 'type'], 'string'); + const expected = state.setIn(['modifiedData', 'name'], 'test'); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the nature change correctly from oneWay to manyToMany', () => { + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + name: 'category test', + nature: 'oneWay', + targetAttribute: '-', + target: 'application::category.category', + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + const action = { + type: 'ON_CHANGE', + keys: ['nature'], + value: 'manyToMany', + targetContentType: 'application::category.category', + oneThatIsCreatingARelationWithAnother: 'address', + }; + const expected = state + .setIn(['modifiedData', 'nature'], 'manyToMany') + .setIn(['modifiedData', 'dominant'], true) + .setIn(['modifiedData', 'name'], 'category_tests') + .setIn(['modifiedData', 'targetAttribute'], 'addresses'); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the nature change correctly from manyToMany to oneWay', () => { + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + name: 'category_tests', + nature: 'manyToMany', + targetAttribute: 'addresses', + target: 'application::category.category', + unique: false, + dominant: true, + columnName: null, + targetColumnName: 'test', + }) + ); + const action = { + type: 'ON_CHANGE', + keys: ['nature'], + value: 'oneWay', + targetContentType: 'application::category.category', + oneThatIsCreatingARelationWithAnother: 'address', + }; + const expected = state + .setIn(['modifiedData', 'nature'], 'oneWay') + .setIn(['modifiedData', 'dominant'], null) + .setIn(['modifiedData', 'name'], 'category_test') + .setIn(['modifiedData', 'targetAttribute'], '-') + .setIn(['modifiedData', 'targetColumnName'], null); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the nature change correctly from oneToOne to oneToMany', () => { + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + name: 'category_test', + nature: 'oneToOne', + targetAttribute: 'address', + target: 'application::category.category', + unique: false, + dominant: null, + columnName: null, + targetColumnName: 'test', + }) + ); + const action = { + type: 'ON_CHANGE', + keys: ['nature'], + value: 'oneToMany', + targetContentType: 'application::category.category', + oneThatIsCreatingARelationWithAnother: 'address', + }; + const expected = state + .setIn(['modifiedData', 'nature'], 'oneToMany') + .setIn(['modifiedData', 'name'], 'category_tests'); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the target change correctly for a one side relation (oneWay, manyWay)', () => { + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + name: 'category test', + nature: 'oneWay', + targetAttribute: '-', + target: 'application::category.category', + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + const action = { + type: 'ON_CHANGE', + keys: ['target'], + value: 'application::address.address', + oneThatIsCreatingARelationWithAnother: 'address', + selectedContentTypeFriendlyName: 'address', + }; + const expected = state + .setIn(['modifiedData', 'target'], 'application::address.address') + .setIn(['modifiedData', 'name'], 'address'); + + expect(reducer(state, action)).toEqual(expected); + }); + + it('Should handle the target change correctly for the manyToMany relation', () => { + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + name: 'categories', + nature: 'manyToMany', + targetAttribute: 'addresses', + target: 'application::category.category', + unique: false, + dominant: true, + columnName: null, + targetColumnName: null, + }) + ); + const action = { + type: 'ON_CHANGE', + keys: ['target'], + value: 'application::country.country', + oneThatIsCreatingARelationWithAnother: 'address', + selectedContentTypeFriendlyName: 'country', + }; + const expected = state + .setIn(['modifiedData', 'target'], 'application::country.country') + .setIn(['modifiedData', 'name'], 'countries'); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('RESET_PROPS', () => { + it('Should return the initialState', () => { + const state = initialState.setIn(['modifiedData'], 'test'); + const action = { type: 'RESET_PROPS' }; + + expect(reducer(state, action)).toEqual(initialState); + }); + }); + + describe('RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO', () => { + it('Should reset the state and update the modifiedData object with the component field basic schema', () => { + const action = { + type: 'RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO', + }; + const state = initialState.setIn(['modifiedData'], 'test'); + const expected = state.setIn( + ['modifiedData'], + fromJS({ type: 'component', repeatable: true }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('RESET_PROPS_AND_SAVE_CURRENT_DATA', () => { + it('Should reset the state and update the modifiedData and componentToCreate objects correctly', () => { + const action = { type: 'RESET_PROPS_AND_SAVE_CURRENT_DATA' }; + // type: "component" + // createComponent: true + // componentToCreate: {type: "component", name: "ccc", icon: "air-freshener", category: "default"} + const state = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'component', + createComponent: true, + componentToCreate: { + type: 'component', + name: 'compo', + icon: 'air-freshener', + category: 'default', + }, + }) + ); + + const expected = initialState + .set( + 'componentToCreate', + fromJS({ + type: 'component', + name: 'compo', + icon: 'air-freshener', + category: 'default', + }) + ) + .set( + 'modifiedData', + fromJS({ + name: 'compo', + type: 'component', + repeatable: false, + component: 'default.compo', + }) + ) + .set('isCreatingComponentWhileAddingAField', true); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ', () => { + it('Should reset the state and prepare the form for adding or creating a component to a dynamic zone', () => { + const action = { + type: 'RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ', + }; + + const state = initialState.set('initialData', 'test').set( + 'modifiedData', + fromJS({ + type: 'dynamiczone', + components: [], + name: 'dz', + }) + ); + const expected = initialState.set( + 'modifiedData', + fromJS({ + type: 'dynamiczone', + components: [], + name: 'dz', + createComponent: true, + componentToCreate: fromJS({ type: 'component' }), + }) + ); + + expect(reducer(state, action)).toEqual(expected); + }); + }); + + describe('SET_DATA_TO_EDIT', () => { + it('Should set the state correctly', () => { + const action = { + type: 'SET_DATA_TO_EDIT', + data: { + test: true, + }, + }; + const expected = initialState + .set('modifiedData', fromJS(action.data)) + .set('initialData', fromJS(action.data)); + + expect(reducer(initialState, action)).toEqual(expected); + }); + }); + + describe('SET_ATTRIBUTE_DATA_SCHEMA', () => { + it('Should handle the edition correcty', () => { + const expected = initialState + .setIn(['modifiedData'], fromJS({ test: true })) + .setIn(['initialData'], fromJS({ test: true })); + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + isEditing: true, + modifiedDataToSetForEditing: { + test: true, + }, + }; + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a component in step 1', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'component', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: '1', + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'component', + createComponent: true, + componentToCreate: { type: 'component' }, + }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a component in step 2', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'component', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: '2', + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'component', + repeatable: true, + }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a dynamiczone', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'dynamiczone', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: '2', + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'dynamiczone', + components: [], + }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a text', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'text', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: null, + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ + type: 'string', + }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a number', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'number', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: null, + }; + const expected = initialState.setIn(['modifiedData'], fromJS({})); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a date', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'date', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: null, + }; + const expected = initialState.setIn(['modifiedData'], fromJS({})); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a media', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'media', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: null, + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ type: 'media', multiple: true }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for an enumeration', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'enumeration', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: null, + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ type: 'enumeration', enum: [] }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for a relation', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'relation', + nameToSetForRelation: 'address test', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null, targetAttribute: '-' }, + step: null, + }; + const expected = initialState.set( + 'modifiedData', + fromJS({ + name: 'address_test', + nature: 'oneWay', + targetAttribute: '-', + target: 'application::address.address', + unique: false, + dominant: null, + columnName: null, + targetColumnName: null, + }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + + it('Should set the state correctly for the other cases', () => { + const action = { + type: 'SET_ATTRIBUTE_DATA_SCHEMA', + attributeType: 'json', + nameToSetForRelation: 'address', + targetUid: 'application::address.address', + isEditing: false, + modifiedDataToSetForEditing: { name: null }, + step: null, + }; + const expected = initialState.setIn( + ['modifiedData'], + fromJS({ type: 'json', default: null }) + ); + + expect(reducer(initialState, action)).toEqual(expected); + }); + }); + + describe('SET_DYNAMIC_ZONE_DATA_SCHEMA', () => { + it('Should set the dynamic zone schema correctly', () => { + const action = { + type: 'SET_DYNAMIC_ZONE_DATA_SCHEMA', + attributeToEdit: { + type: 'dynamiczone', + components: [], + name: 'dz', + createComponent: false, + componentToCreate: { type: 'component' }, + }, + }; + const expected = initialState + .setIn(['modifiedData'], fromJS(action.attributeToEdit)) + .setIn(['initialData'], fromJS(action.attributeToEdit)); + + expect(reducer(initialState, action)).toEqual(expected); + }); + }); + + describe('SET_ERRORS', () => { + it('Should set the formErrors object correctly', () => { + const action = { + type: 'SET_ERRORS', + errors: { + test: 'this is required', + }, + }; + const expected = initialState.set('formErrors', fromJS(action.errors)); + + expect(reducer(initialState, action)).toEqual(expected); + }); + }); + + describe('Default', () => { + it('Should return the initialState', () => { + const action = { type: 'DUMMY' }; + + expect(reducer(initialState, action)).toEqual(initialState); + }); + }); +}); From 6ea595110be072e2f76e156955fdbaaa7395844a Mon Sep 17 00:00:00 2001 From: soupette Date: Thu, 16 Jan 2020 16:08:39 +0100 Subject: [PATCH 15/25] Apply PR feedback Signed-off-by: soupette --- .../src/components/WrapperSelect/index.js | 2 +- .../reducer_add_attribute_action.test.js | 6 ++-- .../tests/reducer_remove_field_action.test.js | 32 ------------------- .../FormModal/tests/reducer.test.js | 4 +-- 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js index 12c060184f..809032c743 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/WrapperSelect/index.js @@ -19,7 +19,7 @@ const WrapperSelect = ({ error, label, name, type, ...rest }) => { border: state.isFocused ? '1px solid #78caff !important' : error - ? '1px solid red !important' + ? '1px solid #F64D0A !important' : '1px solid #E3E9F3 !important', borderRadius: '2px !important', }), diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js index a7878fa6ac..8d405afd4a 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_add_attribute_action.test.js @@ -208,7 +208,7 @@ describe('CTB | containers | DataManagerProvider | reducer | ADD_ATTRIBUTE', () expect(reducer(state, action)).toEqual(expected); }); - it('Should create the component attribute and add the component to the modifiedData.components and only add the nested components that are not in components are in the object to keep previous the modifications', () => { + it('Should create the component attribute and add the component to the modifiedData.components and only add the nested components that are not in the modifiedData.components object to keep previous the modifications', () => { const contentTypeUID = 'application::address.address'; const contentType = get(testData, ['contentTypes', contentTypeUID]); const componentToAddUID = 'default.closingperiod'; @@ -392,7 +392,7 @@ describe('CTB | containers | DataManagerProvider | reducer | ADD_ATTRIBUTE', () expect(reducer(state, action)).toEqual(expected); }); - it('Should add the relation attribute for a component', () => { + it('Should add the relation attribute correctly for a component', () => { const componentUID = 'default.dish'; const targetContentTypeUID = 'application::category.category'; const action = { @@ -440,7 +440,7 @@ describe('CTB | containers | DataManagerProvider | reducer | ADD_ATTRIBUTE', () expect(reducer(state, action)).toEqual(expected); }); - it('Should add the relation correctly for a component from the modifiedData.components object', () => { + it('Should add the relation attribute correctly for a component from the modifiedData.components object', () => { const componentUID = 'default.dish'; const targetContentTypeUID = 'application::category.category'; const action = { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js index 4d2daf9561..3e3c60c7ea 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/DataManagerProvider/tests/reducer_remove_field_action.test.js @@ -67,38 +67,6 @@ describe('CTB | containers | DataManagerProvider | reducer | REMOVE_FIELD', () = }); }); - describe('Removing a relation attribute with another content type', () => { - it('Should remove the attribute correctly if the relation is made with another content type', () => { - const contentTypeUID = 'application::menusection.menusection'; - const attributeToRemoveName = 'menu'; - const action = { - type: 'REMOVE_FIELD', - mainDataKey: 'contentType', - attributeToRemoveName, - componentUid: '', - }; - - const state = initialState - .set('contentTypes', fromJS(testData.contentTypes)) - .set('initialContentTypes', fromJS(testData.contentTypes)) - .setIn( - ['modifiedData', 'contentType'], - fromJS(testData.contentTypes[contentTypeUID]) - ) - .setIn(['modifiedData', 'components'], fromJS({})); - - const expected = state.removeIn([ - 'modifiedData', - 'contentType', - 'schema', - 'attributes', - attributeToRemoveName, - ]); - - expect(reducer(state, action)).toEqual(expected); - }); - }); - describe('Removing a relation attribute with the same content type', () => { it('Should handle the removal of the one side (oneWay or manyWay) nature correctly', () => { const contentTypeUID = 'application::dummy.dummy'; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js index 58fe79448e..a80317e14d 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/tests/reducer.test.js @@ -246,9 +246,7 @@ describe('CTB | containers | FormModal | reducer | actions', () => { describe('RESET_PROPS_AND_SAVE_CURRENT_DATA', () => { it('Should reset the state and update the modifiedData and componentToCreate objects correctly', () => { const action = { type: 'RESET_PROPS_AND_SAVE_CURRENT_DATA' }; - // type: "component" - // createComponent: true - // componentToCreate: {type: "component", name: "ccc", icon: "air-freshener", category: "default"} + const state = initialState.setIn( ['modifiedData'], fromJS({ From 6c27d224f250cb86eaa370c5e18a68019b3c8d39 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 21 Jan 2020 11:33:43 +0100 Subject: [PATCH 16/25] Add eslint config Signed-off-by: soupette --- .eslintrc.js | 44 ++++++++- package.json | 4 + .../components/InputSearchLi/Components.js | 2 +- .../src/components/InputSearchLi/index.js | 5 +- .../admin/src/components/List/index.js | 4 +- .../src/components/PopUpForm/Components.js | 7 -- .../admin/src/components/PopUpForm/index.js | 17 ++-- .../admin/src/containers/App/index.js | 10 +- .../admin/src/containers/EditPage/index.js | 14 +-- .../admin/src/containers/HomePage/actions.js | 2 +- .../containers/HomePage/checkFormValidity.js | 29 ++++-- .../admin/src/containers/HomePage/index.js | 97 ++++++++++--------- .../src/containers/NotFoundPage/index.js | 20 ---- yarn.lock | 77 ++++++++++++++- 14 files changed, 221 insertions(+), 111 deletions(-) delete mode 100644 packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/Components.js delete mode 100644 packages/strapi-plugin-users-permissions/admin/src/containers/NotFoundPage/index.js diff --git a/.eslintrc.js b/.eslintrc.js index c31e0466f0..9e5590e1f8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,10 +4,10 @@ module.exports = { 'eslint:recommended', 'plugin:react/recommended', 'plugin:redux-saga/recommended', - 'prettier', + // 'airbnb', ], - plugins: ['react', 'redux-saga', 'react-hooks', 'import'], + plugins: ['react', 'redux-saga', 'react-hooks', 'import', 'jsx-a11y'], env: { browser: true, commonjs: true, @@ -54,9 +54,47 @@ module.exports = { overrides: [ { files: ['packages/**/admin/src/**/**/*.js'], + extends: ['airbnb'], rules: { - 'no-nested-ternary': ['error'], + 'arrow-body-style': 0, + 'arrow-parens': 0, + camelcase: 0, + 'consistent-return': [ + 2, + { + treatUndefinedAsUnspecified: true, + }, + ], + 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], + 'import/no-extraneous-dependencies': 0, + 'import/no-named-as-default': 0, 'import/order': 2, + 'max-len': [ + 2, + { + code: 120, + ignoreComments: true, + ignoreUrls: true, + ignoreTrailingComments: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + }, + ], + 'no-else-return': 1, + 'no-nested-ternary': ['error'], + 'no-return-assign': 0, + 'no-param-reassign': 0, + 'no-underscore-dangle': 0, + 'object-curly-newline': [2, { multiline: true, consistent: true }], + 'operator-linebreak': 0, + 'prefer-const': 0, + 'prefer-destructuring': 0, + 'prefer-object-spread': 0, + 'react/destructuring-assignment': 1, + 'react/forbid-prop-types': 0, + 'react/jsx-props-no-spreading': 0, + 'react/state-in-constructor': 0, + 'react/static-property-placement': 0, }, }, ], diff --git a/package.json b/package.json index 4fbf56343a..9730062a54 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,11 @@ "enzyme": "^3.9.0", "enzyme-adapter-react-16": "^1.12.1", "eslint": "^6.3.0", + "eslint-config-airbnb": "^18.0.1", + "eslint-config-airbnb-base": "^14.0.0", "eslint-config-prettier": "^6.2.0", "eslint-plugin-import": "^2.19.1", + "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-react": "^7.14.0", "eslint-plugin-react-hooks": "^2.0.0", "eslint-plugin-redux-saga": "^1.1.0", @@ -38,6 +41,7 @@ "build": "lerna run --stream build --no-private", "lint": "npm-run-all -p lint:code", "lint:code": "eslint .", + "lint:fix": "eslint --fix .", "lint:other": "npm run prettier:other -- --check", "format": "npm-run-all -p format:*", "format:code": "npm run prettier:code -- --write", diff --git a/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/Components.js b/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/Components.js index dd13af6bb0..63327b2fff 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/Components.js +++ b/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/Components.js @@ -37,4 +37,4 @@ const Wrapper = styled.div` } `; -export { Wrapper }; +export default Wrapper; diff --git a/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/index.js b/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/index.js index 1f7bc6f6a3..9e1bc3262c 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/components/InputSearchLi/index.js @@ -7,7 +7,10 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Wrapper } from './Components'; +import Wrapper from './Components'; + +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ function InputSearchLi({ onClick, isAdding, item }) { const { id, username } = item; diff --git a/packages/strapi-plugin-users-permissions/admin/src/components/List/index.js b/packages/strapi-plugin-users-permissions/admin/src/components/List/index.js index a1d2a8c71f..1f94585696 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/components/List/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/components/List/index.js @@ -61,7 +61,9 @@ const generateListTitle = (data, settingType) => { return (
- {enabledProviders} {disabledProviders} + {enabledProviders} +   + {disabledProviders}
); } diff --git a/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/Components.js b/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/Components.js deleted file mode 100644 index 9339cd6ec4..0000000000 --- a/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/Components.js +++ /dev/null @@ -1,7 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - padding-bottom: 20px; -`; - -export { Wrapper }; diff --git a/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/index.js b/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/index.js index 0ed9242674..84ceee8e4e 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/components/PopUpForm/index.js @@ -36,6 +36,8 @@ import { HomePageContext } from '../../contexts/HomePage'; // Translations import en from '../../translations/en.json'; +/* eslint-disable react/sort-comp */ +/* eslint-disable no-shadow */ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-stateless-function state = { enabled: false, isEditing: false }; @@ -102,7 +104,7 @@ class PopUpForm extends React.Component { const { name, type } = e.target; const target = Object.assign( { name, type }, - { value: `/auth/${this.props.dataToEdit}/callback` } + { value: `/auth/${this.props.dataToEdit}/callback` }, ); this.props.onChange({ target }); } @@ -132,13 +134,14 @@ class PopUpForm extends React.Component { return acc; }, []) .concat(acc); - } else if (current !== 'icon' && current !== 'scope') { + } + if (current !== 'icon' && current !== 'scope') { acc.push(`${name}${current}`); } return acc; }, - [] + [], ); if (settingType === 'providers') { @@ -166,7 +169,7 @@ class PopUpForm extends React.Component { errors={get( formErrors, [findIndex(formErrors, ['name', value]), 'errors'], - [] + [], )} key={value} label={{ @@ -237,7 +240,7 @@ class PopUpForm extends React.Component { errors={get( this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], - [] + [], )} label={{ id: `users-permissions.PopUpForm.Email.${value}.label` }} name={`${settingType}.${dataToEdit}.${value}`} @@ -259,7 +262,7 @@ class PopUpForm extends React.Component { errors={get( this.props.formErrors, [findIndex(this.props.formErrors, ['name', value]), 'errors'], - [] + [], )} label={{ id: `users-permissions.PopUpForm.Email.${value}.label` }} name={`${settingType}.${dataToEdit}.${value}`} @@ -306,7 +309,7 @@ class PopUpForm extends React.Component { ); } - let subHeader = + const subHeader = display && en[display] ? ( ) : ( diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js b/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js index 82cdf31bb2..39e752a598 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js @@ -6,13 +6,12 @@ */ import React from 'react'; -import PropTypes from 'prop-types'; import { Switch, Route } from 'react-router-dom'; +import { NotFound } from 'strapi-helper-plugin'; import pluginId from '../../pluginId'; import EditPage from '../EditPage'; import HomePage from '../HomePage'; -import NotFoundPage from '../NotFoundPage'; const App = () => { return ( @@ -28,15 +27,10 @@ const App = () => { component={HomePage} exact /> - + ); }; -App.propTypes = { - history: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, -}; - export default App; diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/EditPage/index.js b/packages/strapi-plugin-users-permissions/admin/src/containers/EditPage/index.js index c10b4fca36..07e1237994 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/EditPage/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/containers/EditPage/index.js @@ -57,6 +57,8 @@ import saga from './saga'; import { Loader, Title, Separator, Wrapper } from './Components'; +/* eslint-disable react/sort-comp */ + export class EditPage extends React.Component { // eslint-disable-line react/prefer-stateless-function getChildContext = () => ({ @@ -110,7 +112,7 @@ export class EditPage extends React.Component { ]); } - this.props.submit(this.context); + return this.props.submit(this.context); }; showLoaderForm = () => { @@ -221,7 +223,7 @@ export class EditPage extends React.Component { type: 'submit', disabled: isEqual( this.props.editPage.modifiedData, - this.props.editPage.initialData + this.props.editPage.initialData, ), key: 'button-submit', }, @@ -256,7 +258,7 @@ export class EditPage extends React.Component { description: get( this.props.editPage.initialData, 'description', - '' + '', ), }} > @@ -386,13 +388,13 @@ function mapDispatchToProps(dispatch) { resetProps, resetShouldDisplayPoliciesHint, }, - dispatch + dispatch, ); } const withConnect = connect( mapStateToProps, - mapDispatchToProps + mapDispatchToProps, ); const withReducer = strapi.injectReducer({ key: 'editPage', @@ -404,5 +406,5 @@ const withSaga = strapi.injectSaga({ key: 'editPage', saga, pluginId }); export default compose( withReducer, withSaga, - withConnect + withConnect, )(EditPage); diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/actions.js b/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/actions.js index ef994762c8..b335326d08 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/actions.js +++ b/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/actions.js @@ -52,7 +52,7 @@ export function fetchData(endPoint) { export function fetchDataSucceeded(data) { if (!isArray(data)) { const list = Object.keys(data).reduce((acc, current) => { - const obj = Object.assign({ name: current}, data[current]); + const obj = Object.assign({ name: current }, data[current]); acc.push(obj); return acc; diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/checkFormValidity.js b/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/checkFormValidity.js index e760fce6eb..1c984df00e 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/checkFormValidity.js +++ b/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/checkFormValidity.js @@ -1,6 +1,10 @@ import { get, isEmpty, isObject } from 'lodash'; -export default function checkFormValidity(settingType, data, providerToEdit = '') { +export default function checkFormValidity( + settingType, + data, + providerToEdit = '', +) { const formErrors = []; switch (settingType) { @@ -10,29 +14,40 @@ export default function checkFormValidity(settingType, data, providerToEdit = '' keys.forEach(key => { if (isProviderEnabled && isEmpty(get(data, key))) { - formErrors.push({ name: key, errors: [{ id: 'components.Input.error.validation.required' }] }); + formErrors.push({ + name: key, + errors: [{ id: 'components.Input.error.validation.required' }], + }); } }); break; } case 'email-templates': { - Object.keys(data.options).forEach((value) => { + Object.keys(data.options).forEach(value => { if (isObject(data.options[value])) { Object.keys(data.options[value]).forEach(subValue => { if (isEmpty(get(data, ['options', value, subValue]))) { - formErrors.push({ name: `options.${value}.${subValue}`, errors: [{ id: 'components.Input.error.validation.required' }] }); + formErrors.push({ + name: `options.${value}.${subValue}`, + errors: [{ id: 'components.Input.error.validation.required' }], + }); } }); } - if (value !== 'response_email' && isEmpty(get(data, ['options', value]))) { - formErrors.push({ name: `options.${value}`, errors: [{ id: 'components.Input.error.validation.required' }] }); + if ( + value !== 'response_email' && + isEmpty(get(data, ['options', value])) + ) { + formErrors.push({ + name: `options.${value}`, + errors: [{ id: 'components.Input.error.validation.required' }], + }); } }); break; } default: - } return formErrors; diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/index.js b/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/index.js index a385c82d58..42189e128f 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/containers/HomePage/index.js @@ -34,12 +34,55 @@ import { import reducer from './reducer'; import saga from './saga'; import checkFormValidity from './checkFormValidity'; + +/* eslint-disable consistent-return */ +/* eslint-disable react/sort-comp */ +/* eslint-disable react/no-access-state-in-setstate */ + const keyBoardShortCuts = [18, 78]; export class HomePage extends React.Component { state = { mapKey: {}, showModalEdit: false }; - static contextType = GlobalContext; + headerNavLinks = [ + { + name: getTrad('HeaderNav.link.roles'), + to: `/plugins/${pluginId}/roles`, + }, + { + name: getTrad('HeaderNav.link.providers'), + to: `/plugins/${pluginId}/providers`, + }, + { + name: getTrad('HeaderNav.link.emailTemplates'), + to: `/plugins/${pluginId}/email-templates`, + }, + { + name: getTrad('HeaderNav.link.advancedSettings'), + to: `/plugins/${pluginId}/advanced`, + }, + ]; + + pluginHeaderActions = [ + { + label: this.context.formatMessage({ + id: getTrad('EditPage.cancel'), + }), + color: 'cancel', + onClick: () => this.props.cancelChanges(), + type: 'button', + key: 'button-cancel', + }, + { + color: 'success', + label: this.context.formatMessage({ + id: getTrad('EditPage.submit'), + }), + onClick: () => this.props.submit(this.props.match.params.settingType), + type: 'submit', + key: 'button-submit', + }, + ]; componentDidMount() { this.props.fetchData(this.props.match.params.settingType); @@ -105,7 +148,7 @@ export class HomePage extends React.Component { this.props.history.push(`${this.props.location.pathname}/create`); } else if (this.props.match.params.settingType === 'providers') { this.props.history.push( - `${this.props.location.pathname}#add::${this.props.match.params.settingType}` + `${this.props.location.pathname}#add::${this.props.match.params.settingType}`, ); } }; @@ -123,7 +166,7 @@ export class HomePage extends React.Component { const formErrors = checkFormValidity( this.props.match.params.settingType, modifiedObject, - this.props.dataToEdit + this.props.dataToEdit, ); if (isEqual(initObject, modifiedObject)) { @@ -138,50 +181,10 @@ export class HomePage extends React.Component { } }; - headerNavLinks = [ - { - name: getTrad('HeaderNav.link.roles'), - to: `/plugins/${pluginId}/roles`, - }, - { - name: getTrad('HeaderNav.link.providers'), - to: `/plugins/${pluginId}/providers`, - }, - { - name: getTrad('HeaderNav.link.emailTemplates'), - to: `/plugins/${pluginId}/email-templates`, - }, - { - name: getTrad('HeaderNav.link.advancedSettings'), - to: `/plugins/${pluginId}/advanced`, - }, - ]; - isAdvanded = () => { return this.getEndPoint() === 'advanced'; }; - pluginHeaderActions = [ - { - label: this.context.formatMessage({ - id: getTrad('EditPage.cancel'), - }), - color: 'cancel', - onClick: () => this.props.cancelChanges(), - type: 'button', - key: 'button-cancel', - }, - { - color: 'success', - label: this.context.formatMessage({ - id: getTrad('EditPage.submit'), - }), - onClick: () => this.props.submit(this.props.match.params.settingType), - type: 'submit', - key: 'button-submit', - }, - ]; - showLoaders = () => { const { data, isLoading, modifiedData } = this.props; @@ -195,6 +198,8 @@ export class HomePage extends React.Component { ); }; + static contextType = GlobalContext; + render() { const { data, @@ -313,7 +318,7 @@ function mapDispatchToProps(dispatch) { submit, unsetDataToEdit, }, - dispatch + dispatch, ); } @@ -321,7 +326,7 @@ const mapStateToProps = selectHomePage(); const withConnect = connect( mapStateToProps, - mapDispatchToProps + mapDispatchToProps, ); const withReducer = strapi.injectReducer({ key: 'homePage', @@ -333,5 +338,5 @@ const withSaga = strapi.injectSaga({ key: 'homePage', saga, pluginId }); export default compose( withReducer, withSaga, - withConnect + withConnect, )(injectIntl(HomePage)); diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/NotFoundPage/index.js b/packages/strapi-plugin-users-permissions/admin/src/containers/NotFoundPage/index.js deleted file mode 100644 index 51b2f9977c..0000000000 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/NotFoundPage/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * NotFoundPage - * - * This is the page we show when the user visits a url that doesn't have a route - * - * NOTE: while this component should technically be a stateless functional - * component (SFC), hot reloading does not currently support SFCs. If hot - * reloading is not a neccessity for you then you can refactor it and remove - * the linting exception. - */ - -import React from 'react'; - -import { NotFound } from 'strapi-helper-plugin'; - -export default class NotFoundPage extends React.Component { - render() { - return ; - } -} diff --git a/yarn.lock b/yarn.lock index f3707d9703..2a1ade5b26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -731,6 +731,14 @@ "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" +"@babel/runtime-corejs3@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.3.tgz#a2445836d0699e5ba77eea2c790ad9ea51e2cd27" + integrity sha512-lrIU4aVbmlM/wQPzhEvzvNJskKyYptuXb0fGC0lTQTupTOYtR2Vqbu6/jf8vTr4M8Wt1nIzxVrSvPI5qESa/xA== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.2" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2": version "7.6.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f" @@ -745,6 +753,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1" + integrity sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" @@ -3494,7 +3509,7 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -aria-query@3.0.0: +aria-query@3.0.0, aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= @@ -3668,7 +3683,7 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types-flow@0.0.7: +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= @@ -3782,6 +3797,14 @@ aws4@^1.6.0, aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axobject-query@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.1.tgz#2a3b1271ec722d48a4cd4b3fcc20c853326a49a7" + integrity sha512-lF98xa/yvy6j3fBHAgQXIYl+J4eZadOSqsPojemUqClzNbBV38wWGpUbQbVEyf4eUF5yF7eHmGgGA2JiHyjeqw== + dependencies: + "@babel/runtime" "^7.7.4" + "@babel/runtime-corejs3" "^7.7.4" + babel-eslint@^10.0.0: version "10.0.3" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" @@ -5055,6 +5078,11 @@ configstore@^4.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" +confusing-browser-globals@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" + integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== + connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" @@ -5269,6 +5297,11 @@ core-js-compat@^3.1.1: browserslist "^4.6.6" semver "^6.3.0" +core-js-pure@^3.0.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" + integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -5741,6 +5774,11 @@ cypress@3.1.2: url "0.11.0" yauzl "2.8.0" +damerau-levenshtein@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz#780cf7144eb2e8dbd1c3bb83ae31100ccc31a414" + integrity sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA== + dargs@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" @@ -6431,7 +6469,7 @@ email-validator@^2.0.4: resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== -emoji-regex@^7.0.1: +emoji-regex@^7.0.1, emoji-regex@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== @@ -6685,6 +6723,24 @@ escodegen@1.x.x, escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-airbnb-base@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz#8a7bcb9643d13c55df4dd7444f138bf4efa61e17" + integrity sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA== + dependencies: + confusing-browser-globals "^1.0.7" + object.assign "^4.1.0" + object.entries "^1.1.0" + +eslint-config-airbnb@^18.0.1: + version "18.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.0.1.tgz#a3a74cc29b46413b6096965025381df8fb908559" + integrity sha512-hLb/ccvW4grVhvd6CT83bECacc+s4Z3/AEyWQdIT2KeTsG9dR7nx1gs7Iw4tDmGKozCNHFn4yZmRm3Tgy+XxyQ== + dependencies: + eslint-config-airbnb-base "^14.0.0" + object.assign "^4.1.0" + object.entries "^1.1.0" + eslint-config-prettier@^6.2.0: version "6.4.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz#0a04f147e31d33c6c161b2dd0971418ac52d0477" @@ -6726,6 +6782,21 @@ eslint-plugin-import@^2.19.1: read-pkg-up "^2.0.0" resolve "^1.12.0" +eslint-plugin-jsx-a11y@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" + integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== + dependencies: + "@babel/runtime" "^7.4.5" + aria-query "^3.0.0" + array-includes "^3.0.3" + ast-types-flow "^0.0.7" + axobject-query "^2.0.2" + damerau-levenshtein "^1.0.4" + emoji-regex "^7.0.2" + has "^1.0.3" + jsx-ast-utils "^2.2.1" + eslint-plugin-react-hooks@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.1.2.tgz#1358d2acb2c5e02b7e90c37e611ac258a488e3a7" From f50f89f0a8891ebf8ea372f73b44e08f1d3a3221 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 21 Jan 2020 16:03:31 +0100 Subject: [PATCH 17/25] Update eslint configuration Signed-off-by: soupette --- .eslintignore | 3 + .eslintrc.js | 38 ++++++++- packages/strapi-admin/admin/src/app.js | 2 + .../src/components/LeftMenuFooter/index.js | 4 +- .../src/components/LeftMenuLink/index.js | 2 + .../components/LeftMenuLinkContainer/index.js | 3 +- .../admin/src/components/ListPlugins/index.js | 2 + .../src/components/Notification/index.js | 2 +- .../NotificationsContainer/index.js | 2 + .../src/components/OnboardingVideo/index.js | 2 + .../admin/src/components/Row/index.js | 2 + .../admin/src/containers/Admin/index.js | 26 ++++--- .../admin/src/containers/App/index.js | 1 + .../admin/src/containers/AuthPage/Input.js | 2 + .../admin/src/containers/AuthPage/index.js | 9 +-- .../src/containers/HomePage/SocialLink.js | 2 +- .../src/containers/HomePage/components.js | 1 + .../containers/LanguageProvider/actions.js | 6 +- .../containers/LanguageProvider/constants.js | 1 + .../src/containers/LanguageProvider/index.js | 8 +- .../containers/LanguageProvider/reducer.js | 4 +- .../src/containers/ListPluginsPage/index.js | 2 +- .../src/containers/ListPluginsPage/saga.js | 2 + .../src/containers/LocaleToggle/actions.js | 7 +- .../LocaleToggle/tests/index.test.js | 2 +- .../LocaleToggle/tests/selectors.test.js | 4 +- .../admin/src/containers/Marketplace/index.js | 2 +- .../NotificationProvider/actions.js | 1 + .../containers/NotificationProvider/index.js | 11 ++- .../src/containers/Onboarding/Wrapper.js | 62 +++++++-------- .../admin/src/containers/Onboarding/index.js | 7 +- .../src/containers/Onboarding/reducer.js | 20 +++-- .../src/containers/PrivateRoute/index.js | 3 +- packages/strapi-admin/admin/src/plugins.js | 2 + .../admin/src/utils/injectReducer.js | 2 +- .../admin/src/utils/injectSaga.js | 2 +- .../admin/src/utils/reducerInjectors.js | 4 +- .../admin/src/utils/sagaInjectors.js | 36 +++++---- .../src/components/AddDropdown/components.js | 1 + .../CustomInputCheckbox/components.js | 1 + .../admin/src/components/CustomTable/Row.js | 6 +- .../src/components/CustomTable/TableHeader.js | 4 +- .../admin/src/components/CustomTable/index.js | 2 - .../CustomTable/styledComponents.js | 2 + .../DisplayedFieldsDropdown/MenuDropdown.js | 2 + .../components/DraggedField/GrabWrapper.js | 2 + .../components/DraggedField/NameWrapper.js | 2 + .../components/DraggedField/RemoveWrapper.js | 2 + .../src/components/DraggedField/SubWrapper.js | 2 + .../src/components/DraggedField/Wrapper.js | 2 + .../src/components/DraggedField/index.js | 1 + .../DraggedFieldWithPreview/index.js | 4 +- .../components/DynamicComponentCard/index.js | 2 +- .../src/components/DynamicZone/Button.js | 2 + .../admin/src/components/DynamicZone/index.js | 6 +- .../src/components/FieldComponent/Wrapper.js | 2 + .../src/components/FieldComponent/index.js | 1 + .../src/components/FieldsReorder/Item.js | 5 +- .../components/FieldsReorder/components.js | 2 +- .../src/components/FieldsReorder/index.js | 2 +- .../src/components/FilterPicker/components.js | 2 + .../src/components/FilterPicker/index.js | 4 +- .../components/FilterPickerOption/Input.js | 2 +- .../FilterPickerOption/components.js | 2 + .../admin/src/components/FormTitle/index.js | 4 +- .../components/InputCheckbox/components.js | 2 + .../admin/src/components/InputJSON/index.js | 6 +- .../components/InputJSONWithErrors/index.js | 1 - .../NonRepeatableComponent/index.js | 3 + .../components/PreviewCarret/components.js | 2 + .../RepeatableComponent/AddFieldButton.js | 4 + .../components/RepeatableComponent/Banner.js | 2 + .../RepeatableComponent/BannerWrapper.js | 2 + .../RepeatableComponent/DraggedItem.js | 5 +- .../RepeatableComponent/EmptyComponent.js | 4 +- .../RepeatableComponent/FormWrapper.js | 7 +- .../components/RepeatableComponent/index.js | 1 + .../admin/src/components/Search/index.js | 5 +- .../src/components/SelectMany/Relation.js | 2 + .../src/components/SelectWrapper/index.js | 4 +- .../components/SettingsViewWrapper/index.js | 4 +- .../src/components/Wysiwyg/EditorWrapper.js | 2 +- .../Wysiwyg/PreviewWysiwygWrapper.js | 2 + .../src/components/Wysiwyg/SelectWrapper.js | 2 + .../admin/src/components/Wysiwyg/index.js | 2 + .../src/components/Wysiwyg/previewWysiwyg.js | 3 + .../admin/src/components/Wysiwyg/video.js | 2 + .../components/WysiwygBottomControls/index.js | 4 + .../WysiwygInlineControls/StyledButton.js | 2 + .../src/components/WysiwygWithErrors/index.js | 2 + .../src/containers/EditSettingsView/index.js | 9 +-- .../containers/EditSettingsView/reducer.js | 2 +- .../admin/src/containers/EditView/Header.js | 2 + .../admin/src/containers/EditView/index.js | 4 +- .../EditView/utils/createAttributesLayout.js | 2 + .../containers/EditView/utils/formatData.js | 7 +- .../utils/cleanData.js | 7 +- .../utils/createDefaultForm.js | 2 +- .../utils/schema.js | 20 ++--- .../src/containers/LayoutDndProvider/index.js | 2 - .../src/containers/ListSettingsView/Label.js | 1 - .../src/containers/ListSettingsView/index.js | 1 - .../admin/src/containers/ListView/index.js | 6 +- .../admin/src/containers/Main/index.js | 13 ++-- .../src/containers/RecursivePath/index.js | 1 + .../ContentManager/EditSettingViewButton.js | 2 +- .../admin/src/components/BooleanBox/index.js | 2 +- .../src/components/ComponentCard/index.js | 2 + .../components/ComponentIconPicker/Cell.js | 2 + .../components/ComponentIconPicker/Wrapper.js | 4 + .../components/ComponentIconPicker/index.js | 8 +- .../src/components/ComponentList/index.js | 5 +- .../components/ComponentSelect/MenuList.js | 5 +- .../ComponentSelect/MultipleMenuList.js | 4 +- .../admin/src/components/CustomLink/index.js | 2 +- .../src/components/DynamicZoneList/index.js | 9 ++- .../src/components/HeaderNavLink/Wrapper.js | 2 + .../admin/src/components/List/index.js | 12 +-- .../admin/src/components/ListHeader/index.js | 1 + .../admin/src/components/ListRow/Wrapper.js | 3 +- .../admin/src/components/ListRow/index.js | 1 - .../components/ModalHeader/ComponentInfos.js | 2 + .../components/ModalHeader/DropdownInfos.js | 2 + .../admin/src/components/ModalHeader/index.js | 2 + .../RelationFormNaturePicker/index.js | 23 +++--- .../StyledRelationNaturePicker.js | 53 ------------- .../components/RelationNaturePicker/index.js | 78 ------------------- .../RelationNaturePicker/tests/index.test.js | 66 ---------------- .../admin/src/components/Td/index.js | 6 +- .../containers/DataManagerProvider/index.js | 4 +- .../admin/src/containers/FormModal/index.js | 35 ++++----- .../src/containers/FormModal/utils/forms.js | 25 +++--- .../containers/FormModal/utils/relations.js | 2 + .../FormModal/utils/staticFields.js | 12 +-- .../admin/src/containers/LeftMenu/index.js | 2 + .../admin/src/containers/ListView/index.js | 19 +++-- .../admin/src/icons/ManyToMany.js | 18 +++-- .../admin/src/icons/ManyToOne.js | 18 +++-- .../admin/src/icons/OneToMany.js | 18 +++-- .../admin/src/icons/OneToOne.js | 18 +++-- .../admin/src/icons/OneWay.js | 19 +++-- .../admin/src/containers/HomePage/index.js | 4 +- .../admin/src/containers/HomePage/saga.js | 2 + .../admin/src/utils/openWithNewTab.js | 9 +-- .../admin/src/containers/ConfigPage/index.js | 34 ++++---- 145 files changed, 529 insertions(+), 520 deletions(-) delete mode 100644 packages/strapi-plugin-content-type-builder/admin/src/components/RelationNaturePicker/StyledRelationNaturePicker.js delete mode 100644 packages/strapi-plugin-content-type-builder/admin/src/components/RelationNaturePicker/index.js delete mode 100644 packages/strapi-plugin-content-type-builder/admin/src/components/RelationNaturePicker/tests/index.test.js diff --git a/.eslintignore b/.eslintignore index 8da4651306..6b3786a50f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,7 @@ **/build/** **/dist/** testApp/** +packages/strapi-plugin-users-permissions/admin/** +packages/strapi-plugin-upload/admin/** +packages/strapi-generate-plugin/files/admin/src/** .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js index 9e5590e1f8..ccb70e2656 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -59,16 +59,32 @@ module.exports = { 'arrow-body-style': 0, 'arrow-parens': 0, camelcase: 0, + 'comma-dangle': 0, 'consistent-return': [ 2, { treatUndefinedAsUnspecified: true, }, ], - 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], + indent: [ + 2, + 2, + { + flatTernaryExpressions: false, + SwitchCase: 1, + ignoredNodes: [ + 'ConditionalExpression', + "VariableDeclarator[kind='const']", + ], + }, + ], + 'func-names': ['error', 'never'], + 'function-paren-newline': 0, + 'implicit-arrow-linebreak': 0, 'import/no-extraneous-dependencies': 0, 'import/no-named-as-default': 0, 'import/order': 2, + 'jsx-a11y/click-events-have-key-events': 1, 'max-len': [ 2, { @@ -80,19 +96,37 @@ module.exports = { ignoreTemplateLiterals: true, }, ], + 'no-confusing-arrow': 0, 'no-else-return': 1, 'no-nested-ternary': ['error'], 'no-return-assign': 0, 'no-param-reassign': 0, + 'no-shadow': 0, 'no-underscore-dangle': 0, + 'no-use-before-define': [ + 'error', + { functions: false, classes: false, variables: false }, + ], 'object-curly-newline': [2, { multiline: true, consistent: true }], 'operator-linebreak': 0, + 'prefer-arrow-callback': 0, 'prefer-const': 0, 'prefer-destructuring': 0, 'prefer-object-spread': 0, - 'react/destructuring-assignment': 1, + 'prefer-spread': 0, + 'space-before-function-paren': [ + 'error', + { + anonymous: 'never', + named: 'never', + asyncArrow: 'always', + }, + ], + 'react/destructuring-assignment': 0, + 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], 'react/forbid-prop-types': 0, 'react/jsx-props-no-spreading': 0, + 'react/jsx-one-expression-per-line': 0, 'react/state-in-constructor': 0, 'react/static-property-placement': 0, }, diff --git a/packages/strapi-admin/admin/src/app.js b/packages/strapi-admin/admin/src/app.js index f4184a17fd..ffd6a5d61e 100644 --- a/packages/strapi-admin/admin/src/app.js +++ b/packages/strapi-admin/admin/src/app.js @@ -5,6 +5,8 @@ // * Entry point of the application // */ +/* eslint-disable */ + import '@babel/polyfill'; import 'sanitize.css/sanitize.css'; diff --git a/packages/strapi-admin/admin/src/components/LeftMenuFooter/index.js b/packages/strapi-admin/admin/src/components/LeftMenuFooter/index.js index 004148090d..48d653fb98 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenuFooter/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuFooter/index.js @@ -7,12 +7,10 @@ import React from 'react'; import { defineMessages, FormattedMessage } from 'react-intl'; import { PropTypes } from 'prop-types'; - import LeftMenuLink from '../LeftMenuLink'; - import Wrapper from './Wrapper'; - import messages from './messages.json'; + defineMessages(messages); function LeftMenuFooter({ version, ...rest }) { diff --git a/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js b/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js index 2e3d3ec320..93e2c086d0 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js @@ -13,6 +13,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import en from '../../translations/en.json'; import Li from './Li'; +/* eslint-disable */ + function LeftMenuLink(props) { const isLinkActive = startsWith( props.location.pathname.replace('/admin', '').concat('/'), diff --git a/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js b/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js index b64807ee55..35f5db4a73 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/index.js @@ -8,11 +8,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import { get, snakeCase, isEmpty, map, sortBy } from 'lodash'; - import LeftMenuLink from '../LeftMenuLink'; import Wrapper from './Wrapper'; import messages from './messages.json'; +/* eslint-disable */ + function LeftMenuLinkContainer({ plugins, ...rest }) { // Generate the list of sections const pluginsSections = Object.keys(plugins).reduce((acc, current) => { diff --git a/packages/strapi-admin/admin/src/components/ListPlugins/index.js b/packages/strapi-admin/admin/src/components/ListPlugins/index.js index 4c2a14a705..1ada5aef60 100644 --- a/packages/strapi-admin/admin/src/components/ListPlugins/index.js +++ b/packages/strapi-admin/admin/src/components/ListPlugins/index.js @@ -15,6 +15,8 @@ import { Button } from 'strapi-helper-plugin'; import Row from '../Row'; import Wrapper from './Wrapper'; +/* eslint-disable react/prefer-stateless-function */ + class ListPlugins extends React.Component { render() { const listSize = size(this.props.plugins); diff --git a/packages/strapi-admin/admin/src/components/Notification/index.js b/packages/strapi-admin/admin/src/components/Notification/index.js index 36c00e7cd5..43a89d7075 100644 --- a/packages/strapi-admin/admin/src/components/Notification/index.js +++ b/packages/strapi-admin/admin/src/components/Notification/index.js @@ -3,7 +3,7 @@ * Notification * */ - +/* eslint-disable */ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; diff --git a/packages/strapi-admin/admin/src/components/NotificationsContainer/index.js b/packages/strapi-admin/admin/src/components/NotificationsContainer/index.js index 83cdb4fd85..48bbe62241 100644 --- a/packages/strapi-admin/admin/src/components/NotificationsContainer/index.js +++ b/packages/strapi-admin/admin/src/components/NotificationsContainer/index.js @@ -11,6 +11,8 @@ import { CSSTransition } from 'react-transition-group'; import Notification from '../Notification'; import Wrapper from './Wrapper'; +/* eslint-disable */ + const NotificationsContainer = ({ notifications, onHideNotification }) => { if (notifications.length === 0) { return false; diff --git a/packages/strapi-admin/admin/src/components/OnboardingVideo/index.js b/packages/strapi-admin/admin/src/components/OnboardingVideo/index.js index 5865ff3770..ddbf89da97 100644 --- a/packages/strapi-admin/admin/src/components/OnboardingVideo/index.js +++ b/packages/strapi-admin/admin/src/components/OnboardingVideo/index.js @@ -13,6 +13,8 @@ import { Player } from 'video-react'; import 'video-react/dist/video-react.css'; import Li from './Li'; +/* eslint-disable */ + class OnboardingVideo extends React.Component { componentDidMount() { this.hiddenPlayer.current.subscribeToStateChange(this.handleChangeState); diff --git a/packages/strapi-admin/admin/src/components/Row/index.js b/packages/strapi-admin/admin/src/components/Row/index.js index aee786026e..4db6d43cde 100644 --- a/packages/strapi-admin/admin/src/components/Row/index.js +++ b/packages/strapi-admin/admin/src/components/Row/index.js @@ -22,6 +22,8 @@ import Content from './Content'; const PLUGINS_WITH_CONFIG = ['email', 'upload']; +/* eslint-disable */ + class Row extends React.Component { static contextType = GlobalContext; state = { showModal: false }; diff --git a/packages/strapi-admin/admin/src/containers/Admin/index.js b/packages/strapi-admin/admin/src/containers/Admin/index.js index 9ca62b6658..c996e9a78c 100644 --- a/packages/strapi-admin/admin/src/containers/Admin/index.js +++ b/packages/strapi-admin/admin/src/containers/Admin/index.js @@ -51,6 +51,14 @@ import Content from './Content'; export class Admin extends React.Component { // eslint-disable-line react/prefer-stateless-function + helpers = { + updatePlugin: this.props.updatePlugin, + }; + + componentDidMount() { + this.props.emitEvent('didAccessAuthenticatedAdministration'); + } + shouldComponentUpdate(prevProps) { return !isEmpty(difference(prevProps, this.props)); } @@ -69,10 +77,6 @@ export class Admin extends React.Component { this.props.setAppError(); } - componentDidMount() { - this.props.emitEvent('didAccessAuthenticatedAdministration'); - } - hasApluginNotReady = props => { const { global: { plugins }, @@ -83,10 +87,6 @@ export class Admin extends React.Component { ); }; - helpers = { - updatePlugin: this.props.updatePlugin, - }; - /** * Display the app loader until the app is ready * @returns {Boolean} @@ -136,10 +136,10 @@ export class Admin extends React.Component { // We need the admin data in order to make the initializers work if (this.showLoader()) { return ( - + <> {this.renderInitializers()} - + ); } @@ -200,6 +200,12 @@ export class Admin extends React.Component { } } +Admin.defaultProps = { + intl: { + formatMessage: () => {}, + }, +}; + Admin.propTypes = { admin: PropTypes.shape({ appError: PropTypes.bool, diff --git a/packages/strapi-admin/admin/src/containers/App/index.js b/packages/strapi-admin/admin/src/containers/App/index.js index b71b31099c..f7d718c78e 100644 --- a/packages/strapi-admin/admin/src/containers/App/index.js +++ b/packages/strapi-admin/admin/src/containers/App/index.js @@ -23,6 +23,7 @@ import GlobalStyle from '../../components/GlobalStyle'; import Admin from '../Admin'; import AuthPage from '../AuthPage'; import NotFoundPage from '../NotFoundPage'; +// eslint-disable-next-line import/no-cycle import NotificationProvider from '../NotificationProvider'; import PrivateRoute from '../PrivateRoute'; import Theme from '../Theme'; diff --git a/packages/strapi-admin/admin/src/containers/AuthPage/Input.js b/packages/strapi-admin/admin/src/containers/AuthPage/Input.js index 01436b1f76..3fb9218024 100644 --- a/packages/strapi-admin/admin/src/containers/AuthPage/Input.js +++ b/packages/strapi-admin/admin/src/containers/AuthPage/Input.js @@ -6,6 +6,8 @@ import { get } from 'lodash'; import { InputsIndex as Inputs } from 'strapi-helper-plugin'; import CustomLabel from './CustomLabel'; +/* eslint-disable */ + const Input = ({ autoFocus, customBootstrapClass, diff --git a/packages/strapi-admin/admin/src/containers/AuthPage/index.js b/packages/strapi-admin/admin/src/containers/AuthPage/index.js index c6cb9dda09..f1d3bb8e37 100644 --- a/packages/strapi-admin/admin/src/containers/AuthPage/index.js +++ b/packages/strapi-admin/admin/src/containers/AuthPage/index.js @@ -1,8 +1,7 @@ import React, { memo, useEffect, useReducer, useRef } from 'react'; import PropTypes from 'prop-types'; -import { get, isEmpty, omit, set } from 'lodash'; +import { get, isEmpty, omit, set, upperFirst } from 'lodash'; import { FormattedMessage } from 'react-intl'; -import { upperFirst } from 'lodash'; import { Link, Redirect } from 'react-router-dom'; import { auth, @@ -267,12 +266,12 @@ AuthPage.propTypes = { hasAdminUser: PropTypes.bool.isRequired, location: PropTypes.shape({ search: PropTypes.string.isRequired, - }), + }).isRequired, match: PropTypes.shape({ params: PropTypes.shape({ authType: PropTypes.string, - }), - }), + }).isRequired, + }).isRequired, }; export default memo(AuthPage); diff --git a/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js b/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js index a0bf993694..35d4e14055 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/SocialLink.js @@ -38,7 +38,7 @@ const SocialLink = ({ link, name }) => { return ( - + social {name} diff --git a/packages/strapi-admin/admin/src/containers/HomePage/components.js b/packages/strapi-admin/admin/src/containers/HomePage/components.js index b7f1c52732..4db546003f 100644 --- a/packages/strapi-admin/admin/src/containers/HomePage/components.js +++ b/packages/strapi-admin/admin/src/containers/HomePage/components.js @@ -1,3 +1,4 @@ +/* eslint-disable */ import styled, { css } from 'styled-components'; const Block = styled.div` diff --git a/packages/strapi-admin/admin/src/containers/LanguageProvider/actions.js b/packages/strapi-admin/admin/src/containers/LanguageProvider/actions.js index 779eed0a12..101d6a17c2 100644 --- a/packages/strapi-admin/admin/src/containers/LanguageProvider/actions.js +++ b/packages/strapi-admin/admin/src/containers/LanguageProvider/actions.js @@ -4,9 +4,9 @@ * */ -import { - CHANGE_LOCALE, -} from './constants'; +/* eslint-disable */ + +import { CHANGE_LOCALE } from './constants'; export function changeLocale(languageLocale) { return { diff --git a/packages/strapi-admin/admin/src/containers/LanguageProvider/constants.js b/packages/strapi-admin/admin/src/containers/LanguageProvider/constants.js index 7d2f42564e..8d2bd0d621 100644 --- a/packages/strapi-admin/admin/src/containers/LanguageProvider/constants.js +++ b/packages/strapi-admin/admin/src/containers/LanguageProvider/constants.js @@ -4,4 +4,5 @@ * */ +/* eslint-disable */ export const CHANGE_LOCALE = 'app/LanguageToggle/CHANGE_LOCALE'; diff --git a/packages/strapi-admin/admin/src/containers/LanguageProvider/index.js b/packages/strapi-admin/admin/src/containers/LanguageProvider/index.js index 7c618ad0fe..371c708328 100644 --- a/packages/strapi-admin/admin/src/containers/LanguageProvider/index.js +++ b/packages/strapi-admin/admin/src/containers/LanguageProvider/index.js @@ -14,12 +14,12 @@ import { IntlProvider } from 'react-intl'; import { defaultsDeep } from 'lodash'; import { selectLocale } from './selectors'; +// eslint-disable-next-line react/prefer-stateless-function export class LanguageProvider extends React.Component { - // eslint-disable-line react/prefer-stateless-function render() { const messages = defaultsDeep( this.props.messages[this.props.locale], - this.props.messages.en, + this.props.messages.en ); return ( ({ locale }), + locale => ({ locale }) ); function mapDispatchToProps(dispatch) { @@ -52,5 +52,5 @@ function mapDispatchToProps(dispatch) { export default connect( mapStateToProps, - mapDispatchToProps, + mapDispatchToProps )(LanguageProvider); diff --git a/packages/strapi-admin/admin/src/containers/LanguageProvider/reducer.js b/packages/strapi-admin/admin/src/containers/LanguageProvider/reducer.js index a4d5415029..a2f71a09d8 100644 --- a/packages/strapi-admin/admin/src/containers/LanguageProvider/reducer.js +++ b/packages/strapi-admin/admin/src/containers/LanguageProvider/reducer.js @@ -9,11 +9,10 @@ import { get, includes, split } from 'lodash'; // Import supported languages from the translations folder import trads from '../../translations'; +import { CHANGE_LOCALE } from './constants'; const languages = Object.keys(trads); -import { CHANGE_LOCALE } from './constants'; - // Define a key to store and get user preferences in local storage. const localStorageKey = 'strapi-admin-language'; @@ -24,6 +23,7 @@ const userLanguage = window.navigator.userLanguage; let foundLanguage = includes(languages, userLanguage) && userLanguage; + if (!foundLanguage) { // Split user language in a correct format. const userLanguageShort = get(split(userLanguage, '-'), '0'); diff --git a/packages/strapi-admin/admin/src/containers/ListPluginsPage/index.js b/packages/strapi-admin/admin/src/containers/ListPluginsPage/index.js index e8df101591..7e809901ad 100644 --- a/packages/strapi-admin/admin/src/containers/ListPluginsPage/index.js +++ b/packages/strapi-admin/admin/src/containers/ListPluginsPage/index.js @@ -86,7 +86,7 @@ export class ListPluginsPage extends React.Component { ListPluginsPage.propTypes = { global: PropTypes.shape({ currentEnvironment: PropTypes.string.isRequired, - }), + }).isRequired, getPlugins: PropTypes.func.isRequired, history: PropTypes.object.isRequired, intl: PropTypes.shape({ diff --git a/packages/strapi-admin/admin/src/containers/ListPluginsPage/saga.js b/packages/strapi-admin/admin/src/containers/ListPluginsPage/saga.js index f3c68a755b..bb189ebc2c 100644 --- a/packages/strapi-admin/admin/src/containers/ListPluginsPage/saga.js +++ b/packages/strapi-admin/admin/src/containers/ListPluginsPage/saga.js @@ -7,6 +7,8 @@ import { deletePluginSucceeded, getPluginsSucceeded } from './actions'; import { GET_PLUGINS, ON_DELETE_PLUGIN_CONFIRM } from './constants'; import { makeSelectPluginToDelete } from './selectors'; +/* eslint-disable */ + export function* deletePlugin() { try { const plugin = yield select(makeSelectPluginToDelete()); diff --git a/packages/strapi-admin/admin/src/containers/LocaleToggle/actions.js b/packages/strapi-admin/admin/src/containers/LocaleToggle/actions.js index ee29597f01..18a19ab581 100644 --- a/packages/strapi-admin/admin/src/containers/LocaleToggle/actions.js +++ b/packages/strapi-admin/admin/src/containers/LocaleToggle/actions.js @@ -1,12 +1,9 @@ /** - * + * * LocaleToggle actions */ -import { - RESET_DEFAULT_CLASSNAME, - SET_CUSTOM_CLASSNAME, -} from './constants'; +import { RESET_DEFAULT_CLASSNAME, SET_CUSTOM_CLASSNAME } from './constants'; export function resetLocaleDefaultClassName() { return { diff --git a/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/index.test.js b/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/index.test.js index 646dc47981..4f5664bcc5 100644 --- a/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/index.test.js +++ b/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/index.test.js @@ -89,7 +89,7 @@ describe('', () => { 'https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/flags/4x3/vn.svg' ); }); - + it('should return the sk flag', () => { const renderedComponent = shallow(); const { getFlagUrl } = renderedComponent.instance(); diff --git a/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/selectors.test.js b/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/selectors.test.js index 171b32af32..1472f967b0 100644 --- a/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/selectors.test.js +++ b/packages/strapi-admin/admin/src/containers/LocaleToggle/tests/selectors.test.js @@ -11,7 +11,7 @@ describe(' selectors', () => { const mockedState = fromJS({ localeToggle: state, }); - + expect(selectLocaleToggle()(mockedState)).toEqual(state); }); }); @@ -29,5 +29,3 @@ describe(' selectors', () => { }); }); }); - - diff --git a/packages/strapi-admin/admin/src/containers/Marketplace/index.js b/packages/strapi-admin/admin/src/containers/Marketplace/index.js index 426df44df9..4b5bf4632b 100644 --- a/packages/strapi-admin/admin/src/containers/Marketplace/index.js +++ b/packages/strapi-admin/admin/src/containers/Marketplace/index.js @@ -118,7 +118,7 @@ Marketplace.propTypes = { global: PropTypes.shape({ autoReload: PropTypes.bool.isRequired, currentEnvironment: PropTypes.string.isRequired, - }), + }).isRequired, history: PropTypes.object.isRequired, installedPlugins: PropTypes.array.isRequired, intl: PropTypes.shape({ diff --git a/packages/strapi-admin/admin/src/containers/NotificationProvider/actions.js b/packages/strapi-admin/admin/src/containers/NotificationProvider/actions.js index f831c03159..88bcced5e4 100644 --- a/packages/strapi-admin/admin/src/containers/NotificationProvider/actions.js +++ b/packages/strapi-admin/admin/src/containers/NotificationProvider/actions.js @@ -4,6 +4,7 @@ * */ +/* eslint-disable import/no-cycle */ import { dispatch } from '../../app'; import { SHOW_NOTIFICATION, HIDE_NOTIFICATION } from './constants'; diff --git a/packages/strapi-admin/admin/src/containers/NotificationProvider/index.js b/packages/strapi-admin/admin/src/containers/NotificationProvider/index.js index 38d243f67d..42e391a4f4 100644 --- a/packages/strapi-admin/admin/src/containers/NotificationProvider/index.js +++ b/packages/strapi-admin/admin/src/containers/NotificationProvider/index.js @@ -4,16 +4,16 @@ * */ +/* eslint-disable */ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; - import NotificationsContainer from '../../components/NotificationsContainer'; import { selectNotifications } from './selectors'; import { hideNotification } from './actions'; -export class NotificationProvider extends React.Component { // eslint-disable-line react/prefer-stateless-function +export class NotificationProvider extends React.Component { render() { return ( { + onHideNotification: id => { dispatch(hideNotification(id)); }, dispatch, }; } -export default connect(mapStateToProps, mapDispatchToProps)(NotificationProvider); +export default connect( + mapStateToProps, + mapDispatchToProps +)(NotificationProvider); diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/Wrapper.js b/packages/strapi-admin/admin/src/containers/Onboarding/Wrapper.js index e5577ed905..61febdc32b 100644 --- a/packages/strapi-admin/admin/src/containers/Onboarding/Wrapper.js +++ b/packages/strapi-admin/admin/src/containers/Onboarding/Wrapper.js @@ -1,5 +1,36 @@ import styled, { keyframes } from 'styled-components'; +const fadeIn = keyframes` +0% { + width: auto; + height: auto; + opacity: 0; +} + +5% { + opacity: 0; +} + +100% { + opacity: 1; +} +`; +const fadeOut = keyframes` +0% { + opacity: 1; +} + +60% { + opacity: 0; +} + +100% { + opacity: 0; + width: 0; + height: 0; +} +`; + const Wrapper = styled.div` position: fixed; right: 15px; @@ -93,35 +124,4 @@ const Wrapper = styled.div` } `; -const fadeIn = keyframes` -0% { - width: auto; - height: auto; - opacity: 0; -} - -5% { - opacity: 0; -} - -100% { - opacity: 1; -} -`; -const fadeOut = keyframes` -0% { - opacity: 1; -} - -60% { - opacity: 0; -} - -100% { - opacity: 0; - width: 0; - height: 0; -} -`; - export default Wrapper; diff --git a/packages/strapi-admin/admin/src/containers/Onboarding/index.js b/packages/strapi-admin/admin/src/containers/Onboarding/index.js index 29bfac719a..efd37b3d6e 100644 --- a/packages/strapi-admin/admin/src/containers/Onboarding/index.js +++ b/packages/strapi-admin/admin/src/containers/Onboarding/index.js @@ -27,9 +27,9 @@ import makeSelectOnboarding from './selectors'; import reducer from './reducer'; import saga from './saga'; -export class Onboarding extends React.Component { - static contextType = GlobalContext; +/* eslint-disable react/no-array-index-key */ +export class Onboarding extends React.Component { state = { showVideos: false }; componentDidMount() { @@ -92,6 +92,8 @@ export class Onboarding extends React.Component { this.props.setVideoEnd(index, true); }; + static contextType = GlobalContext; + render() { const { videos, onClick, setVideoDuration } = this.props; const { showVideos } = this.state; @@ -144,6 +146,7 @@ export class Onboarding extends React.Component { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/Button.js b/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/Button.js index 31f0d246c8..99cc45639a 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/Button.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/Button.js @@ -22,6 +22,8 @@ const Button = styled(PlusButton)` } `; } + + return ''; }} &.isOpen { transform: rotate(-45deg); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/index.js b/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/index.js index f0577783f5..dbc6b332cb 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/DynamicZone/index.js @@ -17,6 +17,8 @@ import Label from './Label'; import RoundCTA from './RoundCTA'; import Wrapper from './Wrapper'; +/* eslint-disable react/no-array-index-key */ + const DynamicZone = ({ max, min, name }) => { const [isOpen, setIsOpen] = useState(false); const { @@ -117,7 +119,7 @@ const DynamicZone = ({ max, min, name }) => { removeComponentFromDynamicZone(name, index)} > - + { icon={getDynamicComponentInfos(componentUid).icon} label="" name={`${name}.${index}`} - isFromDynamicZone={true} + isFromDynamicZone /> ); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/Wrapper.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/Wrapper.js index b704c8d273..afd492cb3b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/Wrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/Wrapper.js @@ -12,6 +12,8 @@ const Wrapper = styled.div` background-color: #fff; `; } + + return ''; }} `; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/index.js index 05348f8b10..1dbc61c02a 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldComponent/index.js @@ -1,3 +1,4 @@ +/* eslint-disable import/no-cycle */ import React from 'react'; import PropTypes from 'prop-types'; import { get, size } from 'lodash'; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js index 65e680b511..5e31a446a6 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/Item.js @@ -85,8 +85,6 @@ const Item = ({ item.rowIndex = targetRow; item.itemIndex = hoverIndex; - - return; }, drop(item, monitor) { if (!dropRef.current) { @@ -122,6 +120,7 @@ const Item = ({ item.itemIndex = hoverIndex + 1; item.rowIndex = targetRow; + return; } @@ -136,8 +135,6 @@ const Item = ({ item.itemIndex = hoverIndex; item.rowIndex = targetRow; - - return; }, collect: monitor => ({ canDrop: monitor.canDrop(), diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js index e93b2455b4..fa31ed3831 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/components.js @@ -5,4 +5,4 @@ const Wrapper = styled.div` margin-bottom: 6px; `; -export { Wrapper }; +export default Wrapper; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js index 07877c02d7..f64f860b4b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FieldsReorder/index.js @@ -6,7 +6,7 @@ import useLayoutDnd from '../../hooks/useLayoutDnd'; import Add from '../AddDropdown'; import SortWrapper from '../SortWrapper'; -import { Wrapper } from './components'; +import Wrapper from './components'; import Item from './Item'; const FieldsReorder = ({ className }) => { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/components.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/components.js index 5194551269..e18cea32a5 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/components.js @@ -48,6 +48,8 @@ const Div = styled.div` ? 'margin-top .3s ease-out, margin-bottom .2s ease-out' : 'margin .3s ease-in'; } + + return ''; }}; `; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js index a4b62625bb..4ddf256bcc 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPicker/index.js @@ -153,6 +153,7 @@ function FilterPicker({ }} type={get(schema, ['attributes', filter.name, 'type'], '')} showAddButton={key === modifiedData.length - 1} + // eslint-disable-next-line react/no-array-index-key key={key} /> ))} @@ -180,8 +181,7 @@ FilterPicker.propTypes = { isOpen: PropTypes.bool, location: PropTypes.shape({ search: PropTypes.string.isRequired, - }), - + }).isRequired, name: PropTypes.string, onSubmit: PropTypes.func.isRequired, toggleFilterPickerState: PropTypes.func.isRequired, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js index ea87f470f5..4459ef0506 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/Input.js @@ -48,7 +48,7 @@ function Input({ type, ...rest }) { const styles = type === 'boolean' ? { minWidth: '100px', maxWidth: '200px' } : style; const wrapperStyle = - type == 'boolean' || + type === 'boolean' || ['date', 'timestamp', 'time', 'datetime'].includes(type) ? { marginRight: '20px' } : { marginRight: '10px' }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js index 905d5e2ced..59bc700c2b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FilterPickerOption/components.js @@ -1,5 +1,7 @@ import styled, { css } from 'styled-components'; +/* eslint-disable */ + const Wrapper = styled.div` min-height: 38px; border-left: ${props => props.borderLeft && '3px solid #007EFF'}; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/FormTitle/index.js b/packages/strapi-plugin-content-manager/admin/src/components/FormTitle/index.js index 8766be9c9d..b1f46b72a0 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/FormTitle/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/FormTitle/index.js @@ -3,14 +3,14 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; const FormTitle = ({ description, title }) => ( - + <> {!!title && } {!!description && ( {msg =>

{msg}

}
)} -
+ ); FormTitle.propTypes = { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/InputCheckbox/components.js b/packages/strapi-plugin-content-manager/admin/src/components/InputCheckbox/components.js index efdfcd443b..fe1169a3db 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/InputCheckbox/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/InputCheckbox/components.js @@ -58,6 +58,8 @@ const Label = styled.label` } `; } + + return ''; }} `; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/InputJSON/index.js b/packages/strapi-plugin-content-manager/admin/src/components/InputJSON/index.js index 4d145f538a..150fe02fd3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/InputJSON/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/InputJSON/index.js @@ -24,6 +24,8 @@ const stringify = JSON.stringify; const DEFAULT_THEME = '3024-night'; class InputJSON extends React.Component { + timer = null; + constructor(props) { super(props); this.editor = React.createRef(); @@ -88,7 +90,7 @@ class InputJSON extends React.Component { let content = this.getContentAtLine(line); if (content === '{') { - line = line + 1; + line += 1; content = this.getContentAtLine(line); } const chEnd = content.length; @@ -101,8 +103,6 @@ class InputJSON extends React.Component { this.setState({ markedText }); }; - timer = null; - handleBlur = ({ target }) => { const { name, onBlur } = this.props; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/InputJSONWithErrors/index.js b/packages/strapi-plugin-content-manager/admin/src/components/InputJSONWithErrors/index.js index 0880795c66..2cec1deac7 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/InputJSONWithErrors/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/InputJSONWithErrors/index.js @@ -17,7 +17,6 @@ import Wrapper from './Wrapper'; class InputJSONWithErrors extends React.Component { handleChange = e => { - this.setState({ errors: [] }); this.props.onChange(e); }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/NonRepeatableComponent/index.js b/packages/strapi-plugin-content-manager/admin/src/components/NonRepeatableComponent/index.js index 9a3f5b5c23..56a3a9cb1b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/NonRepeatableComponent/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/NonRepeatableComponent/index.js @@ -1,3 +1,6 @@ +/* eslint-disable react/no-array-index-key */ +/* eslint-disable import/no-cycle */ + import React from 'react'; import PropTypes from 'prop-types'; import { get } from 'lodash'; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/PreviewCarret/components.js b/packages/strapi-plugin-content-manager/admin/src/components/PreviewCarret/components.js index d824bb237a..a6f0972f72 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/PreviewCarret/components.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/PreviewCarret/components.js @@ -14,6 +14,8 @@ const Wrapper = styled.div` padding: 0; `; } + + return ''; }} border-radius: 2px; > div { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/AddFieldButton.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/AddFieldButton.js index 15052ead19..4479a77301 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/AddFieldButton.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/AddFieldButton.js @@ -21,6 +21,8 @@ const Button = styled.button` border-radius: 2px; `; } + + return ''; }} ${({ hasMinError }) => { @@ -30,6 +32,8 @@ const Button = styled.button` border-top-color: rgba(227, 233, 243, 0.75); `; } + + return ''; }} color: #007eff; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/Banner.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/Banner.js index 53f41251e3..29ca56ff07 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/Banner.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/Banner.js @@ -8,6 +8,8 @@ import PreviewCarret from '../PreviewCarret'; import BannerWrapper from './BannerWrapper'; import CarretTop from './CarretTop'; +/* eslint-disable jsx-a11y/no-static-element-interactions */ + const Banner = forwardRef( ( { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/BannerWrapper.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/BannerWrapper.js index 0a703baebd..52e173fd52 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/BannerWrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/BannerWrapper.js @@ -1,5 +1,7 @@ import styled from 'styled-components'; +/* eslint-disable */ + const BannerWrapper = styled.button` display: flex; height: 36px; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/DraggedItem.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/DraggedItem.js index 8831082a9f..7aff47dce6 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/DraggedItem.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/DraggedItem.js @@ -1,3 +1,4 @@ +/* eslint-disable import/no-cycle */ import React, { useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { get } from 'lodash'; @@ -12,6 +13,8 @@ import FieldComponent from '../FieldComponent'; import Banner from './Banner'; import FormWrapper from './FormWrapper'; +/* eslint-disable react/no-array-index-key */ + // Issues: // https://github.com/react-dnd/react-dnd/issues/1368 // https://github.com/frontend-collective/react-sortable-tree/issues/490 @@ -109,8 +112,6 @@ const DraggedItem = ({ // but it's good here for the sake of performance // to avoid expensive index searches. item.originalPath = hoverPath; - - return; }, }); const [{ isDragging }, drag, preview] = useDrag({ diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/EmptyComponent.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/EmptyComponent.js index e57e676d6f..01ced822ac 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/EmptyComponent.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/EmptyComponent.js @@ -12,8 +12,10 @@ const EmptyComponent = styled.div` ${({ hasMinError }) => { if (hasMinError) { - return `border-color: #FAA684`; + return 'border-color: #FAA684'; } + + return ''; }} > p { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/FormWrapper.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/FormWrapper.js index e31e2409e3..f2209d4527 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/FormWrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/FormWrapper.js @@ -1,5 +1,7 @@ import styled from 'styled-components'; +/* eslint-disable indent */ + const FormWrapper = styled.div` padding-top: 24px; padding-left: 20px; @@ -9,11 +11,10 @@ const FormWrapper = styled.div` ${({ hasErrors, isOpen }) => { if (hasErrors) { return '#ffa784'; - } else if (isOpen) { + } if (isOpen) { return '#AED4FB'; - } else { - return 'rgba(227, 233, 243, 0.75)'; } + return 'rgba(227, 233, 243, 0.75)'; }}; `; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/index.js b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/index.js index 2c12b8d5eb..7a23c813e8 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/RepeatableComponent/index.js @@ -1,3 +1,4 @@ +/* eslint-disable import/no-cycle */ import React, { useReducer } from 'react'; import { useDrop } from 'react-dnd'; import PropTypes from 'prop-types'; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js index 0a958ff2c5..4ec43d9a70 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js @@ -12,11 +12,14 @@ import Cross from '../../icons/Cross'; import Filter from '../../icons/Filter'; import SearchIcon from '../../icons/Search'; import { Wrapper, Infos, Clear } from './components'; + const WAIT = 400; class Search extends React.Component { state = { value: this.props.initValue }; + timer = null; + componentDidUpdate(prevProps) { const { model, value } = this.props; @@ -28,8 +31,6 @@ class Search extends React.Component { } } - timer = null; - resetState = () => this.setState({ value: '' }); handleChange = ({ target }) => { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/Relation.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/Relation.js index 58187e2260..88e0aee724 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/Relation.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectMany/Relation.js @@ -7,6 +7,8 @@ import { FormattedMessage } from 'react-intl'; import pluginId from '../../pluginId'; import IconRemove from '../../assets/images/icon_remove.svg'; +/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ + const Relation = ({ data, mainField, onRemove, to }) => { return ( <> diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js index bb23afb7a5..b09792a490 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js @@ -59,7 +59,7 @@ function SelectWrapper({ const data = await request(requestUrl, { method: 'GET', - params: params, + params, signal, }); @@ -220,7 +220,6 @@ SelectWrapper.defaultProps = { editable: true, description: '', label: '', - plugin: '', placeholder: '', }; @@ -231,7 +230,6 @@ SelectWrapper.propTypes = { mainField: PropTypes.string.isRequired, name: PropTypes.string.isRequired, placeholder: PropTypes.string, - plugin: PropTypes.string, relationType: PropTypes.string.isRequired, targetModel: PropTypes.string.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SettingsViewWrapper/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SettingsViewWrapper/index.js index cbe708a49f..e1ecfabb3c 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SettingsViewWrapper/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SettingsViewWrapper/index.js @@ -51,7 +51,7 @@ const SettingsViewWrapper = ({ id: `${pluginId}.popUpWarning.button.cancel`, }), type: 'button', - disabled: isEqual(modifiedData, initialData) ? true : false, + disabled: isEqual(modifiedData, initialData), style: { fontWeight: 600, paddingLeft: 15, @@ -64,7 +64,7 @@ const SettingsViewWrapper = ({ id: `${pluginId}.containers.Edit.submit`, }), type: 'submit', - disabled: isEqual(modifiedData, initialData) ? true : false, + disabled: isEqual(modifiedData, initialData), style: { minWidth: 150, fontWeight: 600, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/EditorWrapper.js b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/EditorWrapper.js index e284a97028..949b8ba9b8 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/EditorWrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/EditorWrapper.js @@ -1,5 +1,5 @@ import styled, { css } from 'styled-components'; - +/* eslint-disable */ const EditorWrapper = styled.div` ${({ isFullscreen }) => { if (isFullscreen) { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/PreviewWysiwygWrapper.js b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/PreviewWysiwygWrapper.js index 0da1afcb66..3745f9bd65 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/PreviewWysiwygWrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/PreviewWysiwygWrapper.js @@ -1,5 +1,7 @@ import styled, { css } from 'styled-components'; +/* eslint-disable */ + const PreviewWysiwygWrapper = styled.div` max-height: 555px; min-height: 294px; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/SelectWrapper.js b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/SelectWrapper.js index 84d6dd02fc..88fb07b88c 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/SelectWrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/SelectWrapper.js @@ -1,5 +1,7 @@ import styled, { css } from 'styled-components'; +/* eslint-disable */ + const SelectWrapper = styled.div` min-width: ${({ isFullScreen }) => (isFullScreen ? '161px' : '115px')} margin-left: 15px; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/index.js index 33c866278a..08f80eefb8 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/index.js @@ -47,6 +47,8 @@ import EditorWrapper from './EditorWrapper'; /* eslint-disable react/jsx-handler-names */ /* eslint-disable react/sort-comp */ +/* eslint-disable */ + class Wysiwyg extends React.Component { constructor(props) { super(props); diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/previewWysiwyg.js b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/previewWysiwyg.js index e3edcb35b5..01ce483900 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/previewWysiwyg.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/previewWysiwyg.js @@ -33,6 +33,9 @@ import Link from './link'; import Video from './video'; /* eslint-disable react/no-unused-state */ +/* eslint-disable no-new */ +/* eslint-disable consistent-return */ +/* eslint-disable react/sort-comp */ function getBlockStyle(block) { switch (block.getType()) { case 'blockquote': diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/video.js b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/video.js index 5e31bedd97..c00d153eae 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/video.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Wysiwyg/video.js @@ -7,6 +7,8 @@ import React from 'react'; import PropTypes from 'prop-types'; +/* eslint-disable jsx-a11y/media-has-caption */ + const Video = props => { const { height, src, width } = props.contentState .getEntity(props.entityKey) diff --git a/packages/strapi-plugin-content-manager/admin/src/components/WysiwygBottomControls/index.js b/packages/strapi-plugin-content-manager/admin/src/components/WysiwygBottomControls/index.js index 018924b7a6..26add895b5 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/WysiwygBottomControls/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/WysiwygBottomControls/index.js @@ -9,6 +9,10 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import { Span, Wrapper } from './components'; +/* eslint-disable jsx-a11y/label-has-associated-control */ +/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ + const WysiwygBottomControls = ({ isPreviewMode, onChange, onClick }) => { const browse = ( diff --git a/packages/strapi-plugin-content-manager/admin/src/components/WysiwygInlineControls/StyledButton.js b/packages/strapi-plugin-content-manager/admin/src/components/WysiwygInlineControls/StyledButton.js index ca4ce1eb6f..3ec2beeb2f 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/WysiwygInlineControls/StyledButton.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/WysiwygInlineControls/StyledButton.js @@ -36,6 +36,8 @@ const Button = styled.button` cursor: not-allowed; `; } + + return ''; }} > svg { diff --git a/packages/strapi-plugin-content-manager/admin/src/components/WysiwygWithErrors/index.js b/packages/strapi-plugin-content-manager/admin/src/components/WysiwygWithErrors/index.js index 84fa2aa9a9..d4d806e901 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/WysiwygWithErrors/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/WysiwygWithErrors/index.js @@ -15,6 +15,7 @@ import { Error } from '@buffetjs/core'; import Wysiwyg from '../Wysiwyg'; import Wrapper from './Wrapper'; +// eslint-disable-next-line react/prefer-stateless-function class WysiwygWithErrors extends React.Component { render() { const { @@ -114,6 +115,7 @@ WysiwygWithErrors.defaultProps = { style: {}, tabIndex: '0', validations: {}, + value: null, }; WysiwygWithErrors.propTypes = { diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/index.js index a4490869b9..e903b8525d 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/index.js @@ -463,16 +463,13 @@ const EditSettingsView = ({ }; EditSettingsView.defaultProps = { - deleteAllLayouts: () => {}, slug: null, }; EditSettingsView.propTypes = { - components: PropTypes.array.isRequired, - models: PropTypes.array.isRequired, - currentEnvironment: PropTypes.string, + currentEnvironment: PropTypes.string.isRequired, deleteLayout: PropTypes.func.isRequired, - deleteLayouts: PropTypes.func, + deleteLayouts: PropTypes.func.isRequired, componentsAndModelsMainPossibleMainFields: PropTypes.object.isRequired, history: PropTypes.shape({ push: PropTypes.func, @@ -480,7 +477,7 @@ EditSettingsView.propTypes = { location: PropTypes.shape({ search: PropTypes.string.isRequired, }).isRequired, - plugins: PropTypes.object, + plugins: PropTypes.object.isRequired, slug: PropTypes.string, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/reducer.js index 668a843206..8a1e74ba9f 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditSettingsView/reducer.js @@ -104,7 +104,7 @@ const reducer = (state, action) => { // Delete the entire row if length is one or if lenght is equal to 2 and the second element is the hidden div used to make the dnd exp smoother if ( row.size === 1 || - (row.size == 2 && row.getIn([1, 'name']) === '_TEMP_') + (row.size === 2 && row.getIn([1, 'name']) === '_TEMP_') ) { newState = state.updateIn(layoutPathEdit, list => list.delete(action.rowIndex) diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header.js index 381df5bbc2..d2e16d2b67 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header.js @@ -37,12 +37,14 @@ const Header = () => { ); const isCreatingEntry = id === 'create'; + /* eslint-disable indent */ const headerTitle = isCreatingEntry ? formatMessage({ id: `${pluginId}.containers.Edit.pluginHeader.title.new`, }) : templateObject({ mainField: currentContentTypeMainField }, initialData) .mainField; + /* eslint-enable indent */ const getHeaderActions = () => { const headerActions = [ diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js index 70b61600de..f43e27e95b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js @@ -26,6 +26,8 @@ import { LinkWrapper, SubWrapper } from './components'; import init from './init'; import reducer, { initialState } from './reducer'; +/* eslint-disable react/no-array-index-key */ + const EditView = ({ components, currentEnvironment, @@ -274,7 +276,7 @@ const EditView = ({ }} icon="layout" key={`${pluginId}.link`} - url={`ctm-configurations/edit-settings/content-types`} + url="ctm-configurations/edit-settings/content-types" onClick={() => { // emitEvent('willEditContentTypeLayoutFromEditView'); }} diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/createAttributesLayout.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/createAttributesLayout.js index 8dab03f62e..e9349598e4 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/createAttributesLayout.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/createAttributesLayout.js @@ -1,5 +1,7 @@ import { get, isEmpty } from 'lodash'; +/* eslint-disable no-restricted-syntax */ + const createAttributesLayout = (currentLayout, attributes) => { const getType = name => get(attributes, [name, 'type'], ''); let currentRowIndex = 0; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/formatData.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/formatData.js index f6904897d8..7bf5aafbec 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/formatData.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/utils/formatData.js @@ -1,5 +1,7 @@ import { get, isArray, isEmpty, isObject } from 'lodash'; +/* eslint-disable indent */ + export const cleanData = (retrievedData, ctLayout, groupLayouts) => { const getType = (schema, attrName) => get(schema, ['attributes', attrName, 'type'], ''); @@ -112,11 +114,10 @@ export const getMediaAttributes = (ctLayout, groupLayouts) => { export const helperCleanData = (value, key) => { if (isArray(value)) { return value.map(obj => (obj[key] ? obj[key] : obj)); - } else if (isObject(value)) { + } if (isObject(value)) { return value[key]; - } else { - return value; } + return value; }; export const mapDataKeysToFilesToUpload = (filesMap, data) => { diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/cleanData.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/cleanData.js index 922ea6c740..7895d4ab07 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/cleanData.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/cleanData.js @@ -1,5 +1,7 @@ import { get, isArray, isObject } from 'lodash'; +/* eslint-disable indent */ + const cleanData = (retrievedData, currentSchema, componentsSchema) => { const getType = (schema, attrName) => get(schema, ['attributes', attrName, 'type'], ''); @@ -90,11 +92,10 @@ const cleanData = (retrievedData, currentSchema, componentsSchema) => { export const helperCleanData = (value, key) => { if (isArray(value)) { return value.map(obj => (obj[key] ? obj[key] : obj)); - } else if (isObject(value)) { + } if (isObject(value)) { return value[key]; - } else { - return value; } + return value; }; export default cleanData; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/createDefaultForm.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/createDefaultForm.js index 10cc0303e4..317bcc8ffc 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/createDefaultForm.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/createDefaultForm.js @@ -42,7 +42,7 @@ const createDefaultForm = (attributes, allComponentsSchema) => { if (min && repeatable === true && required) { acc[current] = []; - for (let i = 0; i < min; i++) { + for (let i = 0; i < min; i += 1) { acc[current].push(currentComponentDefaultForm); } } diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js index 42e5c5bb2a..51d939d45c 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js @@ -119,23 +119,22 @@ const createYupSchema = (model, { components }) => { acc[current] = componentSchema; return acc; - } else { - const componentSchema = yup.lazy(obj => { - if (obj !== undefined) { - return attribute.required === true + } + const componentSchema = yup.lazy(obj => { + if (obj !== undefined) { + return attribute.required === true ? componentFieldSchema.defined() : componentFieldSchema.nullable(); - } + } - return attribute.required === true + return attribute.required === true ? yup.object().defined() : yup.object().nullable(); - }); + }); - acc[current] = componentSchema; + acc[current] = componentSchema; - return acc; - } + return acc; } if (attribute.type === 'dynamiczone') { @@ -156,6 +155,7 @@ const createYupSchema = (model, { components }) => { .required(errorsTrads.required); } } else { + // eslint-disable-next-line no-lonely-if if (min) { dynamicZoneSchema = dynamicZoneSchema.notEmptyMin(min); } diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/LayoutDndProvider/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/LayoutDndProvider/index.js index 2eaf8c435b..9c80e9af3e 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/LayoutDndProvider/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/LayoutDndProvider/index.js @@ -46,7 +46,6 @@ LayoutDndProvider.defaultProps = { buttonData: [], goTo: () => {}, layout: [], - isDraggingSibling: true, metadatas: {}, moveItem: () => {}, moveRow: () => {}, @@ -55,7 +54,6 @@ LayoutDndProvider.defaultProps = { removeField: () => {}, selectedItemName: null, setEditFieldToSelect: () => {}, - setIsDraggingSibling: () => {}, }; LayoutDndProvider.propTypes = { diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/Label.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/Label.js index 3cf61a32bf..06f30d1568 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/Label.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/Label.js @@ -73,7 +73,6 @@ const Label = ({ Label.defaultProps = { index: 0, label: '', - move: () => {}, selectedItem: '', }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/index.js index 64e4b792be..e072107766 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/index.js @@ -334,7 +334,6 @@ ListSettingsView.propTypes = { location: PropTypes.shape({ search: PropTypes.string.isRequired, }).isRequired, - models: PropTypes.array.isRequired, slug: PropTypes.string.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js index e773b3529e..93b04594e3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js @@ -40,6 +40,8 @@ import reducer from './reducer'; import saga from './saga'; import makeSelectListView from './selectors'; +/* eslint-disable react/no-array-index-key */ + function ListView({ count, data, @@ -419,12 +421,12 @@ ListView.propTypes = { location: PropTypes.shape({ pathname: PropTypes.string.isRequired, search: PropTypes.string.isRequired, - }), + }).isRequired, models: PropTypes.array.isRequired, getData: PropTypes.func.isRequired, history: PropTypes.shape({ push: PropTypes.func.isRequired, - }), + }).isRequired, onChangeBulk: PropTypes.func.isRequired, onChangeBulkSelectall: PropTypes.func.isRequired, onChangeListLabels: PropTypes.func.isRequired, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js index 1532a9f467..47a551a8fd 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js @@ -12,10 +12,6 @@ import { DndProvider } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; import pluginId from '../../pluginId'; import DragLayer from '../../components/DragLayer'; - -const EditSettingsView = lazy(() => import('../EditSettingsView')); -const RecursivePath = lazy(() => import('../RecursivePath')); - import { deleteLayout, deleteLayouts, @@ -27,6 +23,9 @@ import reducer from './reducer'; import saga from './saga'; import makeSelectMain from './selectors'; +const EditSettingsView = lazy(() => import('../EditSettingsView')); +const RecursivePath = lazy(() => import('../RecursivePath')); + function Main({ deleteLayout, deleteLayouts, @@ -122,15 +121,15 @@ Main.propTypes = { global: PropTypes.shape({ currentEnvironment: PropTypes.string.isRequired, plugins: PropTypes.object, - }), + }).isRequired, components: PropTypes.array.isRequired, componentsAndModelsMainPossibleMainFields: PropTypes.object.isRequired, - isLoading: PropTypes.bool, + isLoading: PropTypes.bool.isRequired, layouts: PropTypes.object.isRequired, location: PropTypes.shape({ pathname: PropTypes.string.isRequired, search: PropTypes.string, - }), + }).isRequired, models: PropTypes.array.isRequired, resetProps: PropTypes.func.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/RecursivePath/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/RecursivePath/index.js index 001b41a9f3..deea85b569 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/RecursivePath/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/RecursivePath/index.js @@ -1,6 +1,7 @@ import React, { Suspense, lazy } from 'react'; import { Switch, Route, useRouteMatch, useParams } from 'react-router-dom'; import { LoadingIndicatorPage } from 'strapi-helper-plugin'; + const EditView = lazy(() => import('../EditView')); const EditSettingsView = lazy(() => import('../EditSettingsView')); const ListView = lazy(() => import('../ListView')); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js index 95a7155838..a338688a42 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js @@ -64,7 +64,7 @@ function EditViewButton(props) { outline: 0, fontWeight: 600, }} - > + /> ); } diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js index eb03bbf4a7..ec024988b3 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js @@ -25,7 +25,7 @@ const BooleanBox = ({ label, name, onChange, options, value }) => { onChange={onChange} type="radio" value={option.value} - > + /> ); })} {options.map(option => { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentCard/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentCard/index.js index 6b18e5bd1f..3377fb2d99 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentCard/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentCard/index.js @@ -13,6 +13,8 @@ import useDataManager from '../../hooks/useDataManager'; import Wrapper from './Wrapper'; import Close from './Close'; +/* eslint-disable jsx-a11y/no-static-element-interactions */ + function ComponentCard({ component, dzName, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Cell.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Cell.js index 576ed90108..5c01ef2e1e 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Cell.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Cell.js @@ -25,6 +25,8 @@ const Cell = styled.div` } `; } + + return ''; }} > svg { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Wrapper.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Wrapper.js index 5f3d74b10f..35893c77ff 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Wrapper.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/Wrapper.js @@ -2,6 +2,8 @@ import styled from 'styled-components'; import { colors } from '@buffetjs/styles'; import PropTypes from 'prop-types'; +/* eslint-disable indent */ + const Wrapper = styled.div` min-height: 199px; margin-top: -2px; @@ -16,6 +18,8 @@ const Wrapper = styled.div` border-radius: 2px; `; } + + return ''; }} &:focus, diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/index.js index 0bf265042a..1291434043 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ComponentIconPicker/index.js @@ -9,6 +9,8 @@ import Search from './Search'; import SearchWrapper from './SearchWrapper'; import Wrapper from './Wrapper'; +/* eslint-disable jsx-a11y/control-has-associated-label */ + const ComponentIconPicker = ({ error, isCreating, @@ -78,7 +80,7 @@ const ComponentIconPicker = ({ ) : ( - +