Merge branch 'master' into master

This commit is contained in:
Jim LAURIE 2018-04-24 11:29:39 +02:00 committed by GitHub
commit f2cb6d7af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 302 additions and 129 deletions

View File

@ -13,6 +13,12 @@ This will create two files located at `./api/user/models`:
> Note: when you create a new API using the CLI (`strapi generate:api <name>`), a model is automatically created.
## Model Information
The info key on the model-json states information about the model. This information is used in the admin interface, when showing the model.
- `name`: The name of the model, as shown in admin interface.
- `description`: The description of the model.
- `mainField`: Determines which model-attribute is shown when displaying the model.
## Define the attributes
The following types are currently available:
@ -59,7 +65,8 @@ To improve the Developer eXperience when developing or using the administration
"connection": "default",
"info": {
"name": "user",
"description": "This represents the User Model"
"description": "This represents the User Model",
"mainField": "email"
},
"attributes": {
"firstname": {

View File

@ -10,6 +10,8 @@ To setup the development environment please **follow the instructions below:**
2. Clone it to your computer `git clone git@github.com:strapi/strapi.git`.
3. Run `npm run setup` at the root of the directory.
> You can run `npm run setup:build` to build the plugins' admin (the setup time will be longer)
> Note: If the installation failed, please remove the global packages related to Strapi. The command `npm ls strapi` will help you to find where your packages are installed globally.
## Plugin development Setup

View File

@ -24,6 +24,7 @@
"release": "npm run clean:all && npm install && npm run createsymlinkdependencies && lerna exec --concurrency 1 -- npm install && npm run removesymlinkdependencies && node ./scripts/publish.js $TAG",
"createsymlinkdependencies": "node ./scripts/createSymlinkDependencies.js",
"removesymlinkdependencies": "node ./scripts/removeSymlinkDependencies.js",
"setup:build": "npm run setup --build",
"setup": "npm run clean:all && npm install && node ./scripts/setup.js && npm run clean",
"test": "make test"
},

View File

@ -55,16 +55,6 @@ const FIRST_BLOCK = [
},
];
const WELCOME_AGAIN_BLOCK = [
{
title: {
id: 'app.components.HomePage.welcome.again',
},
name: upperFirst(`${get(auth.getUserInfo(), 'username')}!`),
content: () => <WelcomeContent hasContent />,
},
];
const FIRST_BLOCK_LINKS = [
{
link: 'https://strapi.io/documentation/',
@ -169,6 +159,15 @@ export class HomePage extends React.PureComponent {
render() {
const { homePage: { articles, body } } = this.props;
const WELCOME_AGAIN_BLOCK = [
{
title: {
id: 'app.components.HomePage.welcome.again',
},
name: upperFirst(`${get(auth.getUserInfo(), 'username')}!`),
content: () => <WelcomeContent hasContent />,
},
];
return (
<div className={cn('container-fluid', styles.containerFluid)}>

View File

@ -46,7 +46,7 @@
],
"engines": {
"node": ">= 9.0.0",
"npm": ">= 3.0.0"
"npm": ">= 5.0.0"
},
"license": "MIT"
}

View File

@ -709,6 +709,10 @@ module.exports = function(strapi) {
acc[current] = params.values[current];
} else {
switch (association.nature) {
case 'oneWay':
acc[current] = _.get(params.values[current], this.primaryKey, params.values[current]) || null;
break;
case 'oneToOne':
if (response[current] !== params.values[current]) {
const value = _.isNull(params.values[current]) ? response[current] : params.values;

View File

@ -48,9 +48,12 @@ module.exports = {
*/
add: async (values) => {
const data = await <%= globalID %>.create(_.omit(values, _.keys(_.groupBy(strapi.models.<%= id %>.associations, 'alias'))));
await strapi.hook.mongoose.manageRelations('<%= id %>', _.merge(_.clone(data), { values }));
return data;
const query = await <%= globalID %>.create(_.omit(values, _.keys(_.groupBy(strapi.models.<%= id %>.associations, 'alias'))));
const data = query.toJSON ? query.toJSON() : query;
await strapi.hook.mongoose.manageRelations('<%= id %>', _.merge(data, { values }));
return query;
},
/**

View File

@ -71,8 +71,8 @@ module.exports = scope => {
'uuid': uuid()
},
'engines': {
'node': '>= 7.0.0',
'npm': '>= 3.0.0'
'node': '>= 9.0.0',
'npm': '>= 5.0.0'
},
'license': scope.license || 'MIT'
});

View File

@ -29,7 +29,7 @@ module.exports = scope => {
'analyze:clean': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json',
'preanalyze': 'npm run analyze:clean',
'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',
'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',
'build:clean': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build',

View File

@ -116,6 +116,11 @@ module.exports = function (strapi) {
[`${association.via}.${association.filter}`]: association.alias,
[`${association.via}.kind`]: definition.globalId
}
// Select last related to an entity.
this._mongooseOptions.populate[association.alias].options = {
sort: '-createdAt'
}
} else {
this._mongooseOptions.populate[association.alias].path = `${association.alias}.ref`;
}
@ -144,6 +149,8 @@ module.exports = function (strapi) {
save: 'afterSave'
};
// Mongoose doesn't allow post 'remove' event on model.
// See https://github.com/Automattic/mongoose/issues/3054
_.forEach(postLifecycle, (fn, key) => {
if (_.isFunction(target[model.toLowerCase()][fn])) {
collection.schema.post(key, function (doc, next) {
@ -178,6 +185,7 @@ module.exports = function (strapi) {
break;
case 'manyMorphToMany':
case 'manyMorphToOne':
returned[association.alias] = returned[association.alias].map(obj => obj.ref);
break;
default:
@ -465,7 +473,10 @@ module.exports = function (strapi) {
break;
case '_contains':
result.key = `where.${key}`;
result.value = new RegExp('\\b' + value + '\\b', 'i');
result.value = {
$regex: value,
$options: 'i',
};
break;
case '_containss':
result.key = `where.${key}.$regex`;
@ -502,10 +513,13 @@ module.exports = function (strapi) {
acc[current] = params.values[current];
} else {
switch (association.nature) {
case 'oneWay':
acc[current] = _.get(params.values[current], this.primaryKey, params.values[current]) || null;
break;
case 'oneToOne':
if (response[current] !== params.values[current]) {
const value = _.isNull(params.values[current]) ? response[current] : params.values;
const recordId = _.isNull(params.values[current]) ? value[Model.primaryKey] || value.id || value._id : value[current];
if (response[current] && _.isObject(response[current]) && response[current][Model.primaryKey] !== value[current]) {

View File

@ -16,7 +16,7 @@
"main": "./lib",
"dependencies": {
"lodash": "^4.17.4",
"mongoose": "^5.0.4",
"mongoose": "^5.0.15",
"mongoose-float": "^1.0.2",
"pluralize": "^6.0.0",
"strapi-utils": "3.0.0-alpha.12"

View File

@ -8,39 +8,51 @@ import React from 'react';
import Select from 'react-select';
import PropTypes from 'prop-types';
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';
import request from 'utils/request';
import templateObject from 'utils/templateObject';
import styles from './styles.scss';
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) {
super(props);
this.state = {
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',
};
// Set `query` parameter if necessary
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}`;
// Call our request helper (see 'utils/request')
return request(requestUrl, {
@ -48,25 +60,41 @@ class SelectMany extends React.Component { // eslint-disable-line react/prefer-s
params,
})
.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,
})) :
[{
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,
});
})
.catch(() => {
strapi.notification.error('content-manager.notification.error.relationship.fetch');
});
}
};
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 = {
name: `record.${this.props.relation.alias}`,
type: 'select',
@ -74,37 +102,62 @@ class SelectMany extends React.Component { // eslint-disable-line react/prefer-s
};
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 */
return (
<div className={`form-group ${styles.selectMany}`}>
<label htmlFor={this.props.relation.alias}>{this.props.relation.alias}</label>
{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 => {
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,
label:
get(item, 'label') ||
templateObject({ mainField: this.props.relation.displayedAttribute }, item)
.mainField ||
item.value.id,
};
}
})}
})
}
/>
</div>
);
@ -113,10 +166,7 @@ class SelectMany extends React.Component { // eslint-disable-line react/prefer-s
}
SelectMany.propTypes = {
record: PropTypes.oneOfType([
PropTypes.object,
PropTypes.bool,
]).isRequired,
record: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).isRequired,
relation: PropTypes.object.isRequired,
setRecordAttribute: PropTypes.func.isRequired,
};

View File

@ -8,7 +8,7 @@ import React from 'react';
import Select from 'react-select';
import PropTypes from 'prop-types';
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';
import request from 'utils/request';
import templateObject from 'utils/templateObject';
@ -21,23 +21,37 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st
this.state = {
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',
};
// Set `query` parameter if necessary
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}`;
// Call our request helper (see 'utils/request')
@ -56,7 +70,18 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st
label: templateObject({ mainField: this.props.relation.displayedAttribute }, response).mainField,
}];
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,
});
})
.catch(() => {
strapi.notification.error('content-manager.notification.relationship.fetch');
@ -71,8 +96,23 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st
};
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() {
@ -81,17 +121,18 @@ class SelectOne extends React.Component { // eslint-disable-line react/prefer-st
: '';
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 */
return (
<div className={`form-group ${styles.selectOne}`}>
<label htmlFor={this.props.relation.alias}>{this.props.relation.alias}</label>
{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
value={isNull(value) || isUndefined(value) ? null : {
value: isFunction(value.toJS) ? value.toJS() : value,

View File

@ -235,7 +235,7 @@ module.exports = {
})
}
if (association.type === 'model') {
if (association.type === 'model' || (association.type === 'collection' && _.isObject(array))) {
return _.isEmpty(array) ? [] : transformToArrayID([array]);
}

View File

@ -220,7 +220,7 @@ module.exports = {
})
}
if (association.type === 'model') {
if (association.type === 'model' || (association.type === 'collection' && _.isObject(array))) {
return _.isEmpty(array) ? [] : transformToArrayID([array]);
}

View File

@ -11,7 +11,7 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"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",
"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",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
@ -44,7 +44,7 @@
},
"engines": {
"node": ">= 9.0.0",
"npm": ">= 3.0.0"
"npm": ">= 5.0.0"
},
"license": "MIT"
}

View File

@ -11,7 +11,7 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"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",
"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",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
@ -48,7 +48,7 @@
},
"engines": {
"node": ">= 9.0.0",
"npm": ">= 3.0.0"
"npm": ">= 5.0.0"
},
"license": "MIT"
}

View File

@ -11,7 +11,7 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"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",
"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",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
@ -45,8 +45,8 @@
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 7.0.0",
"npm": ">= 3.0.0"
"node": ">= 9.0.0",
"npm": ">= 5.0.0"
},
"license": "MIT"
}

View File

@ -11,7 +11,7 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"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",
"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",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
@ -45,7 +45,7 @@
},
"engines": {
"node": ">= 9.0.0",
"npm": ">= 3.0.0"
"npm": ">= 5.0.0"
},
"license": "MIT"
}

View File

@ -34,8 +34,8 @@ module.exports = async cb => {
size text,
url text,
provider text,
updated_at ${Model.client === 'pg' ? 'timestamp with time zone' : 'timestamp'},
created_at ${Model.client === 'pg' ? 'timestamp with time zone' : 'timestamp'}
updated_at ${Model.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'},
created_at ${Model.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP'}
);
CREATE TABLE ${quote}upload_file_morph${quote} (

View File

@ -11,7 +11,7 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"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",
"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",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",

View File

@ -11,7 +11,7 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"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",
"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",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
@ -51,8 +51,8 @@
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 7.0.0",
"npm": ">= 3.0.0"
"node": ">= 9.0.0",
"npm": ">= 5.0.0"
},
"license": "MIT"
}

View File

@ -460,8 +460,8 @@ CREATE TABLE ${quote}${details[currentModel].tableName}${quote} (
role ${details[currentModel].client === 'pg' ? 'integer' : 'int'},
${quote}resetPasswordToken${quote} text,
password text,
updated_at ${details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp'},
created_at ${details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp'}
updated_at ${details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'},
created_at ${details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP'}
);`);
break;
case 'role':

View File

@ -1,8 +1,21 @@
const shell = require('shelljs');
// Check npm version
const npm = shell.exec('npm -v').stdout;
if (parseFloat(npm) < 5) {
throw new Error('[ERROR: Strapi] You need npm version @>=5');
}
const nodeVersion = shell.exec('node -v').stdout.replace('v', '');
if (parseFloat(nodeVersion) < 8.6) {
throw new Error('[ERROR: Strapi] You need to use node version @>=9');
}
// Store installation start date.
const silent = process.env.npm_config_debug !== 'true';
const installationStartDate = new Date();
const watcher = (label, cmd, withSuccess = true) => {
if (label.length > 0) {
shell.echo(label);
@ -21,6 +34,22 @@ const watcher = (label, cmd, withSuccess = true) => {
shell.echo('✅ Success');
shell.echo('');
}
};
const asyncWatcher = (label, cmd, withSuccess = true, resolve) => {
if (label.length > 0) {
shell.echo(label);
}
return shell.exec(cmd, { silent, async: true }, (code, stdout, stderr) => {
if (stderr && code !== 0) {
console.error(stderr);
process.exit(1);
}
return resolve();
});
};
shell.echo('');
@ -57,7 +86,6 @@ if (shell.test('-e', 'admin/src/config/plugins.json') === false) {
}
watcher('📦 Linking strapi-admin', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-generate-admin');
watcher('', 'npm install ../strapi-admin');
@ -83,6 +111,14 @@ shell.cd('../strapi');
watcher('', 'npm install ../strapi-generate ../strapi-generate-admin ../strapi-generate-api ../strapi-generate-new ../strapi-generate-plugin ../strapi-generate-policy ../strapi-generate-service ../strapi-utils');
watcher('📦 Linking strapi...', 'npm link');
// Upload plugins
shell.cd('../strapi-upload-local');
watcher('📦 Linking strapi-upload-local...', 'npm link --no-optional', false);
shell.cd('../strapi-upload-aws-s3');
watcher('📦 Linking strapi-upload-aws-s3...', 'npm link --no-optional', false);
// Plugins with admin
shell.cd('../strapi-plugin-email');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-email...', 'npm link --no-optional', false);
@ -91,32 +127,24 @@ shell.cd('../strapi-plugin-users-permissions');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-users-permissions...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-content-manager');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-content-manager...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-settings-manager');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-settings-manager...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-upload-local');
watcher('📦 Linking strapi-upload-local...', 'npm link --no-optional', false);
shell.cd('../strapi-upload-aws-s3');
watcher('📦 Linking strapi-upload-aws-s3...', 'npm link --no-optional', false);
// Plugins with admin and other plugin's dependencies
shell.cd('../strapi-plugin-upload');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
watcher('', 'npm install ../strapi-upload-local --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-upload...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-content-type-builder');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
@ -124,15 +152,39 @@ watcher('', 'npm install ../strapi-generate --no-optional');
watcher('', 'npm install ../strapi-generate-api --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-content-type-builder...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-graphql');
watcher('', 'npm install ../strapi-utils --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('📦 Linking strapi-plugin-graphql...', 'npm link --no-optional', false);
const pluginsToBuild = ['admin', 'content-manager', 'content-type-builder', 'upload', 'users-permissions', 'settings-manager'];
// Log installation duration.
const installationEndDate = new Date();
const duration = (installationEndDate.getTime() - installationStartDate.getTime()) / 1000;
shell.echo('✅ Strapi has been succesfully installed.');
shell.echo(`⏳ The installation took ${Math.floor(duration / 60) > 0 ? `${Math.floor(duration / 60)} minutes and ` : ''}${Math.floor(duration % 60)} seconds.`);
const buildPlugins = async () => {
const build = (pckgName) => {
return new Promise(resolve => {
const name = pckgName === 'admin' ? pckgName: `plugin-${pckgName}`;
asyncWatcher(`🏗 Building ${name}...`, `cd ../strapi-${name} && npm run build`, false, resolve);
});
};
return Promise.all(pluginsToBuild.map(plugin => build(plugin)));
};
const setup = async () => {
if (process.env.npm_config_build) {
if (process.platform === 'darwin') { // Allow async build for darwin platform
await buildPlugins();
} else {
pluginsToBuild.map(name => {
const pluginName = name === 'admin' ? name : `plugin-${name}`;
shell.cd(`../strapi-${pluginName}`);
return watcher(`🏗 Building ${pluginName}...`, 'npm run build');
});
}
}
// Log installation duration.
const installationEndDate = new Date();
const duration = (installationEndDate.getTime() - installationStartDate.getTime()) / 1000;
shell.echo('✅ Strapi has been succesfully installed.');
shell.echo(`⏳ The installation took ${Math.floor(duration / 60) > 0 ? `${Math.floor(duration / 60)} minutes and ` : ''}${Math.floor(duration % 60)} seconds.`);
};
setup();