diff --git a/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js b/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js index 0fb8a45fb1..61a0caf3fb 100755 --- a/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuLink/index.js @@ -20,7 +20,13 @@ class LeftMenuLink extends React.Component { // eslint-disable-line react/prefer return (
{pluginsSections[current].name}
Loading...
; } + const source = getQueryParameters(this.props.location.search, 'source'); + const currentModel = get(this.props.models, ['models', this.props.currentModelName]) || get(this.props.models, ['plugins', source, 'models', this.props.currentModelName]); + // Plugin header config - const primaryKey = this.props.models[this.props.currentModelName].primaryKey; - const mainField = get(this.props.models, `${this.props.currentModelName}.info.mainField`) || primaryKey; + const primaryKey = currentModel.primaryKey; + const mainField = get(currentModel, 'info.mainField') || primaryKey; const pluginHeaderTitle = this.props.isCreating ? 'New entry' : templateObject({ mainField }, this.props.record.toJS()).mainField; const pluginHeaderDescription = this.props.isCreating ? 'New entry' : `#${this.props.record && this.props.record.get(primaryKey)}`; @@ -192,6 +207,7 @@ export class Edit extends React.Component { didCheckErrors={this.props.didCheckErrors} formValidations={this.props.formValidations.toJS()} layout={this.layout} + location={this.props.location} /> @@ -204,6 +220,7 @@ export class Edit extends React.Component { setRecordAttribute={this.props.setRecordAttribute} isNull={this.props.isRelationComponentNull} toggleNull={this.props.toggleNull} + location={this.props.location} /> diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js b/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js index e870f816a6..ca0fde4a50 100755 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Edit/sagas.js @@ -19,15 +19,21 @@ import { makeSelectIsCreating, } from './selectors'; -export function* getRecord(params) { +export function* getRecord(action) { const currentModelName = yield select(makeSelectCurrentModelName()); + const params = {}; + + if (action.source !== undefined) { + params.source = action.source; + } try { - const requestUrl = `${strapi.backendURL}/content-manager/explorer/${currentModelName}/${params.id}`; + const requestUrl = `${strapi.backendURL}/content-manager/explorer/${currentModelName}/${action.id}`; // Call our request helper (see 'utils/request') const response = yield request(requestUrl, { method: 'GET', + params, }); yield put(recordLoaded(response)); @@ -36,7 +42,7 @@ export function* getRecord(params) { } } -export function* editRecord() { +export function* editRecord(action) { const currentModelName = yield select(makeSelectCurrentModelName()); const record = yield select(makeSelectRecord()); const recordJSON = record.toJSON(); @@ -49,6 +55,11 @@ export function* editRecord() { const isCreating = yield select(makeSelectIsCreating()); const id = isCreating ? '' : recordCleaned.id; + const params = {}; + + if (action.source !== undefined) { + params.source = action.source; + } try { const requestUrl = `${strapi.backendURL}/content-manager/explorer/${currentModelName}/${id}`; @@ -57,6 +68,7 @@ export function* editRecord() { yield call(request, requestUrl, { method: isCreating ? 'POST' : 'PUT', body: recordCleaned, + params, }); yield put(recordEdited()); @@ -67,21 +79,31 @@ export function* editRecord() { } } -export function* deleteRecord({ id, modelName }) { +export function* deleteRecord({ id, modelName, source }) { function* httpCall(id, modelName) { try { const requestUrl = `${strapi.backendURL}/content-manager/explorer/${modelName}/${id}`; + const params = {}; + if (action.source !== undefined) { + params.source = action.source; + } // Call our request helper (see 'utils/request') yield call(request, requestUrl, { method: 'DELETE', + params, }); yield put(recordDeleted(id)); strapi.notification.success('content-manager.success.record.delete'); // Redirect to the list page. - router.push(`/plugins/content-manager/${modelName}`); + router.push({ + pathname: `/plugins/content-manager/${modelName}`, + state: { + source, + }, + }); } catch (err) { yield put(recordDeleteError()); strapi.notification.error('content-manager.error.record.delete'); diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/List/actions.js b/packages/strapi-plugin-content-manager/admin/src/containers/List/actions.js index b5671067f0..0daef010c6 100755 --- a/packages/strapi-plugin-content-manager/admin/src/containers/List/actions.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/List/actions.js @@ -42,15 +42,17 @@ export function changeSort(sort) { }; } -export function loadCount() { +export function loadCount(source) { return { type: LOAD_COUNT, + source, }; } -export function loadRecords() { +export function loadRecords(source) { return { type: LOAD_RECORDS, + source, }; } diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/List/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/List/index.js index f1d39a5c90..8f44c81d4d 100755 --- a/packages/strapi-plugin-content-manager/admin/src/containers/List/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/List/index.js @@ -9,7 +9,7 @@ import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; import { createStructuredSelector } from 'reselect'; import PropTypes from 'prop-types'; -import { isEmpty, isUndefined, map, replace, split } from 'lodash'; +import { isEmpty, isUndefined, map, get, toInteger } from 'lodash'; import { router } from 'app'; // Selectors. @@ -24,6 +24,9 @@ import PopUpWarning from 'components/PopUpWarning'; import injectReducer from 'utils/injectReducer'; import injectSaga from 'utils/injectSaga'; +// Utils +import getQueryParameters from 'utils/getQueryParameters'; + // Actions. import { deleteRecord, @@ -88,24 +91,24 @@ export class List extends React.Component { // Set current model name this.props.setCurrentModelName(slug.toLowerCase()); - const searchParams = split(replace(props.location.search, '?', ''), '&'); + const source = getQueryParameters(props.location.search, 'source'); - const sort = isEmpty(props.location.search) ? - this.props.models[slug.toLowerCase()].primaryKey || 'id' : - replace(searchParams[2], 'sort=', ''); + const sort = (isEmpty(props.location.search) ? + get(this.props.models, ['models', slug.toLowerCase(), 'primaryKey']) || get(this.props.models.plugins, [source, 'models', slug.toLowerCase(), 'primaryKey']) : + getQueryParameters('sort')) || 'id'; if (!isEmpty(props.location.search)) { - this.props.changePage(parseInt(replace(searchParams[0], 'page=', ''), 10)); - this.props.changeLimit(parseInt(replace(searchParams[1], 'limit=', ''), 10)); + this.props.changePage(toInteger(getQueryParameters('page'))); + this.props.changeLimit(toInteger(getQueryParameters('limit'))); } this.props.changeSort(sort); // Load records - this.props.loadRecords(); + this.props.loadRecords(source); // Get the records count - this.props.loadCount(); + this.props.loadCount(source); // Define the `create` route url this.addRoute = `${this.props.match.path.replace(':slug', slug)}/create`; @@ -139,7 +142,9 @@ export class List extends React.Component { e.preventDefault(); e.stopPropagation(); - this.props.deleteRecord(this.state.target, this.props.currentModelName); + const source = getQueryParameters(this.props.location.search, 'source'); + + this.props.deleteRecord(this.state.target, this.props.currentModelName, source); this.setState({ showWarning: false }); } @@ -156,18 +161,20 @@ export class List extends React.Component { } render() { - if (!this.props.currentModelName || !this.props.schema) { + // Detect current model structure from models list + const source = getQueryParameters(this.props.location.search, 'source'); + const currentModel = get(this.props.models, ['models', this.props.currentModelName]) || get(this.props.models, ['plugins', source, 'models', this.props.currentModelName]); + const currentSchema = get(this.props.schema, [this.props.currentModelName]) || get(this.props.schema, ['plugins', source, this.props.currentModelName]); + + if (!this.props.currentModelName || !currentSchema) { return ; } - // Detect current model structure from models list - const currentModel = this.props.models[this.props.currentModelName]; - // Define table headers - const tableHeaders = map(this.props.schema[this.props.currentModelName].list, (value) => ({ + const tableHeaders = map(currentSchema.list, (value) => ({ name: value, - label: this.props.schema[this.props.currentModelName].fields[value].label, - type: this.props.schema[this.props.currentModelName].fields[value].type, + label: currentSchema.fields[value].label, + type: currentSchema.fields[value].type, })); tableHeaders.splice(0, 0, { name: currentModel.primaryKey || 'id', label: 'Id', type: 'string' }); @@ -183,12 +190,12 @@ export class List extends React.Component { history={this.props.history} primaryKey={currentModel.primaryKey || 'id'} handleDelete={this.toggleModalWarning} - redirectUrl={`?redirectUrl=/plugins/content-manager/${this.props.currentModelName.toLowerCase()}/?page=${this.props.currentPage}&limit=${this.props.limit}&sort=${this.props.sort}`} + redirectUrl={`?redirectUrl=/plugins/content-manager/${this.props.currentModelName.toLowerCase()}/?page=${this.props.currentPage}&limit=${this.props.limit}&sort=${this.props.sort}&source=${source}`} /> ); // Plugin header config - const pluginHeaderTitle = this.props.schema[this.props.currentModelName].label || 'Content Manager'; + const pluginHeaderTitle = currentSchema.label || 'Content Manager'; // Define plugin header actions const pluginHeaderActions = [ diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/List/sagas.js b/packages/strapi-plugin-content-manager/admin/src/containers/List/sagas.js index b4776238d0..910b3e74eb 100755 --- a/packages/strapi-plugin-content-manager/admin/src/containers/List/sagas.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/List/sagas.js @@ -25,7 +25,7 @@ import { makeSelectSort, } from './selectors'; -export function* getRecords() { +export function* getRecords(action) { const currentModel = yield select(makeSelectCurrentModelName()); const limit = yield select(makeSelectLimit()); const currentPage = yield select(makeSelectCurrentPage()); @@ -40,6 +40,10 @@ export function* getRecords() { sort, }; + if (action.source !== undefined) { + params.source = action.source; + } + try { const requestUrl = `${strapi.backendURL}/content-manager/explorer/${currentModel}`; // Call our request helper (see 'utils/request') @@ -54,14 +58,19 @@ export function* getRecords() { } } -export function* getCount() { +export function* getCount(action) { const currentModel = yield select(makeSelectCurrentModelName()); + const params = {}; + + if (action.source !== undefined) { + params.source = action.source; + } try { - const response = yield call( - request, - `${strapi.backendURL}/content-manager/explorer/${currentModel}/count`, - ); + const response = yield call(request,`${strapi.backendURL}/content-manager/explorer/${currentModel}/count`, { + method: 'GET', + params, + }); yield put(loadedCount(response.count)); } catch (err) { diff --git a/packages/strapi-plugin-content-manager/admin/src/utils/schema.js b/packages/strapi-plugin-content-manager/admin/src/utils/schema.js index a3a0fdb5e0..b6f84d3454 100755 --- a/packages/strapi-plugin-content-manager/admin/src/utils/schema.js +++ b/packages/strapi-plugin-content-manager/admin/src/utils/schema.js @@ -1,4 +1,4 @@ -import { forEach, upperFirst, mapValues, pickBy, slice, findKey, keys, get } from 'lodash'; +import { forEach, upperFirst, mapValues, pickBy, slice, findKey, keys, get, set } from 'lodash'; import pluralize from 'pluralize'; /** @@ -7,11 +7,13 @@ import pluralize from 'pluralize'; * * @param models */ -const generateSchema = (models) => { +const generateSchema = (responses) => { // Init `schema` object - const schema = {}; + const schema = { + plugins: {}, + }; - forEach(models, (model, name) => { + const buildSchema = (model, name, plugin = false) => { // Model data const schemaModel = { label: upperFirst(name), @@ -46,8 +48,24 @@ const generateSchema = (models) => { }, {}); } + if (plugin) { + return set(schema.plugins, `${plugin}.${name}`, schemaModel); + } + // Set the formatted model to the schema schema[name] = schemaModel; + }; + + // Generate schema for plugins. + forEach(responses.plugins, (plugin, pluginName) => { + forEach(plugin.models, (model, name) => { + buildSchema(model, name, pluginName); + }); + }); + + // Generate schema for models. + forEach(responses.models, (model, name) => { + buildSchema(model, name); }); return schema; diff --git a/packages/strapi-plugin-content-manager/controllers/ContentManager.js b/packages/strapi-plugin-content-manager/controllers/ContentManager.js index f5fcb6fe9d..8481040c27 100755 --- a/packages/strapi-plugin-content-manager/controllers/ContentManager.js +++ b/packages/strapi-plugin-content-manager/controllers/ContentManager.js @@ -8,28 +8,37 @@ const _ = require('lodash'); module.exports = { models: async ctx => { - ctx.body = _.mapValues(strapi.models, model => - _.pick(model, [ - 'info', - 'connection', - 'collectionName', - 'attributes', - 'identity', - 'globalId', - 'globalName', - 'orm', - 'loadedModel', - 'primaryKey', - 'associations' - ]) - ); + const pickData = (model) => _.pick(model, [ + 'info', + 'connection', + 'collectionName', + 'attributes', + 'identity', + 'globalId', + 'globalName', + 'orm', + 'loadedModel', + 'primaryKey', + 'associations' + ]); + + ctx.body = { + models: _.mapValues(strapi.models, pickData), + plugins: Object.keys(strapi.plugins).reduce((acc, current) => { + acc[current] = { + models: _.mapValues(strapi.plugins[current].models, pickData) + }; + + return acc; + }, {}) + }; }, find: async ctx => { - const { limit, skip = 0, sort, query, queryAttribute } = ctx.request.query; + const { limit, skip = 0, sort, query, queryAttribute, source } = ctx.request.query; // Find entries using `queries` system - const entries = await strapi.query(ctx.params.model).find({ + const entries = await strapi.query(ctx.params.model, source).find({ limit, skip, sort, @@ -41,8 +50,10 @@ module.exports = { }, count: async ctx => { + const { source } = ctx.request.query; + // Count using `queries` system - const count = await strapi.query(ctx.params.model).count(); + const count = await strapi.query(ctx.params.model, source).count(); ctx.body = { count: _.isNumber(count) ? count : _.toNumber(count) @@ -50,8 +61,10 @@ module.exports = { }, findOne: async ctx => { + const { source } = ctx.request.query; + // Find an entry using `queries` system - const entry = await strapi.query(ctx.params.model).findOne({ + const entry = await strapi.query(ctx.params.model, source).findOne({ id: ctx.params.id }); @@ -64,8 +77,10 @@ module.exports = { }, create: async ctx => { + const { source } = ctx.request.query; + // Create an entry using `queries` system - const entryCreated = await strapi.query(ctx.params.model).create({ + const entryCreated = await strapi.query(ctx.params.model, source).create({ values: ctx.request.body }); @@ -73,8 +88,10 @@ module.exports = { }, update: async ctx => { + const { source } = ctx.request.query; + // Add current model to the flow of updates. - const entry = strapi.query(ctx.params.model).update({ + const entry = strapi.query(ctx.params.model, source).update({ id: ctx.params.id, values: ctx.request.body }); @@ -84,7 +101,9 @@ module.exports = { }, delete: async ctx => { + const { source } = ctx.request.query; const params = ctx.params; + const response = await strapi.query(params.model).findOne({ id: params.id }); @@ -102,11 +121,11 @@ module.exports = { if (!_.isEmpty(params.values)) { // Run update to remove all relationships. - await strapi.query(params.model).update(params); + await strapi.query(params.model, source).update(params); } // Delete an entry using `queries` system - const entryDeleted = await strapi.query(params.model).delete({ + const entryDeleted = await strapi.query(params.model, source).delete({ id: params.id }); diff --git a/packages/strapi-plugin-users-permissions/admin/src/bootstrap.js b/packages/strapi-plugin-users-permissions/admin/src/bootstrap.js index 7b02cb89b0..8807e96c4c 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/bootstrap.js +++ b/packages/strapi-plugin-users-permissions/admin/src/bootstrap.js @@ -11,9 +11,9 @@ const bootstrap = (plugin) => new Promise((resolve, reject) => { links: [{ label: 'Users', destination: 'user', - plugin: 'content-manager' + plugin: 'content-manager', }], - name: 'Content Types' + name: 'Content Types', }); return resolve(plugin); diff --git a/packages/strapi-plugin-users-permissions/config/roles.json b/packages/strapi-plugin-users-permissions/config/roles.json index 2e22c65787..afd9f7f7d9 100644 --- a/packages/strapi-plugin-users-permissions/config/roles.json +++ b/packages/strapi-plugin-users-permissions/config/roles.json @@ -6,6 +6,10 @@ "content-manager": { "controllers": { "contentmanager": { + "identity": { + "enabled": false, + "policy": "" + }, "models": { "enabled": false, "policy": "" @@ -33,10 +37,6 @@ "delete": { "enabled": false, "policy": "" - }, - "identity": { - "enabled": false, - "policy": "" } } } diff --git a/scripts/test.sh b/scripts/test.sh index 178a61f44a..a70b27d652 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -22,3 +22,7 @@ npm run test # Test `strapi-plugin-content-type-builder` cd ../strapi-plugin-content-type-builder npm run test + +# Test `strapi-plugin-content-type-builder` +cd ../strapi-plugin-users-permissions +npm run test