mirror of
https://github.com/strapi/strapi.git
synced 2025-10-11 08:02:55 +00:00
Handle plugin model in Content Manager
This commit is contained in:
parent
1c2f625a2b
commit
eceede450b
@ -20,7 +20,13 @@ class LeftMenuLink extends React.Component { // eslint-disable-line react/prefer
|
||||
|
||||
return (
|
||||
<li className={styles.item}>
|
||||
<Link className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`} to={this.props.destination}>
|
||||
<Link
|
||||
className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`}
|
||||
to={{
|
||||
pathname: this.props.destination,
|
||||
search: `?source=${this.props.source}`,
|
||||
}}
|
||||
>
|
||||
<i className={`${styles.linkIcon} fa-${this.props.icon} fa`}></i>
|
||||
<FormattedMessage
|
||||
id={this.props.label}
|
||||
@ -40,6 +46,11 @@ LeftMenuLink.propTypes = {
|
||||
destination: PropTypes.string.isRequired,
|
||||
icon: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
source: PropTypes.string,
|
||||
};
|
||||
|
||||
LeftMenuLink.defaultProps = {
|
||||
source: '',
|
||||
};
|
||||
|
||||
export default LeftMenuLink;
|
||||
|
@ -23,7 +23,8 @@ function LeftMenuLinkContainer({ plugins }) {
|
||||
acc[snakeCase(section.name)] = {
|
||||
name: section.name,
|
||||
links: (get(acc[snakeCase(section.name)], 'links') || []).concat(section.links.map(link => {
|
||||
link.plugin = !isEmpty(pluginsObject[link.plugin] ? link.plugin : pluginsObject[current].id);
|
||||
link.source = current;
|
||||
link.plugin = !isEmpty(pluginsObject[link.plugin]) ? link.plugin : pluginsObject[current].id;
|
||||
|
||||
return link;
|
||||
})),
|
||||
@ -38,7 +39,7 @@ function LeftMenuLinkContainer({ plugins }) {
|
||||
<p className={styles.title}>{pluginsSections[current].name}</p>
|
||||
<ul className={styles.list}>
|
||||
{sortBy(pluginsSections[current].links, 'label').map(link =>
|
||||
<LeftMenuLink key={link.label} icon={link.icon || 'link'} label={link.label} destination={`/plugins/${link.plugin}/${link.destination}`} />
|
||||
<LeftMenuLink key={link.label} icon={link.icon || 'link'} label={link.label} destination={`/plugins/${link.plugin}/${link.destination}`} source={link.source} />
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -0,0 +1,4 @@
|
||||
export default (location, n) => {
|
||||
const half = location.split(n + '=')[1];
|
||||
return half !== undefined ? decodeURIComponent(half.split('&')[0]) : null;
|
||||
};
|
@ -12,6 +12,9 @@ import { findIndex, get, omit, isFunction, merge } from 'lodash';
|
||||
// Components.
|
||||
import Input from 'components/Input';
|
||||
|
||||
// Utils.
|
||||
import getQueryParameters from 'utils/getQueryParameters';
|
||||
|
||||
// Styles.
|
||||
import styles from './styles.scss';
|
||||
|
||||
@ -42,8 +45,12 @@ class EditForm extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const source = getQueryParameters(this.props.location.search, 'source');
|
||||
const currentSchema = get(this.props.schema, [this.props.currentModelName]) || get(this.props.schema, ['plugins', source, this.props.currentModelName]);
|
||||
const currentLayout = source === undefined || source === 'content-manager' ? get(this.props.layout, [this.props.currentModelName]) : get(this.props.layout, ['plugins', source, this.props.currentModelName]);
|
||||
|
||||
// Remove `id` field
|
||||
const displayedFields = merge(this.props.layout[this.props.currentModelName], omit(this.props.schema[this.props.currentModelName].fields, 'id'));
|
||||
const displayedFields = merge(currentLayout, omit(currentSchema.fields, 'id'));
|
||||
|
||||
// List fields inputs
|
||||
const fields = Object.keys(displayedFields).map(attr => {
|
||||
@ -53,14 +60,14 @@ class EditForm extends React.Component {
|
||||
const validationsIndex = findIndex(this.props.formValidations, ['name', attr]);
|
||||
const validations = get(this.props.formValidations[validationsIndex], 'validations') || {};
|
||||
|
||||
const layout = Object.keys(get(this.props.layout[this.props.currentModelName], attr, {})).reduce((acc, current) => {
|
||||
acc[current] = isFunction(this.props.layout[this.props.currentModelName][attr][current]) ?
|
||||
this.props.layout[this.props.currentModelName][attr][current](this) :
|
||||
this.props.layout[this.props.currentModelName][attr][current];
|
||||
const layout = Object.keys(get(currentLayout, attr, {})).reduce((acc, current) => {
|
||||
acc[current] = isFunction(currentLayout[attr][current]) ?
|
||||
currentLayout[attr][current](this) :
|
||||
currentLayout[attr][current];
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
|
||||
return (
|
||||
<Input
|
||||
key={attr}
|
||||
@ -95,6 +102,9 @@ EditForm.propTypes = {
|
||||
formErrors: PropTypes.array.isRequired,
|
||||
formValidations: PropTypes.array.isRequired,
|
||||
layout: PropTypes.object.isRequired,
|
||||
location: PropTypes.shape({
|
||||
search: PropTypes.string,
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
record: PropTypes.oneOfType([
|
||||
|
@ -8,8 +8,14 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get, map, size } from 'lodash';
|
||||
|
||||
// Components.
|
||||
import SelectOne from 'components/SelectOne';
|
||||
import SelectMany from 'components/SelectMany';
|
||||
|
||||
// Utils.
|
||||
import getQueryParameters from 'utils/getQueryParameters';
|
||||
|
||||
// Style.
|
||||
import styles from './styles.scss';
|
||||
|
||||
class EditFormRelations extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||
@ -20,7 +26,10 @@ class EditFormRelations extends React.Component { // eslint-disable-line react/p
|
||||
}
|
||||
|
||||
render() {
|
||||
const relations = map(this.props.schema[this.props.currentModelName].relations, (relation, i) => {
|
||||
const source = getQueryParameters(this.props.location.search, 'source');
|
||||
const currentSchema = get(this.props.schema, [this.props.currentModelName]) || get(this.props.schema, ['plugins', source, this.props.currentModelName]);
|
||||
|
||||
const relations = map(currentSchema.relations, (relation, i) => {
|
||||
|
||||
switch (relation.nature) {
|
||||
case 'oneToOne':
|
||||
@ -75,6 +84,9 @@ EditFormRelations.propTypes = {
|
||||
PropTypes.string,
|
||||
]).isRequired,
|
||||
isNull: PropTypes.bool.isRequired,
|
||||
location: PropTypes.shape({
|
||||
search: PropTypes.string,
|
||||
}).isRequired,
|
||||
record: PropTypes.oneOfType([
|
||||
PropTypes.object,
|
||||
PropTypes.bool,
|
||||
|
@ -19,10 +19,11 @@ export function emptyStore() {
|
||||
};
|
||||
}
|
||||
|
||||
export function getModelEntries(modelName) {
|
||||
export function getModelEntries(modelName, source) {
|
||||
return {
|
||||
type: GET_MODEL_ENTRIES,
|
||||
modelName,
|
||||
source,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -14,39 +14,26 @@ import { isEmpty, get } from 'lodash';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
|
||||
import injectSaga from 'utils/injectSaga';
|
||||
import getQueryParameters from 'utils/getQueryParameters';
|
||||
|
||||
import Home from 'containers/Home';
|
||||
import Edit from 'containers/Edit';
|
||||
import List from 'containers/List';
|
||||
import EmptyAttributesView from 'components/EmptyAttributesView';
|
||||
|
||||
import { emptyStore, getModelEntries, loadModels, updateSchema } from './actions';
|
||||
import { emptyStore, getModelEntries, loadModels } from './actions';
|
||||
import { makeSelectLoading, makeSelectModels, makeSelectModelEntries } from './selectors';
|
||||
|
||||
import saga from './sagas';
|
||||
|
||||
const tryRequire = (path) => {
|
||||
try {
|
||||
return require(`containers/${path}.js`); // eslint-disable-line global-require
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
class App extends React.Component {
|
||||
componentDidMount() {
|
||||
const config = tryRequire('../../../../config/admin.json');
|
||||
|
||||
if (!isEmpty(get(config, 'admin.schema'))) {
|
||||
this.props.updateSchema(config.admin.schema);
|
||||
} else {
|
||||
this.props.loadModels();
|
||||
}
|
||||
this.props.loadModels();
|
||||
|
||||
const modelName = this.props.location.pathname.split('/')[3];
|
||||
|
||||
if (modelName) {
|
||||
this.props.getModelEntries(modelName);
|
||||
this.props.getModelEntries(modelName, getQueryParameters(this.props.location.search, 'source'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +41,7 @@ class App extends React.Component {
|
||||
const currentModelName = this.props.location.pathname.split('/')[3];
|
||||
|
||||
if (prevProps.location.pathname !== this.props.location.pathname && currentModelName) {
|
||||
this.props.getModelEntries(currentModelName);
|
||||
this.props.getModelEntries(currentModelName, getQueryParameters(this.props.location.search, 'source'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,9 +55,12 @@ class App extends React.Component {
|
||||
}
|
||||
|
||||
const currentModelName = this.props.location.pathname.split('/')[3];
|
||||
const source = getQueryParameters(this.props.location.search, 'source');
|
||||
|
||||
if (currentModelName && isEmpty(get(this.props.models, [currentModelName, 'attributes']))) {
|
||||
return <EmptyAttributesView currentModelName={currentModelName} history={this.props.history} modelEntries={this.props.modelEntries} />;
|
||||
if (currentModelName && source && isEmpty(get(this.props.models.plugins, [source, 'models', currentModelName, 'attributes']))) {
|
||||
if (currentModelName && isEmpty(get(this.props.models.models, [currentModelName, 'attributes']))) {
|
||||
return <EmptyAttributesView currentModelName={currentModelName} history={this.props.history} modelEntries={this.props.modelEntries} />;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -101,7 +91,6 @@ App.propTypes = {
|
||||
PropTypes.bool,
|
||||
PropTypes.object,
|
||||
]).isRequired,
|
||||
updateSchema: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export function mapDispatchToProps(dispatch) {
|
||||
@ -110,7 +99,6 @@ export function mapDispatchToProps(dispatch) {
|
||||
emptyStore,
|
||||
getModelEntries,
|
||||
loadModels,
|
||||
updateSchema,
|
||||
},
|
||||
dispatch,
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { map } from 'lodash';
|
||||
import { map, omit } from 'lodash';
|
||||
import { fork, put, select, call, takeLatest } from 'redux-saga/effects';
|
||||
|
||||
import request from 'utils/request';
|
||||
@ -10,7 +10,8 @@ import { makeSelectModels } from './selectors';
|
||||
|
||||
export function* modelEntriesGet(action) {
|
||||
try {
|
||||
const requestUrl = `${strapi.backendURL}/content-manager/explorer/${action.modelName}/count`;
|
||||
const requestUrl = `${strapi.backendURL}/content-manager/explorer/${action.modelName}/count${action.source !== undefined ? `?source=${action.source}`: ''}`;
|
||||
|
||||
const response = yield call(request, requestUrl, { method: 'GET' });
|
||||
|
||||
yield put(getModelEntriesSucceeded(response.count));
|
||||
@ -27,7 +28,7 @@ export const generateMenu = function () {
|
||||
.then(displayedModels => {
|
||||
return [{
|
||||
name: 'Content Types',
|
||||
links: map(displayedModels, (model, key) => ({
|
||||
links: map(omit(displayedModels, 'plugins'), (model, key) => ({
|
||||
label: model.labelPlural || model.label || key,
|
||||
destination: key,
|
||||
})),
|
||||
|
@ -33,24 +33,27 @@ export function cancelChanges() {
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRecord(id, modelName) {
|
||||
export function deleteRecord(id, modelName, source) {
|
||||
return {
|
||||
type: DELETE_RECORD,
|
||||
id,
|
||||
modelName,
|
||||
source,
|
||||
};
|
||||
}
|
||||
|
||||
export function editRecord() {
|
||||
export function editRecord(source) {
|
||||
return {
|
||||
type: EDIT_RECORD,
|
||||
source,
|
||||
};
|
||||
}
|
||||
|
||||
export function loadRecord(id) {
|
||||
export function loadRecord(id, source) {
|
||||
return {
|
||||
type: LOAD_RECORD,
|
||||
id,
|
||||
source,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import PluginHeader from 'components/PluginHeader';
|
||||
import { makeSelectModels, makeSelectSchema } from 'containers/App/selectors';
|
||||
|
||||
// Utils.
|
||||
import getQueryParameters from 'utils/getQueryParameters';
|
||||
import injectReducer from 'utils/injectReducer';
|
||||
import injectSaga from 'utils/injectSaga';
|
||||
import templateObject from 'utils/templateObject';
|
||||
@ -97,15 +98,20 @@ export class Edit extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const source = getQueryParameters(this.props.location.search, 'source');
|
||||
const attributes =
|
||||
get(this.props.models, ['models', this.props.match.params.slug.toLowerCase(), 'attributes']) ||
|
||||
get(this.props.models, ['plugins', source, 'models', this.props.match.params.slug.toLowerCase(), 'attributes']);
|
||||
|
||||
this.props.setInitialState();
|
||||
this.props.setCurrentModelName(this.props.match.params.slug.toLowerCase());
|
||||
this.props.setFormValidations(this.props.models[this.props.match.params.slug.toLowerCase()].attributes);
|
||||
this.props.setForm(this.props.models[this.props.match.params.slug.toLowerCase()].attributes);
|
||||
this.props.setFormValidations(attributes);
|
||||
this.props.setForm(attributes);
|
||||
// Detect that the current route is the `create` route or not
|
||||
if (this.props.match.params.id === 'create') {
|
||||
this.props.setIsCreating();
|
||||
} else {
|
||||
this.props.loadRecord(this.props.match.params.id);
|
||||
this.props.loadRecord(this.props.match.params.id, source);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,11 +133,14 @@ export class Edit extends React.Component {
|
||||
}
|
||||
|
||||
handleChange = (e) => {
|
||||
const source = getQueryParameters(this.props.location.search, 'source');
|
||||
const currentSchema = get(this.props.schema, [this.props.currentModelName]) || get(this.props.schema, ['plugins', source, this.props.currentModelName]);
|
||||
|
||||
let formattedValue = e.target.value;
|
||||
|
||||
if (isObject(e.target.value) && e.target.value._isAMomentObject === true) {
|
||||
formattedValue = moment(e.target.value, 'YYYY-MM-DD HH:mm:ss').format();
|
||||
} else if (['float', 'integer', 'bigint'].indexOf(this.props.schema[this.props.currentModelName].fields[e.target.name].type) !== -1) {
|
||||
} else if (['float', 'integer', 'bigint'].indexOf(currentSchema.fields[e.target.name].type) !== -1) {
|
||||
formattedValue = toNumber(e.target.value);
|
||||
}
|
||||
|
||||
@ -140,12 +149,15 @@ export class Edit extends React.Component {
|
||||
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const form = this.props.form.toJS();
|
||||
map(this.props.record.toJS(), (value, key) => form[key] = value);
|
||||
const formErrors = checkFormValidity(form, this.props.formValidations.toJS());
|
||||
|
||||
const source = getQueryParameters(this.props.location.search, 'source');
|
||||
|
||||
if (isEmpty(formErrors)) {
|
||||
this.props.editRecord();
|
||||
this.props.editRecord(source);
|
||||
} else {
|
||||
this.props.setFormErrors(formErrors);
|
||||
}
|
||||
@ -156,9 +168,12 @@ export class Edit extends React.Component {
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
||||
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}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -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}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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');
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 <div />;
|
||||
}
|
||||
|
||||
// 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 = [
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user