diff --git a/packages/strapi-generate-new/lib/before.js b/packages/strapi-generate-new/lib/before.js index a0e47d9524..1f6381aac8 100755 --- a/packages/strapi-generate-new/lib/before.js +++ b/packages/strapi-generate-new/lib/before.js @@ -152,7 +152,7 @@ module.exports = (scope, cb) => { when: !hasDatabaseConfig, type: 'input', name: 'port', - message: 'Port (It will be ignored if you enable +srv):', + message: `Port${scope.client.database === 'mongo' ? ' (It will be ignored if you enable +srv)' : ''}:`, default: (answers) => { // eslint-disable-line no-unused-vars if (_.get(scope.database, 'port')) { return scope.database.port; @@ -203,7 +203,7 @@ module.exports = (scope, cb) => { } scope.database.settings.host = answers.host; - scope.database.settings.srv = answers.srv; + scope.database.settings.srv = _.toString(answers.srv) === 'true'; scope.database.settings.port = answers.port; scope.database.settings.database = answers.database; scope.database.settings.username = answers.username; diff --git a/packages/strapi-helper-plugin/lib/src/components/InputFile/index.js b/packages/strapi-helper-plugin/lib/src/components/InputFile/index.js index 8763ba4ae6..c86ef7515f 100644 --- a/packages/strapi-helper-plugin/lib/src/components/InputFile/index.js +++ b/packages/strapi-helper-plugin/lib/src/components/InputFile/index.js @@ -8,7 +8,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; -import { cloneDeep } from 'lodash'; +import { cloneDeep, isArray, isObject } from 'lodash'; +import cn from 'classnames'; import ImgPreview from 'components/ImgPreview'; import InputFileDetails from 'components/InputFileDetails'; @@ -75,11 +76,12 @@ class InputFile extends React.Component { if (this.props.multiple) { value.splice(this.state.position, 1); } + // Update the parent's props const target = { name: this.props.name, type: 'file', - value, + value: Object.keys(value).length === 0 ? '' : value, }; this.props.onChange({ target }); @@ -98,6 +100,19 @@ class InputFile extends React.Component { this.setState({ position: newPosition }); } + isVisibleDetails = () => { + const {value} = this.props; + + if (!value || + (isArray(value) && value.length === 0) || + (isObject(value) && Object.keys(value).length === 0) + ) { + return false; + } + + return true; + } + render() { const { multiple, @@ -108,39 +123,43 @@ class InputFile extends React.Component { return (
- - +
+ {this.isVisibleDetails() && ( + + )} ); } @@ -150,9 +169,12 @@ InputFile.defaultProps = { multiple: false, setLabel: () => {}, value: [], + error: false, + }; InputFile.propTypes = { + error: PropTypes.bool, multiple: PropTypes.bool, name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, diff --git a/packages/strapi-helper-plugin/lib/src/components/InputFile/styles.scss b/packages/strapi-helper-plugin/lib/src/components/InputFile/styles.scss index c6c81e3692..26799e7784 100644 --- a/packages/strapi-helper-plugin/lib/src/components/InputFile/styles.scss +++ b/packages/strapi-helper-plugin/lib/src/components/InputFile/styles.scss @@ -32,3 +32,7 @@ .copy { cursor: copy !important; } + +.inputFileControlForm { + padding: 0; +} \ No newline at end of file diff --git a/packages/strapi-helper-plugin/lib/src/components/InputFileWithErrors/index.js b/packages/strapi-helper-plugin/lib/src/components/InputFileWithErrors/index.js index 6ca7ac1ff8..f9a8afed46 100644 --- a/packages/strapi-helper-plugin/lib/src/components/InputFileWithErrors/index.js +++ b/packages/strapi-helper-plugin/lib/src/components/InputFileWithErrors/index.js @@ -14,22 +14,39 @@ import Label from 'components/Label'; import InputDescription from 'components/InputDescription'; import InputFile from 'components/InputFile'; import InputSpacer from 'components/InputSpacer'; +import InputErrors from 'components/InputErrors'; +// Styles import styles from './styles.scss'; class InputFileWithErrors extends React.Component { - state = { label: false, hasValue: false }; + state = { errors: [], label: false, hasValue: false }; componentDidMount() { + const { errors } = this.props; + let newState = Object.assign({}, this.state); + if (this.props.multiple && !isEmpty(this.props.value)) { - this.setState({ label: 1, hasValue: true }); + newState = Object.assign({}, newState, { label: 1, hasValue: true }); } + + if (!isEmpty(errors)) { + newState = Object.assign({}, newState, { errors }); + } + + this.setState(newState); } componentWillReceiveProps(nextProps) { if (!this.state.hasValue && !isEmpty(nextProps.value) && nextProps.multiple && differenceBy(nextProps.value, this.props.value, 'name').length > 0) { this.setState({ label: 1, hasValue: true }); } + // Check if errors have been updated during validations + if (nextProps.didCheckErrors !== this.props.didCheckErrors) { + // Remove from the state the errors that have already been set + const errors = isEmpty(nextProps.errors) ? [] : nextProps.errors; + this.setState({ errors }); + } } setLabel = (label) => { @@ -40,6 +57,9 @@ class InputFileWithErrors extends React.Component { const { className, customBootstrapClass, + errorsClassName, + errorsStyle, + noErrorsDescription, inputDescription, inputDescriptionClassName, inputDescriptionStyle, @@ -76,6 +96,7 @@ class InputFileWithErrors extends React.Component { )} + {spacer} ); @@ -93,8 +119,12 @@ class InputFileWithErrors extends React.Component { } InputFileWithErrors.defaultProps = { + errors: [], + errorsClassName: '', + errorsStyle: {}, className: '', customBootstrapClass: 'col-md-6', + didCheckErrors: false, inputDescription: '', inputDescriptionClassName: '', inputDescriptionStyle: {}, @@ -102,6 +132,7 @@ InputFileWithErrors.defaultProps = { labelClassName: '', labelStyle: {}, multiple: false, + noErrorsDescription: false, style: {}, value: [], }; @@ -109,6 +140,10 @@ InputFileWithErrors.defaultProps = { InputFileWithErrors.propTypes = { className: PropTypes.string, customBootstrapClass: PropTypes.string, + didCheckErrors: PropTypes.bool, + errors: PropTypes.array, + errorsClassName: PropTypes.string, + errorsStyle: PropTypes.object, inputDescription: PropTypes.oneOfType([ PropTypes.string, PropTypes.func, @@ -131,6 +166,7 @@ InputFileWithErrors.propTypes = { labelStyle: PropTypes.object, multiple: PropTypes.bool, name: PropTypes.string.isRequired, + noErrorsDescription: PropTypes.bool, onChange: PropTypes.func.isRequired, style: PropTypes.object, value: PropTypes.oneOfType([ diff --git a/packages/strapi-hook-mongoose/lib/index.js b/packages/strapi-hook-mongoose/lib/index.js index a0c3e5e9d4..2ad6a41574 100755 --- a/packages/strapi-hook-mongoose/lib/index.js +++ b/packages/strapi-hook-mongoose/lib/index.js @@ -51,9 +51,10 @@ module.exports = function (strapi) { initialize: cb => { _.forEach(_.pickBy(strapi.config.connections, {connector: 'strapi-hook-mongoose'}), (connection, connectionName) => { const instance = new Mongoose(); - const { uri, host, port, username, password, database } = _.defaults(connection.settings, strapi.config.hook.settings.mongoose); + const { uri, host, port, username, password, database, srv } = _.defaults(connection.settings, strapi.config.hook.settings.mongoose); const uriOptions = uri ? url.parse(uri, true).query : {}; const { authenticationDatabase, ssl, debug } = _.defaults(connection.options, uriOptions, strapi.config.hook.settings.mongoose); + const isSrv = srv === true || srv === 'true'; // Connect to mongo database const connectOptions = {}; @@ -73,10 +74,16 @@ module.exports = function (strapi) { connectOptions.ssl = ssl === true || ssl === 'true'; connectOptions.useNewUrlParser = true; + connectOptions.dbName = database; options.debug = debug === true || debug === 'true'; - instance.connect(uri || `mongodb://${host}:${port}/${database}`, connectOptions); + /* FIXME: for now, mongoose doesn't support srv auth except the way including user/pass in URI. + * https://github.com/Automattic/mongoose/issues/6881 */ + instance.connect(uri || + `mongodb${isSrv ? '+srv' : ''}://${username}:${password}@${host}${ !isSrv ? ':' + port : '' }/`, + connectOptions + ); for (let key in options) { instance.set(key, options[key]); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/forms.json b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/forms.json index af00853d4e..38d1808991 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/forms.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/Form/forms.json @@ -926,7 +926,10 @@ }, "name": "name", "type": "string", - "value": "" + "value": "", + "validations": { + "required": true + } }, { "label": { diff --git a/packages/strapi-plugin-content-type-builder/services/ContentTypeBuilder.js b/packages/strapi-plugin-content-type-builder/services/ContentTypeBuilder.js index 2170bfec9b..6910be9dc8 100755 --- a/packages/strapi-plugin-content-type-builder/services/ContentTypeBuilder.js +++ b/packages/strapi-plugin-content-type-builder/services/ContentTypeBuilder.js @@ -178,7 +178,8 @@ module.exports = { if (params.plugin === 'upload' && relation.model || relation.collection === 'file') { params = { type: 'media', - multiple: params.collection ? true : false + multiple: params.collection ? true : false, + required: params.required }; } else { params = _.omit(params, ['collection', 'model', 'via']); @@ -288,7 +289,8 @@ module.exports = { attrs[attribute.name] = { [attribute.params.multiple ? 'collection' : 'model']: 'file', via, - plugin: 'upload' + plugin: 'upload', + required: attribute.params.required === true ? true : false }; } } else if (_.has(attribute, 'params.target')) {