strapi-plugin-content-manager
Advanced tools
Comparing version 3.0.0-alpha.12.0.1 to 3.0.0-alpha.12.1
@@ -11,3 +11,3 @@ /** | ||
import 'react-select/dist/react-select.css'; | ||
import { isArray, isNull, isUndefined, get, findIndex } from 'lodash'; | ||
import { cloneDeep, isArray, isNull, isUndefined, get, findIndex, includes } from 'lodash'; | ||
@@ -19,3 +19,4 @@ import request from 'utils/request'; | ||
class SelectMany extends React.Component { // eslint-disable-line react/prefer-stateless-function | ||
class SelectMany extends React.Component { | ||
// eslint-disable-line react/prefer-stateless-function | ||
constructor(props) { | ||
@@ -26,8 +27,21 @@ super(props); | ||
isLoading: true, | ||
options: [], | ||
toSkip: 0, | ||
}; | ||
} | ||
getOptions = (query) => { | ||
componentDidMount() { | ||
this.getOptions(''); | ||
} | ||
componentDidUpdate(prevProps, prevState) { | ||
if (prevState.toSkip !== this.state.toSkip) { | ||
this.getOptions(''); | ||
} | ||
} | ||
getOptions = query => { | ||
const params = { | ||
limit: 20, | ||
skip: this.state.toSkip, | ||
source: this.props.relation.plugin || 'content-manager', | ||
@@ -38,11 +52,9 @@ }; | ||
if (query) { | ||
params.query = query; | ||
params.queryAttribute = this.props.relation.displayedAttribute; | ||
delete params.limit, | ||
delete params.skip, | ||
params[`${this.props.relation.displayedAttribute}_contains`] = query; | ||
} | ||
// Request URL | ||
const requestUrlSuffix = query && this.props.record.get(this.props.relation.alias) ? this.props.record.get(this.props.relation.alias) : ''; | ||
// NOTE: keep this line if we rollback to the old container | ||
// const requestUrlSuffix = query && this.props.record.get(this.props.relation.alias).toJS() ? this.props.record.get(this.props.relation.alias).toJS() : ''; | ||
const requestUrl = `/content-manager/explorer/${this.props.relation.model || this.props.relation.collection}/${requestUrlSuffix}`; | ||
const requestUrl = `/content-manager/explorer/${this.props.relation.model || | ||
this.props.relation.collection}`; | ||
@@ -55,13 +67,27 @@ // Call our request helper (see 'utils/request') | ||
.then(response => { | ||
const options = isArray(response) ? | ||
response.map(item => ({ | ||
const options = isArray(response) | ||
? response.map(item => ({ | ||
value: item, | ||
label: templateObject({ mainField: this.props.relation.displayedAttribute }, item).mainField, | ||
})) : | ||
[{ | ||
value: response, | ||
label: response[this.props.relation.displayedAttribute], | ||
}]; | ||
label: templateObject({ mainField: this.props.relation.displayedAttribute }, item) | ||
.mainField, | ||
})) | ||
: [ | ||
{ | ||
value: response, | ||
label: response[this.props.relation.displayedAttribute], | ||
}, | ||
]; | ||
return { options }; | ||
const newOptions = cloneDeep(this.state.options); | ||
options.map(option => { | ||
// Don't add the values when searching | ||
if (findIndex(newOptions, o => o.value.id === option.value.id) === -1) { | ||
return newOptions.push(option); | ||
} | ||
}); | ||
return this.setState({ | ||
options: newOptions, | ||
isLoading: false, | ||
}); | ||
}) | ||
@@ -71,6 +97,8 @@ .catch(() => { | ||
}); | ||
} | ||
}; | ||
handleChange = (value) => { | ||
const filteredValue = value.filter((data, index ) => findIndex(value, (o) => o.value.id === data.value.id) === index); | ||
handleChange = value => { | ||
const filteredValue = value.filter( | ||
(data, index) => findIndex(value, o => o.value.id === data.value.id) === index | ||
); | ||
const target = { | ||
@@ -83,15 +111,29 @@ name: `record.${this.props.relation.alias}`, | ||
this.props.setRecordAttribute({ target }); | ||
// NOTE: keep this line if we rollback to the old container | ||
// this.props.setRecordAttribute(this.props.relation.alias, filteredValue); | ||
}; | ||
handleBottomScroll = () => { | ||
this.setState(prevState => { | ||
return { | ||
toSkip: prevState.toSkip + 20, | ||
}; | ||
}); | ||
} | ||
handleInputChange = (value) => { | ||
const clonedOptions = this.state.options; | ||
const filteredValues = clonedOptions.filter(data => includes(data.label, value)); | ||
if (filteredValues.length === 0) { | ||
return this.getOptions(value); | ||
} | ||
} | ||
render() { | ||
const description = this.props.relation.description | ||
? <p>{this.props.relation.description}</p> | ||
: ''; | ||
const description = this.props.relation.description ? ( | ||
<p>{this.props.relation.description}</p> | ||
) : ( | ||
'' | ||
); | ||
const value = get(this.props.record, this.props.relation.alias); | ||
// NOTE: keep this line if we rollback to the old container | ||
// const value = this.props.record.get(this.props.relation.alias); | ||
/* eslint-disable jsx-a11y/label-has-for */ | ||
@@ -102,15 +144,26 @@ return ( | ||
{description} | ||
<Select.Async | ||
<Select | ||
onChange={this.handleChange} | ||
loadOptions={this.getOptions} | ||
options={this.state.options} | ||
id={this.props.relation.alias} | ||
isLoading={this.state.isLoading} | ||
onMenuScrollToBottom={this.handleBottomScroll} | ||
onInputChange={this.handleInputChange} | ||
multi | ||
value={isNull(value) || isUndefined(value) || value.size === 0 ? null : value.map(item => { | ||
if (item) { | ||
return { | ||
value: get(item, 'value') || item, | ||
label: get(item, 'label') || templateObject({ mainField: this.props.relation.displayedAttribute }, item).mainField || item.value.id, | ||
}; | ||
} | ||
})} | ||
value={ | ||
isNull(value) || isUndefined(value) || value.size === 0 | ||
? null | ||
: value.map(item => { | ||
if (item) { | ||
return { | ||
value: get(item, 'value') || item, | ||
label: | ||
get(item, 'label') || | ||
templateObject({ mainField: this.props.relation.displayedAttribute }, item) | ||
.mainField || | ||
item.value.id, | ||
}; | ||
} | ||
}) | ||
} | ||
/> | ||
@@ -124,6 +177,3 @@ </div> | ||
SelectMany.propTypes = { | ||
record: PropTypes.oneOfType([ | ||
PropTypes.object, | ||
PropTypes.bool, | ||
]).isRequired, | ||
record: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).isRequired, | ||
relation: PropTypes.object.isRequired, | ||
@@ -130,0 +180,0 @@ setRecordAttribute: PropTypes.func.isRequired, |
@@ -11,3 +11,3 @@ /** | ||
import 'react-select/dist/react-select.css'; | ||
import { map, isArray, isNull, isUndefined, isFunction, get } from 'lodash'; | ||
import { cloneDeep, map, includes, isArray, isNull, isUndefined, isFunction, get, findIndex } from 'lodash'; | ||
@@ -25,8 +25,21 @@ import request from 'utils/request'; | ||
isLoading: true, | ||
options: [], | ||
toSkip: 0, | ||
}; | ||
} | ||
componentDidMount() { | ||
this.getOptions(''); | ||
} | ||
componentDidUpdate(prevProps, prevState) { | ||
if (prevState.toSkip !== this.state.toSkip) { | ||
this.getOptions(''); | ||
} | ||
} | ||
getOptions = (query) => { | ||
const params = { | ||
limit: 20, | ||
skip: this.state.toSkip, | ||
source: this.props.relation.plugin || 'content-manager', | ||
@@ -37,8 +50,9 @@ }; | ||
if (query) { | ||
params.query = query; | ||
params.queryAttribute = this.props.relation.displayedAttribute; | ||
delete params.limit, | ||
delete params.skip, | ||
params[`${this.props.relation.displayedAttribute}_contains`] = query; | ||
} | ||
// Request URL | ||
const requestUrlSuffix = query && this.props.record.get(this.props.relation.alias) ? this.props.record.get(this.props.relation.alias) : ''; | ||
const requestUrlSuffix = query && get(this.props.record, [this.props.relation.alias]) ? get(this.props.record, [this.props.relation.alias]) : ''; | ||
const requestUrl = `/content-manager/explorer/${this.props.relation.model || this.props.relation.collection}/${requestUrlSuffix}`; | ||
@@ -62,3 +76,14 @@ | ||
return {options}; | ||
const newOptions = cloneDeep(this.state.options); | ||
options.map(option => { | ||
// Don't add the values when searching | ||
if (findIndex(newOptions, o => o.value.id === option.value.id) === -1) { | ||
return newOptions.push(option); | ||
} | ||
}); | ||
return this.setState({ | ||
options: newOptions, | ||
isLoading: false, | ||
}); | ||
}) | ||
@@ -78,6 +103,21 @@ .catch(() => { | ||
this.props.setRecordAttribute({ target }); | ||
// NOTE: keep this line if we rollback to the old container | ||
// this.props.setRecordAttribute(this.props.relation.alias, value); | ||
} | ||
handleBottomScroll = () => { | ||
this.setState(prevState => { | ||
return { | ||
toSkip: prevState.toSkip + 20, | ||
}; | ||
}); | ||
} | ||
handleInputChange = (value) => { | ||
const clonedOptions = this.state.options; | ||
const filteredValues = clonedOptions.filter(data => includes(data.label, value)); | ||
if (filteredValues.length === 0) { | ||
return this.getOptions(value); | ||
} | ||
} | ||
render() { | ||
@@ -89,4 +129,2 @@ const description = this.props.relation.description | ||
const value = get(this.props.record, this.props.relation.alias); | ||
// NOTE: keep this line if we rollback to the old container | ||
// const value = this.props.record.get(this.props.relation.alias); | ||
@@ -98,5 +136,8 @@ /* eslint-disable jsx-a11y/label-has-for */ | ||
{description} | ||
<Select.Async | ||
<Select | ||
onChange={this.handleChange} | ||
loadOptions={this.getOptions} | ||
options={this.state.options} | ||
isLoading={this.state.isLoading} | ||
onMenuScrollToBottom={this.handleBottomScroll} | ||
onInputChange={this.handleInputChange} | ||
simpleValue | ||
@@ -103,0 +144,0 @@ value={isNull(value) || isUndefined(value) ? null : { |
import { LOCATION_CHANGE } from 'react-router-redux'; | ||
import { findIndex, get, isArray, isEmpty, isNumber, isString, map } from 'lodash'; | ||
import { findIndex, get, isArray, isEmpty, includes, isNumber, isString, map } from 'lodash'; | ||
import { | ||
@@ -67,2 +67,3 @@ call, | ||
const source = yield select(makeSelectSource()); | ||
let shouldAddTranslationSuffix = false; | ||
@@ -126,2 +127,8 @@ try { | ||
const error = current.messages.reduce((acc, current) => { | ||
if (includes(current.id, 'Auth')) { | ||
acc.id = `users-permissions.${current.id}`; | ||
shouldAddTranslationSuffix = true; | ||
return acc; | ||
} | ||
acc.errorMessage = current.id; | ||
@@ -136,7 +143,9 @@ | ||
const name = get(err.response.payload.message, ['0', 'messages', '0', 'field']); | ||
const name = get(err.response.payload.message, ['0', 'messages', '0', 'field', '0']); | ||
yield put(setFormErrors([{ name, errors }])); | ||
} | ||
strapi.notification.error(isCreating ? 'content-manager.error.record.create' : 'content-manager.error.record.update'); | ||
const notifErrorPrefix = source === 'users-permissions' && shouldAddTranslationSuffix ? 'users-permissions.' : ''; | ||
strapi.notification.error(`${notifErrorPrefix}${get(err.response, ['payload', 'message', '0', 'messages', '0', 'id'], isCreating ? 'content-manager.error.record.create' : 'content-manager.error.record.update')}`); | ||
} finally { | ||
@@ -143,0 +152,0 @@ yield put(unsetLoader()); |
@@ -145,3 +145,3 @@ /** | ||
e.target.name === 'params.limit' | ||
? `page=${params.currentPage}&limit=${e.target.value}&sort=${params.sort}&source=${this.getSource()}` | ||
? `page=${params.page}&limit=${e.target.value}&sort=${params.sort}&source=${this.getSource()}` | ||
: `page=${e.target.value}&limit=${params.limit}&sort=${params.sort}&source=${this.getSource()}`; | ||
@@ -148,0 +148,0 @@ this.props.history.push({ |
@@ -81,3 +81,3 @@ const _ = require('lodash'); | ||
const entry = await this | ||
const request = await this | ||
.forge(values) | ||
@@ -94,7 +94,14 @@ .save() | ||
const entry = request.toJSON ? request.toJSON() : request; | ||
const relations = this.associations.reduce((acc, association) => { | ||
acc[association.alias] = params.values[association.alias]; | ||
return acc; | ||
}, {}); | ||
return module.exports.update.call(this, { | ||
[this.primaryKey]: entry[this.primaryKey], | ||
values: _.merge({ | ||
values: _.assign({ | ||
id: entry[this.primaryKey] | ||
}, params.values) | ||
}, relations) | ||
}); | ||
@@ -172,5 +179,3 @@ }, | ||
case 'manyToMany': | ||
if (association.nature === 'manyToMany' && details.dominant === true) { | ||
acc[current] = params.values[current]; | ||
} else if (response[current] && _.isArray(response[current]) && current !== 'id') { | ||
if (response[current] && _.isArray(response[current]) && current !== 'id') { | ||
// Records to add in the relation. | ||
@@ -219,9 +224,31 @@ const toAdd = _.differenceWith(params.values[current], response[current], (a, b) => | ||
virtualFields.push(module.exports.addRelationMorph.call(this, { | ||
id: response[this.primaryKey], | ||
alias: association.alias, | ||
ref: model.collectionName, | ||
refId: obj.refId, | ||
field: obj.field | ||
})); | ||
// Remove existing relationship because only one file | ||
// can be related to this field. | ||
if (association.nature === 'manyMorphToOne') { | ||
virtualFields.push( | ||
module.exports.removeRelationMorph.call(this, { | ||
alias: association.alias, | ||
ref: model.collectionName, | ||
refId: obj.refId, | ||
field: obj.field | ||
}) | ||
.then(() => | ||
module.exports.addRelationMorph.call(this, { | ||
id: response[this.primaryKey], | ||
alias: association.alias, | ||
ref: model.collectionName, | ||
refId: obj.refId, | ||
field: obj.field | ||
}) | ||
) | ||
); | ||
} else { | ||
virtualFields.push(module.exports.addRelationMorph.call(this, { | ||
id: response[this.primaryKey], | ||
alias: association.alias, | ||
ref: model.collectionName, | ||
refId: obj.refId, | ||
field: obj.field | ||
})); | ||
} | ||
}); | ||
@@ -242,4 +269,4 @@ break; | ||
if (association.type === 'model') { | ||
return _.isEmpty(array) ? [] : transformToArrayID([array]); | ||
if (association.type === 'model' || (association.type === 'collection' && _.isObject(array))) { | ||
return _.isEmpty(_.toString(array)) ? [] : transformToArrayID([array]); | ||
} | ||
@@ -389,3 +416,3 @@ | ||
return await this.morph.forge() | ||
.where({ | ||
.where(_.omitBy({ | ||
[`${this.collectionName}_id`]: params.id, | ||
@@ -395,5 +422,5 @@ [`${params.alias}_id`]: params.refId, | ||
field: params.field | ||
}) | ||
}, _.isEmpty)) | ||
.destroy(); | ||
} | ||
}; |
@@ -38,3 +38,3 @@ const _ = require('lodash'); | ||
const entry = await this.create(values) | ||
const request = await this.create(values) | ||
.catch((err) => { | ||
@@ -48,7 +48,17 @@ const message = err.message.split('index:'); | ||
const entry = request.toJSON ? request.toJSON() : request; | ||
const relations = this.associations.reduce((acc, association) => { | ||
if (params.values[association.alias]) { | ||
acc[association.alias] = params.values[association.alias]; | ||
} | ||
return acc; | ||
}, {}); | ||
return module.exports.update.call(this, { | ||
[this.primaryKey]: entry[this.primaryKey], | ||
values: _.merge({ | ||
values: _.assign({ | ||
id: entry[this.primaryKey] | ||
}, params.values) | ||
}, relations) | ||
}); | ||
@@ -216,17 +226,17 @@ }, | ||
if (_.isArray(array)) { | ||
return array.map(value => { | ||
if (_.isPlainObject(value)) { | ||
return value._id || value.id; | ||
} | ||
return array.map(value => { | ||
if (_.isPlainObject(value)) { | ||
return value._id || value.id; | ||
} | ||
return value; | ||
}) | ||
} | ||
return value; | ||
}) | ||
} | ||
if (association.type === 'model') { | ||
return _.isEmpty(array) ? [] : transformToArrayID([array]); | ||
} | ||
if (association.type === 'model' || (association.type === 'collection' && _.isObject(array))) { | ||
return _.isEmpty(array) ? [] : transformToArrayID([array]); | ||
} | ||
return []; | ||
}; | ||
return []; | ||
}; | ||
@@ -233,0 +243,0 @@ // Compare array of ID to find deleted files. |
@@ -65,3 +65,3 @@ 'use strict'; | ||
// Find an entry using `queries` system | ||
const entry = await strapi.plugins['content-manager'].services['contentmanager'].fetch(ctx.params, source); | ||
const entry = await strapi.plugins['content-manager'].services['contentmanager'].fetch(ctx.params, source, null, false); | ||
@@ -68,0 +68,0 @@ // Entry not found |
{ | ||
"name": "strapi-plugin-content-manager", | ||
"version": "3.0.0-alpha.12.0.1", | ||
"version": "3.0.0-alpha.12.1", | ||
"description": "A powerful UI to easily manage your data.", | ||
@@ -14,3 +14,3 @@ "strapi": { | ||
"analyze": "node ./node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js", | ||
"prebuild": "npm run build:clean && npm run test", | ||
"prebuild": "npm run build:clean", | ||
"build:dev": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress", | ||
@@ -28,3 +28,3 @@ "build": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress", | ||
"react-select": "^1.0.0-rc.5", | ||
"strapi-helper-plugin": "3.0.0-alpha.12.0.1" | ||
"strapi-helper-plugin": "3.0.0-alpha.12.1" | ||
}, | ||
@@ -49,5 +49,5 @@ "author": { | ||
"node": ">= 9.0.0", | ||
"npm": ">= 3.0.0" | ||
"npm": ">= 5.0.0" | ||
}, | ||
"license": "MIT" | ||
} |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
100
1723467
9830