mirror of
https://github.com/apache/superset.git
synced 2026-04-18 15:44:57 +00:00
Renaming field to control (#2210)
This commit is contained in:
committed by
GitHub
parent
d5ba88b407
commit
1e47d6fb41
@@ -0,0 +1,32 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Checkbox } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.bool,
|
||||
label: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
value: false,
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
export default class CheckboxControl extends React.Component {
|
||||
onToggle() {
|
||||
this.props.onChange(!this.props.value);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Checkbox
|
||||
checked={this.props.value}
|
||||
onChange={this.onToggle.bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CheckboxControl.propTypes = propTypes;
|
||||
CheckboxControl.defaultProps = defaultProps;
|
||||
@@ -0,0 +1,138 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
import React, { PropTypes } from 'react';
|
||||
import Select from 'react-select';
|
||||
import { Button, Row, Col } from 'react-bootstrap';
|
||||
import SelectControl from './SelectControl';
|
||||
|
||||
const propTypes = {
|
||||
choices: PropTypes.array,
|
||||
changeFilter: PropTypes.func,
|
||||
removeFilter: PropTypes.func,
|
||||
filter: PropTypes.object.isRequired,
|
||||
datasource: PropTypes.object,
|
||||
having: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
having: false,
|
||||
changeFilter: () => {},
|
||||
removeFilter: () => {},
|
||||
choices: [],
|
||||
datasource: null,
|
||||
};
|
||||
|
||||
export default class Filter extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.opChoices = this.props.having ? ['==', '!=', '>', '<', '>=', '<=']
|
||||
: ['in', 'not in'];
|
||||
}
|
||||
fetchFilterValues(col) {
|
||||
if (!this.props.datasource) {
|
||||
return;
|
||||
}
|
||||
const datasource = this.props.datasource;
|
||||
let choices = [];
|
||||
if (col) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`,
|
||||
success: (data) => {
|
||||
choices = Object.keys(data).map((k) =>
|
||||
([`'${data[k]}'`, `'${data[k]}'`]));
|
||||
this.props.changeFilter('choices', choices);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
changeFilter(control, event) {
|
||||
let value = event;
|
||||
if (event && event.target) {
|
||||
value = event.target.value;
|
||||
}
|
||||
if (event && event.value) {
|
||||
value = event.value;
|
||||
}
|
||||
this.props.changeFilter(control, value);
|
||||
if (control === 'col' && value !== null && this.props.datasource.filter_select) {
|
||||
this.fetchFilterValues(value);
|
||||
}
|
||||
}
|
||||
removeFilter(filter) {
|
||||
this.props.removeFilter(filter);
|
||||
}
|
||||
renderFilterFormControl(filter) {
|
||||
const datasource = this.props.datasource;
|
||||
if (datasource && datasource.filter_select) {
|
||||
if (!filter.choices) {
|
||||
this.fetchFilterValues(filter.col);
|
||||
}
|
||||
}
|
||||
if (this.props.having) {
|
||||
// druid having filter
|
||||
return (
|
||||
<input
|
||||
type="text"
|
||||
onChange={this.changeFilter.bind(this, 'val')}
|
||||
value={filter.value}
|
||||
className="form-control input-sm"
|
||||
placeholder="Filter value"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SelectControl
|
||||
multi
|
||||
freeForm
|
||||
name="filter-value"
|
||||
value={filter.val}
|
||||
choices={filter.choices || []}
|
||||
onChange={this.changeFilter.bind(this, 'val')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
const filter = this.props.filter;
|
||||
return (
|
||||
<div>
|
||||
<Row className="space-1">
|
||||
<Col md={12}>
|
||||
<Select
|
||||
id="select-col"
|
||||
placeholder="Select column"
|
||||
options={this.props.choices.map((c) => ({ value: c[0], label: c[1] }))}
|
||||
value={filter.col}
|
||||
onChange={this.changeFilter.bind(this, 'col')}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="space-1">
|
||||
<Col md={3}>
|
||||
<Select
|
||||
id="select-op"
|
||||
placeholder="Select operator"
|
||||
options={this.opChoices.map((o) => ({ value: o, label: o }))}
|
||||
value={filter.op}
|
||||
onChange={this.changeFilter.bind(this, 'op')}
|
||||
/>
|
||||
</Col>
|
||||
<Col md={7}>
|
||||
{this.renderFilterFormControl(filter)}
|
||||
</Col>
|
||||
<Col md={2}>
|
||||
<Button
|
||||
id="remove-button"
|
||||
bsSize="small"
|
||||
onClick={this.removeFilter.bind(this)}
|
||||
>
|
||||
<i className="fa fa-minus" />
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Filter.propTypes = propTypes;
|
||||
Filter.defaultProps = defaultProps;
|
||||
@@ -0,0 +1,76 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Button, Row, Col } from 'react-bootstrap';
|
||||
import Filter from './Filter';
|
||||
|
||||
const propTypes = {
|
||||
name: PropTypes.string,
|
||||
choices: PropTypes.array,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.array,
|
||||
datasource: PropTypes.object,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
choices: [],
|
||||
onChange: () => {},
|
||||
value: [],
|
||||
};
|
||||
|
||||
export default class FilterControl extends React.Component {
|
||||
addFilter() {
|
||||
const newFilters = Object.assign([], this.props.value);
|
||||
newFilters.push({
|
||||
col: null,
|
||||
op: 'in',
|
||||
val: this.props.datasource.filter_select ? [] : '',
|
||||
});
|
||||
this.props.onChange(newFilters);
|
||||
}
|
||||
changeFilter(index, control, value) {
|
||||
const newFilters = Object.assign([], this.props.value);
|
||||
const modifiedFilter = Object.assign({}, newFilters[index]);
|
||||
modifiedFilter[control] = value;
|
||||
newFilters.splice(index, 1, modifiedFilter);
|
||||
this.props.onChange(newFilters);
|
||||
}
|
||||
removeFilter(index) {
|
||||
this.props.onChange(this.props.value.filter((f, i) => i !== index));
|
||||
}
|
||||
render() {
|
||||
const filters = [];
|
||||
this.props.value.forEach((filter, i) => {
|
||||
const filterBox = (
|
||||
<div key={i}>
|
||||
<Filter
|
||||
having={this.props.name === 'having_filters'}
|
||||
filter={filter}
|
||||
choices={this.props.choices}
|
||||
datasource={this.props.datasource}
|
||||
removeFilter={this.removeFilter.bind(this, i)}
|
||||
changeFilter={this.changeFilter.bind(this, i)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
filters.push(filterBox);
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
{filters}
|
||||
<Row className="space-2">
|
||||
<Col md={2}>
|
||||
<Button
|
||||
id="add-button"
|
||||
bsSize="sm"
|
||||
onClick={this.addFilter.bind(this)}
|
||||
>
|
||||
<i className="fa fa-plus" /> Add Filter
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FilterControl.propTypes = propTypes;
|
||||
FilterControl.defaultProps = defaultProps;
|
||||
@@ -0,0 +1,24 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { FormControl } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]),
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
export default class HiddenControl extends React.PureComponent {
|
||||
render() {
|
||||
// This wouldn't be necessary but might as well
|
||||
return <FormControl type="hidden" value={this.props.value} />;
|
||||
}
|
||||
}
|
||||
|
||||
HiddenControl.propTypes = propTypes;
|
||||
HiddenControl.defaultProps = defaultProps;
|
||||
@@ -0,0 +1,115 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import Select, { Creatable } from 'react-select';
|
||||
|
||||
const propTypes = {
|
||||
choices: PropTypes.array,
|
||||
clearable: PropTypes.bool,
|
||||
description: PropTypes.string,
|
||||
freeForm: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
label: PropTypes.string,
|
||||
multi: PropTypes.bool,
|
||||
name: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]),
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
choices: [],
|
||||
clearable: true,
|
||||
description: null,
|
||||
freeForm: false,
|
||||
isLoading: false,
|
||||
label: null,
|
||||
multi: false,
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
export default class SelectControl extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { options: this.getOptions(props) };
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.renderOption = this.renderOption.bind(this);
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.choices !== this.props.choices) {
|
||||
const options = this.getOptions(nextProps);
|
||||
this.setState({ options });
|
||||
}
|
||||
}
|
||||
onChange(opt) {
|
||||
let optionValue = opt ? opt.value : null;
|
||||
// if multi, return options values as an array
|
||||
if (this.props.multi) {
|
||||
optionValue = opt ? opt.map((o) => o.value) : null;
|
||||
}
|
||||
this.props.onChange(optionValue);
|
||||
}
|
||||
getOptions(props) {
|
||||
const options = props.choices.map((c) => {
|
||||
const label = c.length > 1 ? c[1] : c[0];
|
||||
const newOptions = {
|
||||
value: c[0],
|
||||
label,
|
||||
};
|
||||
if (c[2]) newOptions.imgSrc = c[2];
|
||||
return newOptions;
|
||||
});
|
||||
if (props.freeForm) {
|
||||
// For FreeFormSelect, insert value into options if not exist
|
||||
const values = props.choices.map((c) => c[0]);
|
||||
if (props.value) {
|
||||
if (typeof props.value === 'object') {
|
||||
props.value.forEach((v) => {
|
||||
if (values.indexOf(v) === -1) {
|
||||
options.push({ value: v, label: v });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (values.indexOf(props.value) === -1) {
|
||||
options.push({ value: props.value, label: props.value });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
renderOption(opt) {
|
||||
if (opt.imgSrc) {
|
||||
return (
|
||||
<div>
|
||||
<img className="viz-thumb-option" src={opt.imgSrc} alt={opt.value} />
|
||||
<span>{opt.label}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return opt.label;
|
||||
}
|
||||
render() {
|
||||
// Tab, comma or Enter will trigger a new option created for FreeFormSelect
|
||||
const selectProps = {
|
||||
multi: this.props.multi,
|
||||
name: `select-${this.props.name}`,
|
||||
placeholder: `Select (${this.state.options.length})`,
|
||||
options: this.state.options,
|
||||
value: this.props.value,
|
||||
autosize: false,
|
||||
clearable: this.props.clearable,
|
||||
isLoading: this.props.isLoading,
|
||||
onChange: this.onChange,
|
||||
optionRenderer: this.renderOption,
|
||||
};
|
||||
// Tab, comma or Enter will trigger a new option created for FreeFormSelect
|
||||
const selectWrap = this.props.freeForm ?
|
||||
(<Creatable {...selectProps} />) : (<Select {...selectProps} />);
|
||||
return (
|
||||
<div>
|
||||
{selectWrap}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectControl.propTypes = propTypes;
|
||||
SelectControl.defaultProps = defaultProps;
|
||||
@@ -0,0 +1,38 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { FormGroup, FormControl } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
label: null,
|
||||
description: null,
|
||||
onChange: () => {},
|
||||
value: '',
|
||||
};
|
||||
|
||||
export default class TextAreaControl extends React.Component {
|
||||
onChange(event) {
|
||||
this.props.onChange(event.target.value);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<FormGroup controlId="formControlsTextarea">
|
||||
<FormControl
|
||||
componentClass="textarea"
|
||||
placeholder="textarea"
|
||||
onChange={this.onChange.bind(this)}
|
||||
value={this.props.value}
|
||||
/>
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaControl.propTypes = propTypes;
|
||||
TextAreaControl.defaultProps = defaultProps;
|
||||
@@ -0,0 +1,73 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { FormGroup, FormControl } from 'react-bootstrap';
|
||||
import * as v from '../../validators';
|
||||
|
||||
const propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]),
|
||||
isFloat: PropTypes.bool,
|
||||
isInt: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
label: null,
|
||||
description: null,
|
||||
onChange: () => {},
|
||||
value: '',
|
||||
isInt: false,
|
||||
isFloat: false,
|
||||
};
|
||||
|
||||
export default class TextControl extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const value = props.value ? props.value.toString() : '';
|
||||
this.state = { value };
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
onChange(event) {
|
||||
let value = event.target.value || '';
|
||||
this.setState({ value });
|
||||
|
||||
// Validation & casting
|
||||
const errors = [];
|
||||
if (this.props.isFloat) {
|
||||
const error = v.numeric(value);
|
||||
if (error) {
|
||||
errors.push(error);
|
||||
} else {
|
||||
value = parseFloat(value);
|
||||
}
|
||||
}
|
||||
if (this.props.isInt) {
|
||||
const error = v.integer(value);
|
||||
if (error) {
|
||||
errors.push(error);
|
||||
} else {
|
||||
value = parseInt(value, 10);
|
||||
}
|
||||
}
|
||||
this.props.onChange(value, errors);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<FormGroup controlId="formInlineName" bsSize="small">
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder=""
|
||||
onChange={this.onChange}
|
||||
value={this.state.value}
|
||||
/>
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TextControl.propTypes = propTypes;
|
||||
TextControl.defaultProps = defaultProps;
|
||||
Reference in New Issue
Block a user