mirror of
https://github.com/strapi/strapi.git
synced 2025-08-13 19:27:34 +00:00
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:
parent
90a60879c5
commit
73db8d428b
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useEffect, useReducer, useState, useRef } from 'react';
|
import React, { memo, useEffect, useReducer, useState, useRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { camelCase, get, groupBy, set, size, sortBy } from 'lodash';
|
import { get, groupBy, set, size } from 'lodash';
|
||||||
import {
|
import {
|
||||||
request,
|
request,
|
||||||
LoadingIndicatorPage,
|
LoadingIndicatorPage,
|
||||||
@ -32,6 +32,7 @@ import {
|
|||||||
getComponentsToPost,
|
getComponentsToPost,
|
||||||
formatMainDataType,
|
formatMainDataType,
|
||||||
getCreatedAndModifiedComponents,
|
getCreatedAndModifiedComponents,
|
||||||
|
sortContentType,
|
||||||
} from './utils/cleanData';
|
} from './utils/cleanData';
|
||||||
|
|
||||||
const DataManagerProvider = ({ allIcons, children }) => {
|
const DataManagerProvider = ({ allIcons, children }) => {
|
||||||
@ -86,7 +87,6 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const components = createDataObject(componentsArray);
|
const components = createDataObject(componentsArray);
|
||||||
const contentTypes = createDataObject(contentTypesArray);
|
const contentTypes = createDataObject(contentTypesArray);
|
||||||
const orderedComponents = orderAllDataAttributesWithImmutable({
|
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 shouldRedirect = () => {
|
||||||
const dataSet = isInContentTypeView ? contentTypes : components;
|
const dataSet = isInContentTypeView ? contentTypes : components;
|
||||||
|
|
||||||
@ -520,7 +508,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
|||||||
removeAttribute,
|
removeAttribute,
|
||||||
removeComponentFromDynamicZone,
|
removeComponentFromDynamicZone,
|
||||||
setModifiedData,
|
setModifiedData,
|
||||||
sortedContentTypesList,
|
sortedContentTypesList: sortContentType(contentTypes),
|
||||||
submitData,
|
submitData,
|
||||||
toggleModalCancel,
|
toggleModalCancel,
|
||||||
updateSchema,
|
updateSchema,
|
||||||
|
@ -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
|
const expected = initialState
|
||||||
.set('components', fromJS(components))
|
.set('components', fromJS(components))
|
||||||
.set('contentTypes', fromJS(contentTypes))
|
.set('contentTypes', fromJS(contentTypes))
|
||||||
@ -397,6 +405,7 @@ describe('CTB | containers | DataManagerProvider | reducer | basics actions ', (
|
|||||||
type: 'GET_DATA_SUCCEEDED',
|
type: 'GET_DATA_SUCCEEDED',
|
||||||
components,
|
components,
|
||||||
contentTypes,
|
contentTypes,
|
||||||
|
singleTypes,
|
||||||
})
|
})
|
||||||
).toEqual(expected);
|
).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
@ -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';
|
import makeUnique from '../../../utils/makeUnique';
|
||||||
|
|
||||||
const getCreatedAndModifiedComponents = (allComponents, initialComponents) => {
|
const getCreatedAndModifiedComponents = (allComponents, initialComponents) => {
|
||||||
@ -157,9 +159,24 @@ const getComponentsToPost = (
|
|||||||
return formattedComponents;
|
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 {
|
export {
|
||||||
formatComponent,
|
formatComponent,
|
||||||
getComponentsToPost,
|
getComponentsToPost,
|
||||||
getCreatedAndModifiedComponents,
|
getCreatedAndModifiedComponents,
|
||||||
formatMainDataType,
|
formatMainDataType,
|
||||||
|
sortContentType,
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
formatMainDataType,
|
formatMainDataType,
|
||||||
getComponentsToPost,
|
getComponentsToPost,
|
||||||
getCreatedAndModifiedComponents,
|
getCreatedAndModifiedComponents,
|
||||||
|
sortContentType,
|
||||||
} from '../cleanData';
|
} from '../cleanData';
|
||||||
import rawData from './rawData';
|
import rawData from './rawData';
|
||||||
import expectedData from './expectedFormattedData';
|
import expectedData from './expectedFormattedData';
|
||||||
@ -207,4 +208,19 @@ describe('CleanData utils', () => {
|
|||||||
).toEqual(componentsToFormat.sort());
|
).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([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -96,6 +96,39 @@ const expectedData = {
|
|||||||
'default.nested-compo',
|
'default.nested-compo',
|
||||||
'blog.quote',
|
'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: [
|
components: [
|
||||||
{
|
{
|
||||||
|
@ -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
|
// TODO add test for component
|
||||||
// componentToCreate: {
|
// componentToCreate: {
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ const FormModal = () => {
|
|||||||
const dynamicZoneTarget = query.get('dynamicZoneTarget');
|
const dynamicZoneTarget = query.get('dynamicZoneTarget');
|
||||||
const forTarget = query.get('forTarget');
|
const forTarget = query.get('forTarget');
|
||||||
const modalType = query.get('modalType');
|
const modalType = query.get('modalType');
|
||||||
|
const contentTypeKind = query.get('kind');
|
||||||
const targetUid = query.get('targetUid');
|
const targetUid = query.get('targetUid');
|
||||||
const settingType = query.get('settingType');
|
const settingType = query.get('settingType');
|
||||||
const headerId = query.get('headerId');
|
const headerId = query.get('headerId');
|
||||||
@ -157,6 +158,7 @@ const FormModal = () => {
|
|||||||
header_info_name_5,
|
header_info_name_5,
|
||||||
header_info_category_5,
|
header_info_category_5,
|
||||||
headerId,
|
headerId,
|
||||||
|
contentTypeKind,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset all the modification when opening the edit category modal
|
// Reset all the modification when opening the edit category modal
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { sortBy } from 'lodash';
|
import { sortBy, camelCase, upperFirst } from 'lodash';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { LeftMenuList, useGlobalContext } from 'strapi-helper-plugin';
|
import { LeftMenuList, useGlobalContext } from 'strapi-helper-plugin';
|
||||||
import pluginId from '../../pluginId';
|
import pluginId from '../../pluginId';
|
||||||
@ -32,7 +32,6 @@ function LeftMenu({ wait }) {
|
|||||||
} = useDataManager();
|
} = useDataManager();
|
||||||
const { emitEvent, formatMessage } = useGlobalContext();
|
const { emitEvent, formatMessage } = useGlobalContext();
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
|
|
||||||
const componentsData = sortBy(
|
const componentsData = sortBy(
|
||||||
Object.keys(componentsGroupedByCategory).map(category => ({
|
Object.keys(componentsGroupedByCategory).map(category => ({
|
||||||
name: category,
|
name: category,
|
||||||
@ -86,18 +85,19 @@ function LeftMenu({ wait }) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickOpenModal = async type => {
|
const handleClickOpenModal = async (type, kind = '') => {
|
||||||
if (canOpenModalCreateCTorComponent()) {
|
if (canOpenModalCreateCTorComponent()) {
|
||||||
const eventName =
|
emitEvent(
|
||||||
type === 'contentType'
|
`willCreate${upperFirst(
|
||||||
? 'willCreateContentType'
|
camelCase(kind === 'singleType' ? kind : type)
|
||||||
: 'willCreateComponent';
|
)}`
|
||||||
|
);
|
||||||
emitEvent(eventName);
|
|
||||||
|
|
||||||
await wait();
|
await wait();
|
||||||
push({
|
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`
|
`modalForm.${type}.header-create`
|
||||||
)}&header_icon_name_1=${type}&header_icon_isCustom_1=false&header_label_1=null`,
|
)}&header_icon_name_1=${type}&header_icon_isCustom_1=false&header_label_1=null`,
|
||||||
});
|
});
|
||||||
@ -105,7 +105,6 @@ function LeftMenu({ wait }) {
|
|||||||
displayNotificationCTNotSaved();
|
displayNotificationCTNotSaved();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
{
|
{
|
||||||
name: 'models',
|
name: 'models',
|
||||||
@ -119,12 +118,35 @@ function LeftMenu({ wait }) {
|
|||||||
componentProps: {
|
componentProps: {
|
||||||
id: `${pluginId}.button.model.create`,
|
id: `${pluginId}.button.model.create`,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleClickOpenModal('contentType');
|
handleClickOpenModal('contentType', 'collectionType');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: null,
|
: 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',
|
name: 'components',
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
"button.component.add": "Add a component",
|
"button.component.add": "Add a component",
|
||||||
"button.component.create": "Create new component",
|
"button.component.create": "Create new component",
|
||||||
"button.model.create": "Create new collection-type",
|
"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": "You have already added all your components",
|
||||||
"components.componentSelect.no-component-available.with-search": "There is no component matching your search",
|
"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)",
|
"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.components.name.singular": "Component",
|
||||||
"menu.section.models.name.plural": "Collection Types",
|
"menu.section.models.name.plural": "Collection Types",
|
||||||
"menu.section.models.name.singular": "Collection Type",
|
"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": "Name",
|
||||||
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
|
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
|
||||||
"modalForm.attribute.text.type-selection": "Type",
|
"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.create-component.category.label": "Select a category or enter a name to create a new one",
|
||||||
"modalForm.components.icon.label": "Icon",
|
"modalForm.components.icon.label": "Icon",
|
||||||
"modalForm.contentType.header-create": "Create a collection type",
|
"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.editCategory.base.name.description": "No space is allowed for the name of the category",
|
||||||
"modalForm.header-edit": "Edit {name}",
|
"modalForm.header-edit": "Edit {name}",
|
||||||
"modalForm.header.categories": "Categories",
|
"modalForm.header.categories": "Categories",
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
"attribute.richtext": "Texte enrichi",
|
"attribute.richtext": "Texte enrichi",
|
||||||
"attribute.text": "Texte",
|
"attribute.text": "Texte",
|
||||||
"button.attributes.add.another": "Ajouter un autre champ",
|
"button.attributes.add.another": "Ajouter un autre champ",
|
||||||
"button.component.create": "Créer un Composant",
|
"button.component.create": "Créer un composant",
|
||||||
"button.model.create": "Créer un Type de Collection",
|
"button.model.create": "Créer un type de collection",
|
||||||
"form.attribute.item.customColumnName": "Nom de colonne personalisée",
|
"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.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",
|
"form.attribute.item.defineRelation.fieldName": "Nom du Champ",
|
||||||
@ -44,6 +44,10 @@
|
|||||||
"menu.section.components.name.singular": "Composant",
|
"menu.section.components.name.singular": "Composant",
|
||||||
"menu.section.models.name.plural": "Modèles",
|
"menu.section.models.name.plural": "Modèles",
|
||||||
"menu.section.models.name.singular": "Modèle",
|
"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.attribute.relationWith": "Relation avec",
|
||||||
"modelPage.contentHeader.emptyDescription.description": "Il n'y a pas de description",
|
"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.",
|
"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.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user