From aea545fc1ddbd3dcd6da44dd17c820247a391cf5 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 19 Dec 2018 23:22:04 -0200 Subject: [PATCH 01/20] create DynamicForm React component --- client/app/assets/less/redash/ant.less | 1 + client/app/components/dynamic-form.html | 41 ------ client/app/components/dynamic-form.js | 124 ---------------- .../components/dynamic-form/DynamicForm.jsx | 132 ++++++++++++++++++ .../dynamic-form/dynamicFormHelper.js | 107 ++++++++++++++ client/app/components/proptypes.js | 14 ++ 6 files changed, 254 insertions(+), 165 deletions(-) delete mode 100644 client/app/components/dynamic-form.html delete mode 100644 client/app/components/dynamic-form.js create mode 100644 client/app/components/dynamic-form/DynamicForm.jsx create mode 100644 client/app/components/dynamic-form/dynamicFormHelper.js diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index deb8d75555..47447f739a 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -4,6 +4,7 @@ @import '~antd/lib/date-picker/style/index.less'; @import '~antd/lib/tooltip/style/index.less'; @import '~antd/lib/select/style/index.less'; +@import '~antd/lib/checkbox/style/index.less'; // Overwritting Ant Design defaults to fit into Redash current style @font-family-no-number : @redash-font; diff --git a/client/app/components/dynamic-form.html b/client/app/components/dynamic-form.html deleted file mode 100644 index 50037be5c0..0000000000 --- a/client/app/components/dynamic-form.html +++ /dev/null @@ -1,41 +0,0 @@ -
-
- - - -
-
-
- - - - - - - - -
- - - - - - - - - -
diff --git a/client/app/components/dynamic-form.js b/client/app/components/dynamic-form.js deleted file mode 100644 index 5c3e337ad8..0000000000 --- a/client/app/components/dynamic-form.js +++ /dev/null @@ -1,124 +0,0 @@ -import { isUndefined, each, includes } from 'lodash'; -import template from './dynamic-form.html'; - -function orderedInputs(properties, order) { - const inputs = new Array(order.length); - Object.keys(properties).forEach((key) => { - const position = order.indexOf(key); - const input = { name: key, property: properties[key] }; - if (position > -1) { - inputs[position] = input; - } else { - inputs.push(input); - } - }); - return inputs; -} - -function normalizeSchema(configurationSchema) { - each(configurationSchema.properties, (prop, name) => { - if (name === 'password' || name === 'passwd') { - prop.type = 'password'; - } - - if (name.endsWith('File')) { - prop.type = 'file'; - } - - if (prop.type === 'boolean') { - prop.type = 'checkbox'; - } - - prop.required = includes(configurationSchema.required, name); - }); - - configurationSchema.order = configurationSchema.order || []; -} - -function setDefaults(configurationSchema, options) { - if (Object.keys(options).length === 0) { - const properties = configurationSchema.properties; - Object.keys(properties).forEach((property) => { - if (!isUndefined(properties[property].default)) { - options[property] = properties[property].default; - } - }); - } -} - -function DynamicForm($http, toastr) { - return { - restrict: 'E', - replace: 'true', - transclude: true, - template, - scope: { - target: '=', - type: '=', - actions: '=', - }, - link($scope) { - const configurationSchema = $scope.type.configuration_schema; - normalizeSchema(configurationSchema); - $scope.fields = orderedInputs(configurationSchema.properties, configurationSchema.order); - setDefaults(configurationSchema, $scope.target.options); - - $scope.inProgressActions = {}; - if ($scope.actions) { - $scope.actions.forEach((action) => { - const originalCallback = action.callback; - const name = action.name; - action.callback = () => { - action.name = ` ${name}`; - - $scope.inProgressActions[action.name] = true; - function release() { - $scope.inProgressActions[action.name] = false; - action.name = name; - } - - originalCallback(release); - }; - }); - } - - $scope.files = {}; - - $scope.$watchCollection('files', () => { - each($scope.files, (v, k) => { - // THis is needed because angular-base64-upload sets the value to null at initialization, - // causing the field to be marked as dirty even if it wasn't changed. - if (!v && $scope.target.options[k]) { - $scope.dynamicForm.$setPristine(); - } - if (v) { - $scope.target.options[k] = v.base64; - } - }); - }); - - $scope.saveChanges = () => { - $scope.target.$save( - () => { - toastr.success('Saved.'); - $scope.dynamicForm.$setPristine(); - }, - (error) => { - if (error.status === 400 && 'message' in error.data) { - toastr.error(error.data.message); - } else { - toastr.error('Failed saving.'); - } - }, - ); - }; - }, - }; -} - -export default function init(ngModule) { - ngModule.directive('dynamicForm', DynamicForm); -} - -init.init = true; - diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx new file mode 100644 index 0000000000..a7c5a46460 --- /dev/null +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -0,0 +1,132 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Form, Input, Checkbox } from 'antd'; +import { react2angular } from 'react2angular'; +import { Field, Action } from '../proptypes'; +import helper from './dynamicFormHelper'; + +export class DynamicForm extends React.Component { + static propTypes = { + fields: PropTypes.arrayOf(Field), + actions: PropTypes.arrayOf(Action), + onSubmit: PropTypes.func, + }; + + static defaultProps = { + fields: [ + { + name: 'name', + title: 'Name', + type: 'text', + placeholder: 'Name', + }, + { + name: 'test', + title: 'Test', + type: 'text', + placeholder: 'Name', + }, + { + name: 'check', + title: 'Test Checkbox', + type: 'checkbox', + }, + ], + actions: [], + onSubmit: () => {}, + }; + + constructor(props) { + super(props); + + const data = this.props.fields.reduce((acc, cur) => ({ + ...acc, + [cur.name]: cur.defaultValue, + }), {}); + + this.state = { + data, + }; + + this.handleInputChange = this.handleInputChange.bind(this); + this.renderFields = this.renderFields.bind(this); + } + + handleInputChange = (e) => { + const data = { + ...this.state.data, + [e.target.name]: e.target.type === 'checkbox' ? e.target.checked : e.target.value, + }; + + this.setState({ + data, + }); + }; + + renderFields() { + const [firstItem] = this.props.fields; + + return this.props.fields.map((field) => { + const FormItem = Form.Item; + const { + name, + title, + type, + placeholder, + } = field; + const fieldLabel = title || helper.toHuman(name); + + const value = this.state.data[name]; + + const props = { + autoFocus: (firstItem === field), + onChange: this.handleInputChange, + name, + placeholder, + }; + + switch (type) { + case 'checkbox': + return ( + + {fieldLabel} + + ); + default: + return ( + + + + ); + } + }); + } + + render() { + const { onSubmit } = this.props; + + return ( +
+ {this.renderFields()} +
+ ); + } +} + +export default function init(ngModule) { + ngModule.component('dynamicForm', { + template: ` + + `, + bindings: { + target: '=', + type: '=', + actions: '=', + onSubmit: '=', + }, + }); + ngModule.component('dynamicFormImpl', react2angular(DynamicForm)); +} + +init.init = true; diff --git a/client/app/components/dynamic-form/dynamicFormHelper.js b/client/app/components/dynamic-form/dynamicFormHelper.js new file mode 100644 index 0000000000..a4a7a9f5d1 --- /dev/null +++ b/client/app/components/dynamic-form/dynamicFormHelper.js @@ -0,0 +1,107 @@ +import { isUndefined, each, includes } from 'lodash'; + +function orderedInputs(properties, order) { + const inputs = new Array(order.length); + Object.keys(properties).forEach((key) => { + const position = order.indexOf(key); + const input = { + name: key, + property: properties[key], + }; + + if (position > -1) { + inputs[position] = input; + } else { + inputs.push(input); + } + }); + return inputs; +} + +function normalizeSchema(configurationSchema) { + each(configurationSchema.properties, (prop, name) => { + if (name === 'password' || name === 'passwd') { + prop.type = 'password'; + } + + if (name.endsWith('File')) { + prop.type = 'file'; + } + + if (prop.type === 'boolean') { + prop.type = 'checkbox'; + } + + prop.required = includes(configurationSchema.required, name); + }); + + configurationSchema.order = configurationSchema.order || []; +} + +function setDefaults(configurationSchema, options) { + if (Object.keys(options).length === 0) { + const properties = configurationSchema.properties; + Object.keys(properties).forEach((property) => { + if (!isUndefined(properties[property].default)) { + options[property] = properties[property].default; + } + }); + } +} + +function getInputs(configurationSchema, targetOptions) { + normalizeSchema(configurationSchema); + setDefaults(configurationSchema, targetOptions); + const inputs = orderedInputs(configurationSchema.properties, configurationSchema.order); + + inputs.forEach((input) => { + input.hasErrors = input.property.required && !targetOptions[input.name]; + }); + + return inputs; +} + +function toHuman(text) { + return text.replace(/_/g, ' ').replace(/(?:^|\s)\S/g, a => a.toUpperCase()); +} + +const updateFieldState = (fieldName, value, hasErrors) => { + if (!this) return; + + const fields = this.state.fields + .map(field => ( + field.name === fieldName ? { ...field, value, hasErrors } : field + )); + + const nameErrors = fieldName === 'name' ? hasErrors : this.state.nameErrors; + + this.setState({ + target: { + ...this.state.target, + options: { + ...this.state.target.options, + [fieldName]: value, + }, + }, + nameErrors, + fields, + }); +}; + +const setActionInProgress = (actionName, inProgress) => { + if (!this) return; + + this.setState({ + inProgressActions: { + ...this.state.inProgressActions, + [actionName]: inProgress, + }, + }); +}; + +export default { + getInputs, + updateFieldState, + setActionInProgress, + toHuman, +}; diff --git a/client/app/components/proptypes.js b/client/app/components/proptypes.js index a6db8a8c18..0532c773de 100644 --- a/client/app/components/proptypes.js +++ b/client/app/components/proptypes.js @@ -14,3 +14,17 @@ export const Table = PropTypes.shape({ }); export const Schema = PropTypes.arrayOf(Table); + +export const Field = PropTypes.shape({ + name: PropTypes.string.isRequired, + title: PropTypes.string, + type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'checkbox']).isRequired, + defaultValue: PropTypes.oneOf([PropTypes.string, PropTypes.number, PropTypes.bool]), + required: PropTypes.bool, + placeholder: PropTypes.string, +}); + +export const Action = PropTypes.shape({ + name: PropTypes.string.isRequired, + callback: PropTypes.func.isRequired, +}); From 4aa9ca3fbe8633e1f501fb70624a284bf67fee75 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 23 Dec 2018 14:23:23 -0200 Subject: [PATCH 02/20] Render fields based on target in DynamicForm --- client/app/assets/less/redash/ant.less | 7 + .../components/dynamic-form/DynamicForm.jsx | 140 ++++++++---------- .../dynamic-form/dynamicFormHelper.js | 68 +++------ client/app/components/proptypes.js | 6 +- 4 files changed, 95 insertions(+), 126 deletions(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 47447f739a..f53f25a33f 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -1,10 +1,13 @@ @import '~antd/lib/style/core/iconfont.less'; @import '~antd/lib/style/core/motion.less'; @import '~antd/lib/input/style/index.less'; +@import '~antd/lib/input-number/style/index.less'; @import '~antd/lib/date-picker/style/index.less'; @import '~antd/lib/tooltip/style/index.less'; @import '~antd/lib/select/style/index.less'; @import '~antd/lib/checkbox/style/index.less'; +@import '~antd/lib/button/style/index.less'; +@import '~antd/lib/form/style/index.less'; // Overwritting Ant Design defaults to fit into Redash current style @font-family-no-number : @redash-font; @@ -37,3 +40,7 @@ .ant-dropdown-in-bootstrap-modal { z-index: 1050; } + +.ant-form-item-label label { + color: inherit; +} diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index a7c5a46460..bfa15e7eee 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -1,8 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Form, Input, Checkbox } from 'antd'; +import { Form, Input, InputNumber, Checkbox, Button } from 'antd'; import { react2angular } from 'react2angular'; -import { Field, Action } from '../proptypes'; +import { Field, Action, AntdForm } from '../proptypes'; import helper from './dynamicFormHelper'; export class DynamicForm extends React.Component { @@ -10,123 +10,105 @@ export class DynamicForm extends React.Component { fields: PropTypes.arrayOf(Field), actions: PropTypes.arrayOf(Action), onSubmit: PropTypes.func, + form: AntdForm.isRequired, }; static defaultProps = { - fields: [ - { - name: 'name', - title: 'Name', - type: 'text', - placeholder: 'Name', - }, - { - name: 'test', - title: 'Test', - type: 'text', - placeholder: 'Name', - }, - { - name: 'check', - title: 'Test Checkbox', - type: 'checkbox', - }, - ], + fields: [], actions: [], onSubmit: () => {}, }; - constructor(props) { - super(props); - - const data = this.props.fields.reduce((acc, cur) => ({ - ...acc, - [cur.name]: cur.defaultValue, - }), {}); + handleSubmit = (e) => { + e.preventDefault(); + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + this.props.onSubmit(values); + } + }); + } - this.state = { - data, + renderField(field) { + const [firstItem] = this.props.fields; + const { getFieldDecorator } = this.props.form; + const { name, type, initialValue } = field; + const fieldLabel = field.title || helper.toHuman(name); + + const props = { + autoFocus: (firstItem === field), + name, + placeholder: field.placeholder, }; - this.handleInputChange = this.handleInputChange.bind(this); - this.renderFields = this.renderFields.bind(this); - } - - handleInputChange = (e) => { - const data = { - ...this.state.data, - [e.target.name]: e.target.type === 'checkbox' ? e.target.checked : e.target.value, + const options = { + rules: [ + { required: field.required, message: `${fieldLabel} is required!` }, + ], + valuePropName: type === 'checkbox' ? 'checked' : 'value', + initialValue, }; - this.setState({ - data, - }); - }; + switch (type) { + case 'checkbox': + return getFieldDecorator(name, options)({fieldLabel}); + case 'number': + return getFieldDecorator(name, options)(); + default: + return getFieldDecorator(name, options)(); + } + } renderFields() { - const [firstItem] = this.props.fields; - return this.props.fields.map((field) => { const FormItem = Form.Item; - const { - name, - title, - type, - placeholder, - } = field; + const { name, title, type } = field; const fieldLabel = title || helper.toHuman(name); - const value = this.state.data[name]; - - const props = { - autoFocus: (firstItem === field), - onChange: this.handleInputChange, - name, - placeholder, + const formItemProps = { + key: name, + label: type === 'checkbox' ? '' : fieldLabel, }; - switch (type) { - case 'checkbox': - return ( - - {fieldLabel} - - ); - default: - return ( - - - - ); - } + return ( + + {this.renderField(field)} + + ); }); } render() { - const { onSubmit } = this.props; - return ( -
+ {this.renderFields()} +
); } } export default function init(ngModule) { - ngModule.component('dynamicForm', { + ngModule.directive('dynamicForm', () => ({ + restrict: 'E', + transclude: true, template: ` `, - bindings: { + scope: { target: '=', type: '=', actions: '=', - onSubmit: '=', }, - }); - ngModule.component('dynamicFormImpl', react2angular(DynamicForm)); + link($scope) { + $scope.fields = helper.getFields($scope.type.configuration_schema, $scope.target); + }, + })); + + ngModule.component('dynamicFormImpl', react2angular(Form.create()(DynamicForm), ['fields'])); } init.init = true; diff --git a/client/app/components/dynamic-form/dynamicFormHelper.js b/client/app/components/dynamic-form/dynamicFormHelper.js index a4a7a9f5d1..5f3ace15d7 100644 --- a/client/app/components/dynamic-form/dynamicFormHelper.js +++ b/client/app/components/dynamic-form/dynamicFormHelper.js @@ -1,12 +1,15 @@ import { isUndefined, each, includes } from 'lodash'; -function orderedInputs(properties, order) { +function orderedInputs(properties, order, targetOptions) { const inputs = new Array(order.length); Object.keys(properties).forEach((key) => { const position = order.indexOf(key); const input = { name: key, - property: properties[key], + type: properties[key].type, + placeholder: properties[key].default && properties[key].default.toString(), + required: properties[key].required, + initialValue: targetOptions[key], }; if (position > -1) { @@ -32,6 +35,10 @@ function normalizeSchema(configurationSchema) { prop.type = 'checkbox'; } + if (prop.type === 'string') { + prop.type = 'text'; + } + prop.required = includes(configurationSchema.required, name); }); @@ -49,14 +56,19 @@ function setDefaults(configurationSchema, options) { } } -function getInputs(configurationSchema, targetOptions) { +function getFields(configurationSchema, target) { normalizeSchema(configurationSchema); - setDefaults(configurationSchema, targetOptions); - const inputs = orderedInputs(configurationSchema.properties, configurationSchema.order); - - inputs.forEach((input) => { - input.hasErrors = input.property.required && !targetOptions[input.name]; - }); + setDefaults(configurationSchema, target.options); + const inputs = [ + { + name: 'name', + title: 'Name', + type: 'text', + required: true, + initialValue: target.name, + }, + ...orderedInputs(configurationSchema.properties, configurationSchema.order, target.options), + ]; return inputs; } @@ -65,43 +77,7 @@ function toHuman(text) { return text.replace(/_/g, ' ').replace(/(?:^|\s)\S/g, a => a.toUpperCase()); } -const updateFieldState = (fieldName, value, hasErrors) => { - if (!this) return; - - const fields = this.state.fields - .map(field => ( - field.name === fieldName ? { ...field, value, hasErrors } : field - )); - - const nameErrors = fieldName === 'name' ? hasErrors : this.state.nameErrors; - - this.setState({ - target: { - ...this.state.target, - options: { - ...this.state.target.options, - [fieldName]: value, - }, - }, - nameErrors, - fields, - }); -}; - -const setActionInProgress = (actionName, inProgress) => { - if (!this) return; - - this.setState({ - inProgressActions: { - ...this.state.inProgressActions, - [actionName]: inProgress, - }, - }); -}; - export default { - getInputs, - updateFieldState, - setActionInProgress, + getFields, toHuman, }; diff --git a/client/app/components/proptypes.js b/client/app/components/proptypes.js index 0532c773de..ed48f7e692 100644 --- a/client/app/components/proptypes.js +++ b/client/app/components/proptypes.js @@ -19,7 +19,7 @@ export const Field = PropTypes.shape({ name: PropTypes.string.isRequired, title: PropTypes.string, type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'checkbox']).isRequired, - defaultValue: PropTypes.oneOf([PropTypes.string, PropTypes.number, PropTypes.bool]), + initialValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]), required: PropTypes.bool, placeholder: PropTypes.string, }); @@ -28,3 +28,7 @@ export const Action = PropTypes.shape({ name: PropTypes.string.isRequired, callback: PropTypes.func.isRequired, }); + +export const AntdForm = PropTypes.shape({ + validateFieldsAndScroll: PropTypes.func, +}); From 9fd2cf22d794b44e47e63acd68b11a3305d4a7fb Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 23 Dec 2018 14:32:48 -0200 Subject: [PATCH 03/20] Add missing title property to fields --- client/app/components/dynamic-form/dynamicFormHelper.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/app/components/dynamic-form/dynamicFormHelper.js b/client/app/components/dynamic-form/dynamicFormHelper.js index 5f3ace15d7..ee072d6341 100644 --- a/client/app/components/dynamic-form/dynamicFormHelper.js +++ b/client/app/components/dynamic-form/dynamicFormHelper.js @@ -6,6 +6,7 @@ function orderedInputs(properties, order, targetOptions) { const position = order.indexOf(key); const input = { name: key, + title: properties[key].title, type: properties[key].type, placeholder: properties[key].default && properties[key].default.toString(), required: properties[key].required, From 53f344328c75373517f0348e1da7b43ec80c1ab5 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 23 Dec 2018 17:35:07 -0200 Subject: [PATCH 04/20] Fix style properties in DynamicForm --- client/app/assets/less/redash/ant.less | 5 +++++ client/app/components/dynamic-form/DynamicForm.jsx | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index f53f25a33f..1ff5e33625 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -44,3 +44,8 @@ .ant-form-item-label label { color: inherit; } + +.has-success .ant-input, +.has-success .ant-input:hover { + border-color: @border-color-base !important; +} diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index bfa15e7eee..5d38f9677d 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -36,7 +36,9 @@ export class DynamicForm extends React.Component { const props = { autoFocus: (firstItem === field), + className: 'w-100', name, + type, placeholder: field.placeholder, }; @@ -66,6 +68,8 @@ export class DynamicForm extends React.Component { const formItemProps = { key: name, + className: 'm-b-10', + hasFeedback: false, label: type === 'checkbox' ? '' : fieldLabel, }; From 3e671ba168278558920118fbf52d461a14726209 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 23 Dec 2018 18:06:38 -0200 Subject: [PATCH 05/20] Render File fields in DynamicForm --- client/app/assets/less/redash/ant.less | 1 + .../components/dynamic-form/DynamicForm.jsx | 23 +++++++++++++++---- client/app/components/proptypes.js | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 1ff5e33625..93d7175e10 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -6,6 +6,7 @@ @import '~antd/lib/tooltip/style/index.less'; @import '~antd/lib/select/style/index.less'; @import '~antd/lib/checkbox/style/index.less'; +@import '~antd/lib/upload/style/index.less'; @import '~antd/lib/button/style/index.less'; @import '~antd/lib/form/style/index.less'; diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 5d38f9677d..2b02fd70b5 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -1,10 +1,21 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Form, Input, InputNumber, Checkbox, Button } from 'antd'; +import { Form, Input, InputNumber, Checkbox, Button, Upload, Icon } from 'antd'; import { react2angular } from 'react2angular'; import { Field, Action, AntdForm } from '../proptypes'; import helper from './dynamicFormHelper'; +const getValuePropNameForType = (type) => { + switch (type) { + case 'checkbox': + return 'checked'; + case 'file': + return 'fileList'; + default: + return 'value'; + } +}; + export class DynamicForm extends React.Component { static propTypes = { fields: PropTypes.arrayOf(Field), @@ -43,16 +54,18 @@ export class DynamicForm extends React.Component { }; const options = { - rules: [ - { required: field.required, message: `${fieldLabel} is required!` }, - ], - valuePropName: type === 'checkbox' ? 'checked' : 'value', + rules: [{ required: field.required, message: `${fieldLabel} is required!` }], + valuePropName: getValuePropNameForType(type), initialValue, }; + const uploadButton = (); + switch (type) { case 'checkbox': return getFieldDecorator(name, options)({fieldLabel}); + case 'file': + return getFieldDecorator(name, options)({uploadButton}); case 'number': return getFieldDecorator(name, options)(); default: diff --git a/client/app/components/proptypes.js b/client/app/components/proptypes.js index ed48f7e692..4af36fb9e9 100644 --- a/client/app/components/proptypes.js +++ b/client/app/components/proptypes.js @@ -18,7 +18,7 @@ export const Schema = PropTypes.arrayOf(Table); export const Field = PropTypes.shape({ name: PropTypes.string.isRequired, title: PropTypes.string, - type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'checkbox']).isRequired, + type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'checkbox', 'file']).isRequired, initialValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]), required: PropTypes.bool, placeholder: PropTypes.string, From 6816e2487ae0695301b42039c062eb3176d505e3 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 25 Dec 2018 15:47:00 -0200 Subject: [PATCH 06/20] Use React for middle component instead of Angular --- .../components/dynamic-form/DynamicForm.jsx | 33 ++++++++----------- client/app/components/proptypes.js | 2 ++ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 2b02fd70b5..feca0ea9ae 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -54,7 +54,7 @@ export class DynamicForm extends React.Component { }; const options = { - rules: [{ required: field.required, message: `${fieldLabel} is required!` }], + rules: [{ required: field.required, message: `${fieldLabel} is required.` }], valuePropName: getValuePropNameForType(type), initialValue, }; @@ -107,25 +107,18 @@ export class DynamicForm extends React.Component { } export default function init(ngModule) { - ngModule.directive('dynamicForm', () => ({ - restrict: 'E', - transclude: true, - template: ` - - `, - scope: { - target: '=', - type: '=', - actions: '=', - }, - link($scope) { - $scope.fields = helper.getFields($scope.type.configuration_schema, $scope.target); - }, - })); - - ngModule.component('dynamicFormImpl', react2angular(Form.create()(DynamicForm), ['fields'])); + ngModule.component('dynamicForm', react2angular((props) => { + const UpdatedDynamicForm = Form.create()(DynamicForm); + const fields = helper.getFields(props.type.configuration_schema, props.target); + + const updatedProps = { + fields, + actions: props.actions, + onSubmit: props.target.$save, + }; + + return (); + }, ['target', 'type', 'actions'])); } init.init = true; diff --git a/client/app/components/proptypes.js b/client/app/components/proptypes.js index 4af36fb9e9..f69c49a977 100644 --- a/client/app/components/proptypes.js +++ b/client/app/components/proptypes.js @@ -27,6 +27,8 @@ export const Field = PropTypes.shape({ export const Action = PropTypes.shape({ name: PropTypes.string.isRequired, callback: PropTypes.func.isRequired, + class: PropTypes.string, + disabledWhenDirty: PropTypes.bool, }); export const AntdForm = PropTypes.shape({ From 70f3a4b5720b16177c37ee1cc4e39f6a42e6be9b Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 26 Dec 2018 20:18:53 -0200 Subject: [PATCH 07/20] Functional save button --- client/app/assets/less/redash/ant.less | 1 + .../components/dynamic-form/DynamicForm.jsx | 28 ++++++++++++++++--- .../dynamic-form/dynamicFormHelper.js | 10 +++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 93d7175e10..990be9a56b 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -9,6 +9,7 @@ @import '~antd/lib/upload/style/index.less'; @import '~antd/lib/button/style/index.less'; @import '~antd/lib/form/style/index.less'; +@import '~antd/lib/message/style/index.less'; // Overwritting Ant Design defaults to fit into Redash current style @font-family-no-number : @redash-font; diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index feca0ea9ae..6034199990 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Form, Input, InputNumber, Checkbox, Button, Upload, Icon } from 'antd'; +import { Form, Input, InputNumber, Checkbox, Button, Upload, Icon, message } from 'antd'; import { react2angular } from 'react2angular'; import { Field, Action, AntdForm } from '../proptypes'; import helper from './dynamicFormHelper'; @@ -34,7 +34,11 @@ export class DynamicForm extends React.Component { e.preventDefault(); this.props.form.validateFieldsAndScroll((err, values) => { if (!err) { - this.props.onSubmit(values); + this.props.onSubmit( + values, + message.success, + message.error, + ); } }); } @@ -98,7 +102,7 @@ export class DynamicForm extends React.Component { return (
{this.renderFields()} -
@@ -111,10 +115,26 @@ export default function init(ngModule) { const UpdatedDynamicForm = Form.create()(DynamicForm); const fields = helper.getFields(props.type.configuration_schema, props.target); + const onSubmit = (values, onSuccess, onError) => { + helper.updateTargetWithValues(props.target, values); + props.target.$save( + () => { + onSuccess('Saved.'); + }, + (error) => { + if (error.status === 400 && 'message' in error.data) { + onError(error.data.message); + } else { + onError('Failed saving.'); + } + }, + ); + }; + const updatedProps = { fields, actions: props.actions, - onSubmit: props.target.$save, + onSubmit, }; return (); diff --git a/client/app/components/dynamic-form/dynamicFormHelper.js b/client/app/components/dynamic-form/dynamicFormHelper.js index ee072d6341..cd1aaf65e3 100644 --- a/client/app/components/dynamic-form/dynamicFormHelper.js +++ b/client/app/components/dynamic-form/dynamicFormHelper.js @@ -74,11 +74,21 @@ function getFields(configurationSchema, target) { return inputs; } +function updateTargetWithValues(target, values) { + target.name = values.name; + Object.keys(values).forEach((key) => { + if (key !== 'name') { + target.options[key] = values[key]; + } + }); +} + function toHuman(text) { return text.replace(/_/g, ' ').replace(/(?:^|\s)\S/g, a => a.toUpperCase()); } export default { getFields, + updateTargetWithValues, toHuman, }; From a5f7f14652799720ab7276c12aa8dad90b554396 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 26 Dec 2018 20:37:36 -0200 Subject: [PATCH 08/20] Update label style --- client/app/assets/less/redash/ant.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 990be9a56b..38a9b41e62 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -45,6 +45,9 @@ .ant-form-item-label label { color: inherit; + white-space: initial; + line-height: initial; + text-align: left; } .has-success .ant-input, From b65c43c2c9263f60dc3ed3db79e1149aed3c008e Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 27 Dec 2018 02:13:23 -0200 Subject: [PATCH 09/20] Render functional actions --- client/app/assets/less/redash/ant.less | 9 ++ .../components/dynamic-form/DynamicForm.jsx | 98 ++++++++++++++++--- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 38a9b41e62..24ac86ac70 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -43,6 +43,7 @@ z-index: 1050; } +// Make Ant labels more like Redash .ant-form-item-label label { color: inherit; white-space: initial; @@ -50,6 +51,14 @@ text-align: left; } +// Fix for text becoming black on disabled buttons +.btn-danger, .btn-primary, .btn-success, .btn-info { + &[disabled] { + color: @white !important; + } +} + +// Remove green border from Ant inputs .has-success .ant-input, .has-success .ant-input:hover { border-color: @border-color-base !important; diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 6034199990..71f8c1cff6 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -30,16 +30,62 @@ export class DynamicForm extends React.Component { onSubmit: () => {}, }; + constructor(props) { + super(props); + + this.state = { + isSubmitting: false, + inProgressActions: [], + }; + + this.actionCallbacks = this.props.actions.reduce((acc, cur) => ({ + ...acc, + [cur.name]: cur.callback, + }), []); + + props.actions.forEach((action) => { + this.state.inProgressActions[action.name] = false; + }); + } + handleSubmit = (e) => { + this.setState({ isSubmitting: true }); e.preventDefault(); this.props.form.validateFieldsAndScroll((err, values) => { if (!err) { this.props.onSubmit( values, - message.success, - message.error, + (msg) => { + const { setFieldsValue, getFieldsValue } = this.props.form; + this.setState({ isSubmitting: false }); + setFieldsValue(getFieldsValue()); // reset form touched state + message.success(msg); + }, + (msg) => { + this.setState({ isSubmitting: false }); + message.error(msg); + }, ); - } + } else this.setState({ isSubmitting: false }); + }); + } + + handleAction = (e) => { + const actionName = e.target.dataset.action; + + this.setState({ + inProgressActions: { + ...this.state.inProgressActions, + [actionName]: true, + }, + }); + this.actionCallbacks[actionName](() => { + this.setState({ + inProgressActions: { + ...this.state.inProgressActions, + [actionName]: false, + }, + }); }); } @@ -65,16 +111,14 @@ export class DynamicForm extends React.Component { const uploadButton = (); - switch (type) { - case 'checkbox': - return getFieldDecorator(name, options)({fieldLabel}); - case 'file': - return getFieldDecorator(name, options)({uploadButton}); - case 'number': - return getFieldDecorator(name, options)(); - default: - return getFieldDecorator(name, options)(); + if (type === 'checkbox') { + return getFieldDecorator(name, options)({fieldLabel}); + } else if (type === 'file') { + return getFieldDecorator(name, options)({uploadButton}); + } else if (type === 'number') { + return getFieldDecorator(name, options)(); } + return getFieldDecorator(name, options)(); } renderFields() { @@ -98,13 +142,39 @@ export class DynamicForm extends React.Component { }); } + renderActions() { + return this.props.actions.map((action) => { + const inProgress = this.state.inProgressActions[action.name]; + + const actionProps = { + key: action.name, + htmlType: 'button', + className: `${action.class} m-t-10`, + disabled: inProgress || this.props.form.isFieldsTouched(), + loading: inProgress, + onClick: this.handleAction, + }; + + return (); + }); + } + render() { + const submitProps = { + type: 'primary', + htmlType: 'submit', + className: 'w-100', + disabled: this.state.isSubmitting, + loading: this.state.isSubmitting, + }; + return (
{this.renderFields()} - + {this.renderActions()}
); } @@ -133,7 +203,7 @@ export default function init(ngModule) { const updatedProps = { fields, - actions: props.actions, + actions: props.target.id ? props.actions : [], onSubmit, }; From 553aea17645664f8137982cac2832c43aed9dd87 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 30 Dec 2018 17:49:34 -0200 Subject: [PATCH 10/20] Handle file inputs --- .../components/dynamic-form/DynamicForm.jsx | 67 +++++++++++-------- .../dynamic-form/dynamicFormHelper.js | 10 +++ client/app/services/toastr.js | 10 +++ .../data-source/create_data_source_spec.js | 2 +- 4 files changed, 59 insertions(+), 30 deletions(-) create mode 100644 client/app/services/toastr.js diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 71f8c1cff6..9c22f72999 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -1,20 +1,16 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Form, Input, InputNumber, Checkbox, Button, Upload, Icon, message } from 'antd'; +import { Form, Input, InputNumber, Checkbox, Button, Upload, Icon } from 'antd'; import { react2angular } from 'react2angular'; +import { toastr } from '@/services/toastr'; import { Field, Action, AntdForm } from '../proptypes'; import helper from './dynamicFormHelper'; -const getValuePropNameForType = (type) => { - switch (type) { - case 'checkbox': - return 'checked'; - case 'file': - return 'fileList'; - default: - return 'value'; - } -}; +const renderUpload = (props, disabled) => ( + false}> + + +); export class DynamicForm extends React.Component { static propTypes = { @@ -48,6 +44,15 @@ export class DynamicForm extends React.Component { }); } + setActionInProgress = (actionName, inProgress) => { + this.setState({ + inProgressActions: { + ...this.state.inProgressActions, + [actionName]: inProgress, + }, + }); + } + handleSubmit = (e) => { this.setState({ isSubmitting: true }); e.preventDefault(); @@ -59,11 +64,11 @@ export class DynamicForm extends React.Component { const { setFieldsValue, getFieldsValue } = this.props.form; this.setState({ isSubmitting: false }); setFieldsValue(getFieldsValue()); // reset form touched state - message.success(msg); + toastr.success(msg); }, (msg) => { this.setState({ isSubmitting: false }); - message.error(msg); + toastr.error(msg); }, ); } else this.setState({ isSubmitting: false }); @@ -73,25 +78,23 @@ export class DynamicForm extends React.Component { handleAction = (e) => { const actionName = e.target.dataset.action; - this.setState({ - inProgressActions: { - ...this.state.inProgressActions, - [actionName]: true, - }, - }); + this.setActionInProgress(actionName, true); this.actionCallbacks[actionName](() => { - this.setState({ - inProgressActions: { - ...this.state.inProgressActions, - [actionName]: false, - }, - }); + this.setActionInProgress(actionName, false); }); } + base64File = (fieldName, e) => { + if (e && e.fileList[0]) { + helper.getBase64(e.file).then((value) => { + this.props.form.setFieldsValue({ [fieldName]: value }); + }); + } + } + renderField(field) { const [firstItem] = this.props.fields; - const { getFieldDecorator } = this.props.form; + const { getFieldDecorator, getFieldValue } = this.props.form; const { name, type, initialValue } = field; const fieldLabel = field.title || helper.toHuman(name); @@ -101,20 +104,26 @@ export class DynamicForm extends React.Component { name, type, placeholder: field.placeholder, + 'data-test': fieldLabel, }; const options = { rules: [{ required: field.required, message: `${fieldLabel} is required.` }], - valuePropName: getValuePropNameForType(type), + valuePropName: type === 'checkbox' ? 'checked' : 'value', initialValue, }; - const uploadButton = (); + const fileOptions = { + rules: [{ required: field.required, message: `${fieldLabel} is required.` }], + initialValue, + getValueFromEvent: this.base64File.bind(this, name), + }; if (type === 'checkbox') { return getFieldDecorator(name, options)({fieldLabel}); } else if (type === 'file') { - return getFieldDecorator(name, options)({uploadButton}); + const disabled = getFieldValue(name) !== undefined && getFieldValue(name) !== initialValue; + return getFieldDecorator(name, fileOptions)(renderUpload(props, disabled)); } else if (type === 'number') { return getFieldDecorator(name, options)(); } diff --git a/client/app/components/dynamic-form/dynamicFormHelper.js b/client/app/components/dynamic-form/dynamicFormHelper.js index cd1aaf65e3..bca9e47e63 100644 --- a/client/app/components/dynamic-form/dynamicFormHelper.js +++ b/client/app/components/dynamic-form/dynamicFormHelper.js @@ -87,8 +87,18 @@ function toHuman(text) { return text.replace(/_/g, ' ').replace(/(?:^|\s)\S/g, a => a.toUpperCase()); } +function getBase64(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result.substr(reader.result.indexOf(',') + 1)); + reader.onerror = error => reject(error); + }); +} + export default { getFields, updateTargetWithValues, toHuman, + getBase64, }; diff --git a/client/app/services/toastr.js b/client/app/services/toastr.js new file mode 100644 index 0000000000..c46f3728e5 --- /dev/null +++ b/client/app/services/toastr.js @@ -0,0 +1,10 @@ +// eslint-disable-next-line import/no-mutable-exports +export let toastr = null; + +export default function init(ngModule) { + ngModule.run(($injector) => { + toastr = $injector.get('toastr'); + }); +} + +init.init = true; diff --git a/cypress/integration/data-source/create_data_source_spec.js b/cypress/integration/data-source/create_data_source_spec.js index 773b000ab4..52adef85fc 100644 --- a/cypress/integration/data-source/create_data_source_spec.js +++ b/cypress/integration/data-source/create_data_source_spec.js @@ -7,7 +7,7 @@ describe('Create Data Source', () => { it('creates a new PostgreSQL data source', () => { cy.getByTestId('DatabaseSource').contains('PostgreSQL').click(); - cy.getByTestId('TargetName').type('Redash'); + cy.getByTestId('Name').type('Redash'); cy.getByTestId('Host').type('{selectall}postgres'); cy.getByTestId('User').type('postgres'); cy.getByTestId('Password').type('postgres'); From d5c185bbbdebe0133486d2cb862fa5aa16426e54 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 30 Dec 2018 18:35:55 -0200 Subject: [PATCH 11/20] Update render methods to fix code climate issues --- .../components/dynamic-form/DynamicForm.jsx | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 9c22f72999..75aad70383 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -6,12 +6,6 @@ import { toastr } from '@/services/toastr'; import { Field, Action, AntdForm } from '../proptypes'; import helper from './dynamicFormHelper'; -const renderUpload = (props, disabled) => ( - false}> - - -); - export class DynamicForm extends React.Component { static propTypes = { fields: PropTypes.arrayOf(Field), @@ -92,38 +86,43 @@ export class DynamicForm extends React.Component { } } - renderField(field) { - const [firstItem] = this.props.fields; + renderUpload(field, props) { const { getFieldDecorator, getFieldValue } = this.props.form; - const { name, type, initialValue } = field; + const { name, initialValue, required } = field; const fieldLabel = field.title || helper.toHuman(name); - const props = { - autoFocus: (firstItem === field), - className: 'w-100', - name, - type, - placeholder: field.placeholder, - 'data-test': fieldLabel, + const fileOptions = { + rules: [{ required, message: `${fieldLabel} is required.` }], + initialValue, + getValueFromEvent: this.base64File.bind(this, name), }; + const disabled = getFieldValue(name) !== undefined && getFieldValue(name) !== initialValue; + + const upload = ( + false}> + + + ); + + return getFieldDecorator(name, fileOptions)(upload); + } + + renderField(field, props) { + const { getFieldDecorator } = this.props.form; + const { name, type, initialValue } = field; + const fieldLabel = field.title || helper.toHuman(name); + const options = { rules: [{ required: field.required, message: `${fieldLabel} is required.` }], valuePropName: type === 'checkbox' ? 'checked' : 'value', initialValue, }; - const fileOptions = { - rules: [{ required: field.required, message: `${fieldLabel} is required.` }], - initialValue, - getValueFromEvent: this.base64File.bind(this, name), - }; - if (type === 'checkbox') { return getFieldDecorator(name, options)({fieldLabel}); } else if (type === 'file') { - const disabled = getFieldValue(name) !== undefined && getFieldValue(name) !== initialValue; - return getFieldDecorator(name, fileOptions)(renderUpload(props, disabled)); + return this.renderUpload(field, props); } else if (type === 'number') { return getFieldDecorator(name, options)(); } @@ -132,6 +131,7 @@ export class DynamicForm extends React.Component { renderFields() { return this.props.fields.map((field) => { + const [firstItem] = this.props.fields; const FormItem = Form.Item; const { name, title, type } = field; const fieldLabel = title || helper.toHuman(name); @@ -143,11 +143,16 @@ export class DynamicForm extends React.Component { label: type === 'checkbox' ? '' : fieldLabel, }; - return ( - - {this.renderField(field)} - - ); + const fieldProps = { + autoFocus: (firstItem === field), + className: 'w-100', + name, + type, + placeholder: field.placeholder, + 'data-test': fieldLabel, + }; + + return ({this.renderField(field, fieldProps)}); }); } From e4d65bfb6e4f415a880d9cd84eff16c7d8816981 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 30 Dec 2018 19:41:50 -0200 Subject: [PATCH 12/20] Fix ant input number showing duplicate arrows --- client/app/assets/less/redash/ant.less | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 24ac86ac70..4301992196 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -43,7 +43,7 @@ z-index: 1050; } -// Make Ant labels more like Redash +// Make Ant labels more Redash like .ant-form-item-label label { color: inherit; white-space: initial; @@ -51,6 +51,17 @@ text-align: left; } +// Fix ant input number showing duplicate arrows +.ant-input-number-input::-webkit-outer-spin-button, +.ant-input-number-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +.ant-input-number-input { + -moz-appearance: textfield; +} + // Fix for text becoming black on disabled buttons .btn-danger, .btn-primary, .btn-success, .btn-info { &[disabled] { From c5d82bde65fc712ac92bf3b7f0dc172e66e6ede2 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sat, 5 Jan 2019 17:08:50 -0200 Subject: [PATCH 13/20] Update DynamicForm style to be vertical --- client/app/assets/less/redash/ant.less | 2 -- client/app/components/dynamic-form/DynamicForm.jsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 4301992196..99c662416b 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -47,8 +47,6 @@ .ant-form-item-label label { color: inherit; white-space: initial; - line-height: initial; - text-align: left; } // Fix ant input number showing duplicate arrows diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 75aad70383..50e4d5a1cb 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -183,7 +183,7 @@ export class DynamicForm extends React.Component { }; return ( -
+ {this.renderFields()} + diff --git a/client/app/pages/destinations/show.js b/client/app/pages/destinations/show.js index 024ac5718e..f3f3976224 100644 --- a/client/app/pages/destinations/show.js +++ b/client/app/pages/destinations/show.js @@ -28,7 +28,7 @@ function DestinationCtrl( $scope.destination = new Destination({ options: {} }); }; - $scope.delete = () => { + function deleteDestination(callback) { const doDelete = () => { $scope.destination.$delete(() => { toastrSuccessAndPath('Destination', 'destinations', toastr, $location); @@ -40,8 +40,12 @@ function DestinationCtrl( const title = 'Delete Destination'; const message = `Are you sure you want to delete the "${$scope.destination.name}" destination?`; - AlertDialog.open(title, message, deleteConfirm).then(doDelete); - }; + AlertDialog.open(title, message, deleteConfirm).then(doDelete, callback); + } + + $scope.actions = [ + { name: 'Delete', type: 'danger', callback: deleteDestination }, + ]; } export default function init(ngModule) { From 8a2016e3cd3e5e9297d9556c9721d2452141db3f Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 7 Jan 2019 01:21:52 -0200 Subject: [PATCH 17/20] Remove setDefaults method from DynamicForm fields --- client/app/components/dynamic-form/DynamicForm.jsx | 1 - .../components/dynamic-form/dynamicFormHelper.js | 14 +------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/client/app/components/dynamic-form/DynamicForm.jsx b/client/app/components/dynamic-form/DynamicForm.jsx index 64357c03c8..a35ede9107 100644 --- a/client/app/components/dynamic-form/DynamicForm.jsx +++ b/client/app/components/dynamic-form/DynamicForm.jsx @@ -231,7 +231,6 @@ export default function init(ngModule) { feedbackIcons: true, onSubmit, }; - return (); }, ['target', 'type', 'actions'])); } diff --git a/client/app/components/dynamic-form/dynamicFormHelper.js b/client/app/components/dynamic-form/dynamicFormHelper.js index bca9e47e63..1a5606ab9d 100644 --- a/client/app/components/dynamic-form/dynamicFormHelper.js +++ b/client/app/components/dynamic-form/dynamicFormHelper.js @@ -1,4 +1,4 @@ -import { isUndefined, each, includes } from 'lodash'; +import { each, includes } from 'lodash'; function orderedInputs(properties, order, targetOptions) { const inputs = new Array(order.length); @@ -46,20 +46,8 @@ function normalizeSchema(configurationSchema) { configurationSchema.order = configurationSchema.order || []; } -function setDefaults(configurationSchema, options) { - if (Object.keys(options).length === 0) { - const properties = configurationSchema.properties; - Object.keys(properties).forEach((property) => { - if (!isUndefined(properties[property].default)) { - options[property] = properties[property].default; - } - }); - } -} - function getFields(configurationSchema, target) { normalizeSchema(configurationSchema); - setDefaults(configurationSchema, target.options); const inputs = [ { name: 'name', From d72ad8f55aa3d3b3c15ca7634630cc0eaa2282ec Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 13 Jan 2019 18:17:15 -0200 Subject: [PATCH 18/20] Update antd version --- client/app/assets/less/redash/ant.less | 1 - package-lock.json | 527 +++++++++++++++---------- package.json | 2 +- 3 files changed, 315 insertions(+), 215 deletions(-) diff --git a/client/app/assets/less/redash/ant.less b/client/app/assets/less/redash/ant.less index 041e22540a..8c4a26087f 100644 --- a/client/app/assets/less/redash/ant.less +++ b/client/app/assets/less/redash/ant.less @@ -48,7 +48,6 @@ // Make Ant labels more Redash like .ant-form-item-label label { color: inherit; - white-space: initial; // remove when ant-design/ant-design#14135 lands } // Fix ant input number showing duplicate arrows diff --git a/package-lock.json b/package-lock.json index b2d7f5c025..3c549b6dd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,20 @@ "right-now": "^1.0.0" } }, + "@ant-design/icons": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-1.1.16.tgz", + "integrity": "sha512-0zNVP5JYBJkfMi9HotN6QBQjF3SFmUlumJNJXZIH+pZWp/5EbrCczzlG3YTmBWoyRHAsuOGIjSFIy8v/76DTPg==" + }, + "@ant-design/icons-react": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-1.1.2.tgz", + "integrity": "sha512-7Fgt9d8ABgxrhZxsFjHk/VpPcxodQJJhbJO8Lsh7u58pGN4NoxxW++92naeGTXCyqZsbDPBReP+SC0bdBtbsGQ==", + "requires": { + "ant-design-palettes": "^1.1.3", + "babel-runtime": "^6.26.0" + } + }, "@babel/code-frame": { "version": "7.0.0-beta.44", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", @@ -635,9 +649,9 @@ "dev": true }, "add-dom-event-listener": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.0.2.tgz", - "integrity": "sha1-j67SxBAIchzxEdodMNmVuFvkK+0=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz", + "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==", "requires": { "object-assign": "4.x" } @@ -827,59 +841,90 @@ "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=" }, + "ant-design-palettes": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ant-design-palettes/-/ant-design-palettes-1.1.3.tgz", + "integrity": "sha512-UpkkTp8egEN21KZNvY7sTcabLlkHvLvS71EVPk4CYi77Z9AaGGCaVn7i72tbOgWDrQp2wjIg8WgMbKBdK7GtWA==", + "requires": { + "tinycolor2": "^1.4.1" + } + }, "antd": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/antd/-/antd-3.7.1.tgz", - "integrity": "sha512-lQDOtrEo6KJsx44s/cOdJEcYnNqjRQtTYb7ch0ajPzM6tFMOMydDaxASekQrUmKdKVTOlYfM0XGBqCr9n7r1yQ==", + "version": "3.12.3", + "resolved": "https://registry.npmjs.org/antd/-/antd-3.12.3.tgz", + "integrity": "sha512-fKLqE5rqiAqKwi3nT8lopYZFj/Kbc3UCEkX4EsZOh8ZZHVNGirvZofRxLt4smpHmpj6NLbhR6va/kXLFe35RiQ==", "requires": { - "array-tree-filter": "^2.0.0", + "@ant-design/icons": "~1.1.16", + "@ant-design/icons-react": "~1.1.2", + "array-tree-filter": "^2.1.0", "babel-runtime": "6.x", - "classnames": "~2.2.0", - "create-react-class": "^15.6.0", - "create-react-context": "^0.2.2", - "css-animation": "^1.2.5", + "classnames": "~2.2.6", + "create-react-class": "^15.6.3", + "create-react-context": "0.2.2", + "css-animation": "^1.5.0", "dom-closest": "^0.2.0", - "enquire.js": "^2.1.1", - "intersperse": "^1.0.0", - "lodash": "^4.17.5", - "moment": "^2.19.3", + "enquire.js": "^2.1.6", + "lodash": "^4.17.11", + "moment": "^2.22.2", "omit.js": "^1.0.0", - "prop-types": "^15.5.7", + "prop-types": "^15.6.2", "raf": "^3.4.0", - "rc-animate": "^2.4.1", - "rc-calendar": "~9.6.0", - "rc-cascader": "~0.14.0", + "rc-animate": "^2.5.4", + "rc-calendar": "~9.10.3", + "rc-cascader": "~0.17.0", "rc-checkbox": "~2.1.5", - "rc-collapse": "~1.9.0", - "rc-dialog": "~7.1.0", - "rc-drawer": "~1.5.9", - "rc-dropdown": "~2.2.0", - "rc-editor-mention": "^1.0.2", - "rc-form": "^2.1.0", - "rc-input-number": "~4.0.0", - "rc-menu": "~7.0.2", - "rc-notification": "~3.1.1", - "rc-pagination": "~1.16.1", - "rc-progress": "~2.2.2", - "rc-rate": "~2.4.0", - "rc-select": "~8.0.7", - "rc-slider": "~8.6.0", - "rc-steps": "~3.1.0", - "rc-switch": "~1.6.0", - "rc-table": "~6.2.2", - "rc-tabs": "~9.2.0", - "rc-time-picker": "~3.3.0", - "rc-tooltip": "~3.7.0", - "rc-tree": "~1.12.0", - "rc-tree-select": "~2.0.5", - "rc-trigger": "^2.5.4", - "rc-upload": "~2.5.0", - "rc-util": "^4.0.4", - "react-lazy-load": "^3.0.12", - "react-lifecycles-compat": "^3.0.2", - "react-slick": "~0.23.1", - "shallowequal": "^1.0.1", - "warning": "~4.0.1" + "rc-collapse": "~1.10.2", + "rc-dialog": "~7.3.0", + "rc-drawer": "~1.7.6", + "rc-dropdown": "~2.4.1", + "rc-editor-mention": "^1.1.7", + "rc-form": "^2.4.0", + "rc-input-number": "~4.3.7", + "rc-menu": "~7.4.12", + "rc-notification": "~3.3.0", + "rc-pagination": "~1.17.7", + "rc-progress": "~2.2.6", + "rc-rate": "~2.5.0", + "rc-select": "^8.6.7", + "rc-slider": "~8.6.3", + "rc-steps": "~3.3.0", + "rc-switch": "~1.8.0", + "rc-table": "~6.4.0", + "rc-tabs": "~9.5.2", + "rc-time-picker": "~3.5.0", + "rc-tooltip": "~3.7.3", + "rc-tree": "~1.14.6", + "rc-tree-select": "~2.5.0", + "rc-trigger": "^2.6.2", + "rc-upload": "~2.6.0", + "rc-util": "^4.5.1", + "react-lazy-load": "^3.0.13", + "react-lifecycles-compat": "^3.0.4", + "react-slick": "~0.23.2", + "resize-observer-polyfill": "^1.5.0", + "shallowequal": "^1.1.0", + "warning": "~4.0.2" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "moment": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" + }, + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + } } }, "anymatch": { @@ -1186,9 +1231,9 @@ "dev": true }, "async-validator": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.4.tgz", - "integrity": "sha512-9M6Q6Q3iqFKSdyhliLG8gUH9E73p/TQU1XNH/qiybX5eFIgwB++IIZ/wcPM1f+x9WeqemxGkm0CCx69Mkx3EEg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", "requires": { "babel-runtime": "6.x" } @@ -3972,9 +4017,9 @@ } }, "css-animation": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.4.1.tgz", - "integrity": "sha1-W4gTEl3g+7uwu+G0cq6EIhRpt6g=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.5.0.tgz", + "integrity": "sha512-hWYoWiOZ7Vr20etzLh3kpWgtC454tW5vn4I6rLANDgpzNSkO7UfOqyCEeaoBSG9CYWQpRkFWTWbWW8o3uZrNLw==", "requires": { "babel-runtime": "6.x", "component-classes": "^1.2.5" @@ -4780,6 +4825,13 @@ "fbjs": "^0.8.15", "immutable": "~3.7.4", "object-assign": "^4.1.0" + }, + "dependencies": { + "immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" + } } }, "draw-svg-path": { @@ -6754,11 +6806,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6771,15 +6825,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -6882,7 +6939,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -6892,6 +6950,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6904,6 +6963,7 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7003,7 +7063,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -7013,6 +7074,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -7118,6 +7180,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8643,9 +8706,9 @@ "optional": true }, "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" }, "import-local": { "version": "2.0.0", @@ -8836,11 +8899,6 @@ "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", "dev": true }, - "intersperse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/intersperse/-/intersperse-1.0.0.tgz", - "integrity": "sha1-8lYfsc/vn1J3zDNHoiiGtDUaUYE=" - }, "interval-tree-1d": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/interval-tree-1d/-/interval-tree-1d-1.0.3.tgz", @@ -9258,6 +9316,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "ismobilejs": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-0.5.1.tgz", + "integrity": "sha512-QX4STsOcBYqlTjVGuAdP1MiRVxtiUbRHOKH0v7Gn1EvfUVIQnrSdgCM4zB4VCZuIejnb2NUMUx0Bwd3EIG6yyA==" + }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -11643,12 +11706,13 @@ } }, "mini-store": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mini-store/-/mini-store-1.1.0.tgz", - "integrity": "sha512-/Ou2jdD7/CDyJBjHnpRuc8aehh2WHxBpUpVvVHn0XhvLHk35YOiUlOYhX55NX00/e4phr1F3aNnhWKkGMqLUfQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mini-store/-/mini-store-2.0.0.tgz", + "integrity": "sha512-EG0CuwpQmX+XL4QVS0kxNwHW5ftSbhygu1qxQH0pipugjnPkbvkalCdQbEihMwtQY6d3MTN+MS0q+aurs+RfLQ==", "requires": { "hoist-non-react-statics": "^2.3.1", "prop-types": "^15.6.0", + "react-lifecycles-compat": "^3.0.4", "shallowequal": "^1.0.2" } }, @@ -11899,6 +11963,11 @@ "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" }, + "mutationobserver-shim": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz", + "integrity": "sha1-9NXa56SXGiIHkU+1qQ69UUtlrMo=" + }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", @@ -14005,6 +14074,11 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, + "prettier": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.15.3.tgz", + "integrity": "sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg==" + }, "pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -14410,53 +14484,50 @@ } }, "rc-animate": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.4.4.tgz", - "integrity": "sha512-DjJLTUQj7XKKcuS8cczN0uOLfuSmgrVXFGieP1SZc87xUUTFGh8B/KjNmEtlfvxkSrSuVfb2rrEPER4SqKUtEA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.6.0.tgz", + "integrity": "sha512-JXDycchgbOI+7T/VKmFWnAIn042LLScK1fNkmNunb0jz5q5aPGCAybx2bTo7X5t31Jkj9OsxKNb/vZPDPWufCg==", "requires": { "babel-runtime": "6.x", + "classnames": "^2.2.6", "css-animation": "^1.3.2", - "prop-types": "15.x" + "prop-types": "15.x", + "raf": "^3.4.0", + "react-lifecycles-compat": "^3.0.4" } }, "rc-calendar": { - "version": "9.6.2", - "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.6.2.tgz", - "integrity": "sha512-RtWav1aeYEFiFWxc0toYga06orrw3229qwDSsQu4RcaS7+swja14+nxOpWCMic7K2AakBZh4OfJ/ZEdCMvHewQ==", + "version": "9.10.5", + "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.10.5.tgz", + "integrity": "sha512-Gu8eLkN0qNi2hLuHpJ42Hu33rTKkTxigmvWZ6p+TUBy6zCot84Zw5fiUrD5FWURNwvrO6Na+KYY/9blfhKrC0Q==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", - "create-react-class": "^15.5.2", "moment": "2.x", "prop-types": "^15.5.8", "rc-trigger": "^2.2.0", - "rc-util": "^4.1.1" + "rc-util": "^4.1.1", + "react-lifecycles-compat": "^3.0.4" } }, "rc-cascader": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.14.0.tgz", - "integrity": "sha512-+wSriiSOC4B/9oTld3zaZ5aLFsYreGM4jdvFa6X1zZ9j3K9PfkvIO6OGv8slJQEXSv1E3HInbk/j6bGtYoesmg==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.17.1.tgz", + "integrity": "sha512-JED1iOLpj1+uob+0Asd4zwhhMRp3gLs2iYOY2/0OsdEsPc8Qj6TUwj8+isVtqyXiwGWG3vo8XgO6KCM/i7ZFqQ==", "requires": { - "array-tree-filter": "^1.0.0", + "array-tree-filter": "^2.1.0", "prop-types": "^15.5.8", "rc-trigger": "^2.2.0", "rc-util": "^4.0.4", + "react-lifecycles-compat": "^3.0.4", "shallow-equal": "^1.0.0", "warning": "^4.0.1" - }, - "dependencies": { - "array-tree-filter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-1.0.1.tgz", - "integrity": "sha1-CorR7v04zoiFhjL5zAQj12NOTV0=" - } } }, "rc-checkbox": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.5.tgz", - "integrity": "sha512-WXKnZV6ipS3Jsmd7mVenVUQf+ictgWZW0RqiH+7MeYdzGj/SL4g/S6MZgRdgzaBS2tGBCp4bvhGcyZLns6uQxw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.6.tgz", + "integrity": "sha512-+VxQbt2Cwe1PxCvwosrAYXT6EQeGwrbLJB2K+IPGCSRPCKnk9zcub/0eW8A4kxjyyfh60PkwsAUZ7qmB31OmRA==", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", @@ -14465,20 +14536,28 @@ } }, "rc-collapse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.9.3.tgz", - "integrity": "sha512-8cG+FzudmgFCC9zRGKXJZA36zoI9Dmyjp6UDi8N80sXUch0JOpsZDxgcFzw4HPpPpK/dARtTilEe9zyuspnW0w==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.10.2.tgz", + "integrity": "sha512-AtEE4rMXEBT05gScduc+NQf/257wqE0xk4tNX4N1DBq0qTx19xGcwX3EXDD+ZF8KuZ/A25pgmviXad/hthNQSg==", "requires": { "classnames": "2.x", "css-animation": "1.x", "prop-types": "^15.5.6", - "rc-animate": "2.x" + "rc-animate": "2.x", + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.7.0.tgz", + "integrity": "sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==" + } } }, "rc-dialog": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.1.8.tgz", - "integrity": "sha512-iWbV+r0cZpV5TFPtXQDRf+lBW322uSVXK20ULvXEEBWbnsSmg3c9D/RlOcDNV6WJvOLOwIof0CKZPFyhl8Szww==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.3.0.tgz", + "integrity": "sha512-YLQHqZuU0cO02LUwhCsCCtvSw24SKLrT4DkNHCNGGcH9YpZP/IOFaH4zVUmXGEQiwyt0D1f3volHthMCKzLzMg==", "requires": { "babel-runtime": "6.x", "rc-animate": "2.x", @@ -14486,9 +14565,9 @@ } }, "rc-drawer": { - "version": "1.5.9", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-1.5.9.tgz", - "integrity": "sha512-Uw4QA+TyutJVM2irfiOondyjUqAW8PHJep8CGRCmnu/mxAJSeKOTfRMUBSr/KiP3OKNm8obMJSMuvcu+YR8TPw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-1.7.7.tgz", + "integrity": "sha512-7dESNkClYdWGSdBdwcfeOz6DUCqzrW44QT013fsTBJIiWNLSLgDV5KoHKXG8VTJWU4mBn7M5Lqgyr94CRZcxGA==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14497,20 +14576,21 @@ } }, "rc-dropdown": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-2.2.0.tgz", - "integrity": "sha512-gVqR8eC4iGuDeIIXm3vcfoo4Ui9FvjE2Gh1FSbztWE7Lr68zI/8Zb4Pc/Z1ZGJflpo6PGMCwy5zWyuIFH28G7Q==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-2.4.1.tgz", + "integrity": "sha512-p0XYn0wrOpAZ2fUGE6YJ6U8JBNc5ASijznZ6dkojdaEfQJAeZtV9KMEewhxkVlxGSbbdXe10ptjBlTEW9vEwEg==", "requires": { "babel-runtime": "^6.26.0", + "classnames": "^2.2.6", "prop-types": "^15.5.8", "rc-trigger": "^2.5.1", "react-lifecycles-compat": "^3.0.2" } }, "rc-editor-core": { - "version": "0.8.6", - "resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.6.tgz", - "integrity": "sha512-6M4C0qLTf/UvQA0XNb8BWlb5+tZ5LCZKc9Hs0oH6Fn+18XMRILYiUKBCdLObaj0LVeq5vhq+zra9sjfqBEguHQ==", + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.8.tgz", + "integrity": "sha512-4zT4Z8BtQSDcdh9mGXrsVCzUXmXKpe2U2VJSKOAErh5J4yTzJxSOfJon+nHxZyJZEKXg7rZvwrnhogXZzYNIng==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.5", @@ -14522,25 +14602,26 @@ } }, "rc-editor-mention": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.7.tgz", - "integrity": "sha512-5z9OX8gxh76oD8kx0Hi2fTZEyrmrfDo35ouFgpFrhB3H1L+WY4yvi1yUUZJG1uAxq/3Hlhnet4AFy1SnepinyQ==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.12.tgz", + "integrity": "sha512-cPm2rQ7P+hXaKMsO0ajVv08QlTDcSPVtw8/lVr9D+QzQKRPChCqLw9rVGOa4YGYTeS3gVe8lBfLr8a9JKFk3gA==", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.5", "dom-scroll-into-view": "^1.2.0", "draft-js": "~0.10.0", + "immutable": "^3.7.4", "prop-types": "^15.5.8", "rc-animate": "^2.3.0", "rc-editor-core": "~0.8.3" } }, "rc-form": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.2.1.tgz", - "integrity": "sha512-Hwzq2IL4gdbEgbG3wXtkUA37QXQxfXFp93PGmwlnHzbH7A8TiLQiiI8quS3b2FMtSVjBw3922E6yl6PmPGbfWw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.4.1.tgz", + "integrity": "sha512-ZWnAR5w63fNUdeY/EuSpmrScM9EDxtgUbsSnao2BS9HIKIjqSCu6bJNX6SKvU7jRnklLOfEf8nCEMzibFZwplA==", "requires": { - "async-validator": "1.x", + "async-validator": "~1.8.5", "babel-runtime": "6.x", "create-react-class": "^15.5.3", "dom-scroll-into-view": "1.x", @@ -14570,9 +14651,9 @@ } }, "rc-input-number": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.0.12.tgz", - "integrity": "sha512-lVop5/bJPqNF57kT8Y9gr1bhKF0twEv44z4OYswN4YTWLJtCLoeT+6Hv4IJABOfGQbyK5owXki7zKEVcOehNMQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.3.7.tgz", + "integrity": "sha512-uIrUSJ3mURDBIcoBE3Suq6hvO7OyfNJHLeai0xN2hXMxOkR9ePH4B/RbiqNjMPflmj6/fxbtK5odOXqVV7BemQ==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.0", @@ -14583,24 +14664,27 @@ } }, "rc-menu": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.0.5.tgz", - "integrity": "sha512-VG8Ncjb4UuklxZvk/u3gN4vU8xuJF5WJfdLQIVWB3fu01lnMZF8adN1YWWvpftM0t9zGEppDkNGumZFKmx0WGA==", + "version": "7.4.21", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.4.21.tgz", + "integrity": "sha512-TfcwybKLuw2WhEkplYH7iFMGlDbH6KhPcd+gv5J2oLQcgiGeUECzyOWSVaFRRlkpB7g2eNzXbha/AXN/Xyzvnw==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", "dom-scroll-into-view": "1.x", - "mini-store": "^1.1.0", + "ismobilejs": "^0.5.1", + "mini-store": "^2.0.0", + "mutationobserver-shim": "^0.3.2", "prop-types": "^15.5.6", "rc-animate": "2.x", "rc-trigger": "^2.3.0", - "rc-util": "^4.1.0" + "rc-util": "^4.1.0", + "resize-observer-polyfill": "^1.5.0" } }, "rc-notification": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-3.1.1.tgz", - "integrity": "sha512-70a/qR3SRnYr728H0viEyv8QtLjWzUb3kTZV96yqU/Ro5jWSF/Q3qK7dRGEuyfqjWyGVEuTCyiKNu/qAp26m9g==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-3.3.0.tgz", + "integrity": "sha512-T7wUryaKTNTO9gsWPCwRyC9P4FcKFTrIRsiNVXJhjlRbHKT0xZF3ag/gxXxZzPBDAf0l1vfgIrT+11cfWtZW0g==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", @@ -14610,66 +14694,58 @@ } }, "rc-pagination": { - "version": "1.16.5", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.16.5.tgz", - "integrity": "sha512-h8xUK5JeFMBH23wVOZ2HuqUPM+jss37yemxDlDCjhKeur5Ne2z6Q8L8gz+pKoE5Qz7kqLi7Vp7U2aogrwK9WtA==", + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.17.8.tgz", + "integrity": "sha512-duEV+K/b/nZNGr943+TMCEcY4xWkjAkpKW0Vr7fSR8wQk0DY7aTJC+k+vjl4X2EzEmPXqy85hibzpsO9vydKAw==", "requires": { "babel-runtime": "6.x", - "prop-types": "^15.5.7" + "prop-types": "^15.5.7", + "react-lifecycles-compat": "^3.0.4" } }, "rc-progress": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-2.2.5.tgz", - "integrity": "sha1-5h0FRL+dQgjlujL8UJYhWef5UqM=", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-2.2.6.tgz", + "integrity": "sha512-73Ul9WrWf474q0ze+XblpcR8q2No0tybHt+zdGXYyQ7fUZy4b+I5dUQcoxr9UXY6W5Ele9ZsPWJWHSDz/IAOUw==", "requires": { "babel-runtime": "6.x", "prop-types": "^15.5.8" } }, "rc-rate": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.4.0.tgz", - "integrity": "sha512-gYHxaXqObiIw1ekRS8tq2YUKpTGL/Q9LxMdSCXZS++d5bVsmmTCZUvJFKEt0IfLb19sZtxCaQvwanzNpqaxY7Q==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.5.0.tgz", + "integrity": "sha512-aXX5klRqbVZxvLghcKnLqqo7LvLVCHswEDteWsm5Gb7NBIPa1YKTcAbvb5SZ4Z4i4EeRoZaPwygRAWsQgGtbKw==", "requires": { - "babel-runtime": "^6.26.0", "classnames": "^2.2.5", "prop-types": "^15.5.8", - "rc-util": "^4.3.0" + "rc-util": "^4.3.0", + "react-lifecycles-compat": "^3.0.4" } }, "rc-select": { - "version": "8.0.14", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-8.0.14.tgz", - "integrity": "sha512-eOZeN3q+dBkDZGnzbT5AsRAw86zS6d85GlN5onk3L4vbCS3iaItKp1PRby+oady+3nuNarKaQ+YqS21wW7wjuw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-8.7.0.tgz", + "integrity": "sha512-YaNO4peulgvrqQCHGB2kdmS61enJUyQzxrpVKGDJkc+9wjnZ59X2O62QYyy8c/AcE/DNYawUmRVwN9xE3e0kVQ==", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", "component-classes": "1.x", "dom-scroll-into-view": "1.x", "prop-types": "^15.5.8", + "raf": "^3.4.0", "rc-animate": "2.x", - "rc-menu": "^7.0.2", - "rc-trigger": "^2.2.0", + "rc-menu": "^7.3.0", + "rc-trigger": "^2.5.4", "rc-util": "^4.0.4", "react-lifecycles-compat": "^3.0.2", - "warning": "^3.0.0" - }, - "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "requires": { - "loose-envify": "^1.0.0" - } - } + "warning": "^4.0.2" } }, "rc-slider": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.6.1.tgz", - "integrity": "sha512-6DoLW5pWR8K/7Z55E5wKZGGa22HFY6LB4Z0PegzSXrQ/RqUHm9hFHRA3FYCuPOsg/Zsi+SgGPvzC2P/I/YZ6Lg==", + "version": "8.6.4", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.6.4.tgz", + "integrity": "sha512-CV2i2Ww6ib0EjFuBKvgjw3PgT6QwvWKC93iEpqPtrztZrx5wO9Iw//AUri4KHRqptW13AuBvFdEHovqLi6XFTw==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14691,9 +14767,9 @@ } }, "rc-steps": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-3.1.1.tgz", - "integrity": "sha512-oon2VdAHWrZmkB07MUMhq7k2IazFmtOi+6CCPn1ao3ZJ/89/aArP9/3pDQBm88FBQBcDh1E04kSHufbdY1kxfw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-3.3.1.tgz", + "integrity": "sha512-LGzmPYS9ETePo+6YbHlFukCdcKppeBZXO49ZxewaC7Cba00q0zrMXlexquZ4fm+9iz0IkpzwgmenvjsVWCmGOw==", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.3", @@ -14702,9 +14778,9 @@ } }, "rc-switch": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-1.6.0.tgz", - "integrity": "sha512-tlnYj92N/PxFLWJObATgSPYWESCFTUtdFjDRbCJFvSd4j2a8IFLz20X/5d3OTnFtf7DcxLTa/aGIPmsI3mFn3g==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-1.8.0.tgz", + "integrity": "sha512-n4H+K2XJCqGwVQKwWOjbxl1kpdov0PVE9DGhzs/S20gk65s/nAOkpdO9tBD7IM/20KRNTBh0fEWkEedByrqh6w==", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.1", @@ -14712,15 +14788,15 @@ } }, "rc-table": { - "version": "6.2.7", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.2.7.tgz", - "integrity": "sha512-PTKSWiF7/hBPvHZ1TQvyFcwegn3ce7yeAOWNNZwdJwNLUqCM4TQ1TSN8b6YNe9gBon4a2JsA/YT3rjpiNDX67Q==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.4.3.tgz", + "integrity": "sha512-4/f7mS87EtNxM2vhIaA7I1J8hPZ5OiOQwmjac7RJTmGOFVA8PJDGwEipeyU/eC9RM7f3v4Lc+a05KCfIbRU4tg==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", "component-classes": "^1.2.6", "lodash": "^4.17.5", - "mini-store": "^1.0.2", + "mini-store": "^2.0.0", "prop-types": "^15.5.8", "rc-util": "^4.0.4", "react-lifecycles-compat": "^3.0.2", @@ -14739,20 +14815,29 @@ } }, "rc-tabs": { - "version": "9.2.6", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.2.6.tgz", - "integrity": "sha512-J4HsAPinn/utapHjCg36HdEI/WsL0Ma61t0mTkkEf6Z/LQQWS16LhgLbycF3lTNUIgcZu3dhQFjRDg4kpaFbAQ==", + "version": "9.5.8", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.5.8.tgz", + "integrity": "sha512-fvkM5FLa0Kq9jz7YNE72T9WeMEbF264FIhqRnKyvmKtaam2lI81qxbofMEfBGhNxcv1whWlZStHj9b1Wi3Q24w==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", - "create-react-class": "15.x", + "create-react-context": "0.2.2", "lodash": "^4.17.5", "prop-types": "15.x", + "raf": "^3.4.1", "rc-hammerjs": "~0.6.0", "rc-util": "^4.0.4", "warning": "^3.0.0" }, "dependencies": { + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, "warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", @@ -14764,11 +14849,10 @@ } }, "rc-time-picker": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.3.1.tgz", - "integrity": "sha512-iCo6Fs6Bp/HjjSvdA+nv/yJEWSe+vDyunV57uVzZkW+4QDQ+BOvZGGwJcfL407u/eP1QKmeljZN8Iu3KjdKIGg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.5.0.tgz", + "integrity": "sha512-swJyFZgR3P4UgFix5DP0fQQPKHP7WYEKlzbAWXd72TmFV80VCxmR+l0OWyCOjZgXfo9VJ/mEDzUnMSjP8/xyrg==", "requires": { - "babel-runtime": "6.x", "classnames": "2.x", "moment": "2.x", "prop-types": "^15.5.8", @@ -14776,9 +14860,9 @@ } }, "rc-tooltip": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.2.tgz", - "integrity": "sha512-vsF29ohlfgr7lEP12aJ5j4U/4hzqSBYjWQo8I09re+q95v1o4nDjH1q/B3qFkf9aml2FbgdkJw9KYz/zXUgApA==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.3.tgz", + "integrity": "sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww==", "requires": { "babel-runtime": "6.x", "prop-types": "^15.5.8", @@ -14786,18 +14870,34 @@ } }, "rc-tree": { - "version": "1.12.6", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-1.12.6.tgz", - "integrity": "sha512-/XusoOv1yxULlu0rdbcUZKCGyutkmr3Regr6c/0lxs3IkTuK6Q8Wq6WuZ4FBv/MpagPYuAtqbqh2ZDmgv2FLjA==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-1.14.8.tgz", + "integrity": "sha512-jaI7D6q/Usvyaj2lIgRmOdyFD9M3GsxRdkVDtpCURJGuaBtH5eiAAYqj1xb1YR8gx9g6GiNZhaFd5srQcdM/aw==", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", "prop-types": "^15.5.8", - "rc-animate": "2.x", - "rc-util": "^4.0.4", + "rc-animate": "^3.0.0-rc.5", + "rc-util": "^4.5.1", + "react-lifecycles-compat": "^3.0.4", "warning": "^3.0.0" }, "dependencies": { + "rc-animate": { + "version": "3.0.0-rc.6", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", + "integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.5", + "component-classes": "^1.2.6", + "fbjs": "^0.8.16", + "prop-types": "15.x", + "raf": "^3.4.0", + "rc-util": "^4.5.0", + "react-lifecycles-compat": "^3.0.4" + } + }, "warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", @@ -14809,16 +14909,16 @@ } }, "rc-tree-select": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.0.11.tgz", - "integrity": "sha512-bvuMk1+xwoSPv2525YHqakKeoLNanD38Qg8Rnb0XE9fX1qPR4DpYZZQSwGEH/eHi6mWu5LEJqu8isUmupR4h0g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.5.0.tgz", + "integrity": "sha512-KpmJ30+WlX/2LHpfKmAFQ8+4WR/NL5LzYltIAFzp2ZaBlVXSSLo6LnBb33kYnIU0NngVbsS5/dpsOeiHhdV0TA==", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.1", "prop-types": "^15.5.8", "raf": "^3.4.0", - "rc-animate": "^3.0.0-rc.1", - "rc-tree": "~1.12.2", + "rc-animate": "^3.0.0-rc.4", + "rc-tree": "~1.14.3", "rc-trigger": "^3.0.0-rc.2", "rc-util": "^4.5.0", "react-lifecycles-compat": "^3.0.4", @@ -14827,9 +14927,9 @@ }, "dependencies": { "rc-animate": { - "version": "3.0.0-rc.1", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.1.tgz", - "integrity": "sha512-wlFdca44Y0PE/0FdK6FWs1BXVMiYsp0ighUCw97oaELTpxxZ5wA9fkfCzVhYc3xiCQHP20fSjYp77ZcalO6h/A==", + "version": "3.0.0-rc.6", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", + "integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14858,9 +14958,9 @@ } }, "rc-trigger": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.5.4.tgz", - "integrity": "sha512-clgXOdazDW2qg4vTZSAExpvOuojPNuMoamG+SxAm5Ih+rpVcrtEiDlDZWY4yUHyfEWJZBzgbrr4np/z2FK6RfA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.2.tgz", + "integrity": "sha512-op4xCu95/gdHVaysyxxiYxbY+Z+UcIBSUY9nQfLqm1FlitdtnAN+owD5iMPfnnsRXntgcQ5+RdYKNUFQT5DjzA==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.6", @@ -14871,9 +14971,9 @@ } }, "rc-upload": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.5.1.tgz", - "integrity": "sha512-tFZTEfWlIqlKrvl9UHLGkSXj8oOrOsXcILVjMwTZCf61gJNZXMfyigifClsPqz+EEXkQvpovu/9zgLqBpbJlLA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.6.1.tgz", + "integrity": "sha512-cYuHgy+wZZfQwwbuJuIBPdTmRYcfMddukZ9ayzuxlUJT77BUf6kgImfCj2CYTvpnTeIlDn8Wh79AAaC2PF1dIQ==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14892,11 +14992,11 @@ } }, "rc-util": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.5.1.tgz", - "integrity": "sha512-PdCmHyBBodZdw6Oaikt0l+/R79IcRXpYkTrqD/Rbl4ZdoOi61t5TtEe40Q+A7rkWG5U1xjcN+h8j9H6GdtnICw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.6.0.tgz", + "integrity": "sha512-rbgrzm1/i8mgfwOI4t1CwWK7wGe+OwX+dNa7PVMgxZYPBADGh86eD4OcJO1UKGeajIMDUUKMluaZxvgraQIOmw==", "requires": { - "add-dom-event-listener": "1.x", + "add-dom-event-listener": "^1.1.0", "babel-runtime": "6.x", "prop-types": "^15.5.10", "shallowequal": "^0.2.2" @@ -14990,14 +15090,15 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "react-slick": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.23.1.tgz", - "integrity": "sha512-vn4E+JeTUrjRgXDEV0QEiWo3fNdB6Lg/e8eMYSh3OjuadqYBsgn0OfbqNxVJs7cv1VmSKm14razHEbpRFP/mvw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.23.2.tgz", + "integrity": "sha512-fM6DXX7+22eOcYE9cgaXUfioZL/Zw6fwS6aPMDBt0kLHl4H4fFNEbp4JsJQdEWMLUNFtUytNcvd9KRml22Tp5w==", "requires": { "classnames": "^2.2.5", "enquire.js": "^2.1.6", "json2mq": "^0.2.0", "lodash.debounce": "^4.0.8", + "prettier": "^1.14.3", "resize-observer-polyfill": "^1.5.0" } }, @@ -15563,9 +15664,9 @@ "dev": true }, "resize-observer-polyfill": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz", - "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" }, "resolve": { "version": "1.4.0", @@ -18354,9 +18455,9 @@ } }, "warning": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.1.tgz", - "integrity": "sha512-rAVtTNZw+cQPjvGp1ox0XC5Q2IBFyqoqh+QII4J/oguyu83Bax1apbo2eqB8bHRS+fqYUBagys6lqUoVwKSmXQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.2.tgz", + "integrity": "sha512-wbTp09q/9C+jJn4KKJfJfoS6VleK/Dti0yqWSm6KMvJ4MRCXFQNapHuJXutJIrWV0Cf4AhTdeIe4qdKHR1+Hug==", "requires": { "loose-envify": "^1.0.0" } diff --git a/package.json b/package.json index c56347ee7a..8bbcaa21f6 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "angular-ui-ace": "^0.2.3", "angular-ui-bootstrap": "^2.5.0", "angular-vs-repeat": "^1.1.7", - "antd": "^3.7.1", + "antd": "^3.12.3", "bootstrap": "^3.3.7", "brace": "^0.11.0", "chroma-js": "^1.3.6", From f74d1d38f9f1f074a6d68c3492debf21e3fd6b6f Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 15 Jan 2019 08:47:41 -0200 Subject: [PATCH 19/20] Remove unnecessary class selectors --- client/app/assets/less/ant.less | 18 ------------------ package-lock.json | 23 ++++++----------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/client/app/assets/less/ant.less b/client/app/assets/less/ant.less index d8ca9efdef..8ecbbaa2d3 100644 --- a/client/app/assets/less/ant.less +++ b/client/app/assets/less/ant.less @@ -51,11 +51,6 @@ z-index: 1050; } -// Make Ant labels more Redash like -.ant-form-item-label label { - color: inherit; -} - // Fix ant input number showing duplicate arrows .ant-input-number-input::-webkit-outer-spin-button, .ant-input-number-input::-webkit-inner-spin-button { @@ -66,16 +61,3 @@ .ant-input-number-input { -moz-appearance: textfield; } - -// Fix for text becoming black on disabled buttons -.btn-danger, .btn-primary, .btn-success, .btn-info { - &[disabled] { - color: @white !important; - } -} - -// Remove green border from Ant inputs -.has-success .ant-input, -.has-success .ant-input:hover { - border-color: @border-color-base !important; -} diff --git a/package-lock.json b/package-lock.json index 3c549b6dd1..d44c23c8f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6806,13 +6806,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6825,18 +6823,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -6939,8 +6934,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -6950,7 +6944,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6963,7 +6956,6 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7063,8 +7055,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -7074,7 +7065,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -7180,7 +7170,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", From e4998b768c8606796b42fced32ba728b113a348a Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 15 Jan 2019 09:12:27 -0200 Subject: [PATCH 20/20] Remove another unnecessary class selector --- client/app/assets/less/ant.less | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/app/assets/less/ant.less b/client/app/assets/less/ant.less index 8ecbbaa2d3..9607696513 100644 --- a/client/app/assets/less/ant.less +++ b/client/app/assets/less/ant.less @@ -57,7 +57,3 @@ -webkit-appearance: none; margin: 0; } - -.ant-input-number-input { - -moz-appearance: textfield; -}