This is an automated email from the ASF dual-hosted git repository.
graceguo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new d96bb87 fix: [filter_box] fix 2 issues in single value filter_box
(#9829)
d96bb87 is described below
commit d96bb874f2dfa27ff41736982cc0d8027efaaefa
Author: Grace Guo <[email protected]>
AuthorDate: Mon May 18 21:25:10 2020 -0700
fix: [filter_box] fix 2 issues in single value filter_box (#9829)
* fix: [filter_box] fix 2 issues in single value filter_box
* add unit test
* add fix per comments
---
.../components/FilterBoxItemControl_spec.jsx | 49 ++++++++++++++++++++++
.../dashboard/util/getFilterConfigsFromFormdata.js | 12 ++++--
.../components/controls/FilterBoxItemControl.jsx | 49 ++++++++++++++++++++--
superset-frontend/src/explore/constants.js | 5 +++
.../src/visualizations/FilterBox/FilterBox.jsx | 18 +++++---
5 files changed, 121 insertions(+), 12 deletions(-)
diff --git
a/superset-frontend/spec/javascripts/explore/components/FilterBoxItemControl_spec.jsx
b/superset-frontend/spec/javascripts/explore/components/FilterBoxItemControl_spec.jsx
index 162ab47..c1a38ec 100644
---
a/superset-frontend/spec/javascripts/explore/components/FilterBoxItemControl_spec.jsx
+++
b/superset-frontend/spec/javascripts/explore/components/FilterBoxItemControl_spec.jsx
@@ -52,4 +52,53 @@ describe('FilterBoxItemControl', () => {
const popover = shallow(inst.renderForm());
expect(popover.find(FormRow)).toHaveLength(7);
});
+
+ it('convert type for single value filter_box', () => {
+ inst = getWrapper({
+ datasource: {
+ columns: [
+ {
+ column_name: 'SP_POP_TOTL',
+ description: null,
+ expression: null,
+ filterable: true,
+ groupby: true,
+ id: 312,
+ is_dttm: false,
+ type: 'FLOAT',
+ verbose_name: null,
+ },
+ ],
+ metrics: [
+ {
+ d3format: null,
+ description: null,
+ expression: 'sum("SP_POP_TOTL")',
+ id: 3,
+ metric_name: 'sum__SP_POP_TOTL',
+ verbose_name: null,
+ warning_text: null,
+ },
+ ],
+ },
+ }).instance();
+ inst.setState({
+ asc: true,
+ clearable: true,
+ column: 'SP_POP_TOTL',
+ defaultValue: 254454778,
+ metric: undefined,
+ multiple: false,
+ });
+ inst.setState = sinon.spy();
+
+ inst.onControlChange('defaultValue', '1');
+ expect(inst.setState.callCount).toBe(1);
+ expect(inst.setState.getCall(0).args[0]).toEqual({ defaultValue: 1 });
+
+ // user input is invalid for number type column
+ inst.onControlChange('defaultValue', 'abc');
+ expect(inst.setState.callCount).toBe(2);
+ expect(inst.setState.getCall(1).args[0]).toEqual({ defaultValue: null });
+ });
});
diff --git
a/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js
b/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js
index fb7102c..192f7cb 100644
--- a/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js
+++ b/superset-frontend/src/dashboard/util/getFilterConfigsFromFormdata.js
@@ -18,7 +18,10 @@
*/
/* eslint-disable camelcase */
import { TIME_FILTER_MAP } from '../../visualizations/FilterBox/FilterBox';
-import { TIME_FILTER_LABELS } from '../../explore/constants';
+import {
+ FILTER_CONFIG_ATTRIBUTES,
+ TIME_FILTER_LABELS,
+} from '../../explore/constants';
export default function getFilterConfigsFromFormdata(form_data = {}) {
const {
@@ -31,10 +34,13 @@ export default function
getFilterConfigsFromFormdata(form_data = {}) {
} = form_data;
let configs = filter_configs.reduce(
({ columns, labels }, config) => {
- let defaultValues = config.defaultValue;
+ let defaultValues = config[FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE];
// defaultValue could be ; separated values,
// could be null or ''
- if (config.defaultValue) {
+ if (
+ config[FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE] &&
+ config[FILTER_CONFIG_ATTRIBUTES.MULTIPLE]
+ ) {
defaultValues = config.defaultValue.split(';');
}
const updatedColumns = {
diff --git
a/superset-frontend/src/explore/components/controls/FilterBoxItemControl.jsx
b/superset-frontend/src/explore/components/controls/FilterBoxItemControl.jsx
index 2928dca..c23e1fb 100644
--- a/superset-frontend/src/explore/components/controls/FilterBoxItemControl.jsx
+++ b/superset-frontend/src/explore/components/controls/FilterBoxItemControl.jsx
@@ -26,6 +26,24 @@ import FormRow from '../../../components/FormRow';
import SelectControl from './SelectControl';
import CheckboxControl from './CheckboxControl';
import TextControl from './TextControl';
+import { FILTER_CONFIG_ATTRIBUTES } from '../../constants';
+
+const INTEGRAL_TYPES = new Set([
+ 'TINYINT',
+ 'SMALLINT',
+ 'INT',
+ 'INTEGER',
+ 'BIGINT',
+ 'LONG',
+]);
+const DECIMAL_TYPES = new Set([
+ 'FLOAT',
+ 'DOUBLE',
+ 'REAL',
+ 'NUMERIC',
+ 'DECIMAL',
+ 'MONEY',
+]);
const propTypes = {
datasource: PropTypes.object.isRequired,
@@ -60,7 +78,28 @@ export default class FilterBoxItemControl extends
React.Component {
this.props.onChange(this.state);
}
onControlChange(attr, value) {
- this.setState({ [attr]: value }, this.onChange);
+ let typedValue = value;
+ const { column: selectedColumnName, multiple } = this.state;
+ if (value && !multiple && attr === FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE)
{
+ // if single value filter_box,
+ // convert input value string to the column's data type
+ const { datasource } = this.props;
+ const selectedColumn = datasource.columns.find(
+ col => col.column_name === selectedColumnName,
+ );
+
+ if (selectedColumn && selectedColumn.type) {
+ const type = selectedColumn.type.toUpperCase();
+ if (type === 'BOOLEAN') {
+ typedValue = value === 'true';
+ } else if (INTEGRAL_TYPES.has(type)) {
+ typedValue = isNaN(value) ? null : parseInt(value, 10);
+ } else if (DECIMAL_TYPES.has(type)) {
+ typedValue = isNaN(value) ? null : parseFloat(value);
+ }
+ }
+ }
+ this.setState({ [attr]: typedValue }, this.onChange);
}
setType() {}
textSummary() {
@@ -110,7 +149,9 @@ export default class FilterBoxItemControl extends
React.Component {
<TextControl
value={this.state.defaultValue}
name="defaultValue"
- onChange={v => this.onControlChange('defaultValue', v)}
+ onChange={v =>
+ this.onControlChange(FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE, v)
+ }
/>
}
/>
@@ -155,7 +196,9 @@ export default class FilterBoxItemControl extends
React.Component {
control={
<CheckboxControl
value={this.state.multiple}
- onChange={v => this.onControlChange('multiple', v)}
+ onChange={v =>
+ this.onControlChange(FILTER_CONFIG_ATTRIBUTES.MULTIPLE, v)
+ }
/>
}
/>
diff --git a/superset-frontend/src/explore/constants.js
b/superset-frontend/src/explore/constants.js
index de99199..975a7fe 100644
--- a/superset-frontend/src/explore/constants.js
+++ b/superset-frontend/src/explore/constants.js
@@ -78,3 +78,8 @@ export const TIME_FILTER_LABELS = {
druid_time_origin: t('Origin'),
granularity: t('Time Granularity'),
};
+
+export const FILTER_CONFIG_ATTRIBUTES = {
+ DEFAULT_VALUE: 'defaultValue',
+ MULTIPLE: 'multiple',
+};
diff --git a/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
b/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
index 4f6f63c..fb84ba6 100644
--- a/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
+++ b/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
@@ -31,7 +31,10 @@ import OnPasteSelect from '../../components/OnPasteSelect';
import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
import { getDashboardFilterKey } from
'../../dashboard/util/getDashboardFilterKey';
import { getFilterColorMap } from
'../../dashboard/util/dashboardFiltersColorMap';
-import { TIME_FILTER_LABELS } from '../../explore/constants';
+import {
+ FILTER_CONFIG_ATTRIBUTES,
+ TIME_FILTER_LABELS,
+} from '../../explore/constants';
import FilterBadgeIcon from '../../components/FilterBadgeIcon';
import './FilterBox.less';
@@ -259,19 +262,22 @@ class FilterBox extends React.Component {
let value = selectedValues[key] || null;
// Assign default value if required
- if (!value && filterConfig.defaultValue) {
- if (filterConfig.multiple) {
+ if (
+ value === undefined &&
+ filterConfig[FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE]
+ ) {
+ if (filterConfig[FILTER_CONFIG_ATTRIBUTES.MULTIPLE]) {
// Support for semicolon-delimited multiple values
- value = filterConfig.defaultValue.split(';');
+ value =
filterConfig[FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE].split(';');
} else {
- value = filterConfig.defaultValue;
+ value = filterConfig[FILTER_CONFIG_ATTRIBUTES.DEFAULT_VALUE];
}
}
return (
<OnPasteSelect
placeholder={t('Select [%s]', label)}
key={key}
- multi={filterConfig.multiple}
+ multi={filterConfig[FILTER_CONFIG_ATTRIBUTES.MULTIPLE]}
clearable={filterConfig.clearable}
value={value}
options={data.map(opt => {