mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
fix(native-filters): loop bug by simplify state handling (#14788)
This commit is contained in:
@@ -73,6 +73,7 @@ const DefaultValue: FC<DefaultValueProps> = ({
|
||||
chartType={formFilter?.filterType}
|
||||
hooks={{ setDataMask }}
|
||||
enableNoResults={enableNoResults}
|
||||
filterState={formFilter.defaultDataMask?.filterState}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
} from '@superset-ui/core';
|
||||
import React, { useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { Select } from 'src/common/components';
|
||||
import { debounce } from 'lodash';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { SLOW_DEBOUNCE } from 'src/constants';
|
||||
import { PluginFilterSelectProps, SelectValue } from './types';
|
||||
import { StyledSelect, Styles } from '../common';
|
||||
@@ -91,7 +91,6 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
||||
appSection,
|
||||
} = props;
|
||||
const {
|
||||
defaultValue,
|
||||
enableEmptyFilter,
|
||||
multiSelect,
|
||||
showSearch,
|
||||
@@ -100,29 +99,36 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
||||
defaultToFirstItem,
|
||||
searchAllOptions,
|
||||
} = formData;
|
||||
const groupby = ensureIsArray<string>(formData.groupby);
|
||||
const [col] = groupby;
|
||||
const [currentSuggestionSearch, setCurrentSuggestionSearch] = useState('');
|
||||
const [dataMask, dispatchDataMask] = useReducer<DataMaskReducer>(reducer, {
|
||||
filterState,
|
||||
ownState: {
|
||||
coltypeMap,
|
||||
},
|
||||
});
|
||||
const updateDataMask = (values: SelectValue) => {
|
||||
const emptyFilter =
|
||||
enableEmptyFilter && !inverseSelection && !values?.length;
|
||||
|
||||
dispatchDataMask({
|
||||
type: 'filterState',
|
||||
extraFormData: getSelectExtraFormData(
|
||||
col,
|
||||
values,
|
||||
emptyFilter,
|
||||
inverseSelection,
|
||||
),
|
||||
filterState: {
|
||||
value: values,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const isDisabled =
|
||||
appSection === AppSection.FILTER_CONFIG_MODAL && defaultToFirstItem;
|
||||
|
||||
const groupby = ensureIsArray<string>(formData.groupby);
|
||||
// Correct initial value for Ant Select
|
||||
|
||||
// If we are in config modal we always need show empty select for `defaultToFirstItem`
|
||||
const [values, setValues] = useState<SelectValue>(
|
||||
!isDisabled && defaultValue?.length ? defaultValue : [],
|
||||
);
|
||||
const [currentSuggestionSearch, setCurrentSuggestionSearch] = useState('');
|
||||
const [dataMask, dispatchDataMask] = useReducer<DataMaskReducer>(
|
||||
reducer,
|
||||
searchAllOptions
|
||||
? {
|
||||
ownState: {
|
||||
coltypeMap,
|
||||
},
|
||||
}
|
||||
: {},
|
||||
);
|
||||
|
||||
const debouncedOwnStateFunc = useCallback(
|
||||
debounce((val: string) => {
|
||||
dispatchDataMask({
|
||||
@@ -154,67 +160,46 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const firstItem: SelectValue = data[0]
|
||||
? (groupby.map(col => data[0][col]) as string[])
|
||||
: null;
|
||||
if (!isDisabled && defaultToFirstItem && firstItem) {
|
||||
// initialize to first value if set to default to first item
|
||||
setValues(firstItem);
|
||||
} else if (!isDisabled && defaultValue?.length) {
|
||||
// initialize to saved value
|
||||
setValues(defaultValue);
|
||||
}
|
||||
}, [defaultToFirstItem, defaultValue]);
|
||||
|
||||
const handleBlur = () => {
|
||||
clearSuggestionSearch();
|
||||
unsetFocusedFilter();
|
||||
};
|
||||
|
||||
const [col] = groupby;
|
||||
const datatype: GenericDataType = coltypeMap[col];
|
||||
const labelFormatter = getDataRecordFormatter({
|
||||
timeFormatter: smartDateDetailedFormatter,
|
||||
});
|
||||
|
||||
const handleChange = (value?: SelectValue | number | string) => {
|
||||
setValues(ensureIsArray(value));
|
||||
const values = ensureIsArray(value);
|
||||
if (values.length === 0) {
|
||||
updateDataMask(null);
|
||||
} else {
|
||||
updateDataMask(values);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const firstItem: SelectValue = data[0]
|
||||
? (groupby.map(col => data[0][col]) as string[])
|
||||
: null;
|
||||
if (isDisabled) {
|
||||
setValues([]);
|
||||
// empty selection if filter is disabled
|
||||
updateDataMask(null);
|
||||
} else if (!isDisabled && defaultToFirstItem && firstItem) {
|
||||
// initialize to first value if set to default to first item
|
||||
updateDataMask(firstItem);
|
||||
} else {
|
||||
// reset data mask based on filter state
|
||||
updateDataMask(filterState.value);
|
||||
}
|
||||
}, [isDisabled]);
|
||||
|
||||
useEffect(() => {
|
||||
const emptyFilter =
|
||||
enableEmptyFilter && !inverseSelection && values?.length === 0;
|
||||
|
||||
dispatchDataMask({
|
||||
type: 'filterState',
|
||||
extraFormData: getSelectExtraFormData(
|
||||
col,
|
||||
values,
|
||||
emptyFilter,
|
||||
inverseSelection,
|
||||
),
|
||||
filterState: {
|
||||
// We need to save in state `FIRST_VALUE` as some const and not as REAL value,
|
||||
// because when FiltersBar check if all filters initialized it compares `defaultValue` with this value
|
||||
// and because REAL value can be unpredictable for users that have different data for same dashboard we use `FIRST_VALUE`
|
||||
value: values,
|
||||
},
|
||||
});
|
||||
}, [col, enableEmptyFilter, inverseSelection, JSON.stringify(values)]);
|
||||
|
||||
useEffect(() => {
|
||||
// handle changes coming from application, e.g. "Clear all" button
|
||||
if (JSON.stringify(values) !== JSON.stringify(filterState.value)) {
|
||||
handleChange(filterState.value);
|
||||
}
|
||||
}, [JSON.stringify(filterState.value)]);
|
||||
}, [
|
||||
col,
|
||||
isDisabled,
|
||||
defaultToFirstItem,
|
||||
enableEmptyFilter,
|
||||
inverseSelection,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setDataMask(dataMask);
|
||||
@@ -229,7 +214,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
||||
<StyledSelect
|
||||
allowClear={!enableEmptyFilter}
|
||||
// @ts-ignore
|
||||
value={values}
|
||||
value={filterState.value || []}
|
||||
disabled={isDisabled}
|
||||
showSearch={showSearch}
|
||||
mode={multiSelect ? 'multiple' : undefined}
|
||||
@@ -253,7 +238,7 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
||||
);
|
||||
})}
|
||||
{currentSuggestionSearch &&
|
||||
!ensureIsArray(values).some(
|
||||
!ensureIsArray(filterState.value).some(
|
||||
suggestion => suggestion === currentSuggestionSearch,
|
||||
) && (
|
||||
<Option value={currentSuggestionSearch}>
|
||||
|
||||
Reference in New Issue
Block a user