diff --git a/packages/strapi-plugin-content-manager/admin/src/components/EditFormRelation/index.js b/packages/strapi-plugin-content-manager/admin/src/components/EditFormRelation/index.js index 859d506a99..f3ce03e09a 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/EditFormRelation/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/EditFormRelation/index.js @@ -40,7 +40,7 @@ class EditFormRelation extends React.Component { // eslint-disable-line react/pr } // Request URL - const requestUrlSuffix = query ? '' : this.props.record.get(this.props.relation.attribute); + const requestUrlSuffix = query && this.props.record.get(this.props.relation.attribute) ? this.props.record.get(this.props.relation.attribute) : ''; const requestUrl = `/content-manager/explorer/${this.props.relation.model}/${requestUrlSuffix}`; // Call our request helper (see 'utils/request') @@ -51,11 +51,11 @@ class EditFormRelation extends React.Component { // eslint-disable-line react/pr .then(response => { const options = _.isArray(response) ? _.map(response, item => ({ - value: Number(item.id), + value: item.id, label: item[this.props.relation.displayedAttribute], })) : [{ - value: Number(response.id), + value: response.id, label: response[this.props.relation.displayedAttribute], }]; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/App/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/App/index.js index 4928092247..7a48cd8f4c 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/App/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/App/index.js @@ -8,21 +8,33 @@ import React from 'react'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; +import _ from 'lodash'; -import config from '../../../../config/admin.json'; import { loadModels, updateSchema } from './actions'; -import { makeSelectModels, makeSelectLoading } from './selectors'; +import { makeSelectLoading } from './selectors'; + +const tryRequire = (path) => { + try { + return require(`containers/${path}.js`); // eslint-disable-line global-require + } catch (err) { + return null; + } +}; class App extends React.Component { componentWillMount() { - this.props.loadModels(); - this.props.updateSchema(config.admin.schema); + const config = tryRequire('../../../../config/admin.json'); + if (!_.isEmpty(_.get(config, 'admin.schema'))) { + this.props.updateSchema(config.admin.schema); + } else { + this.props.loadModels(); + } } render() { let content =
; - if (this.props.models) { + if (!this.props.loading) { // Assign plugin component to children content = React.Children.map(this.props.children, child => React.cloneElement(child, { @@ -46,11 +58,8 @@ App.contextTypes = { App.propTypes = { children: React.PropTypes.node.isRequired, exposedComponents: React.PropTypes.object.isRequired, + loading: React.PropTypes.bool, loadModels: React.PropTypes.func.isRequired, - models: React.PropTypes.oneOfType([ - React.PropTypes.object, - React.PropTypes.bool, - ]), updateSchema: React.PropTypes.func.isRequired, }; @@ -63,7 +72,6 @@ export function mapDispatchToProps(dispatch) { } const mapStateToProps = createStructuredSelector({ - models: makeSelectModels(), loading: makeSelectLoading(), }); diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/App/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/App/reducer.js index cb3faf9457..304a862440 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/App/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/App/reducer.js @@ -9,7 +9,7 @@ import { fromJS } from 'immutable'; import { LOAD_MODELS, LOADED_MODELS, UPDATE_SCHEMA } from './constants'; const initialState = fromJS({ - loading: false, + loading: true, models: false, schema: false, }); @@ -17,11 +17,14 @@ const initialState = fromJS({ function appReducer(state = initialState, action) { switch (action.type) { case LOAD_MODELS: - return state.set('loading', true); + return state; case LOADED_MODELS: - return state.set('loading', false).set('models', action.models); + return state + .set('models', action.models); case UPDATE_SCHEMA: - return state.set('schema', action.schema); + return state + .set('loading', false) + .set('schema', action.schema); default: return state; } diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/App/sagas.js b/packages/strapi-plugin-content-manager/admin/src/containers/App/sagas.js index 3d7316261a..ce124c50a3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/App/sagas.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/App/sagas.js @@ -1,9 +1,13 @@ import _ from 'lodash'; -import {takeLatest} from 'redux-saga'; -import {fork, put} from 'redux-saga/effects'; +import { takeLatest } from 'redux-saga'; +import { fork, put, select } from 'redux-saga/effects'; + +import { generateSchema } from 'utils/schema'; + +import { loadedModels, updateSchema } from './actions'; +import { LOAD_MODELS, LOADED_MODELS, UPDATE_SCHEMA } from './constants'; +import { makeSelectModels } from './selectors'; -import {loadedModels} from './actions'; -import {LOAD_MODELS, UPDATE_SCHEMA} from './constants'; export function* getModels() { try { @@ -26,6 +30,22 @@ export function* getModels() { } } +export function* modelsLoaded() { + const models = yield select(makeSelectModels()); + let schema; + + try { + schema = generateSchema(models); + } catch (err) { + window.Strapi.notification.error( + 'An error occurred during schema generation.' + ); + throw new Error(err); + } + + yield put(updateSchema(schema)); +} + export function* schemaUpdated(action) { // Display the links only if the `displayed` attribute is not set to false const displayedModels = _.pickBy(action.schema, model => (model.displayed !== false)); @@ -44,6 +64,7 @@ export function* schemaUpdated(action) { export function* defaultSaga() { yield fork(takeLatest, LOAD_MODELS, getModels); yield fork(takeLatest, UPDATE_SCHEMA, schemaUpdated); + yield fork(takeLatest, LOADED_MODELS, modelsLoaded); } // All sagas to be loaded diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/schema.js b/packages/strapi-plugin-content-manager/admin/src/utils/schema.js new file mode 100644 index 0000000000..e5c9bf0ee9 --- /dev/null +++ b/packages/strapi-plugin-content-manager/admin/src/utils/schema.js @@ -0,0 +1,56 @@ +import _ from 'lodash'; +import pluralize from 'pluralize'; + +/** + * Generate a schema according to the models + * of the Strapi application. + * + * @param models + */ +const generateSchema = (models) => { + // Init `schema` object + const schema = {}; + + _.forEach(models, (model, name) => { + // Model data + const schemaModel = { + label: _.upperFirst(name), + labelPlural: _.upperFirst(pluralize(name)), + orm: model.orm || 'mongoose', + }; + + // Fields (non relation) + schemaModel.fields = _.mapValues(_.pickBy(model.attributes, attribute => + !attribute.model && !attribute.collection + ), (value, attribute) => ({ + label: _.upperFirst(attribute), + description: '', + type: value.type || 'string', + })); + + // Select fields displayed in list view + schemaModel.list = _.slice(_.keys(schemaModel.fields), 0, 4); + + // Model relations + schemaModel.relations = _.mapValues(_.pickBy(model.attributes, attribute => + attribute.model + ), (value, attribute) => ({ + columnName: attribute, + model: value.model, + attribute, + label: _.upperFirst(attribute), + description: '', + displayedAttribute: _.findKey(models[value.model].attributes, { type: 'string' }) || 'id', + }) + ); + + // Set the formatted model to the schema + schema[name] = schemaModel; + }); + + return schema; +}; + +export { + generateSchema, +}; \ No newline at end of file diff --git a/packages/strapi-plugin-content-manager/controllers/ContentManager.js b/packages/strapi-plugin-content-manager/controllers/ContentManager.js index 2187021256..40ab989e98 100644 --- a/packages/strapi-plugin-content-manager/controllers/ContentManager.js +++ b/packages/strapi-plugin-content-manager/controllers/ContentManager.js @@ -23,7 +23,7 @@ module.exports = { find: async ctx => { const model = strapi.models[ctx.params.model]; - const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']); + const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']) || model.orm; const queries = _.get(strapi.plugins, ['content-manager', 'config', 'queries', orm]); const primaryKey = model.primaryKey; const {limit, skip = 0, sort = primaryKey, query, queryAttribute} = ctx.request.query; @@ -44,7 +44,7 @@ module.exports = { count: async ctx => { const model = strapi.models[ctx.params.model]; - const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']); + const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']) || model.orm; const queries = _.get(strapi.plugins, ['content-manager', 'config', 'queries', orm]); // Count using `queries` system @@ -57,7 +57,7 @@ module.exports = { findOne: async ctx => { const model = strapi.models[ctx.params.model]; - const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']); + const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']) || model.orm; const queries = _.get(strapi.plugins, ['content-manager', 'config', 'queries', orm]); const primaryKey = model.primaryKey; const id = ctx.params.id; @@ -79,7 +79,7 @@ module.exports = { create: async ctx => { const model = strapi.models[ctx.params.model]; - const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']); + const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']) || model.orm; const queries = _.get(strapi.plugins, ['content-manager', 'config', 'queries', orm]); const values = ctx.request.body; @@ -94,7 +94,7 @@ module.exports = { update: async ctx => { const model = strapi.models[ctx.params.model]; - const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']); + const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']) || model.orm; const queries = _.get(strapi.plugins, ['content-manager', 'config', 'queries', orm]); const primaryKey = model.primaryKey; const id = ctx.params.id; @@ -113,7 +113,7 @@ module.exports = { delete: async ctx => { const model = strapi.models[ctx.params.model]; - const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']); + const orm = _.get(strapi.plugins, ['content-manager', 'config', 'admin', 'schema', ctx.params.model, 'orm']) || model.orm; const queries = _.get(strapi.plugins, ['content-manager', 'config', 'queries', orm]); const primaryKey = model.primaryKey; const id = ctx.params.id;