Merge branch 'custom-fields/add-custom-field-attribute' of github.com:strapi/strapi into add-custom-field-attribute/error-handling

This commit is contained in:
Mark Kaylor 2022-08-10 11:42:29 +02:00
commit b3384fb6e8
19 changed files with 260 additions and 110 deletions

View File

@ -49,10 +49,21 @@ export default {
id: 'color-picker.color.format.label', id: 'color-picker.color.format.label',
defaultMessage: 'Color format', defaultMessage: 'Color format',
}, },
name: 'options.color-picker.format', name: 'options.format',
type: 'select', type: 'select',
value: 'hex', value: 'hex',
options: [ options: [
{
key: '__null_reset_value__',
value: '',
metadatas: {
intlLabel: {
id: 'color-picker.color.format.placeholder',
defaultMessage: 'Select a format',
},
hidden: true,
},
},
{ {
key: 'hex', key: 'hex',
value: 'hex', value: 'hex',
@ -111,11 +122,9 @@ export default {
}, },
], ],
validator: args => ({ validator: args => ({
'color-picker': yup.object().shape({ format: yup.string().required({
format: yup.string().required({ id: 'options.color-picker.format.error',
id: 'options.color-picker.format.error', defaultMessage: 'The color format is required',
defaultMessage: 'The color format is required',
}),
}), }),
}), }),
}, },

View File

@ -173,17 +173,19 @@ const DataManagerProvider = ({
}); });
}; };
const addCustomFieldAttribute = ( const addCustomFieldAttribute = ({ attributeToSet, forTarget, targetUid, initialAttribute }) => {
attributeToSet,
forTarget,
targetUid,
isEditing = false,
initialAttribute
) => {
const actionType = isEditing ? EDIT_CUSTOM_FIELD_ATTRIBUTE : ADD_CUSTOM_FIELD_ATTRIBUTE;
dispatch({ dispatch({
type: actionType, type: ADD_CUSTOM_FIELD_ATTRIBUTE,
attributeToSet,
forTarget,
targetUid,
initialAttribute,
});
};
const editCustomFieldAttribute = ({ attributeToSet, forTarget, targetUid, initialAttribute }) => {
dispatch({
type: EDIT_CUSTOM_FIELD_ATTRIBUTE,
attributeToSet, attributeToSet,
forTarget, forTarget,
targetUid, targetUid,
@ -573,6 +575,7 @@ const DataManagerProvider = ({
deleteCategory, deleteCategory,
deleteData, deleteData,
editCategory, editCategory,
editCustomFieldAttribute,
isInDevelopmentMode, isInDevelopmentMode,
initialData, initialData,
isInContentTypeView, isInContentTypeView,

View File

@ -36,65 +36,58 @@ const findAttributeIndex = (schema, attributeToFind) => {
return schema.schema.attributes.findIndex(({ name }) => name === attributeToFind); return schema.schema.attributes.findIndex(({ name }) => name === attributeToFind);
}; };
const getAddAttributeUpdate = (action, state) => {
const {
attributeToSet: { name, ...rest },
forTarget,
targetUid,
} = action;
delete rest.createComponent;
const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
? [forTarget]
: [forTarget, targetUid];
const currentAttributes = get(
state,
['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'],
[]
).slice();
// Add the createdAttribute
const updatedAttributes = [...currentAttributes, { ...rest, name }];
return { pathToDataToEdit, updatedAttributes, attributeToSet: { ...rest, name } };
};
const getEditAttributeUpdate = (action, state) => {
const { forTarget, targetUid, initialAttribute } = action;
const initialAttributeName = initialAttribute.name;
const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
? [forTarget]
: [forTarget, targetUid];
const initialAttributeIndex = findAttributeIndex(
get(state, ['modifiedData', ...pathToDataToEdit]),
initialAttributeName
);
return { pathToDataToEdit, initialAttributeIndex };
};
const reducer = (state = initialState, action) => const reducer = (state = initialState, action) =>
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
produce(state, draftState => { produce(state, draftState => {
switch (action.type) { switch (action.type) {
case actions.ADD_CUSTOM_FIELD_ATTRIBUTE: { case actions.ADD_CUSTOM_FIELD_ATTRIBUTE: {
const { pathToDataToEdit, updatedAttributes } = getAddAttributeUpdate(action, state); const {
attributeToSet: { name, ...rest },
forTarget,
targetUid,
} = action;
const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
? [forTarget]
: [forTarget, targetUid];
const currentAttributes = get(
state,
['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'],
[]
).slice();
// Add the createdAttribute
const updatedAttributes = [...currentAttributes, { ...rest, name }];
set( set(
draftState, draftState,
['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'], ['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'],
updatedAttributes updatedAttributes
); );
break; break;
} }
case actions.ADD_ATTRIBUTE: { case actions.ADD_ATTRIBUTE: {
const { const {
pathToDataToEdit,
updatedAttributes,
attributeToSet: { name, ...rest }, attributeToSet: { name, ...rest },
} = getAddAttributeUpdate(action, state); forTarget,
targetUid,
} = action;
delete rest.createComponent;
const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
? [forTarget]
: [forTarget, targetUid];
const currentAttributes = get(
state,
['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'],
[]
).slice();
// Add the createdAttribute
const updatedAttributes = [...currentAttributes, { ...rest, name }];
set( set(
draftState, draftState,
@ -270,9 +263,17 @@ const reducer = (state = initialState, action) =>
break; break;
} }
case actions.EDIT_CUSTOM_FIELD_ATTRIBUTE: { case actions.EDIT_CUSTOM_FIELD_ATTRIBUTE: {
const { attributeToSet } = action; const { forTarget, targetUid, initialAttribute, attributeToSet } = action;
const { pathToDataToEdit, initialAttributeIndex } = getEditAttributeUpdate(action, state); const initialAttributeName = initialAttribute.name;
const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
? [forTarget]
: [forTarget, targetUid];
const initialAttributeIndex = findAttributeIndex(
get(state, ['modifiedData', ...pathToDataToEdit]),
initialAttributeName
);
set( set(
draftState, draftState,
@ -285,10 +286,20 @@ const reducer = (state = initialState, action) =>
case actions.EDIT_ATTRIBUTE: { case actions.EDIT_ATTRIBUTE: {
const { const {
attributeToSet: { name, ...rest }, attributeToSet: { name, ...rest },
forTarget,
targetUid,
initialAttribute, initialAttribute,
} = action; } = action;
const { pathToDataToEdit, initialAttributeIndex } = getEditAttributeUpdate(action, state); const initialAttributeName = initialAttribute.name;
const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
? [forTarget]
: [forTarget, targetUid];
const initialAttributeIndex = findAttributeIndex(
get(state, ['modifiedData', ...pathToDataToEdit]),
initialAttributeName
);
const isEditingRelation = rest.type === 'relation'; const isEditingRelation = rest.type === 'relation';

View File

@ -7,16 +7,9 @@ import { createComponentSchema, componentForm } from '../component';
import { dynamiczoneForm } from '../dynamicZone'; import { dynamiczoneForm } from '../dynamicZone';
import { nameField } from '../attributes/nameField'; import { nameField } from '../attributes/nameField';
import addItemsToFormSection from './utils/addItemsToFormSection'; import addItemsToFormSection from './utils/addItemsToFormSection';
import getUsedAttributeNames from './utils/getUsedAttributeNames';
import getTrad from '../../../utils/getTrad'; import getTrad from '../../../utils/getTrad';
const getUsedAttributeNames = (attributes, schemaData) => {
return attributes
.filter(({ name }) => {
return name !== schemaData.initialData.name;
})
.map(({ name }) => name);
};
const forms = { const forms = {
customField: { customField: {
schema({ schema({
@ -68,7 +61,6 @@ const forms = {
} }
if (injectedInputs) { if (injectedInputs) {
// TODO: Discuss how to handle settings from other plugins
const extendedSettings = { const extendedSettings = {
sectionTitle: { sectionTitle: {
id: getTrad('modalForm.custom-fields.advanced.settings.extended'), id: getTrad('modalForm.custom-fields.advanced.settings.extended'),

View File

@ -15,7 +15,7 @@ const addItemsToFormSection = (formTypeOptions, sections) => {
return; return;
} }
// Otherwise, when no sectionTitle is present or sectionTitle has a value (including null), // Otherwise, when sectionTitle has a value (including null),
// add the item as a new section // add the item as a new section
sections.push(item); sections.push(item);
}); });

View File

@ -0,0 +1,15 @@
/**
*
* @param {array} attributes The attributes found on the dataManager's modifiedData object
* @param {object} schemaData The modifiedData and SchemaData objects from the reducer state
* @returns A list of names already being used
*/
const getUsedAttributeNames = (attributes, schemaData) => {
return attributes
.filter(({ name }) => {
return name !== schemaData.initialData.name;
})
.map(({ name }) => name);
};
export default getUsedAttributeNames;

View File

@ -116,6 +116,7 @@ const FormModal = () => {
deleteCategory, deleteCategory,
deleteData, deleteData,
editCategory, editCategory,
editCustomFieldAttribute,
submitData, submitData,
modifiedData: allDataSchema, modifiedData: allDataSchema,
nestedComponents, nestedComponents,
@ -347,7 +348,6 @@ const FormModal = () => {
ctbFormsAPI, ctbFormsAPI,
customFieldValidator: customField.options.validator, customFieldValidator: customField.options.validator,
}); });
// Check for validity for creating a component // Check for validity for creating a component
// This is happening when the user creates a component "on the fly" // This is happening when the user creates a component "on the fly"
// Since we temporarily store the component info in another object // Since we temporarily store the component info in another object
@ -550,13 +550,18 @@ const FormModal = () => {
// Add/edit a field to a content type // Add/edit a field to a content type
// Add/edit a field to a created component (the end modal is not step 2) // Add/edit a field to a created component (the end modal is not step 2)
} else if (isCreatingCustomFieldAttribute) { } else if (isCreatingCustomFieldAttribute) {
addCustomFieldAttribute( const customFieldAttributeUpdate = {
{ ...modifiedData, customField: customFieldUid }, attributeToSet: { ...modifiedData, customField: customFieldUid },
forTarget, forTarget,
targetUid, targetUid,
actionType === 'edit', initialAttribute: initialData,
initialData };
);
if (actionType === 'edit') {
editCustomFieldAttribute(customFieldAttributeUpdate);
} else {
addCustomFieldAttribute(customFieldAttributeUpdate);
}
if (shouldContinue) { if (shouldContinue) {
onNavigateToChooseAttributeModal({ onNavigateToChooseAttributeModal({
@ -1050,10 +1055,10 @@ const FormModal = () => {
onSubmitCreateContentType={handleSubmit} onSubmitCreateContentType={handleSubmit}
onSubmitCreateDz={handleSubmit} onSubmitCreateDz={handleSubmit}
onSubmitEditAttribute={handleSubmit} onSubmitEditAttribute={handleSubmit}
onSubmitEditCusomFieldAttribute={handleSubmit}
onSubmitEditCategory={handleSubmit} onSubmitEditCategory={handleSubmit}
onSubmitEditComponent={handleSubmit} onSubmitEditComponent={handleSubmit}
onSubmitEditContentType={handleSubmit} onSubmitEditContentType={handleSubmit}
onSubmitEditCustomFieldAttribute={handleSubmit}
onSubmitEditDz={handleSubmit} onSubmitEditDz={handleSubmit}
/> />
} }

View File

@ -0,0 +1,91 @@
import addItemsToFormSections from '../forms/utils/addItemsToFormSection';
describe('addItemsToFormSection', () => {
it('adds items to the default section', () => {
const sections = [{ sectionTitle: null, items: [] }];
const itemsToAdd = [
{
intlLabel: {
id: 'color-picker.color.format.label',
defaultMessage: 'Color format',
},
name: 'options.color-picker.format',
type: 'select',
value: 'hex',
options: [
{
key: 'hex',
value: 'hex',
metadatas: {
intlLabel: {
id: 'color-picker.color.format.hex',
defaultMessage: 'Hexadecimal',
},
},
},
{
key: 'rgba',
value: 'rgba',
metadatas: {
intlLabel: {
id: 'color-picker.color.format.rgba',
defaultMessage: 'RGBA',
},
},
},
],
},
];
addItemsToFormSections(itemsToAdd, sections);
expect(sections.length).toBe(1);
expect(sections[0].items.length).toBe(1);
});
it('adds the item as a new section', () => {
const sections = [{ sectionTitle: null, items: [] }];
const itemsToAdd = [
{
sectionTitle: null,
items: [
{
intlLabel: {
id: 'color-picker.color.format.label',
defaultMessage: 'Color format',
},
name: 'options.color-picker.format',
type: 'select',
value: 'hex',
options: [
{
key: 'hex',
value: 'hex',
metadatas: {
intlLabel: {
id: 'color-picker.color.format.hex',
defaultMessage: 'Hexadecimal',
},
},
},
{
key: 'rgba',
value: 'rgba',
metadatas: {
intlLabel: {
id: 'color-picker.color.format.rgba',
defaultMessage: 'RGBA',
},
},
},
],
},
],
},
];
addItemsToFormSections(itemsToAdd, sections);
expect(sections.length).toBe(2);
});
});

View File

@ -38,10 +38,10 @@ const FormModalEndActions = ({
onSubmitCreateComponent, onSubmitCreateComponent,
onSubmitCreateDz, onSubmitCreateDz,
onSubmitEditAttribute, onSubmitEditAttribute,
onSubmitEditCusomFieldAttribute,
onSubmitEditCategory, onSubmitEditCategory,
onSubmitEditComponent, onSubmitEditComponent,
onSubmitEditContentType, onSubmitEditContentType,
onSubmitEditCustomFieldAttribute,
onSubmitEditDz, onSubmitEditDz,
}) => { }) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
@ -394,7 +394,7 @@ const FormModalEndActions = ({
onClick={e => { onClick={e => {
e.preventDefault(); e.preventDefault();
onSubmitEditCusomFieldAttribute(e, true); onSubmitEditCustomFieldAttribute(e, true);
}} }}
startIcon={<Plus />} startIcon={<Plus />}
> >
@ -409,7 +409,7 @@ const FormModalEndActions = ({
onClick={e => { onClick={e => {
e.preventDefault(); e.preventDefault();
onSubmitEditCusomFieldAttribute(e, false); onSubmitEditCustomFieldAttribute(e, false);
}} }}
> >
{formatMessage({ {formatMessage({
@ -455,10 +455,10 @@ FormModalEndActions.propTypes = {
onSubmitCreateComponent: PropTypes.func.isRequired, onSubmitCreateComponent: PropTypes.func.isRequired,
onSubmitCreateDz: PropTypes.func.isRequired, onSubmitCreateDz: PropTypes.func.isRequired,
onSubmitEditAttribute: PropTypes.func.isRequired, onSubmitEditAttribute: PropTypes.func.isRequired,
onSubmitEditCusomFieldAttribute: PropTypes.func.isRequired,
onSubmitEditCategory: PropTypes.func.isRequired, onSubmitEditCategory: PropTypes.func.isRequired,
onSubmitEditComponent: PropTypes.func.isRequired, onSubmitEditComponent: PropTypes.func.isRequired,
onSubmitEditContentType: PropTypes.func.isRequired, onSubmitEditContentType: PropTypes.func.isRequired,
onSubmitEditCustomFieldAttribute: PropTypes.func.isRequired,
onSubmitEditDz: PropTypes.func.isRequired, onSubmitEditDz: PropTypes.func.isRequired,
}; };

View File

@ -14,7 +14,6 @@ const FormModalNavigationProvider = ({ children }) => {
return { return {
...prevState, ...prevState,
actionType: 'create', actionType: 'create',
// TODO: Create a new modalType on EXPANSION-245
modalType: 'customField', modalType: 'customField',
attributeType, attributeType,
customFieldUid, customFieldUid,

View File

@ -17,14 +17,6 @@ const FormModalSubHeader = ({
customField, customField,
}) => { }) => {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const type =
modalType === 'customField'
? upperFirst(formatMessage(customField.intlLabel))
: upperFirst(
formatMessage({
id: getTrad(`attribute.${attributeType}`),
})
);
return ( return (
<Typography as="h2" variant="beta"> <Typography as="h2" variant="beta">
@ -40,7 +32,9 @@ const FormModalSubHeader = ({
defaultMessage: 'Add new field', defaultMessage: 'Add new field',
}, },
{ {
type, type: upperFirst(
formatMessage(customField?.intlLabel ?? { id: getTrad(`attribute.${attributeType}`) })
),
name: upperFirst(attributeName), name: upperFirst(attributeName),
step, step,
} }

View File

@ -88,8 +88,12 @@ const formsAPI = {
return sectionsToAdd; return sectionsToAdd;
}, },
makeCustomFieldValidator(initShape, validator, ...validatorArgs) { makeCustomFieldValidator(attributeShape, validator, ...validatorArgs) {
return initShape.shape({ options: yup.object().shape(validator(validatorArgs)) }); // When no validator, return the attribute shape
if (!validator) return attributeShape;
// Otherwise extend the shape with the provided validator
return attributeShape.shape({ options: yup.object().shape(validator(validatorArgs)) });
}, },
makeValidator(target, initShape, ...args) { makeValidator(target, initShape, ...args) {

View File

@ -4,7 +4,6 @@ const _ = require('lodash');
const { formatAttributes, replaceTemporaryUIDs } = require('../utils/attributes'); const { formatAttributes, replaceTemporaryUIDs } = require('../utils/attributes');
const createBuilder = require('./schema-builder'); const createBuilder = require('./schema-builder');
const convertCustomFieldType = require('./utils/convert-custom-field-type');
/** /**
* Formats a component attributes * Formats a component attributes
@ -42,11 +41,9 @@ const createComponent = async ({ component, components = [] }) => {
const uidMap = builder.createNewComponentUIDMap(components); const uidMap = builder.createNewComponentUIDMap(components);
const replaceTmpUIDs = replaceTemporaryUIDs(uidMap); const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
convertCustomFieldType(component.attributes);
const newComponent = builder.createComponent(replaceTmpUIDs(component)); const newComponent = builder.createComponent(replaceTmpUIDs(component));
components.forEach(component => { components.forEach(component => {
convertCustomFieldType(component.attributes);
if (!_.has(component, 'uid')) { if (!_.has(component, 'uid')) {
return builder.createComponent(replaceTmpUIDs(component)); return builder.createComponent(replaceTmpUIDs(component));
} }
@ -70,14 +67,12 @@ const editComponent = async (uid, { component, components = [] }) => {
const uidMap = builder.createNewComponentUIDMap(components); const uidMap = builder.createNewComponentUIDMap(components);
const replaceTmpUIDs = replaceTemporaryUIDs(uidMap); const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
convertCustomFieldType(component.attributes);
const updatedComponent = builder.editComponent({ const updatedComponent = builder.editComponent({
uid, uid,
...replaceTmpUIDs(component), ...replaceTmpUIDs(component),
}); });
components.forEach(component => { components.forEach(component => {
convertCustomFieldType(component.attributes);
if (!_.has(component, 'uid')) { if (!_.has(component, 'uid')) {
return builder.createComponent(replaceTmpUIDs(component)); return builder.createComponent(replaceTmpUIDs(component));
} }

View File

@ -8,7 +8,6 @@ const { ApplicationError } = require('@strapi/utils').errors;
const { formatAttributes, replaceTemporaryUIDs } = require('../utils/attributes'); const { formatAttributes, replaceTemporaryUIDs } = require('../utils/attributes');
const createBuilder = require('./schema-builder'); const createBuilder = require('./schema-builder');
const { coreUids, pluginsUids } = require('./constants'); const { coreUids, pluginsUids } = require('./constants');
const convertCustomFieldType = require('./utils/convert-custom-field-type');
const isContentTypeVisible = model => const isContentTypeVisible = model =>
getOr(true, 'pluginOptions.content-type-builder.visible', model) === true; getOr(true, 'pluginOptions.content-type-builder.visible', model) === true;
@ -85,7 +84,6 @@ const createContentType = async ({ contentType, components = [] }, options = {})
const replaceTmpUIDs = replaceTemporaryUIDs(uidMap); const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
convertCustomFieldType(contentType.attributes);
const newContentType = builder.createContentType(replaceTmpUIDs(contentType)); const newContentType = builder.createContentType(replaceTmpUIDs(contentType));
// allow components to target the new contentType // allow components to target the new contentType
@ -101,7 +99,6 @@ const createContentType = async ({ contentType, components = [] }, options = {})
}; };
components.forEach(component => { components.forEach(component => {
convertCustomFieldType(component.attributes);
const options = replaceTmpUIDs(targetContentType(component)); const options = replaceTmpUIDs(targetContentType(component));
if (!_.has(component, 'uid')) { if (!_.has(component, 'uid')) {
@ -173,15 +170,12 @@ const editContentType = async (uid, { contentType, components = [] }) => {
const uidMap = builder.createNewComponentUIDMap(components); const uidMap = builder.createNewComponentUIDMap(components);
const replaceTmpUIDs = replaceTemporaryUIDs(uidMap); const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
convertCustomFieldType(contentType.attributes);
const updatedContentType = builder.editContentType({ const updatedContentType = builder.editContentType({
uid, uid,
...replaceTmpUIDs(contentType), ...replaceTmpUIDs(contentType),
}); });
components.forEach(component => { components.forEach(component => {
convertCustomFieldType(component.attributes);
if (!_.has(component, 'uid')) { if (!_.has(component, 'uid')) {
return builder.createComponent(replaceTmpUIDs(component)); return builder.createComponent(replaceTmpUIDs(component));
} }

View File

@ -8,6 +8,7 @@ const { nameToSlug, nameToCollectionName } = require('@strapi/utils');
const { ApplicationError } = require('@strapi/utils').errors; const { ApplicationError } = require('@strapi/utils').errors;
const { isConfigurable } = require('../../utils/attributes'); const { isConfigurable } = require('../../utils/attributes');
const createSchemaHandler = require('./schema-handler'); const createSchemaHandler = require('./schema-handler');
const convertCustomFieldType = require('./utils/convert-custom-field-type');
module.exports = function createComponentBuilder() { module.exports = function createComponentBuilder() {
return { return {
@ -32,12 +33,15 @@ module.exports = function createComponentBuilder() {
* create a component in the tmpComponent map * create a component in the tmpComponent map
*/ */
createComponent(infos) { createComponent(infos) {
const { attributes } = infos;
const uid = this.createComponentUID(infos); const uid = this.createComponentUID(infos);
if (this.components.has(uid)) { if (this.components.has(uid)) {
throw new ApplicationError('component.alreadyExists'); throw new ApplicationError('component.alreadyExists');
} }
convertCustomFieldType(attributes);
const handler = createSchemaHandler({ const handler = createSchemaHandler({
dir: path.join(strapi.dirs.components, nameToSlug(infos.category)), dir: path.join(strapi.dirs.components, nameToSlug(infos.category)),
filename: `${nameToSlug(infos.displayName)}.json`, filename: `${nameToSlug(infos.displayName)}.json`,
@ -72,12 +76,13 @@ module.exports = function createComponentBuilder() {
* create a component in the tmpComponent map * create a component in the tmpComponent map
*/ */
editComponent(infos) { editComponent(infos) {
const { uid } = infos; const { uid, attributes } = infos;
if (!this.components.has(uid)) { if (!this.components.has(uid)) {
throw new ApplicationError('component.notFound'); throw new ApplicationError('component.notFound');
} }
convertCustomFieldType(attributes);
const component = this.components.get(uid); const component = this.components.get(uid);
const [, nameUID] = uid.split('.'); const [, nameUID] = uid.split('.');

View File

@ -8,6 +8,7 @@ const { ApplicationError } = require('@strapi/utils').errors;
const { isRelation, isConfigurable } = require('../../utils/attributes'); const { isRelation, isConfigurable } = require('../../utils/attributes');
const { typeKinds } = require('../constants'); const { typeKinds } = require('../constants');
const createSchemaHandler = require('./schema-handler'); const createSchemaHandler = require('./schema-handler');
const convertCustomFieldType = require('./utils/convert-custom-field-type');
const reuseUnsetPreviousProperties = (newAttribute, oldAttribute) => { const reuseUnsetPreviousProperties = (newAttribute, oldAttribute) => {
_.defaults( _.defaults(
@ -71,12 +72,15 @@ module.exports = function createComponentBuilder() {
* @returns {object} new content type * @returns {object} new content type
*/ */
createContentType(infos) { createContentType(infos) {
const { attributes } = infos;
const uid = createContentTypeUID(infos); const uid = createContentTypeUID(infos);
if (this.contentTypes.has(uid)) { if (this.contentTypes.has(uid)) {
throw new ApplicationError('contentType.alreadyExists'); throw new ApplicationError('contentType.alreadyExists');
} }
convertCustomFieldType(attributes);
const contentType = createSchemaHandler({ const contentType = createSchemaHandler({
modelName: infos.singularName, modelName: infos.singularName,
dir: path.join(strapi.dirs.api, infos.singularName, 'content-types', infos.singularName), dir: path.join(strapi.dirs.api, infos.singularName, 'content-types', infos.singularName),
@ -124,12 +128,14 @@ module.exports = function createComponentBuilder() {
}, },
editContentType(infos) { editContentType(infos) {
const { uid } = infos; const { uid, attributes } = infos;
if (!this.contentTypes.has(uid)) { if (!this.contentTypes.has(uid)) {
throw new ApplicationError('contentType.notFound'); throw new ApplicationError('contentType.notFound');
} }
convertCustomFieldType(attributes);
const contentType = this.contentTypes.get(uid); const contentType = this.contentTypes.get(uid);
const oldAttributes = contentType.schema.attributes; const oldAttributes = contentType.schema.attributes;

View File

@ -26,6 +26,16 @@ describe('format attributes', () => {
}, },
}, },
}, },
components: {
'default.test': {
attributes: {
color: {
type: 'customField',
customField: 'plugin::mycustomfields.color',
},
},
},
},
}; };
convertCustomFieldType(global.strapi); convertCustomFieldType(global.strapi);
@ -42,6 +52,16 @@ describe('format attributes', () => {
}, },
}, },
}, },
components: {
'default.test': {
attributes: {
color: {
type: 'text',
customField: 'plugin::mycustomfields.color',
},
},
},
},
}; };
expect(global.strapi).toEqual(expected); expect(global.strapi).toEqual(expected);

View File

@ -1,7 +1,14 @@
'use strict'; 'use strict';
const convertCustomFieldType = strapi => { const convertCustomFieldType = strapi => {
const allSchemasAttributes = Object.values(strapi.contentTypes).map(schema => schema.attributes); const allContentTypeSchemaAttributes = Object.values(strapi.contentTypes).map(
schema => schema.attributes
);
const allComponentSchemaAttributes = Object.values(strapi.components).map(
schema => schema.attributes
);
const allSchemasAttributes = [...allContentTypeSchemaAttributes, ...allComponentSchemaAttributes];
for (const schemaAttrbutes of allSchemasAttributes) { for (const schemaAttrbutes of allSchemasAttributes) {
for (const attribute of Object.values(schemaAttrbutes)) { for (const attribute of Object.values(schemaAttrbutes)) {
if (attribute.type === 'customField') { if (attribute.type === 'customField') {