diff --git a/examples/getstarted/api/menusection/models/Menusection.settings.json b/examples/getstarted/api/menusection/models/Menusection.settings.json index db3e0d7629..00f896e527 100755 --- a/examples/getstarted/api/menusection/models/Menusection.settings.json +++ b/examples/getstarted/api/menusection/models/Menusection.settings.json @@ -20,7 +20,7 @@ "minLength": 6 }, "dishes": { - "component": "dish", + "component": "default.dish", "type": "component", "repeatable": true }, diff --git a/examples/getstarted/api/restaurant/models/Restaurant.settings.json b/examples/getstarted/api/restaurant/models/Restaurant.settings.json index c5f2f4684b..376825c29c 100755 --- a/examples/getstarted/api/restaurant/models/Restaurant.settings.json +++ b/examples/getstarted/api/restaurant/models/Restaurant.settings.json @@ -47,7 +47,7 @@ "required": true }, "opening_times": { - "component": "openingtimes", + "component": "default.openingtimes", "type": "component", "required": true, "repeatable": true, @@ -55,11 +55,11 @@ "max": 10 }, "closing_period": { - "component": "closingperiod", + "component": "default.closingperiod", "type": "component" }, "services": { - "component": "restaurantservice", + "component": "default.restaurantservice", "required": true, "repeatable": true, "type": "component" @@ -69,6 +69,11 @@ }, "short_description": { "type": "text" + }, + "metas": { + "type": "component", + "component": "seo.meta", + "repeatable": true } } } diff --git a/examples/getstarted/components/closingperiod.json b/examples/getstarted/components/default/closingperiod.json similarity index 92% rename from examples/getstarted/components/closingperiod.json rename to examples/getstarted/components/default/closingperiod.json index 69ef162215..030f738aca 100755 --- a/examples/getstarted/components/closingperiod.json +++ b/examples/getstarted/components/default/closingperiod.json @@ -18,7 +18,7 @@ "required": true }, "dish": { - "component": "dish", + "component": "default.dish", "type": "component" } } diff --git a/examples/getstarted/components/dish.json b/examples/getstarted/components/default/dish.json similarity index 100% rename from examples/getstarted/components/dish.json rename to examples/getstarted/components/default/dish.json diff --git a/examples/getstarted/components/openingtimes.json b/examples/getstarted/components/default/openingtimes.json similarity index 100% rename from examples/getstarted/components/openingtimes.json rename to examples/getstarted/components/default/openingtimes.json diff --git a/examples/getstarted/components/restaurantservice.json b/examples/getstarted/components/default/restaurantservice.json similarity index 100% rename from examples/getstarted/components/restaurantservice.json rename to examples/getstarted/components/default/restaurantservice.json diff --git a/examples/getstarted/components/seo/meta.json b/examples/getstarted/components/seo/meta.json new file mode 100755 index 0000000000..b076ad44d0 --- /dev/null +++ b/examples/getstarted/components/seo/meta.json @@ -0,0 +1,16 @@ +{ + "info": { + "name": "meta", + "description": "" + }, + "connection": "default", + "collectionName": "seo_meta", + "attributes": { + "key": { + "type": "string" + }, + "value": { + "type": "text" + } + } +} diff --git a/packages/strapi-plugin-content-type-builder/controllers/Components.js b/packages/strapi-plugin-content-type-builder/controllers/Components.js index 42c7b09e44..8b29eede4d 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/Components.js +++ b/packages/strapi-plugin-content-type-builder/controllers/Components.js @@ -51,7 +51,7 @@ module.exports = { } const service = strapi.plugins['content-type-builder'].services.components; - const uid = service.createComponentUID(body.name); + const uid = service.createComponentUID(body); if (service.getComponent(uid)) { return ctx.send({ error: 'component.alreadyExists' }, 400); diff --git a/packages/strapi-plugin-content-type-builder/controllers/validation/component.js b/packages/strapi-plugin-content-type-builder/controllers/validation/component.js index 4eb4602b33..ac545b092c 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/validation/component.js +++ b/packages/strapi-plugin-content-type-builder/controllers/validation/component.js @@ -22,8 +22,16 @@ const componentSchema = yup name: yup .string() .min(1) - .test(isValidName) .required('name.required'), + icon: yup + .string() + .test(isValidName) + .required('icon.required'), + category: yup + .string() + .min(3) + .test(isValidName) + .required('category.required'), description: yup.string(), connection: yup.string(), collectionName: yup diff --git a/packages/strapi-plugin-content-type-builder/services/Components.js b/packages/strapi-plugin-content-type-builder/services/Components.js index a1eaab1748..100bde3ab3 100644 --- a/packages/strapi-plugin-content-type-builder/services/Components.js +++ b/packages/strapi-plugin-content-type-builder/services/Components.js @@ -1,6 +1,8 @@ 'use strict'; +const path = require('path'); const _ = require('lodash'); +const fse = require('fs-extra'); const pluralize = require('pluralize'); const slugify = require('@sindresorhus/slugify'); @@ -30,11 +32,13 @@ const getComponent = uid => { * @param {Object} component - strapi component model */ const formatComponent = (uid, component) => { - const { connection, collectionName, attributes, info } = component; + const { connection, collectionName, attributes, info, category } = component; return { uid, + category, schema: { + icon: _.get(info, 'icon'), name: _.get(info, 'name') || _.upperFirst(pluralize(uid)), description: _.get(info, 'description', ''), connection, @@ -104,9 +108,10 @@ const formatAttribute = (key, attribute, { component }) => { * @param {Object} infos */ async function createComponent(uid, infos) { + const { name, category } = infos; const schema = createSchema(uid, infos); - await writeSchema(uid, schema); + await writeSchema({ name, schema, category }); return { uid }; } @@ -156,6 +161,8 @@ async function updateComponent(component, infos) { const createSchema = (uid, infos) => { const { name, + icon, + category, connection = _.get( strapi, ['config', 'currentEnvironment', 'database', 'defaultConnection'], @@ -170,10 +177,11 @@ const createSchema = (uid, infos) => { info: { name, description, + icon, }, connection, collectionName: - collectionName || `components_${pluralize(uid).toLowerCase()}`, + collectionName || `components_${category}_${nameToSlug(pluralize(name))}`, attributes: convertAttributes(attributes), }; }; @@ -224,7 +232,14 @@ const convertAttributes = attributes => { * Returns a uid from a string * @param {string} str - string to slugify */ -const createComponentUID = str => slugify(str, { separator: '_' }); +const createComponentUID = ({ category, name }) => + `${category}.${nameToSlug(name)}`; + +/** + * Converts a name to a slug + * @param {string} name a name to convert + */ +const nameToSlug = name => slugify(name, { separator: '_' }); /** * Deletes a component @@ -237,11 +252,17 @@ async function deleteComponent(component) { /** * Writes a component schema file */ -async function writeSchema(uid, schema) { - await strapi.fs.writeAppFile( - `components/${uid}.json`, - JSON.stringify(schema, null, 2) - ); +async function writeSchema({ name, schema, category }) { + const categoryDir = path.join(strapi.dir, 'components', category); + + if (!(await fse.pathExists(categoryDir))) { + await fse.mkdir(categoryDir); + } + + const filename = nameToSlug(name); + const filepath = path.join(categoryDir, `${filename}.json`); + + await fse.writeFile(filepath, JSON.stringify(schema, null, 2)); } /** diff --git a/packages/strapi/lib/core/load-components.js b/packages/strapi/lib/core/load-components.js index d97ab94437..7ba603456f 100644 --- a/packages/strapi/lib/core/load-components.js +++ b/packages/strapi/lib/core/load-components.js @@ -11,5 +11,14 @@ module.exports = async ({ dir }) => { return {}; } - return await loadFiles(componentsDir, '*.*(js|json)'); + const map = await loadFiles(componentsDir, '*/*.*(js|json)'); + + return Object.keys(map).reduce((acc, category) => { + Object.keys(map[category]).forEach(key => { + acc[`${category}.${key}`] = Object.assign(map[category][key], { + category, + }); + }); + return acc; + }, {}); };