You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2021/02/02 09:28:47 UTC

[superset] branch master updated: feat(native-filters): Add defaultValue for Native filters modal (#12199)

This is an automated email from the ASF dual-hosted git repository.

villebro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 465d986  feat(native-filters): Add defaultValue for Native filters modal (#12199)
465d986 is described below

commit 465d986617233ab401c99f9eab0f55488e0dae09
Author: simcha90 <56...@users.noreply.github.com>
AuthorDate: Tue Feb 2 11:28:12 2021 +0200

    feat(native-filters): Add defaultValue for Native filters modal (#12199)
    
    * refactor: sync Scoping tree with Forms data
    
    * refactor: update scoping tree
    
    * refactor: update scope tree logic to be more UX friendly
    
    * test: fix tests
    
    * lint: fix lin CR notes
    
    * chore: temp
    
    * fix: fix jsx
    
    * feat: Init value
    
    * refactor: move effect to utils
    
    * chore: add comments
    
    * feat: updates for default value in native filters
    
    * refactor: move multi values management to Modal
    
    * feat: added currentState to filterState
    fix: Reset all fixed
    
    * style: update filter styles
    
    * fix: process selection of same filter
    
    * fix: fix double choose select
    
    * fix: fix order of cascading filters
    
    * fix: fix CR comments
    
    * fix: fix CR comments
---
 .../spec/fixtures/mockNativeFilters.ts             |   9 +-
 .../src/dashboard/actions/nativeFilters.ts         |   5 +
 .../components/nativeFilters/CascadePopover.tsx    |  51 +++---
 .../components/nativeFilters/FilterBar.tsx         | 184 ++++++++++-----------
 .../components/nativeFilters/FilterConfigForm.tsx  | 129 +++++++++++++--
 .../components/nativeFilters/FilterConfigModal.tsx |   4 +-
 .../dashboard/components/nativeFilters/state.ts    | 108 ++++++++++--
 .../dashboard/components/nativeFilters/types.ts    |  24 ++-
 .../dashboard/components/nativeFilters/utils.ts    |  66 +++++++-
 .../src/dashboard/reducers/nativeFilters.ts        |   1 +
 .../filters/components/Select/AntdSelectFilter.tsx |  54 ++++--
 .../src/filters/components/Select/types.ts         |   6 +-
 superset-frontend/src/filters/utils.ts             |   2 +-
 13 files changed, 461 insertions(+), 182 deletions(-)

diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts
index 9aa6e10..24872d8 100644
--- a/superset-frontend/spec/fixtures/mockNativeFilters.ts
+++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts
@@ -16,14 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { NativeFiltersState } from 'src/dashboard/components/nativeFilters/types';
+import {
+  FilterType,
+  NativeFiltersState,
+} from 'src/dashboard/components/nativeFilters/types';
 
 export const nativeFilters: NativeFiltersState = {
   filters: {
     'NATIVE_FILTER-e7Q8zKixx': {
       id: 'NATIVE_FILTER-e7Q8zKixx',
       name: 'region',
-      type: 'text',
+      filterType: FilterType.filter_select,
       targets: [
         {
           datasetId: 2,
@@ -46,7 +49,7 @@ export const nativeFilters: NativeFiltersState = {
     'NATIVE_FILTER-x9QPw0so1': {
       id: 'NATIVE_FILTER-x9QPw0so1',
       name: 'country_code',
-      type: 'text',
+      filterType: FilterType.filter_select,
       targets: [
         {
           datasetId: 2,
diff --git a/superset-frontend/src/dashboard/actions/nativeFilters.ts b/superset-frontend/src/dashboard/actions/nativeFilters.ts
index 2bafb73..a327eba 100644
--- a/superset-frontend/src/dashboard/actions/nativeFilters.ts
+++ b/superset-frontend/src/dashboard/actions/nativeFilters.ts
@@ -20,6 +20,7 @@
 import { ExtraFormData, makeApi } from '@superset-ui/core';
 import { Dispatch } from 'redux';
 import {
+  CurrentFilterState,
   Filter,
   FilterConfiguration,
   SelectedValues,
@@ -99,6 +100,7 @@ export interface SetExtraFormData {
   type: typeof SET_EXTRA_FORM_DATA;
   filterId: string;
   extraFormData: ExtraFormData;
+  currentState: CurrentFilterState;
 }
 
 export function setFilterState(
@@ -117,15 +119,18 @@ export function setFilterState(
  * Sets the selected option(s) for a given filter
  * @param filterId the id of the native filter
  * @param extraFormData the selection translated into extra form data
+ * @param currentState
  */
 export function setExtraFormData(
   filterId: string,
   extraFormData: ExtraFormData,
+  currentState: CurrentFilterState,
 ): SetExtraFormData {
   return {
     type: SET_EXTRA_FORM_DATA,
     filterId,
     extraFormData,
+    currentState,
   };
 }
 
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/CascadePopover.tsx b/superset-frontend/src/dashboard/components/nativeFilters/CascadePopover.tsx
index e12c933..b131ba6 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/CascadePopover.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/CascadePopover.tsx
@@ -22,14 +22,19 @@ import Popover from 'src/common/components/Popover';
 import Icon from 'src/components/Icon';
 import { Pill } from 'src/dashboard/components/FiltersBadge/Styles';
 import { CascadeFilterControl, FilterControl } from './FilterBar';
-import { Filter, CascadeFilter } from './types';
+import { Filter, CascadeFilter, CurrentFilterState } from './types';
+import { useFilterState } from './state';
 
 interface CascadePopoverProps {
   filter: CascadeFilter;
   visible: boolean;
   directPathToChild?: string[];
   onVisibleChange: (visible: boolean) => void;
-  onExtraFormDataChange: (filter: Filter, extraFormData: ExtraFormData) => void;
+  onFilterSelectionChange: (
+    filter: Filter,
+    extraFormData: ExtraFormData,
+    currentState: CurrentFilterState,
+  ) => void;
 }
 
 const StyledTitleBox = styled.div`
@@ -73,10 +78,11 @@ const CascadePopover: React.FC<CascadePopoverProps> = ({
   filter,
   visible,
   onVisibleChange,
-  onExtraFormDataChange,
+  onFilterSelectionChange,
   directPathToChild,
 }) => {
   const [currentPathToChild, setCurrentPathToChild] = useState<string[]>();
+  const filterState = useFilterState(filter.id);
 
   useEffect(() => {
     setCurrentPathToChild(directPathToChild);
@@ -86,26 +92,27 @@ const CascadePopover: React.FC<CascadePopoverProps> = ({
     return () => clearTimeout(timeout);
   }, [directPathToChild, setCurrentPathToChild]);
 
-  const getActiveChildren = useCallback((filter: CascadeFilter):
-    | CascadeFilter[]
-    | null => {
-    const children = filter.cascadeChildren || [];
-    const currentValue = filter.currentValue || [];
+  const getActiveChildren = useCallback(
+    (filter: CascadeFilter): CascadeFilter[] | null => {
+      const children = filter.cascadeChildren || [];
+      const currentValue = filterState.currentState?.value;
 
-    const activeChildren = children.flatMap(
-      childFilter => getActiveChildren(childFilter) || [],
-    );
+      const activeChildren = children.flatMap(
+        childFilter => getActiveChildren(childFilter) || [],
+      );
 
-    if (activeChildren.length > 0) {
-      return activeChildren;
-    }
+      if (activeChildren.length > 0) {
+        return activeChildren;
+      }
 
-    if (currentValue.length > 0) {
-      return [filter];
-    }
+      if (currentValue) {
+        return [filter];
+      }
 
-    return null;
-  }, []);
+      return null;
+    },
+    [filterState],
+  );
 
   const getAllFilters = (filter: CascadeFilter): CascadeFilter[] => {
     const children = filter.cascadeChildren || [];
@@ -139,7 +146,7 @@ const CascadePopover: React.FC<CascadePopoverProps> = ({
       <FilterControl
         filter={filter}
         directPathToChild={directPathToChild}
-        onExtraFormDataChange={onExtraFormDataChange}
+        onFilterSelectionChange={onFilterSelectionChange}
       />
     );
   }
@@ -160,7 +167,7 @@ const CascadePopover: React.FC<CascadePopoverProps> = ({
       key={filter.id}
       filter={filter}
       directPathToChild={visible ? currentPathToChild : undefined}
-      onExtraFormDataChange={onExtraFormDataChange}
+      onFilterSelectionChange={onFilterSelectionChange}
     />
   );
 
@@ -180,7 +187,7 @@ const CascadePopover: React.FC<CascadePopoverProps> = ({
           <FilterControl
             key={activeFilter.id}
             filter={activeFilter}
-            onExtraFormDataChange={onExtraFormDataChange}
+            onFilterSelectionChange={onFilterSelectionChange}
             directPathToChild={currentPathToChild}
             icon={
               <>
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar.tsx
index 617928c..e7ad83f 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar.tsx
@@ -23,16 +23,9 @@ import {
   t,
   ExtraFormData,
 } from '@superset-ui/core';
-import React, {
-  useState,
-  useEffect,
-  useMemo,
-  useCallback,
-  useRef,
-} from 'react';
+import React, { useState, useEffect, useMemo, useRef } from 'react';
 import { useSelector } from 'react-redux';
 import cx from 'classnames';
-import { Form } from 'src/common/components';
 import Button from 'src/components/Button';
 import Icon from 'src/components/Icon';
 import { getChartDataRequest } from 'src/chart/chartAction';
@@ -40,15 +33,19 @@ import { areObjectsEqual } from 'src/reduxUtils';
 import Loading from 'src/components/Loading';
 import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
 import FilterConfigurationLink from './FilterConfigurationLink';
-// import FilterScopeModal from 'src/dashboard/components/filterscope/FilterScopeModal';
-
 import {
   useCascadingFilters,
   useFilterConfiguration,
+  useFilters,
+  useFilterState,
   useSetExtraFormData,
 } from './state';
-import { Filter, CascadeFilter } from './types';
-import { buildCascadeFiltersTree, mapParentFiltersToChildren } from './utils';
+import { Filter, CascadeFilter, CurrentFilterState } from './types';
+import {
+  buildCascadeFiltersTree,
+  getFormData,
+  mapParentFiltersToChildren,
+} from './utils';
 import CascadePopover from './CascadePopover';
 
 const barWidth = `250px`;
@@ -60,6 +57,10 @@ const BarWrapper = styled.div`
   }
 `;
 
+const FilterItem = styled.div`
+  padding-bottom: 10px;
+`;
+
 const Bar = styled.div`
   position: absolute;
   top: 0;
@@ -201,7 +202,11 @@ interface FilterProps {
   filter: Filter;
   icon?: React.ReactElement;
   directPathToChild?: string[];
-  onExtraFormDataChange: (filter: Filter, extraFormData: ExtraFormData) => void;
+  onFilterSelectionChange: (
+    filter: Filter,
+    extraFormData: ExtraFormData,
+    currentState: CurrentFilterState,
+  ) => void;
 }
 
 interface FiltersBarProps {
@@ -213,17 +218,18 @@ interface FiltersBarProps {
 const FilterValue: React.FC<FilterProps> = ({
   filter,
   directPathToChild,
-  onExtraFormDataChange,
+  onFilterSelectionChange,
 }) => {
   const {
     id,
     allowsMultipleValues,
     inverseSelection,
     targets,
-    currentValue,
     defaultValue,
+    filterType,
   } = filter;
   const cascadingFilters = useCascadingFilters(id);
+  const filterState = useFilterState(id);
   const [loading, setLoading] = useState<boolean>(true);
   const [state, setState] = useState([]);
   const [error, setError] = useState<boolean>(false);
@@ -232,29 +238,17 @@ const FilterValue: React.FC<FilterProps> = ({
   const [target] = targets;
   const { datasetId = 18, column } = target;
   const { name: groupby } = column;
-
-  const getFormData = (): Partial<QueryFormData> => ({
-    adhoc_filters: [],
-    datasource: `${datasetId}__table`,
-    extra_filters: [],
-    extra_form_data: cascadingFilters,
-    granularity_sqla: 'ds',
-    groupby: [groupby],
-    inverseSelection,
-    metrics: ['count'],
-    multiSelect: allowsMultipleValues,
-    row_limit: 10000,
-    showSearch: true,
-    time_range: 'No filter',
-    time_range_endpoints: ['inclusive', 'exclusive'],
-    url_params: {},
-    viz_type: 'filter_select',
-    defaultValues: currentValue || defaultValue || [],
-    inputRef,
-  });
-
+  const currentValue = filterState.currentState?.value;
   useEffect(() => {
-    const newFormData = getFormData();
+    const newFormData = getFormData({
+      datasetId,
+      cascadingFilters,
+      groupby,
+      allowsMultipleValues,
+      defaultValue,
+      currentValue,
+      inverseSelection,
+    });
     if (!areObjectsEqual(formData || {}, newFormData)) {
       setFormData(newFormData);
       getChartDataRequest({
@@ -272,7 +266,7 @@ const FilterValue: React.FC<FilterProps> = ({
           setLoading(false);
         });
     }
-  }, [cascadingFilters, datasetId, groupby]);
+  }, [cascadingFilters, datasetId, groupby, defaultValue, currentValue]);
 
   useEffect(() => {
     if (directPathToChild?.[0] === filter.id) {
@@ -285,8 +279,13 @@ const FilterValue: React.FC<FilterProps> = ({
     return undefined;
   }, [inputRef, directPathToChild, filter.id]);
 
-  const setExtraFormData = (extraFormData: ExtraFormData) =>
-    onExtraFormDataChange(filter, extraFormData);
+  const setExtraFormData = ({
+    extraFormData,
+    currentState,
+  }: {
+    extraFormData: ExtraFormData;
+    currentState: CurrentFilterState;
+  }) => onFilterSelectionChange(filter, extraFormData, currentState);
 
   if (loading) {
     return (
@@ -307,29 +306,24 @@ const FilterValue: React.FC<FilterProps> = ({
   }
 
   return (
-    <Form
-      onFinish={values => {
-        setExtraFormData(values.value);
-      }}
-    >
-      <Form.Item name="value">
-        <SuperChart
-          height={20}
-          width={220}
-          formData={getFormData()}
-          queriesData={state}
-          chartType="filter_select"
-          hooks={{ setExtraFormData }}
-        />
-      </Form.Item>
-    </Form>
+    <FilterItem>
+      <SuperChart
+        height={20}
+        width={220}
+        formData={formData}
+        queriesData={state}
+        chartType={filterType}
+        // @ts-ignore (update superset-ui)
+        hooks={{ setExtraFormData }}
+      />
+    </FilterItem>
   );
 };
 
 export const FilterControl: React.FC<FilterProps> = ({
   filter,
   icon,
-  onExtraFormDataChange,
+  onFilterSelectionChange,
   directPathToChild,
 }) => {
   const { name = '<undefined>' } = filter;
@@ -342,7 +336,7 @@ export const FilterControl: React.FC<FilterProps> = ({
       <FilterValue
         filter={filter}
         directPathToChild={directPathToChild}
-        onExtraFormDataChange={onExtraFormDataChange}
+        onFilterSelectionChange={onFilterSelectionChange}
       />
     </StyledFilterControlContainer>
   );
@@ -351,13 +345,17 @@ export const FilterControl: React.FC<FilterProps> = ({
 interface CascadeFilterControlProps {
   filter: CascadeFilter;
   directPathToChild?: string[];
-  onExtraFormDataChange: (filter: Filter, extraFormData: ExtraFormData) => void;
+  onFilterSelectionChange: (
+    filter: Filter,
+    extraFormData: ExtraFormData,
+    currentState: CurrentFilterState,
+  ) => void;
 }
 
 export const CascadeFilterControl: React.FC<CascadeFilterControlProps> = ({
   filter,
   directPathToChild,
-  onExtraFormDataChange,
+  onFilterSelectionChange,
 }) => (
   <>
     <StyledFilterControlBox>
@@ -365,7 +363,7 @@ export const CascadeFilterControl: React.FC<CascadeFilterControlProps> = ({
       <FilterControl
         filter={filter}
         directPathToChild={directPathToChild}
-        onExtraFormDataChange={onExtraFormDataChange}
+        onFilterSelectionChange={onFilterSelectionChange}
       />
     </StyledFilterControlBox>
 
@@ -375,7 +373,7 @@ export const CascadeFilterControl: React.FC<CascadeFilterControlProps> = ({
           <CascadeFilterControl
             filter={childFilter}
             directPathToChild={directPathToChild}
-            onExtraFormDataChange={onExtraFormDataChange}
+            onFilterSelectionChange={onFilterSelectionChange}
           />
         </li>
       ))}
@@ -388,11 +386,15 @@ const FilterBar: React.FC<FiltersBarProps> = ({
   toggleFiltersBar,
   directPathToChild,
 }) => {
-  const [filterData, setFilterData] = useState<{ [id: string]: ExtraFormData }>(
-    {},
-  );
+  const [filterData, setFilterData] = useState<{
+    [id: string]: {
+      extraFormData: ExtraFormData;
+      currentState: CurrentFilterState;
+    };
+  }>({});
   const setExtraFormData = useSetExtraFormData();
   const filterConfigs = useFilterConfiguration();
+  const filters = useFilters();
   const canEdit = useSelector<any, boolean>(
     ({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
   );
@@ -404,25 +406,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({
     }
   }, [filterConfigs]);
 
-  const getFilterValue = useCallback(
-    (filter: Filter): (string | number | boolean)[] | null => {
-      const filters = filterData[filter.id]?.append_form_data?.filters;
-      if (filters?.length) {
-        const filter = filters[0];
-        if ('val' in filter) {
-          // need to nest these if statements to get a reference to val to appease TS
-          const { val } = filter;
-          if (Array.isArray(val)) {
-            return val;
-          }
-          return [val];
-        }
-      }
-      return null;
-    },
-    [filterData],
-  );
-
   const cascadeChildren = useMemo(
     () => mapParentFiltersToChildren(filterConfigs),
     [filterConfigs],
@@ -431,24 +414,28 @@ const FilterBar: React.FC<FiltersBarProps> = ({
   const cascadeFilters = useMemo(() => {
     const filtersWithValue = filterConfigs.map(filter => ({
       ...filter,
-      currentValue: getFilterValue(filter),
+      currentValue: filterData[filter.id]?.currentState?.value,
     }));
     return buildCascadeFiltersTree(filtersWithValue);
-  }, [filterConfigs, getFilterValue]);
+  }, [filterConfigs]);
 
-  const handleExtraFormDataChange = (
+  const handleFilterSelectionChange = (
     filter: Filter,
     extraFormData: ExtraFormData,
+    currentState: CurrentFilterState,
   ) => {
     setFilterData(prevFilterData => ({
       ...prevFilterData,
-      [filter.id]: extraFormData,
+      [filter.id]: {
+        extraFormData,
+        currentState,
+      },
     }));
 
     const children = cascadeChildren[filter.id] || [];
     // force instant updating for parent filters
     if (filter.isInstant || children.length > 0) {
-      setExtraFormData(filter.id, extraFormData);
+      setExtraFormData(filter.id, extraFormData, currentState);
     }
   };
 
@@ -456,18 +443,21 @@ const FilterBar: React.FC<FiltersBarProps> = ({
     const filterIds = Object.keys(filterData);
     filterIds.forEach(filterId => {
       if (filterData[filterId]) {
-        setExtraFormData(filterId, filterData[filterId]);
+        setExtraFormData(
+          filterId,
+          filterData[filterId]?.extraFormData,
+          filterData[filterId]?.currentState,
+        );
       }
     });
   };
 
   const handleResetAll = () => {
-    setFilterData({});
-    const filterIds = Object.keys(filterData);
-    filterIds.forEach(filterId => {
-      if (filterData[filterId]) {
-        setExtraFormData(filterId, {});
-      }
+    filterConfigs.forEach(filter => {
+      setExtraFormData(filter.id, filterData[filter.id]?.extraFormData, {
+        ...filterData[filter.id]?.currentState,
+        value: filters[filter.id]?.defaultValue,
+      });
     });
   };
 
@@ -521,7 +511,7 @@ const FilterBar: React.FC<FiltersBarProps> = ({
                 setVisiblePopoverId(visible ? filter.id : null)
               }
               filter={filter}
-              onExtraFormDataChange={handleExtraFormDataChange}
+              onFilterSelectionChange={handleFilterSelectionChange}
               directPathToChild={directPathToChild}
             />
           ))}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigForm.tsx
index 9489209..82269d0 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigForm.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigForm.tsx
@@ -16,9 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { styled, t } from '@superset-ui/core';
+import { styled, SuperChart, t } from '@superset-ui/core';
 import { FormInstance } from 'antd/lib/form';
-import React, { useCallback, useState } from 'react';
+import React, { useCallback } from 'react';
 import {
   Button,
   Checkbox,
@@ -27,14 +27,19 @@ import {
   Typography,
 } from 'src/common/components';
 import { Select } from 'src/components/Select/SupersetStyledSelect';
-import SupersetResourceSelect, {
-  Value,
-} from 'src/components/SupersetResourceSelect';
+import SupersetResourceSelect from 'src/components/SupersetResourceSelect';
 import { addDangerToast } from 'src/messageToasts/actions';
 import { ClientErrorObject } from 'src/utils/getClientErrorObject';
 import { ColumnSelect } from './ColumnSelect';
-import { Filter, NativeFiltersForm } from './types';
+import { Filter, FilterType, NativeFiltersForm } from './types';
 import FilterScope from './FilterScope';
+import {
+  FilterTypeNames,
+  getFormData,
+  setFilterFieldValues,
+  useForceUpdate,
+} from './utils';
+import { useBackendFormUpdate } from './state';
 
 type DatasetSelectValue = {
   value: number;
@@ -77,6 +82,10 @@ const StyledLabel = styled.span`
   text-transform: uppercase;
 `;
 
+const CleanFormItem = styled(Form.Item)`
+  margin-bottom: 0;
+`;
+
 export interface FilterConfigFormProps {
   filterId: string;
   filterToEdit?: Filter;
@@ -98,11 +107,19 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
   form,
   parentFilters,
 }) => {
-  const [dataset, setDataset] = useState<Value<number> | undefined>(
-    filterToEdit?.targets[0].datasetId
-      ? { label: '', value: filterToEdit?.targets[0].datasetId }
-      : undefined,
-  );
+  const forceUpdate = useForceUpdate();
+  const formFilter = (form.getFieldValue('filters') || {})[filterId];
+  useBackendFormUpdate(form, filterId, filterToEdit);
+
+  const initDatasetId = filterToEdit?.targets[0].datasetId;
+  const initColumn = filterToEdit?.targets[0]?.column?.name;
+  const newFormData = getFormData({
+    datasetId: formFilter?.dataset?.value,
+    groupby: formFilter?.column,
+    allowsMultipleValues: formFilter?.allowsMultipleValues,
+    defaultValue: formFilter?.defaultValue,
+    inverseSelection: formFilter?.inverseSelection,
+  });
 
   const onDatasetSelectError = useCallback(
     ({ error, message }: ClientErrorObject) => {
@@ -146,21 +163,30 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
         >
           <Input />
         </StyledFormItem>
-
         <StyledFormItem
           name={['filters', filterId, 'dataset']}
+          initialValue={{ value: initDatasetId }}
           label={<StyledLabel>{t('Datasource')}</StyledLabel>}
           rules={[{ required: !removed, message: t('Datasource is required') }]}
           data-test="datasource-input"
         >
           <SupersetResourceSelect
-            initialId={filterToEdit?.targets[0].datasetId}
+            initialId={initDatasetId}
             resource="dataset"
             searchColumn="table_name"
             transformItem={datasetToSelectOption}
             isMulti={false}
-            onChange={setDataset}
             onError={onDatasetSelectError}
+            onChange={e => {
+              // We need reset column when dataset changed
+              const datasetId = formFilter?.dataset?.value;
+              if (datasetId && e?.value !== datasetId) {
+                setFilterFieldValues(form, filterId, {
+                  column: null,
+                });
+              }
+              forceUpdate();
+            }}
           />
         </StyledFormItem>
       </StyledContainer>
@@ -168,7 +194,7 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
         // don't show the column select unless we have a dataset
         // style={{ display: datasetId == null ? undefined : 'none' }}
         name={['filters', filterId, 'column']}
-        initialValue={filterToEdit?.targets[0]?.column?.name}
+        initialValue={initColumn}
         label={<StyledLabel>{t('Field')}</StyledLabel>}
         rules={[{ required: !removed, message: t('Field is required') }]}
         data-test="field-input"
@@ -176,10 +202,69 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
         <ColumnSelect
           form={form}
           filterId={filterId}
-          datasetId={dataset?.value}
+          datasetId={formFilter?.dataset?.value}
+          onChange={forceUpdate}
         />
       </StyledFormItem>
       <StyledFormItem
+        name={['filters', filterId, 'filterType']}
+        rules={[{ required: !removed, message: t('Name is required') }]}
+        initialValue={filterToEdit?.filterType || FilterType.filter_select}
+        label={<StyledLabel>{t('Filter Type')}</StyledLabel>}
+      >
+        <Select
+          options={Object.values(FilterType).map(filterType => ({
+            value: filterType,
+            label: FilterTypeNames[filterType],
+          }))}
+          onChange={({ value }: { value: FilterType }) => {
+            setFilterFieldValues(form, filterId, {
+              filterType: value,
+              defaultValue: null,
+            });
+            forceUpdate();
+          }}
+        />
+      </StyledFormItem>
+      {formFilter?.dataset && formFilter?.column && (
+        <CleanFormItem
+          name={['filters', filterId, 'defaultValueFormData']}
+          hidden
+          initialValue={newFormData}
+        />
+      )}
+      <CleanFormItem
+        name={['filters', filterId, 'defaultValueQueriesData']}
+        hidden
+        initialValue={null}
+      />
+      <StyledFormItem
+        name={['filters', filterId, 'defaultValue']}
+        initialValue={filterToEdit?.defaultValue}
+        label={<StyledLabel>{t('Default Value')}</StyledLabel>}
+      >
+        {formFilter?.dataset &&
+          formFilter?.column &&
+          formFilter?.defaultValueQueriesData && (
+            <SuperChart
+              height={20}
+              width={220}
+              formData={newFormData}
+              queriesData={formFilter?.defaultValueQueriesData}
+              chartType={formFilter?.filterType}
+              hooks={{
+                // @ts-ignore
+                setExtraFormData: ({ currentState }) => {
+                  setFilterFieldValues(form, filterId, {
+                    defaultValue: currentState?.value,
+                  });
+                  forceUpdate();
+                },
+              }}
+            />
+          )}
+      </StyledFormItem>
+      <StyledFormItem
         name={['filters', filterId, 'parentFilter']}
         label={<StyledLabel>{t('Parent filter')}</StyledLabel>}
         initialValue={parentFilterOptions.find(
@@ -192,7 +277,6 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
           isClearable
         />
       </StyledFormItem>
-
       <StyledCheckboxFormItem
         name={['filters', filterId, 'isInstant']}
         initialValue={filterToEdit?.isInstant}
@@ -207,7 +291,16 @@ export const FilterConfigForm: React.FC<FilterConfigFormProps> = ({
         valuePropName="checked"
         colon={false}
       >
-        <Checkbox>{t('Allow multiple selections')}</Checkbox>
+        <Checkbox
+          onChange={() => {
+            setFilterFieldValues(form, filterId, {
+              defaultValue: null,
+            });
+            forceUpdate();
+          }}
+        >
+          {t('Allow multiple selections')}
+        </Checkbox>
       </StyledCheckboxFormItem>
       <StyledCheckboxFormItem
         name={['filters', filterId, 'inverseSelection']}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal.tsx
index 7980d79..0017bae 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterConfigModal.tsx
@@ -402,7 +402,7 @@ export function FilterConfigModal({
         return {
           id,
           name: formInputs.name,
-          type: 'text',
+          filterType: formInputs.filterType,
           // for now there will only ever be one target
           targets: [
             {
@@ -497,6 +497,7 @@ export function FilterConfigModal({
       visible={isOpen}
       title={t('Filter configuration and scoping')}
       width="55%"
+      destroyOnClose
       onCancel={handleCancel}
       onOk={onOk}
       centered
@@ -506,6 +507,7 @@ export function FilterConfigModal({
       <ErrorBoundary>
         <StyledModalBody>
           <StyledForm
+            preserve={false}
             form={form}
             onValuesChange={(changes, values: NativeFiltersForm) => {
               if (
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/state.ts
index 282c75b..16ffa62 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/state.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/state.ts
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { useCallback, useMemo } from 'react';
+import { useCallback, useEffect, useMemo } from 'react';
 import { useDispatch, useSelector } from 'react-redux';
 import { setExtraFormData } from 'src/dashboard/actions/nativeFilters';
 import { getInitialFilterState } from 'src/dashboard/reducers/nativeFilters';
@@ -27,14 +27,24 @@ import {
   CHART_TYPE,
   DASHBOARD_ROOT_TYPE,
 } from 'src/dashboard/util/componentTypes';
+import { FormInstance } from 'antd/lib/form';
+import { getChartDataRequest } from 'src/chart/chartAction';
 import {
+  CurrentFilterState,
   Filter,
   FilterConfiguration,
   FilterState,
+  NativeFiltersForm,
   NativeFiltersState,
   TreeItem,
 } from './types';
-import { buildTree, mergeExtraFormData } from './utils';
+import {
+  buildTree,
+  getFormData,
+  mergeExtraFormData,
+  setFilterFieldValues,
+  useForceUpdate,
+} from './utils';
 
 const defaultFilterConfiguration: Filter[] = [];
 
@@ -68,11 +78,24 @@ export function useFilterState(id: string) {
   );
 }
 
+export function useFiltersState() {
+  return useSelector<any, FilterState>(
+    state => state.nativeFilters.filtersState,
+  );
+}
+
+export function useFilters() {
+  return useSelector<any, FilterState>(state => state.nativeFilters.filters);
+}
+
 export function useSetExtraFormData() {
   const dispatch = useDispatch();
   return useCallback(
-    (id: string, extraFormData: ExtraFormData) =>
-      dispatch(setExtraFormData(id, extraFormData)),
+    (
+      id: string,
+      extraFormData: ExtraFormData,
+      currentState: CurrentFilterState,
+    ) => dispatch(setExtraFormData(id, extraFormData, currentState)),
     [dispatch],
   );
 }
@@ -113,17 +136,70 @@ export function useFilterScopeTree(): {
 }
 
 export function useCascadingFilters(id: string) {
-  return useSelector<any, ExtraFormData>(state => {
-    const { nativeFilters }: { nativeFilters: NativeFiltersState } = state;
-    const { filters, filtersState } = nativeFilters;
-    const filter = filters[id];
-    const cascadeParentIds = filter?.cascadeParentIds ?? [];
-    let cascadedFilters = {};
-    cascadeParentIds.forEach(parentId => {
-      const parentState = filtersState[parentId] || {};
-      const { extraFormData: parentExtra = {} } = parentState;
-      cascadedFilters = mergeExtraFormData(cascadedFilters, parentExtra);
-    });
-    return cascadedFilters;
+  const nativeFilters = useSelector<any, NativeFiltersState>(
+    state => state.nativeFilters,
+  );
+  const { filters, filtersState } = nativeFilters;
+  const filter = filters[id];
+  const cascadeParentIds = filter?.cascadeParentIds ?? [];
+  let cascadedFilters = {};
+  cascadeParentIds.forEach(parentId => {
+    const parentState = filtersState[parentId] || {};
+    const { extraFormData: parentExtra = {} } = parentState;
+    cascadedFilters = mergeExtraFormData(cascadedFilters, parentExtra);
   });
+  return cascadedFilters;
 }
+
+// When some fields in form changed we need re-fetch data for Filter defaultValue
+export const useBackendFormUpdate = (
+  form: FormInstance<NativeFiltersForm>,
+  filterId: string,
+  filterToEdit?: Filter,
+) => {
+  const forceUpdate = useForceUpdate();
+  const formFilter = (form.getFieldValue('filters') || {})[filterId];
+  useEffect(() => {
+    let resolvedDefaultValue: any = null;
+    // No need to check data set change because it cascading update column
+    // So check that column exists is enough
+    if (!formFilter?.column) {
+      setFilterFieldValues(form, filterId, {
+        defaultValueQueriesData: [],
+        defaultValue: resolvedDefaultValue,
+      });
+      return;
+    }
+    const formData = getFormData({
+      datasetId: formFilter?.dataset?.value,
+      groupby: formFilter?.column,
+      allowsMultipleValues: formFilter?.allowsMultipleValues,
+      defaultValue: formFilter?.defaultValue,
+      inverseSelection: formFilter?.inverseSelection,
+    });
+    getChartDataRequest({
+      formData,
+      force: false,
+      requestParams: { dashboardId: 0 },
+    }).then(response => {
+      if (
+        filterToEdit?.filterType === formFilter?.filterType &&
+        filterToEdit?.targets[0].datasetId === formFilter?.dataset?.value &&
+        formFilter?.column === filterToEdit?.targets[0]?.column?.name &&
+        filterToEdit?.allowsMultipleValues === formFilter?.allowsMultipleValues
+      ) {
+        resolvedDefaultValue = filterToEdit?.defaultValue;
+      }
+      setFilterFieldValues(form, filterId, {
+        defaultValueQueriesData: response.result,
+        defaultValue: resolvedDefaultValue,
+      });
+      forceUpdate();
+    });
+  }, [
+    formFilter?.filterType,
+    formFilter?.column,
+    formFilter?.dataset?.value,
+    filterId,
+  ]);
+};
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/types.ts
index 311c308..ac90309 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/types.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/types.ts
@@ -16,7 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { ExtraFormData, QueryObjectFilterClause } from '@superset-ui/core';
+import {
+  ExtraFormData,
+  JsonObject,
+  QueryObjectFilterClause,
+} from '@superset-ui/core';
 
 export enum Scoping {
   all,
@@ -29,12 +33,13 @@ export type AntCallback = (value1?: any, value2?: any) => void;
 interface NativeFiltersFormItem {
   scope: Scope;
   name: string;
+  filterType: FilterType;
   dataset: {
     value: number;
     label: string;
   };
   column: string;
-  defaultValue: string;
+  defaultValue: any;
   parentFilter: {
     value: string;
     label: string;
@@ -69,7 +74,10 @@ export interface Target {
   // clarityColumns?: Column[];
 }
 
-export type FilterType = 'text' | 'date';
+export enum FilterType {
+  filter_select = 'filter_select',
+  filter_range = 'filter_range',
+}
 
 /**
  * This is a filter configuration object, stored in the dashboard's json metadata.
@@ -78,15 +86,15 @@ export type FilterType = 'text' | 'date';
 export interface Filter {
   allowsMultipleValues: boolean;
   cascadeParentIds: string[];
-  defaultValue: string | null;
-  currentValue?: (string | number | boolean)[] | null;
+  defaultValue: any;
+  currentValue?: any;
   inverseSelection: boolean;
   isInstant: boolean;
   isRequired: boolean;
   id: string; // randomly generated at filter creation
   name: string;
   scope: Scope;
-  type: FilterType;
+  filterType: FilterType;
   // for now there will only ever be one target
   // when multiple targets are supported, change this to Target[]
   targets: [Target];
@@ -99,11 +107,15 @@ export interface CascadeFilter extends Filter {
 export type FilterConfiguration = Filter[];
 
 export type SelectedValues = string[] | null;
+export type CurrentFilterState = JsonObject & {
+  value: any;
+};
 
 /** Current state of the filter, stored in `nativeFilters` in redux */
 export type FilterState = {
   id: string; // ties this filter state to the config object
   extraFormData?: ExtraFormData;
+  currentState?: CurrentFilterState;
 };
 
 export type AllFilterState = {
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
index 7f89aee..3257ef0 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
@@ -16,7 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { ExtraFormData, QueryObject } from '@superset-ui/core';
+import {
+  ExtraFormData,
+  QueryFormData,
+  QueryObject,
+  t,
+} from '@superset-ui/core';
 import { Charts, Layout, LayoutItem } from 'src/dashboard/types';
 import {
   CHART_TYPE,
@@ -24,10 +29,11 @@ import {
   TAB_TYPE,
 } from 'src/dashboard/util/componentTypes';
 import { FormInstance } from 'antd/lib/form';
-import React from 'react';
+import React, { RefObject } from 'react';
 import {
   CascadeFilter,
   Filter,
+  FilterType,
   NativeFiltersState,
   Scope,
   TreeItem,
@@ -238,6 +244,11 @@ export function buildCascadeFiltersTree(filters: Filter[]): CascadeFilter[] {
     .map(getCascadeFilter);
 }
 
+export const FilterTypeNames = {
+  [FilterType.filter_select]: t('Select'),
+  [FilterType.filter_range]: t('Range'),
+};
+
 export const setFilterFieldValues = (
   form: FormInstance,
   filterId: string,
@@ -257,3 +268,54 @@ export const setFilterFieldValues = (
 
 export const isScopingAll = (scope: Scope) =>
   !scope || (scope.rootPath[0] === DASHBOARD_ROOT_ID && !scope.excluded.length);
+
+export const getFormData = ({
+  datasetId = 18,
+  cascadingFilters = {},
+  groupby,
+  allowsMultipleValues = false,
+  defaultValue,
+  currentValue,
+  inverseSelection,
+  inputRef,
+}: Partial<Filter> & {
+  datasetId?: number;
+  inputRef?: RefObject<HTMLInputElement>;
+  cascadingFilters?: object;
+  groupby: string;
+}): Partial<QueryFormData> => ({
+  adhoc_filters: [],
+  datasource: `${datasetId}__table`,
+  extra_filters: [],
+  extra_form_data: cascadingFilters,
+  granularity_sqla: 'ds',
+  groupby: [groupby],
+  inverseSelection,
+  metrics: ['count'],
+  multiSelect: allowsMultipleValues,
+  row_limit: 10000,
+  showSearch: true,
+  currentValue,
+  time_range: 'No filter',
+  time_range_endpoints: ['inclusive', 'exclusive'],
+  url_params: {},
+  viz_type: 'filter_select',
+  // TODO: need process per filter type after will be decided approach
+  defaultValue,
+  inputRef,
+});
+
+type AppendFormData = {
+  filters: {
+    val?: number | string | null;
+  }[];
+};
+
+export const extractDefaultValue = {
+  [FilterType.filter_select]: (appendFormData: AppendFormData) =>
+    appendFormData.filters?.[0]?.val,
+  [FilterType.filter_range]: (appendFormData: AppendFormData) => ({
+    min: appendFormData.filters?.[0].val,
+    max: appendFormData.filters?.[1].val,
+  }),
+};
diff --git a/superset-frontend/src/dashboard/reducers/nativeFilters.ts b/superset-frontend/src/dashboard/reducers/nativeFilters.ts
index b69ccd5..56e34b9 100644
--- a/superset-frontend/src/dashboard/reducers/nativeFilters.ts
+++ b/superset-frontend/src/dashboard/reducers/nativeFilters.ts
@@ -63,6 +63,7 @@ export default function nativeFilterReducer(
           [action.filterId]: {
             ...filtersState[action.filterId],
             extraFormData: action.extraFormData,
+            currentState: action.currentState,
           },
         },
       };
diff --git a/superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx b/superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx
index b97312c..d9f89c9 100644
--- a/superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx
+++ b/superset-frontend/src/filters/components/Select/AntdSelectFilter.tsx
@@ -33,13 +33,13 @@ const { Option } = Select;
 export default function AntdPluginFilterSelect(
   props: AntdPluginFilterSelectProps,
 ) {
-  const [values, setValues] = useState<(string | number)[]>([]);
   const { data, formData, height, width, setExtraFormData } = props;
   const {
-    defaultValues,
+    defaultValue,
     enableEmptyFilter,
     multiSelect,
     showSearch,
+    currentValue,
     inverseSelection,
     inputRef,
   } = {
@@ -47,24 +47,50 @@ export default function AntdPluginFilterSelect(
     ...formData,
   };
 
-  useEffect(() => {
-    setValues(defaultValues || []);
-  }, [defaultValues]);
+  const [values, setValues] = useState<(string | number)[]>(defaultValue ?? []);
 
   let { groupby = [] } = formData;
   groupby = Array.isArray(groupby) ? groupby : [groupby];
 
-  function handleChange(value?: number[] | string[] | null) {
-    setValues(value || []);
+  const handleChange = (
+    value?: (number | string)[] | number | string | null,
+  ) => {
+    let resultValue: (number | string)[];
+    // Works only with arrays even for single select
+    if (!Array.isArray(value)) {
+      resultValue = value ? [value] : [];
+    } else {
+      resultValue = value;
+    }
+    setValues(resultValue);
     const [col] = groupby;
     const emptyFilter =
-      enableEmptyFilter &&
-      !inverseSelection &&
-      (value === undefined || value === null || value.length === 0);
-    setExtraFormData(
-      getSelectExtraFormData(col, value, emptyFilter, inverseSelection),
-    );
-  }
+      enableEmptyFilter && !inverseSelection && resultValue?.length === 0;
+    setExtraFormData({
+      // @ts-ignore
+      extraFormData: getSelectExtraFormData(
+        col,
+        resultValue,
+        emptyFilter,
+        inverseSelection,
+      ),
+      // @ts-ignore (add to superset-ui/core)
+      currentState: {
+        value: resultValue,
+      },
+    });
+  };
+
+  useEffect(() => {
+    handleChange(currentValue ?? []);
+  }, [JSON.stringify(currentValue)]);
+
+  useEffect(() => {
+    handleChange(defaultValue ?? []);
+    // I think after Config Modal update some filter it re-creates default value for all other filters
+    // so we can process it like this `JSON.stringify` or start to use `Immer`
+  }, [JSON.stringify(defaultValue)]);
+
   const placeholderText =
     (data || []).length === 0
       ? 'No data'
diff --git a/superset-frontend/src/filters/components/Select/types.ts b/superset-frontend/src/filters/components/Select/types.ts
index d8f554b..5720978 100644
--- a/superset-frontend/src/filters/components/Select/types.ts
+++ b/superset-frontend/src/filters/components/Select/types.ts
@@ -25,7 +25,8 @@ import { RefObject } from 'react';
 import { AntdPluginFilterStylesProps } from '../types';
 
 interface AntdPluginFilterSelectCustomizeProps {
-  defaultValues?: (string | number)[];
+  defaultValue?: (string | number)[] | null;
+  currentValue?: (string | number)[] | null;
   enableEmptyFilter: boolean;
   fetchPredicate?: string;
   inverseSelection: boolean;
@@ -45,7 +46,8 @@ export type AntdPluginFilterSelectProps = AntdPluginFilterStylesProps & {
 };
 
 export const DEFAULT_FORM_DATA: AntdPluginFilterSelectCustomizeProps = {
-  defaultValues: [],
+  defaultValue: null,
+  currentValue: null,
   enableEmptyFilter: false,
   fetchPredicate: '',
   inverseSelection: false,
diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts
index 1a5d11c..364cd9c 100644
--- a/superset-frontend/src/filters/utils.ts
+++ b/superset-frontend/src/filters/utils.ts
@@ -20,7 +20,7 @@ import { QueryObjectFilterClause } from '@superset-ui/core';
 
 export const getSelectExtraFormData = (
   col: string,
-  value?: undefined | null | string[] | number[],
+  value?: null | (string | number)[],
   emptyFilter = false,
   inverseSelection = false,
 ) => ({