Single types list in CTB

Signed-off-by: Hicham EL ABBASSI <hichamelabbassi@MacBook-Pro-de-Hicham.local>
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
Hicham EL ABBASSI 2020-01-29 10:06:46 +01:00 committed by HichamELBSI
parent 90a60879c5
commit 73db8d428b
10 changed files with 144 additions and 31 deletions

View File

@ -1,6 +1,6 @@
import React, { memo, useEffect, useReducer, useState, useRef } from 'react';
import PropTypes from 'prop-types';
import { camelCase, get, groupBy, set, size, sortBy } from 'lodash';
import { get, groupBy, set, size } from 'lodash';
import {
request,
LoadingIndicatorPage,
@ -32,6 +32,7 @@ import {
getComponentsToPost,
formatMainDataType,
getCreatedAndModifiedComponents,
sortContentType,
} from './utils/cleanData';
const DataManagerProvider = ({ allIcons, children }) => {
@ -86,7 +87,6 @@ const DataManagerProvider = ({ allIcons, children }) => {
});
})
);
const components = createDataObject(componentsArray);
const contentTypes = createDataObject(contentTypesArray);
const orderedComponents = orderAllDataAttributesWithImmutable({
@ -373,18 +373,6 @@ const DataManagerProvider = ({ allIcons, children }) => {
});
};
const sortedContentTypesList = sortBy(
Object.keys(contentTypes)
.map(uid => ({
name: uid,
title: contentTypes[uid].schema.name,
uid,
to: `/plugins/${pluginId}/content-types/${uid}`,
}))
.filter(obj => obj !== null),
obj => camelCase(obj.title)
);
const shouldRedirect = () => {
const dataSet = isInContentTypeView ? contentTypes : components;
@ -520,7 +508,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
removeAttribute,
removeComponentFromDynamicZone,
setModifiedData,
sortedContentTypesList,
sortedContentTypesList: sortContentType(contentTypes),
submitData,
toggleModalCancel,
updateSchema,

View File

@ -385,6 +385,14 @@ describe('CTB | containers | DataManagerProvider | reducer | basics actions ', (
},
},
};
const singleTypes = {
'application::aboutpage.aboutpage': {
uid: 'application::aboutpage.aboutpage',
schema: {
attributes: {},
},
},
};
const expected = initialState
.set('components', fromJS(components))
.set('contentTypes', fromJS(contentTypes))
@ -397,6 +405,7 @@ describe('CTB | containers | DataManagerProvider | reducer | basics actions ', (
type: 'GET_DATA_SUCCEEDED',
components,
contentTypes,
singleTypes,
})
).toEqual(expected);
});

View File

@ -1,4 +1,6 @@
import { get, has, isEqual, omit } from 'lodash';
import { get, has, isEqual, omit, sortBy, camelCase } from 'lodash';
import pluginId from '../../../pluginId';
import makeUnique from '../../../utils/makeUnique';
const getCreatedAndModifiedComponents = (allComponents, initialComponents) => {
@ -157,9 +159,24 @@ const getComponentsToPost = (
return formattedComponents;
};
const sortContentType = types =>
sortBy(
Object.keys(types)
.map(uid => ({
name: uid,
title: types[uid].schema.name,
uid,
to: `/plugins/${pluginId}/content-types/${uid}`,
kind: types[uid].schema.kind,
}))
.filter(obj => obj !== null),
obj => camelCase(obj.title)
);
export {
formatComponent,
getComponentsToPost,
getCreatedAndModifiedComponents,
formatMainDataType,
sortContentType,
};

View File

@ -3,6 +3,7 @@ import {
formatMainDataType,
getComponentsToPost,
getCreatedAndModifiedComponents,
sortContentType,
} from '../cleanData';
import rawData from './rawData';
import expectedData from './expectedFormattedData';
@ -207,4 +208,19 @@ describe('CleanData utils', () => {
).toEqual(componentsToFormat.sort());
});
});
describe('sortContentType', () => {
it('should return sorted collection types array', () => {
const { sortedContentTypes } = expectedData;
const {
rawData: { contentTypesToSort },
} = rawData;
const actual = sortContentType(contentTypesToSort);
expect(actual.sort()).toEqual(sortedContentTypes.sort());
});
it('should return an empty array if no content types', () => {
expect(sortContentType({})).toEqual([]);
});
});
});

View File

@ -96,6 +96,39 @@ const expectedData = {
'default.nested-compo',
'blog.quote',
],
sortedContentTypes: [
{
uid: 'plugins::myplugins.atest',
name: 'plugins::myplugins.atest',
title: 'plugins::myplugins.atest',
to:
'/plugins/content-type-builder/content-types/plugins::myplugins.atest',
kind: 'collectionType',
},
{
uid: 'plugins::myplugins.btest',
name: 'plugins::myplugins.btest',
title: 'plugins::myplugins.btest',
to:
'/plugins/content-type-builder/content-types/plugins::myplugins.btest',
kind: 'collectionType',
},
{
uid: 'plugins::myplugins.ctest',
name: 'plugins::myplugins.ctest',
title: 'plugins::myplugins.ctest',
to:
'/plugins/content-type-builder/content-types/plugins::myplugins.ctest',
kind: 'collectionType',
},
{
uid: 'plugins::myplugins.test',
name: 'plugins::myplugins.test',
title: 'plugins::myplugins.test',
to: '/plugins/content-type-builder/content-types/plugins::myplugins.test',
kind: 'singleType',
},
],
components: [
{

View File

@ -147,6 +147,24 @@ const data = {
},
},
},
contentTypesToSort: {
'plugins::myplugins.test': {
uid: 'plugins::myplugins.test',
schema: { name: 'plugins::myplugins.test', kind: 'singleType' },
},
'plugins::myplugins.btest': {
uid: 'plugins::myplugins.btest',
schema: { name: 'plugins::myplugins.btest', kind: 'collectionType' },
},
'plugins::myplugins.atest': {
uid: 'plugins::myplugins.atest',
schema: { name: 'plugins::myplugins.atest', kind: 'collectionType' },
},
'plugins::myplugins.ctest': {
uid: 'plugins::myplugins.ctest',
schema: { name: 'plugins::myplugins.ctest', kind: 'collectionType' },
},
},
// TODO add test for component
// componentToCreate: {

View File

@ -86,6 +86,7 @@ const FormModal = () => {
const dynamicZoneTarget = query.get('dynamicZoneTarget');
const forTarget = query.get('forTarget');
const modalType = query.get('modalType');
const contentTypeKind = query.get('kind');
const targetUid = query.get('targetUid');
const settingType = query.get('settingType');
const headerId = query.get('headerId');
@ -157,6 +158,7 @@ const FormModal = () => {
header_info_name_5,
header_info_category_5,
headerId,
contentTypeKind,
});
// Reset all the modification when opening the edit category modal

View File

@ -6,7 +6,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { sortBy } from 'lodash';
import { sortBy, camelCase, upperFirst } from 'lodash';
import { useHistory } from 'react-router-dom';
import { LeftMenuList, useGlobalContext } from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
@ -32,7 +32,6 @@ function LeftMenu({ wait }) {
} = useDataManager();
const { emitEvent, formatMessage } = useGlobalContext();
const { push } = useHistory();
const componentsData = sortBy(
Object.keys(componentsGroupedByCategory).map(category => ({
name: category,
@ -86,18 +85,19 @@ function LeftMenu({ wait }) {
);
};
const handleClickOpenModal = async type => {
const handleClickOpenModal = async (type, kind = '') => {
if (canOpenModalCreateCTorComponent()) {
const eventName =
type === 'contentType'
? 'willCreateContentType'
: 'willCreateComponent';
emitEvent(eventName);
emitEvent(
`willCreate${upperFirst(
camelCase(kind === 'singleType' ? kind : type)
)}`
);
await wait();
push({
search: `modalType=${type}&actionType=create&settingType=base&forTarget=${type}&headerId=${getTrad(
search: `modalType=${type}${
kind ? `&kind=${kind}` : ''
}&actionType=create&settingType=base&forTarget=${type}&headerId=${getTrad(
`modalForm.${type}.header-create`
)}&header_icon_name_1=${type}&header_icon_isCustom_1=false&header_label_1=null`,
});
@ -105,7 +105,6 @@ function LeftMenu({ wait }) {
displayNotificationCTNotSaved();
}
};
const data = [
{
name: 'models',
@ -119,12 +118,35 @@ function LeftMenu({ wait }) {
componentProps: {
id: `${pluginId}.button.model.create`,
onClick: () => {
handleClickOpenModal('contentType');
handleClickOpenModal('contentType', 'collectionType');
},
},
}
: null,
links: sortedContentTypesList,
links: sortedContentTypesList.filter(
contentType => contentType.kind === 'collectionType'
),
},
{
name: 'singleTypes',
title: {
id: `${pluginId}.menu.section.single-types.name.`,
},
searchable: true,
customLink: isInDevelopmentMode
? {
Component: CustomLink,
componentProps: {
id: `${pluginId}.button.single-types.create`,
onClick: () => {
handleClickOpenModal('contentType', 'singleType');
},
},
}
: null,
links: sortedContentTypesList.filter(
singleType => singleType.kind === 'singleType'
),
},
{
name: 'components',

View File

@ -34,6 +34,7 @@
"button.component.add": "Add a component",
"button.component.create": "Create new component",
"button.model.create": "Create new collection-type",
"button.single-types.create": "Create new single-type",
"components.componentSelect.no-component-available": "You have already added all your components",
"components.componentSelect.no-component-available.with-search": "There is no component matching your search",
"components.componentSelect.value-component": "{number} component selected (type to search for a component)",
@ -111,6 +112,8 @@
"menu.section.components.name.singular": "Component",
"menu.section.models.name.plural": "Collection Types",
"menu.section.models.name.singular": "Collection Type",
"menu.section.single-types.name.plural": "Single Types",
"menu.section.single-types.name.singular": "Single Type",
"modalForm.attribute.form.base.name": "Name",
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
"modalForm.attribute.text.type-selection": "Type",
@ -120,6 +123,7 @@
"modalForm.components.create-component.category.label": "Select a category or enter a name to create a new one",
"modalForm.components.icon.label": "Icon",
"modalForm.contentType.header-create": "Create a collection type",
"modalForm.singleType.header-create": "Create a single type",
"modalForm.editCategory.base.name.description": "No space is allowed for the name of the category",
"modalForm.header-edit": "Edit {name}",
"modalForm.header.categories": "Categories",

View File

@ -10,8 +10,8 @@
"attribute.richtext": "Texte enrichi",
"attribute.text": "Texte",
"button.attributes.add.another": "Ajouter un autre champ",
"button.component.create": "Créer un Composant",
"button.model.create": "Créer un Type de Collection",
"button.component.create": "Créer un composant",
"button.model.create": "Créer un type de collection",
"form.attribute.item.customColumnName": "Nom de colonne personalisée",
"form.attribute.item.customColumnName.description": "Pratique pour renommer la colonne de la db dans un format plus comprehensible pour les responses de l'API",
"form.attribute.item.defineRelation.fieldName": "Nom du Champ",
@ -44,6 +44,10 @@
"menu.section.components.name.singular": "Composant",
"menu.section.models.name.plural": "Modèles",
"menu.section.models.name.singular": "Modèle",
"menu.section.single-types.name.plural": "Single Types",
"menu.section.single-types.name.singular": "Single Type",
"modalForm.singleType.header-create": "Créer un single type",
"button.single-types.create": "Créer un single type",
"modelPage.attribute.relationWith": "Relation avec",
"modelPage.contentHeader.emptyDescription.description": "Il n'y a pas de description",
"plugin.description.long": "Modélisez la structure de données de votre API. Créer des nouveaux champs et relations en un instant. Les fichiers se créent et se mettent à jour automatiquement.",