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
This commit is contained in:
parent
e121e090c7
commit
d96bb874f2
|
|
@ -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 });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue