diff --git a/.travis.yml b/.travis.yml index 23c1a181ee..f2486aa99c 100755 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,16 @@ before_install: - export CHROME_BIN=chromium-browser - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - - sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share} - - npm cache clean --force - - rm -rf node_modules/ + # - sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share} + # - npm cache clean --force + # - rm -rf node_modules/ install: - npm run setup --debug script: - npm run doc + +cache: + directories: + - "node_modules" diff --git a/docs/3.x.x/en/configurations/configurations.md b/docs/3.x.x/en/configurations/configurations.md index c9f8eab486..d038fc99ec 100644 --- a/docs/3.x.x/en/configurations/configurations.md +++ b/docs/3.x.x/en/configurations/configurations.md @@ -179,6 +179,10 @@ Most of the application's configurations are defined by environment. It means th - `password` (string): Password used to establish the connection. - `options` (object): List of additional options used by the connector. - `timezone` (string): Set the default behavior for local time (used only for a SQL database). Default value: `utc`. + - `options` Options used for database connection. + - `ssl` (boolean): For ssl database connection. + - `debug` (boolean): Show database exchanges and errors. + - `autoMigration` (boolean): To disable auto tables/columns creation for SQL database. #### Example diff --git a/packages/strapi-bookshelf/lib/index.js b/packages/strapi-bookshelf/lib/index.js index cec982670c..d73418eba4 100755 --- a/packages/strapi-bookshelf/lib/index.js +++ b/packages/strapi-bookshelf/lib/index.js @@ -501,6 +501,25 @@ module.exports = function(strapi) { } }; + const storeTable = async (table, attributes) => { + const existTable = await StrapiConfigs.forge({key: `db_model_${table}`}).fetch(); + + if (existTable) { + await StrapiConfigs.forge({id: existTable.id}).save({ + value: JSON.stringify(attributes) + }, { + path: true + }); + } else { + await StrapiConfigs.forge({ + key: `db_model_${table}`, + type: 'object', + value: JSON.stringify(attributes) + }).save(); + } + }; + + if (!tableExist) { const columns = generateColumns(attributes, [`id ${definition.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY`]).join(',\n\r'); @@ -513,7 +532,10 @@ module.exports = function(strapi) { // Generate indexes. await generateIndexes(table, attributes); + + await storeTable(table, attributes); } else { + const columns = Object.keys(attributes); // Fetch existing column @@ -546,9 +568,21 @@ module.exports = function(strapi) { await Promise.all(queries.map(query => ORM.knex.raw(query))); } + let previousAttributes; + try { + previousAttributes = JSON.parse((await StrapiConfigs.forge({key: `db_model_${table}`}).fetch()).toJSON().value); + } catch (err) { + await storeTable(table, attributes); + previousAttributes = JSON.parse((await StrapiConfigs.forge({key: `db_model_${table}`}).fetch()).toJSON().value); + } + // Execute query to update column type await Promise.all(columns.map(attribute => new Promise(async (resolve) => { + if (JSON.stringify(previousAttributes[attribute]) === JSON.stringify(attributes[attribute])) { + return resolve(); + } + const type = getType(attributes[attribute], attribute); if (type) { @@ -567,6 +601,8 @@ module.exports = function(strapi) { resolve(); }) )); + + await storeTable(table, attributes); } }; @@ -583,7 +619,9 @@ module.exports = function(strapi) { } // Equilize tables - await handler(loadedModel.tableName, definition.attributes); + if (connection.options && connection.options.autoMigration !== false) { + await handler(loadedModel.tableName, definition.attributes); + } // Equilize polymorphic releations const morphRelations = definition.associations.find((association) => { @@ -606,7 +644,9 @@ module.exports = function(strapi) { } }; - await handler(`${loadedModel.tableName}_morph`, attributes); + if (connection.options && connection.options.autoMigration !== false) { + await handler(`${loadedModel.tableName}_morph`, attributes); + } } // Equilize many to many releations diff --git a/packages/strapi-helper-plugin/lib/src/components/ImgPreview/index.js b/packages/strapi-helper-plugin/lib/src/components/ImgPreview/index.js index 8162593d31..197af53f44 100644 --- a/packages/strapi-helper-plugin/lib/src/components/ImgPreview/index.js +++ b/packages/strapi-helper-plugin/lib/src/components/ImgPreview/index.js @@ -8,7 +8,7 @@ /* eslint-disable no-console */ import React from 'react'; import PropTypes from 'prop-types'; -import { get, has, isArray, isEmpty, size } from 'lodash'; +import { get, has, isArray, isEmpty, startsWith, size } from 'lodash'; import cn from 'classnames'; import BkgImg from 'assets/icons/icon_upload.svg'; @@ -31,9 +31,10 @@ class ImgPreview extends React.Component { componentDidMount() { // We don't need the generateImgURL function here since the compo will // always have an init value here + const file = this.props.multiple ? get(this.props.files, ['0', 'name'], '') : get(this.props.files, 'name'); this.setState({ imgURL: get(this.props.files, ['0', 'url'], '') || get(this.props.files, 'url', ''), - isImg: this.isPictureType(get(this.props.files, ['0', 'name'], '')), + isImg: this.isPictureType(file), }); } @@ -142,10 +143,12 @@ class ImgPreview extends React.Component { renderContent = () => { const fileType = this.getFileType(this.state.imgURL); - + if (this.state.isImg) { + const imgURL = startsWith(this.state.imgURL, '/') ? `${strapi.backendURL}${this.state.imgURL}` : this.state.imgURL; + return ( - + ); } @@ -159,6 +162,7 @@ class ImgPreview extends React.Component { render() { const { files, onBrowseClick } = this.props; const { imgURL } = this.state; + const containerStyle = isEmpty(imgURL) ? { backgroundImage: `url(${BkgImg})`, diff --git a/packages/strapi-helper-plugin/lib/src/components/PageFooter/index.js b/packages/strapi-helper-plugin/lib/src/components/PageFooter/index.js index 898adbf6de..56053b72a4 100644 --- a/packages/strapi-helper-plugin/lib/src/components/PageFooter/index.js +++ b/packages/strapi-helper-plugin/lib/src/components/PageFooter/index.js @@ -14,6 +14,7 @@ import GlobalPagination from 'components/GlobalPagination'; import styles from './styles.scss'; +/* eslint-disable jsx-a11y/label-has-for */ function PageFooter(props) { return (
diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpRelations/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpRelations/index.js index e7f81ab9b0..2061ac395b 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpRelations/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/PopUpRelations/index.js @@ -123,8 +123,9 @@ class PopUpRelations extends React.Component { value[0], ); } else { + const keyValue = get(this.props.values, 'params.nature') === 'oneWay' ? '-' : ''; this.props.onChange({ target: { name: 'name', value: '' } }); - this.props.onChange({ target: { name: 'params.key', value: '' } }); + this.props.onChange({ target: { name: 'params.key', value: keyValue } }); } } }; @@ -237,6 +238,8 @@ class PopUpRelations extends React.Component { const errs = findIndex(this.props.formErrors, ['name',get(this.props.form, ['items', '0', 'name'])]) !== -1 ? this.props.formErrors[findIndex(this.props.formErrors, ['name', get(this.props.form, ['items', '0', 'name'])])].errors: []; const errors = findIndex(this.props.formErrors, ['name', get(this.props.form, ['items', '1', 'name'])]) !== -1 ? this.props.formErrors[findIndex(this.props.formErrors, ['name', get(this.props.form, ['items', '1', 'name'])])].errors : []; + const contentTypeTargetPlaceholder = get(this.props.values, 'params.nature', '') === 'oneWay' ? '-' : get(this.props.contentType, 'name'); + const contentTypeTargetValue = get(this.props.values, 'params.nature') === 'oneWay' ? '-' : get(this.props.values, ['params', 'key']); return ( @@ -262,12 +265,12 @@ class PopUpRelations extends React.Component { />