From bc28d3daf18f1b75484481dd7b8027dffd1e49b5 Mon Sep 17 00:00:00 2001 From: soupette Date: Mon, 25 Nov 2019 14:49:50 +0100 Subject: [PATCH] Allow component creation --- .../src/components/CreatableSelect/index.js | 40 ++++++++----- .../containers/DataManagerProvider/index.js | 12 ++-- .../containers/DataManagerProvider/reducer.js | 23 +++++++- .../admin/src/containers/FormModal/index.js | 48 ++++++++++------ .../containers/FormModal/utils/createUid.js | 7 ++- .../src/containers/FormModal/utils/forms.js | 56 ++++++++++++++++--- .../admin/src/translations/en.json | 3 +- 7 files changed, 141 insertions(+), 48 deletions(-) diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/CreatableSelect/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/CreatableSelect/index.js index 514a7f8682..0855679d09 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/CreatableSelect/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/CreatableSelect/index.js @@ -1,26 +1,32 @@ import React from 'react'; import Creatable from 'react-select/creatable'; import PropTypes from 'prop-types'; -import { - SelectWrapper, - SelectNav, - useGlobalContext, -} from 'strapi-helper-plugin'; +import { SelectWrapper, SelectNav } from 'strapi-helper-plugin'; +import { ErrorMessage } from '@buffetjs/styles'; import useDataManager from '../../hooks/useDataManager'; -const CreatableSelect = ({ label, name }) => { +const CreatableSelect = ({ error, label, onChange, name }) => { const { allComponentsCategories } = useDataManager(); - console.log({ label }); - const { formatMessage } = useGlobalContext(); - const handleInputChange = (newValue, actionMeta) => { - console.log({ actionMeta, newValue }); - console.log(actionMeta); + + const handleChange = (inputValue, actionMeta) => { + const { action } = actionMeta; + + if (action === 'clear') { + onChange({ target: { name, value: '' } }); + } + + if (action === 'create-option' || action === 'select-option') { + onChange({ target: { name, value: inputValue.value } }); + } }; + const styles = { control: (base, state) => ({ ...base, border: state.isFocused ? '1px solid #78caff !important' + : error + ? '1px solid red !important' : '1px solid #E3E9F3 !important', }), menu: base => { @@ -36,7 +42,7 @@ const CreatableSelect = ({ label, name }) => { }; return ( - +
@@ -44,18 +50,24 @@ const CreatableSelect = ({ label, name }) => { + {error && {error}} ); }; +CreatableSelect.defaultProps = { + error: null, +}; + CreatableSelect.propTypes = { + error: PropTypes.string, label: PropTypes.string.isRequired, name: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, }; export default CreatableSelect; 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 aa2bbc52bf..2bf3f63227 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 @@ -93,10 +93,16 @@ const DataManagerProvider = ({ children }) => { }); }; - const createSchema = (data, schemaType, uid) => { + const createSchema = (data, schemaType, uid, componentCategory) => { + const type = + schemaType === 'contentType' + ? 'CREATE_SCHEMA' + : 'CREATE_COMPONENT_SCHEMA'; + dispatch({ - type: 'CREATE_SCHEMA', + type, data, + componentCategory, schemaType, uid, }); @@ -169,8 +175,6 @@ const DataManagerProvider = ({ children }) => { return ; } - console.log({ modifiedData }); - return ( { attributes: {}, }, }; - const key = - action.schemaType === 'contentType' ? 'contentTypes' : 'components'; - return state.updateIn([key, action.uid], () => fromJS(newSchema)); + // const key = + // action.schemaType === 'contentType' ? 'contentTypes' : 'components'; + + return state.updateIn(['contentTypes', action.uid], () => + fromJS(newSchema) + ); + } + case 'CREATE_COMPONENT_SCHEMA': { + const newSchema = { + uid: action.uid, + isTemporary: true, + category: action.componentCategory, + schema: { + ...action.data, + attributes: {}, + }, + }; + return state.updateIn(['components', action.uid], () => + fromJS(newSchema) + ); } case 'EDIT_ATTRIBUTE': { const { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js index 3369f580f7..7ede721f6c 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js @@ -28,7 +28,7 @@ import HeaderNavLink from '../../components/HeaderNavLink'; import getTrad from '../../utils/getTrad'; import getAttributes from './utils/attributes'; import forms from './utils/forms'; -import { createUid } from './utils/createUid'; +import { createComponentUid, createUid } from './utils/createUid'; import init from './init'; import reducer, { initialState } from './reducer'; import RelationForm from '../../components/RelationForm'; @@ -57,6 +57,7 @@ const FormModal = () => { const { addAttribute, contentTypes, + components, createSchema, modifiedData: allDataSchema, sortedContentTypesList, @@ -155,13 +156,14 @@ const FormModal = () => { const checkFormValidity = async () => { let schema; - if (state.modalType === 'contentType' || state.modalType === 'component') { - schema = forms[state.modalType].schema(Object.keys(contentTypes)); - } else if ( - state.modalType === 'attribute' - // && state.forTarget !== 'components' && - // state.forTarget !== 'component' - ) { + if (state.modalType === 'contentType') { + schema = forms.contentType.schema(Object.keys(contentTypes)); + } else if (state.modalType === 'component') { + schema = forms.component.schema( + Object.keys(components), + modifiedData.category || '' + ); + } else if (state.modalType === 'attribute') { const type = state.attributeType === 'relation' ? 'relation' : modifiedData.type; @@ -275,11 +277,12 @@ const FormModal = () => { await checkFormValidity(); const targetUid = state.forTarget === 'components' ? state.targetUid : uid; - - const nextSearch = `modalType=chooseAttribute&forTarget=${ - state.forTarget - }&targetUid=${targetUid}&headerDisplayName=${state.headerDisplayName || - modifiedData.name}`; + const createNextSearch = searchUid => { + return `modalType=chooseAttribute&forTarget=${ + state.forTarget + }&targetUid=${searchUid}&headerDisplayName=${state.headerDisplayName || + modifiedData.name}`; + }; if (state.modalType === 'contentType') { // Create the content type schema @@ -289,7 +292,7 @@ const FormModal = () => { : 'component-categories'; push({ pathname: `/plugins/${pluginId}/${nextSlug}/${uid}`, - search: nextSearch, + search: createNextSearch(targetUid), }); } else if (state.modalType === 'attribute') { addAttribute( @@ -299,9 +302,22 @@ const FormModal = () => { state.actionType === 'edit', initialData ); - push({ search: nextSearch }); + push({ search: createNextSearch(targetUid) }); + } else if (state.modalType === 'component') { + // Create the component schema + const componentUid = createComponentUid( + modifiedData.name, + modifiedData.category + ); + const { category, ...rest } = modifiedData; + createSchema(rest, 'component', componentUid, category); + + push({ + search: createNextSearch(componentUid), + pathname: `/plugins/${pluginId}/component-categories/${category}/${componentUid}`, + }); } else { - console.log('Do something with component later'); + console.log('Do somethign later'); } dispatch({ type: 'RESET_PROPS', diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createUid.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createUid.js index d842624a6e..9ef96ad8b3 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createUid.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/createUid.js @@ -9,4 +9,9 @@ const createUid = name => { return uid; }; -export { createUid, nameToSlug }; +// From `content-type-builder/services/Components/createComponentUid` +const createComponentUid = (name, category) => { + return `${nameToSlug(category)}.${nameToSlug(name)}`; +}; + +export { createComponentUid, createUid, nameToSlug }; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js index 299bfb1f44..7cc8da0477 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js @@ -5,7 +5,7 @@ import { translatedErrors as errorsTrads } from 'strapi-helper-plugin'; import { FormattedMessage } from 'react-intl'; import pluginId from '../../../pluginId'; import getTrad from '../../../utils/getTrad'; -import { createUid, nameToSlug } from './createUid'; +import { createComponentUid, createUid, nameToSlug } from './createUid'; yup.addMethod(yup.mixed, 'defined', function() { return this.test( @@ -18,7 +18,8 @@ yup.addMethod(yup.mixed, 'defined', function() { yup.addMethod(yup.string, 'unique', function( message, alreadyTakenAttributes, - validator + validator, + category = '' ) { return this.test('unique', message, function(string) { if (!string) { @@ -26,7 +27,7 @@ yup.addMethod(yup.string, 'unique', function( } return !alreadyTakenAttributes.includes( - typeof validator === 'function' ? validator(string) : string + typeof validator === 'function' ? validator(string, category) : string ); }); }); @@ -604,8 +605,6 @@ const forms = { ]); } - console.log({ items }); - return { items, }; @@ -676,14 +675,44 @@ const forms = { }, }, component: { - schema(alreadyTakenAttributes) { + schema(alreadyTakenAttributes, componentCategory) { return yup.object().shape({ - name: yup.string().required(), + name: yup + .string() + .unique( + errorsTrads.unique, + alreadyTakenAttributes, + createComponentUid, + componentCategory + ) + .required(), category: yup.string().required(), + icon: yup.string().required(), + collectionName: yup.string(), }); }, form: { - base(data) { + advanced() { + return { + items: [ + [ + { + autoFocus: true, + label: { + id: `${pluginId}.contentType.collectionName.label`, + }, + description: { + id: `${pluginId}.contentType.collectionName.description`, + }, + name: 'collectionName', + type: 'text', + validations: {}, + }, + ], + ], + }; + }, + base() { const defaultItems = [ [ { @@ -706,7 +735,7 @@ const forms = { type: 'creatableSelect', label: { id: getTrad( - 'modalForm.components.create-component.categoryLabel' + 'modalForm.components.create-component.category.label' ), }, validations: { @@ -714,6 +743,15 @@ const forms = { }, }, ], + [ + { + name: 'icon', + type: 'componentIconPicker', + label: { + id: getTrad('modalForm.components.icon.label'), + }, + }, + ], ]; return { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json index 74014af04c..d1c7aebe22 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json @@ -246,5 +246,6 @@ "modalForm.sub-header.chooseAttribute.contentType": "Select a field for your content type", "modalForm.sub-header.attribute.create": "Add new {type} field", "modalForm.sub-header.attribute.edit": "Edit {name}", - "modalForm.components.create-component.categoryLabel": "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" }