diff --git a/packages/strapi-plugin-content-manager/admin/src/components/DragLayer/index.js b/packages/strapi-plugin-content-manager/admin/src/components/DragLayer/index.js index 32f4effda2..305c8ed9e6 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/DragLayer/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/DragLayer/index.js @@ -68,6 +68,7 @@ const CustomDragLayer = () => {
  • { if (action.value && action.value._isAMomentObject === true) { - return moment(action.value, 'YYYY-MM-DD HH:mm:ss').format(); + return action.value.toISOString(); } return action.value; 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 fba48296e3..5ea71aced0 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 @@ -382,7 +382,7 @@ function ListView({ - {filters.map(({ filter: filterName, name }, key) => ( + {filters.map(({ filter: filterName, name, value }, key) => ( ))} diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js index da4294ee11..68f0c88c58 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js @@ -2,6 +2,53 @@ import { cloneDeep, get, set } from 'lodash'; import { mergeMetasWithSchema } from '../../../utils'; import pluginId from '../../../pluginId'; +// editRelations is an array of strings... +const formatEditRelationsLayoutWithMetas = (obj, models) => { + const formatted = obj.layouts.editRelations.reduce((acc, current) => { + const fieldSchema = get(obj, ['attributes', current], {}); + const metadatas = get(obj, ['metadatas', current, 'edit'], {}); + const size = 6; + + const queryInfos = generateRelationQueryInfos(obj, current, models); + + acc.push({ + name: current, + size, + fieldSchema, + metadatas, + queryInfos, + }); + + return acc; + }, []); + + return formatted; +}; + +const formatLayouts = (initialData, models) => { + const data = mergeMetasWithSchema(cloneDeep(initialData), models, 'contentType'); + const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, null, models); + const ctUid = data.contentType.uid; + const formattedEditRelationsLayout = formatEditRelationsLayoutWithMetas(data.contentType, models); + const formattedListLayout = formatListLayoutWithMetas(data.contentType); + + set(data, ['contentType', 'layouts', 'edit'], formattedCTEditLayout); + set(data, ['contentType', 'layouts', 'editRelations'], formattedEditRelationsLayout); + set(data, ['contentType', 'layouts', 'list'], formattedListLayout); + + Object.keys(data.components).forEach(compoUID => { + const formattedCompoEditLayout = formatLayoutWithMetas( + data.components[compoUID], + ctUid, + models + ); + + set(data, ['components', compoUID, 'layouts', 'edit'], formattedCompoEditLayout); + }); + + return data; +}; + const formatLayoutWithMetas = (obj, ctUid, models) => { const formatted = obj.layouts.edit.reduce((acc, current) => { const row = current.map(attribute => { @@ -32,8 +79,18 @@ const formatLayoutWithMetas = (obj, ctUid, models) => { return formatted; }; -const getDisplayedModels = models => - models.filter(model => model.isDisplayed).map(({ uid }) => uid); +const formatListLayoutWithMetas = obj => { + const formatted = obj.layouts.list.reduce((acc, current) => { + const fieldSchema = get(obj, ['attributes', current], {}); + const metadatas = get(obj, ['metadatas', current, 'list'], {}); + + acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas }); + + return acc; + }, []); + + return formatted; +}; const generateRelationQueryInfos = (obj, fieldName, models) => { const uid = obj.uid; @@ -70,65 +127,15 @@ const generateRelationQueryInfosForComponents = (obj, fieldName, ctUid, models) return queryInfos; }; -// editRelations is an array of strings... -const formatEditRelationsLayoutWithMetas = (obj, models) => { - const formatted = obj.layouts.editRelations.reduce((acc, current) => { - const fieldSchema = get(obj, ['attributes', current], {}); - const metadatas = get(obj, ['metadatas', current, 'edit'], {}); - const size = 6; - - const queryInfos = generateRelationQueryInfos(obj, current, models); - - acc.push({ - name: current, - size, - fieldSchema, - metadatas, - queryInfos, - }); - - return acc; - }, []); - - return formatted; -}; - -const formatListLayoutWithMetas = obj => { - const formatted = obj.layouts.list.reduce((acc, current) => { - const fieldSchema = get(obj, ['attributes', current], {}); - const metadatas = get(obj, ['metadatas', current, 'list'], {}); - - acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas }); - - return acc; - }, []); - - return formatted; -}; - -const formatLayouts = (initialData, models) => { - const data = mergeMetasWithSchema(cloneDeep(initialData), models, 'contentType'); - const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, models); - const ctUid = data.contentType.uid; - const formattedEditRelationsLayout = formatEditRelationsLayoutWithMetas(data.contentType, models); - const formattedListLayout = formatListLayoutWithMetas(data.contentType); - - set(data, ['contentType', 'layouts', 'edit'], formattedCTEditLayout); - set(data, ['contentType', 'layouts', 'editRelations'], formattedEditRelationsLayout); - set(data, ['contentType', 'layouts', 'list'], formattedListLayout); - - Object.keys(data.components).forEach(compoUID => { - const formattedCompoEditLayout = formatLayoutWithMetas( - data.components[compoUID], - ctUid, - models - ); - - set(data, ['components', compoUID, 'layouts', 'edit'], formattedCompoEditLayout); - }); - - return data; -}; +const getDisplayedModels = models => + models.filter(model => model.isDisplayed).map(({ uid }) => uid); export default formatLayouts; -export { formatEditRelationsLayoutWithMetas, formatLayoutWithMetas }; +export { + formatEditRelationsLayoutWithMetas, + formatLayoutWithMetas, + formatListLayoutWithMetas, + generateRelationQueryInfos, + generateRelationQueryInfosForComponents, + getDisplayedModels, +}; diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js index 1484de1116..3315ef5c82 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/tests/formatLayouts.test.js @@ -1,12 +1,70 @@ -import formatLayouts, { formatLayoutWithMetas } from '../formatLayouts'; +import formatLayouts, { + formatEditRelationsLayoutWithMetas, + formatLayoutWithMetas, + formatListLayoutWithMetas, + generateRelationQueryInfos, + generateRelationQueryInfosForComponents, + getDisplayedModels, +} from '../formatLayouts'; + +const addressSchema = { + uid: 'application::address.address', + attributes: { + categories: { + targetModel: 'application::category.category', + }, + }, + layouts: { + editRelations: ['categories'], + }, + metadatas: { + categories: { + edit: { + mainField: 'name', + }, + }, + }, +}; +const simpleModels = [ + { + uid: 'application::category.category', + isDisplayed: true, + }, +]; + +describe('Content Manager | hooks | useFetchContentTypeLayout | utils ', () => { + describe('formatEditRelationsLayoutWithMetas', () => { + it('should format editRelations layout correctly', () => { + const expectedLayout = [ + { + name: 'categories', + size: 6, + fieldSchema: { + targetModel: 'application::category.category', + }, + metadatas: { + mainField: 'name', + }, + queryInfos: { + endPoint: '/content-manager/relations/application::address.address/categories', + containsKey: 'name_contains', + defaultParams: {}, + shouldDisplayRelationLink: true, + }, + }, + ]; + + expect(formatEditRelationsLayoutWithMetas(addressSchema, simpleModels)).toEqual( + expectedLayout + ); + }); + }); -describe('Content Manager | hooks | useFetchContentTypeLayout | utils | formatLayoutWithMetas', () => { describe('formatLayouts', () => { it('should format the content type and components layouts', () => { const models = [ { uid: 'compo', - attributes: { full_name: { type: 'string', @@ -33,7 +91,6 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils | formatLa type: 'string', required: true, }, - city: { type: 'string', maxLength: 100, @@ -53,7 +110,6 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils | formatLa components: { compo: { uid: 'compo', - layouts: { edit: [ [ @@ -157,7 +213,6 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils | formatLa expect(result.contentType).toHaveProperty('attributes'); expect(result.contentType).toHaveProperty('layouts'); expect(result.contentType).toHaveProperty('metadatas'); - expect(result.contentType.layouts.edit).toEqual([ [ { @@ -421,4 +476,76 @@ describe('Content Manager | hooks | useFetchContentTypeLayout | utils | formatLa expect(formatLayoutWithMetas(data)).toEqual(expected); }); }); + + describe('formatListLayoutWithMetas', () => { + it('should format the list layout correctly', () => { + const data = { + layouts: { + list: ['test'], + }, + metadatas: { + test: { + list: { ok: true }, + }, + }, + attributes: { + test: { type: 'string' }, + }, + }; + const expected = [ + { + name: 'test', + key: '__test_key__', + metadatas: { ok: true }, + fieldSchema: { type: 'string' }, + }, + ]; + + expect(formatListLayoutWithMetas(data)).toEqual(expected); + }); + }); + + describe('generateRelationQueryInfos', () => { + it('should return an object with the correct keys', () => { + expect(generateRelationQueryInfos(addressSchema, 'categories', simpleModels)).toEqual({ + endPoint: '/content-manager/relations/application::address.address/categories', + containsKey: 'name_contains', + defaultParams: {}, + shouldDisplayRelationLink: true, + }); + }); + }); + + describe('generateRelationQueryInfosForComponents', () => { + it('should return an object with the correct keys', () => { + expect( + generateRelationQueryInfosForComponents( + addressSchema, + 'categories', + 'application::address.address', + simpleModels + ) + ).toEqual({ + endPoint: '/content-manager/relations/application::address.address/categories', + containsKey: 'name_contains', + defaultParams: { + _component: 'application::address.address', + }, + shouldDisplayRelationLink: true, + }); + }); + }); + + describe('getDisplayedModels', () => { + it('should return an array containing only the displayable models', () => { + const models = [ + { uid: 'test', isDisplayed: false }, + { uid: 'testtest', isDisplayed: true }, + ]; + + expect(getDisplayedModels([])).toHaveLength(0); + expect(getDisplayedModels(models)).toHaveLength(1); + expect(getDisplayedModels(models)[0]).toEqual('testtest'); + }); + }); }); diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersFromQuery.js b/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersFromQuery.js index ade4770628..12874a714a 100644 --- a/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersFromQuery.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/formatFiltersFromQuery.js @@ -1,30 +1,37 @@ -const findAppliedFilter = str => { - let filter = '='; - let name = str; +// List of all the possible filters +const VALID_REST_OPERATORS = [ + 'eq', + 'ne', + 'in', + 'nin', + 'contains', + 'ncontains', + 'containss', + 'ncontainss', + 'lt', + 'lte', + 'gt', + 'gte', + 'null', +]; - const filters = [ - '_ne', - '_lt', - '_lte', - '_gt', - '_gte', - '_contains', - '_containss', - '_ncontains', - '_in', - '_nin', - ]; +// from strapi-utims/convert-rest-query-params +const findAppliedFilter = whereClause => { + const separatorIndex = whereClause.lastIndexOf('_'); - filters.forEach(filterName => { - const split = str.split(filterName); + if (separatorIndex === -1) { + return { operator: '=', field: whereClause }; + } - if (split[1] === '') { - filter = filterName; - name = split[0]; - } - }); + const fieldName = whereClause.substring(0, separatorIndex); + const operator = whereClause.slice(separatorIndex + 1); - return { filter, name }; + // the field as underscores + if (!VALID_REST_OPERATORS.includes(operator)) { + return { operator: '=', field: whereClause }; + } + + return { operator: `_${operator}`, field: fieldName }; }; const formatFiltersFromQuery = ({ _where }) => { @@ -34,11 +41,11 @@ const formatFiltersFromQuery = ({ _where }) => { return _where.map(obj => { const [key] = Object.keys(obj); - const { filter, name } = findAppliedFilter(key); + const { field, operator } = findAppliedFilter(key); const value = obj[key]; - return { name, filter, value }; + return { name: field, filter: operator, value }; }); }; diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFilterFromQuery.test.js b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFilterFromQuery.test.js new file mode 100644 index 0000000000..5203a67b79 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatFilterFromQuery.test.js @@ -0,0 +1,45 @@ +import formatFiltersFromQuery, { findAppliedFilter } from '../formatFiltersFromQuery'; + +describe('CONTENT MANAGER | utils', () => { + describe('findAppliedFilter', () => { + it('should return the correct filter', () => { + expect(findAppliedFilter('city')).toEqual({ operator: '=', field: 'city' }); + expect(findAppliedFilter('city_nee')).toEqual({ operator: '=', field: 'city_nee' }); + expect(findAppliedFilter('city_ne')).toEqual({ operator: '_ne', field: 'city' }); + expect(findAppliedFilter('city_lt')).toEqual({ operator: '_lt', field: 'city' }); + expect(findAppliedFilter('city_lte')).toEqual({ operator: '_lte', field: 'city' }); + expect(findAppliedFilter('city_gt')).toEqual({ operator: '_gt', field: 'city' }); + expect(findAppliedFilter('city_gte')).toEqual({ operator: '_gte', field: 'city' }); + }); + }); + + describe('formatFiltersFromQuery', () => { + it('should return an empty array if there is no where clause', () => { + expect(formatFiltersFromQuery({})).toHaveLength(0); + }); + + it('should return array of filter', () => { + const query = { + _where: [ + { + city_ne_ne: 'paris', + }, + { + city_ne: 'paris', + }, + { + city: 'paris', + }, + ], + }; + + const expected = [ + { name: 'city_ne', filter: '_ne', value: 'paris' }, + { name: 'city', filter: '_ne', value: 'paris' }, + { name: 'city', filter: '=', value: 'paris' }, + ]; + + expect(formatFiltersFromQuery(query)).toEqual(expected); + }); + }); +}); diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js new file mode 100644 index 0000000000..98c96d0ce2 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/utils/tests/formatLayoutToApi.test.js @@ -0,0 +1,23 @@ +import formatLayoutToApi from '../formatLayoutToApi'; + +describe('CONTENT MANAGER | utils | formatLayoutToApi', () => { + it('should format the list layout correctly if it is an array of objects', () => { + const layouts = { + list: [{ name: 'test', size: 6 }], + edit: [], + editRelations: [], + }; + + expect(formatLayoutToApi({ layouts }).layouts.list).toEqual(['test']); + }); + + it('should format the list layout correctly if it is an array of strings', () => { + const layouts = { + list: ['test'], + edit: [], + editRelations: [], + }; + + expect(formatLayoutToApi({ layouts }).layouts.list).toEqual(['test']); + }); +});