diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index 655a6569a..96eb79b7d 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -47,7 +47,6 @@ type PickedSelectProps = Pick< AntdSelectAllProps, | 'allowClear' | 'autoFocus' - | 'value' | 'disabled' | 'filterOption' | 'notFoundContent' diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx index 4865501e1..718193706 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx @@ -20,6 +20,7 @@ import { AppSection, DataMask, + DataRecordValue, ensureIsArray, ExtraFormData, GenericDataType, @@ -36,7 +37,11 @@ import { useImmerReducer } from 'use-immer'; import { FormItemProps } from 'antd/lib/form'; import { PluginFilterSelectProps, SelectValue } from './types'; import { StyledFormItem, FilterPluginStyle, StatusMessage } from '../common'; -import { getDataRecordFormatter, getSelectExtraFormData } from '../../utils'; +import { + formatFilterValue, + getDataRecordFormatter, + getSelectExtraFormData, +} from '../../utils'; type DataMaskAction = | { type: 'ownState'; ownState: JsonObject } @@ -119,7 +124,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { filterState: { ...filterState, label: values?.length - ? `${(values || []).join(', ')}${suffix}` + ? `${(values || []).map(formatFilterValue).join(', ')}${suffix}` : undefined, value: appSection === AppSection.FILTER_CONFIG_MODAL && defaultToFirstItem @@ -249,12 +254,12 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { } const options = useMemo(() => { - const options: { label: string; value: string | number }[] = []; + const options: { label: string; value: DataRecordValue }[] = []; data.forEach(row => { const [value] = groupby.map(col => row[col]); options.push({ label: labelFormatter(value, datatype), - value: typeof value === 'number' ? value : String(value), + value, }); }); return options; @@ -286,6 +291,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { loading={isRefreshing} maxTagCount={5} invertSelection={inverseSelection} + // @ts-ignore options={options} /> diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts index ecd7268ad..464dc41c3 100644 --- a/superset-frontend/src/filters/utils.ts +++ b/superset-frontend/src/filters/utils.ts @@ -28,7 +28,7 @@ import { FALSE_STRING, NULL_STRING, TRUE_STRING } from 'src/utils/common'; export const getSelectExtraFormData = ( col: string, - value?: null | (string | number)[], + value?: null | (string | number | boolean | null)[], emptyFilter = false, inverseSelection = false, ): ExtraFormData => { @@ -46,6 +46,7 @@ export const getSelectExtraFormData = ( { col, op: inverseSelection ? ('NOT IN' as const) : ('IN' as const), + // @ts-ignore val: value, }, ]; @@ -116,3 +117,18 @@ export function getDataRecordFormatter({ return String(value); }; } + +export function formatFilterValue( + value: string | number | boolean | null, +): string { + if (value === null) { + return NULL_STRING; + } + if (typeof value === 'string') { + return value; + } + if (typeof value === 'number') { + return String(value); + } + return value ? TRUE_STRING : FALSE_STRING; +} diff --git a/superset/utils/core.py b/superset/utils/core.py index a549a753c..646b04c02 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -457,7 +457,7 @@ def cast_to_num(value: Optional[Union[float, int, str]]) -> Optional[Union[float return None -def cast_to_boolean(value: Any) -> bool: +def cast_to_boolean(value: Any) -> Optional[bool]: """Casts a value to an int/float >>> cast_to_boolean(1) @@ -473,12 +473,13 @@ def cast_to_boolean(value: Any) -> bool: >>> cast_to_boolean('False') False >>> cast_to_boolean(None) - False :param value: value to be converted to boolean representation :returns: value cast to `bool`. when value is 'true' or value that are not 0 - converte into True + converted into True. Return `None` if value is `None` """ + if value is None: + return None if isinstance(value, (int, float)): return value != 0 if isinstance(value, str):