mirror of
https://github.com/strapi/strapi.git
synced 2025-08-18 13:45:25 +00:00
Merge branch 'master' into language-ko_kr
This commit is contained in:
commit
236d2a62ed
10
.travis.yml
10
.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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
@ -144,8 +145,10 @@ class ImgPreview extends React.Component {
|
||||
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 (
|
||||
<img src={this.state.imgURL} alt="" />
|
||||
<img src={imgURL} alt="" />
|
||||
);
|
||||
}
|
||||
|
||||
@ -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})`,
|
||||
|
@ -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 (
|
||||
<div className={cn('row', styles.pageFooter)} style={props.style}>
|
||||
|
@ -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 (
|
||||
<ModalBody className={`${styles.modalBody} ${styles.flex}`}>
|
||||
@ -262,12 +265,12 @@ class PopUpRelations extends React.Component {
|
||||
/>
|
||||
<RelationBox
|
||||
tabIndex="2"
|
||||
contentTypeTargetPlaceholder={get(this.props.contentType, 'name')}
|
||||
contentTypeTargetPlaceholder={contentTypeTargetPlaceholder}
|
||||
relationType={get(this.props.values, ['params', 'nature'])}
|
||||
onSubmit={this.props.onSubmit}
|
||||
header={header}
|
||||
input={get(this.props.form, ['items', '1'])}
|
||||
value={get(this.props.values, ['params', 'key'])}
|
||||
value={contentTypeTargetValue}
|
||||
onChange={this.props.onChange}
|
||||
didCheckErrors={this.props.didCheckErrors}
|
||||
errors={errors}
|
||||
|
@ -143,7 +143,8 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
||||
}
|
||||
|
||||
// Check if user is adding a relation with the same content type
|
||||
if (includes(this.props.hash, 'attributerelation') && this.props.modifiedDataAttribute.params.target === this.props.modelName) {
|
||||
|
||||
if (includes(this.props.hash, 'attributerelation') && this.props.modifiedDataAttribute.params.target === this.props.modelName && get(this.props.modifiedDataAttribute, ['params', 'nature'], '') !== 'oneWay') {
|
||||
// Insert two attributes
|
||||
this.props.addAttributeRelationToContentType(this.props.modifiedDataAttribute);
|
||||
} else {
|
||||
@ -168,7 +169,8 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
||||
const contentType = this.props.modifiedDataEdit;
|
||||
// Add the new attribute to the content type attribute list
|
||||
const newAttribute = this.setTempAttribute();
|
||||
contentType.attributes = compact(concat(contentType.attributes, newAttribute, this.setParallelAttribute(newAttribute)));
|
||||
const parallelAttribute = this.props.modelName === get(newAttribute, ['params', 'target']) && get(newAttribute, ['params', 'nature'], '') === 'oneWay' ? null : this.setParallelAttribute(newAttribute);
|
||||
contentType.attributes = compact(concat(contentType.attributes, newAttribute, parallelAttribute));
|
||||
// Reset the store and update the parent container
|
||||
this.props.contentTypeCreate(contentType);
|
||||
// Get the displayed model from the localStorage
|
||||
|
Loading…
x
Reference in New Issue
Block a user