Skip to content

Commit

Permalink
Split setup in advanced and regular for data sources and destinations (
Browse files Browse the repository at this point in the history
…#4160)

* DynamicForm support for advanced options

* Randomly select a few options to be advanced

* Merge conditions with the same logic

* Address some comments

* Update styling for the button

* Some style adjustments (#4162)

* Don't set default value to additional settings

* Rename advanced -> extra

* Show extra fields by default when they are filled

* Update hasFilledExtraField logic

* Add example field from destination as extra
  • Loading branch information
gabrieldutra authored and arikfr committed Oct 6, 2019
1 parent 569c325 commit 8ea285d
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 16 deletions.
2 changes: 1 addition & 1 deletion client/app/components/CreateSourceDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class CreateSourceDialog extends React.Component {
const fields = helper.getFields(selectedType);
const helpTriggerType = `${helpTriggerPrefix}${toUpper(selectedType.type)}`;
return (
<div className="p-5">
<div>
<div className="d-flex justify-content-center align-items-center">
<img
className="p-5"
Expand Down
47 changes: 38 additions & 9 deletions client/app/components/dynamic-form/DynamicForm.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import Form from 'antd/lib/form';
import Input from 'antd/lib/input';
import InputNumber from 'antd/lib/input-number';
import Checkbox from 'antd/lib/checkbox';
import Button from 'antd/lib/button';
import Upload from 'antd/lib/upload';
import Icon from 'antd/lib/icon';
import { includes, isFunction } from 'lodash';
import { includes, isFunction, filter, difference, isEmpty, some, isNumber, isBoolean } from 'lodash';
import Select from 'antd/lib/select';
import notification from '@/services/notification';
import Collapse from '@/components/Collapse';
import AceEditorInput from '@/components/AceEditorInput';
import { toHuman } from '@/filters';
import { Field, Action, AntdForm } from '../proptypes';
import helper from './dynamicFormHelper';

import './DynamicForm.less';

const fieldRules = ({ type, required, minLength }) => {
const requiredRule = required;
const minLengthRule = minLength && includes(['text', 'email', 'password'], type);
Expand Down Expand Up @@ -51,9 +56,14 @@ class DynamicForm extends React.Component {
constructor(props) {
super(props);

const hasFilledExtraField = some(props.fields, (field) => {
const { extra, initialValue } = field;
return extra && (!isEmpty(initialValue) || isNumber(initialValue) || isBoolean(initialValue) && initialValue);
});
this.state = {
isSubmitting: false,
inProgressActions: [],
showExtraFields: hasFilledExtraField,
};

this.actionCallbacks = this.props.actions.reduce((acc, cur) => ({
Expand Down Expand Up @@ -169,7 +179,7 @@ class DynamicForm extends React.Component {
renderField(field, props) {
const { getFieldDecorator } = this.props.form;
const { name, type, initialValue } = field;
const fieldLabel = field.title || helper.toHuman(name);
const fieldLabel = field.title || toHuman(name);

const options = {
rules: fieldRules(field),
Expand All @@ -195,11 +205,11 @@ class DynamicForm extends React.Component {
return getFieldDecorator(name, options)(<Input {...props} />);
}

renderFields() {
return this.props.fields.map((field) => {
renderFields(fields) {
return fields.map((field) => {
const FormItem = Form.Item;
const { name, title, type, readOnly, autoFocus, contentAfter } = field;
const fieldLabel = title || helper.toHuman(name);
const fieldLabel = title || toHuman(name);
const { feedbackIcons, form } = this.props;

const formItemProps = {
Expand Down Expand Up @@ -251,16 +261,35 @@ class DynamicForm extends React.Component {
const submitProps = {
type: 'primary',
htmlType: 'submit',
className: 'w-100',
className: 'w-100 m-t-20',
disabled: this.state.isSubmitting,
loading: this.state.isSubmitting,
};
const { id, hideSubmitButton, saveText } = this.props;
const { id, hideSubmitButton, saveText, fields } = this.props;
const { showExtraFields } = this.state;
const saveButton = !hideSubmitButton;
const extraFields = filter(fields, { extra: true });
const regularFields = difference(fields, extraFields);

return (
<Form id={id} layout="vertical" onSubmit={this.handleSubmit}>
{this.renderFields()}
<Form id={id} className="dynamic-form" layout="vertical" onSubmit={this.handleSubmit}>
{this.renderFields(regularFields)}
{!isEmpty(extraFields) && (
<div className="extra-options">
<Button
type="dashed"
block
className="extra-options-button"
onClick={() => this.setState({ showExtraFields: !showExtraFields })}
>
Additional Settings
<i className={cx('fa m-l-5', { 'fa-caret-up': showExtraFields, 'fa-caret-down': !showExtraFields })} />
</Button>
<Collapse collapsed={!showExtraFields} className="extra-options-content">
{this.renderFields(extraFields)}
</Collapse>
</div>
)}
{saveButton && <Button {...submitProps}>{saveText}</Button>}
{this.renderActions()}
</Form>
Expand Down
29 changes: 29 additions & 0 deletions client/app/components/dynamic-form/DynamicForm.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@import '~@/assets/less/ant';

.dynamic-form{
.extra-options {
margin: 25px 0 10px;
}

.extra-options-button {
&, &:focus, &:hover {
height: 40px;
font-weight: 500;
background-color: @btn-danger-bg;
border-color: @btn-danger-border;
color: @btn-default-color;
}

&:focus, &:hover {
background-color: fade(@btn-danger-bg, 15%);
}
}

.extra-options-content {
margin-top: 15px;

.ant-form-item:last-of-type {
margin-bottom: 0 !important;
}
}
}
7 changes: 2 additions & 5 deletions client/app/components/dynamic-form/dynamicFormHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function orderedInputs(properties, order, targetOptions) {
type: properties[key].type,
placeholder: properties[key].default && properties[key].default.toString(),
required: properties[key].required,
extra: properties[key].extra,
initialValue: targetOptions[key],
};

Expand Down Expand Up @@ -57,6 +58,7 @@ function normalizeSchema(configurationSchema) {
}

prop.required = includes(configurationSchema.required, name);
prop.extra = includes(configurationSchema.extra_options, name);
});

configurationSchema.order = configurationSchema.order || [];
Expand Down Expand Up @@ -113,10 +115,6 @@ function updateTargetWithValues(target, values) {
});
}

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();
Expand All @@ -129,6 +127,5 @@ function getBase64(file) {
export default {
getFields,
updateTargetWithValues,
toHuman,
getBase64,
};
1 change: 1 addition & 0 deletions client/app/components/proptypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const Field = PropTypes.shape({
content: PropTypes.node,
mode: PropTypes.string,
required: PropTypes.bool,
extra: PropTypes.bool,
readOnly: PropTypes.bool,
autoFocus: PropTypes.bool,
minLength: PropTypes.number,
Expand Down
3 changes: 2 additions & 1 deletion redash/destinations/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ def configuration_schema(cls):
"title": "Subject Template"
}
},
"required": ["addresses"]
"required": ["addresses"],
"extra_options": ["subject_template"]
}

@classmethod
Expand Down
3 changes: 3 additions & 0 deletions redash/query_runner/athena.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def configuration_schema(cls):
},
},
'required': ['region', 's3_staging_dir'],
'extra_options': ['glue'],
'order': ['region', 's3_staging_dir', 'schema', 'work_group'],
'secret': ['aws_secret_key']
}
Expand All @@ -101,6 +102,8 @@ def configuration_schema(cls):
'title': 'KMS Key',
},
})
schema['extra_options'].append('encryption_option')
schema['extra_options'].append('kms_key')

if ASSUME_ROLE:
del schema['properties']['aws_access_key']
Expand Down
1 change: 1 addition & 0 deletions redash/query_runner/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def configuration_schema(cls):
}
},
"required": ["dbname"],
"extra_options": ["timeout"],
"secret": ["password"]
}

Expand Down

0 comments on commit 8ea285d

Please sign in to comment.