feat(native-filters): add refresh button to default value picker (#14375)

* feat(native-filters): add refresh button to default value picker

* skip flaky test
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index 776e1e9..d1cabf9b 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -17,13 +17,14 @@
  * under the License.
  */
 import {
-  styled,
-  t,
-  getChartMetadataRegistry,
-  Behavior,
   AdhocFilter,
+  Behavior,
+  ChartDataResponseResult,
+  getChartMetadataRegistry,
   JsonResponse,
+  styled,
   SupersetApiError,
+  t,
 } from '@superset-ui/core';
 import { ColumnMeta, DatasourceMeta } from '@superset-ui/chart-controls';
 import { FormInstance } from 'antd/lib/form';
@@ -38,6 +39,10 @@
 import DateFilterControl from 'src/explore/components/controls/DateFilterControl';
 import { addDangerToast } from 'src/messageToasts/actions';
 import { ClientErrorObject } from 'src/utils/getClientErrorObject';
+import Button from 'src/components/Button';
+import { getChartDataRequest } from 'src/chart/chartAction';
+import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
+import { waitForAsyncData } from 'src/middleware/asyncEvent';
 import { ColumnSelect } from './ColumnSelect';
 import { NativeFiltersForm } from '../types';
 import {
@@ -111,8 +116,22 @@
   parentFilters,
 }) => {
   const forceUpdate = useForceUpdate();
-  const formFilter = (form.getFieldValue('filters') || {})[filterId];
   const [datasetDetails, setDatasetDetails] = useState<Record<string, any>>();
+
+  // make sure the formFilter is populated
+  if (!form.getFieldValue('filters')) {
+    setNativeFilterFieldValues(form, filterId, filterToEdit || {});
+    forceUpdate();
+  }
+  const formFilter = form.getFieldValue('filters')[filterId];
+
+  useEffect(() => {
+    setNativeFilterFieldValues(form, filterId, {
+      defaultValue: filterToEdit?.defaultValue,
+    });
+    forceUpdate();
+  }, [form, forceUpdate, filterId, filterToEdit?.defaultValue]);
+
   const nativeFilterItems = getChartMetadataRegistry().items;
   const nativeFilterVizTypes = Object.entries(nativeFilterItems)
     // @ts-ignore
@@ -158,7 +177,56 @@
     formFilter?.filterType,
   );
 
-  useBackendFormUpdate(form, filterId, filterToEdit, hasDataset, hasColumn);
+  const isDataDirty = formFilter?.isDataDirty ?? true;
+
+  useBackendFormUpdate(form, filterId);
+
+  const refreshHandler = () => {
+    if (!hasDataset || !formFilter?.dataset?.value) {
+      forceUpdate();
+      return;
+    }
+    const formData = getFormData({
+      datasetId: formFilter?.dataset?.value,
+      groupby: formFilter?.column,
+      defaultValue: formFilter?.defaultValue,
+      ...formFilter,
+    });
+    setNativeFilterFieldValues(form, filterId, {
+      defaultValueQueriesData: null,
+      isDataDirty: false,
+    });
+    forceUpdate();
+    getChartDataRequest({
+      formData,
+      force: false,
+      requestParams: { dashboardId: 0 },
+    }).then(response => {
+      if (isFeatureEnabled(FeatureFlag.GLOBAL_ASYNC_QUERIES)) {
+        // deal with getChartDataRequest transforming the response data
+        const result = 'result' in response ? response.result[0] : response;
+        waitForAsyncData(result)
+          .then((asyncResult: ChartDataResponseResult[]) => {
+            setNativeFilterFieldValues(form, filterId, {
+              defaultValueQueriesData: asyncResult,
+            });
+            forceUpdate();
+          })
+          .catch((error: ClientErrorObject) => {
+            // TODO: show error once this logic is moved into new NativeFilter
+            //  component
+            console.error(
+              error.message || error.error || t('Check configuration'),
+            );
+          });
+      } else {
+        setNativeFilterFieldValues(form, filterId, {
+          defaultValueQueriesData: response.result,
+        });
+        forceUpdate();
+      }
+    });
+  };
 
   const defaultDatasetSelectOptions = Object.values(loadedDatasets).map(
     datasetToSelectOption,
@@ -254,6 +322,7 @@
                 // We need reset column when dataset changed
                 if (datasetId && e?.value !== datasetId) {
                   setNativeFilterFieldValues(form, filterId, {
+                    defaultValue: null,
                     column: null,
                   });
                 }
@@ -275,7 +344,13 @@
                 form={form}
                 filterId={filterId}
                 datasetId={datasetId}
-                onChange={forceUpdate}
+                onChange={e => {
+                  // We need reset default value when when column changed
+                  setNativeFilterFieldValues(form, filterId, {
+                    defaultValue: null,
+                  });
+                  forceUpdate();
+                }}
               />
             </StyledFormItem>
           )}
@@ -347,27 +422,36 @@
           isClearable
         />
       </StyledFormItem>
-      <StyledFormItem
-        name={['filters', filterId, 'defaultValue']}
-        initialValue={filterToEdit?.defaultValue}
-        data-test="default-input"
-        label={<StyledLabel>{t('Default Value')}</StyledLabel>}
-      >
-        {(hasFilledDataset || !hasDataset) && (
-          <DefaultValue
-            setDataMask={({ filterState }) => {
-              setNativeFilterFieldValues(form, filterId, {
-                defaultValue: filterState?.value,
-              });
-              forceUpdate();
-            }}
-            filterId={filterId}
-            hasDataset={hasDataset}
-            form={form}
-            formData={newFormData}
-          />
-        )}
-      </StyledFormItem>
+      <StyledContainer>
+        <StyledFormItem className="bottom" label={<StyledLabel />}>
+          {hasDataset && hasFilledDataset && (
+            <Button onClick={refreshHandler}>
+              {isDataDirty ? t('Populate') : t('Refresh')}
+            </Button>
+          )}
+        </StyledFormItem>
+        <StyledFormItem
+          name={['filters', filterId, 'defaultValue']}
+          initialValue={filterToEdit?.defaultValue}
+          data-test="default-input"
+          label={<StyledLabel>{t('Default Value')}</StyledLabel>}
+        >
+          {!isDataDirty && (hasFilledDataset || !hasDataset) && (
+            <DefaultValue
+              setDataMask={({ filterState }) => {
+                setNativeFilterFieldValues(form, filterId, {
+                  defaultValue: filterState?.value,
+                });
+                forceUpdate();
+              }}
+              filterId={filterId}
+              hasDataset={hasDataset}
+              form={form}
+              formData={newFormData}
+            />
+          )}
+        </StyledFormItem>
+      </StyledContainer>
       <StyledCheckboxFormItem
         name={['filters', filterId, 'isInstant']}
         initialValue={filterToEdit?.isInstant || false}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
index c48076f..2ade134 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
@@ -18,102 +18,38 @@
  */
 import { useEffect } from 'react';
 import { FormInstance } from 'antd/lib/form';
-import { getChartDataRequest } from 'src/chart/chartAction';
-import { ChartDataResponseResult, t } from '@superset-ui/core';
-import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
-import { waitForAsyncData } from 'src/middleware/asyncEvent';
-import { ClientErrorObject } from 'src/utils/getClientErrorObject';
 import { NativeFiltersForm } from '../types';
 import { setNativeFilterFieldValues, useForceUpdate } from './utils';
-import { Filter } from '../../types';
-import { getFormData } from '../../utils';
 
 // When some fields in form changed we need re-fetch data for Filter defaultValue
 // eslint-disable-next-line import/prefer-default-export
 export const useBackendFormUpdate = (
   form: FormInstance<NativeFiltersForm>,
   filterId: string,
-  filterToEdit?: Filter,
-  hasDatasource?: boolean,
-  hasColumn?: boolean,
 ) => {
   const forceUpdate = useForceUpdate();
   const formFilter = (form.getFieldValue('filters') || {})[filterId];
   useEffect(() => {
-    let resolvedDefaultValue: any = null;
-    if (!hasDatasource) {
-      forceUpdate();
-      return;
-    }
-    // No need to check data set change because it cascading update column
-    // So check that column exists is enough
-    if (hasColumn && !formFilter?.column) {
-      setNativeFilterFieldValues(form, filterId, {
-        defaultValueQueriesData: [],
-        defaultValue: resolvedDefaultValue,
-      });
-      return;
-    }
-    if (!formFilter?.dataset?.value) {
-      // no need to make chart data request if no dataset is defined
-      return;
-    }
-    const formData = getFormData({
-      datasetId: formFilter?.dataset?.value,
-      groupby: formFilter?.column,
-      defaultValue: formFilter?.defaultValue,
-      ...formFilter,
-    });
     setNativeFilterFieldValues(form, filterId, {
+      isDataDirty: true,
       defaultValueQueriesData: null,
-      defaultValue: resolvedDefaultValue,
     });
     forceUpdate();
-    getChartDataRequest({
-      formData,
-      force: false,
-      requestParams: { dashboardId: 0 },
-    }).then(response => {
-      if (
-        filterToEdit?.filterType === formFilter?.filterType &&
-        filterToEdit?.targets[0].datasetId === formFilter?.dataset?.value &&
-        (!hasColumn ||
-          formFilter?.column === filterToEdit?.targets[0].column?.name)
-      ) {
-        resolvedDefaultValue = filterToEdit?.defaultValue;
-      }
-      if (isFeatureEnabled(FeatureFlag.GLOBAL_ASYNC_QUERIES)) {
-        // deal with getChartDataRequest transforming the response data
-        const result = 'result' in response ? response.result[0] : response;
-        waitForAsyncData(result)
-          .then((asyncResult: ChartDataResponseResult[]) => {
-            setNativeFilterFieldValues(form, filterId, {
-              defaultValueQueriesData: asyncResult,
-              defaultValue: resolvedDefaultValue,
-            });
-            forceUpdate();
-          })
-          .catch((error: ClientErrorObject) => {
-            // TODO: show error once this logic is moved into new NativeFilter
-            //  component
-            console.error(
-              error.message || error.error || t('Check configuration'),
-            );
-          });
-      } else {
-        setNativeFilterFieldValues(form, filterId, {
-          defaultValueQueriesData: response.result,
-          defaultValue: resolvedDefaultValue,
-        });
-        forceUpdate();
-      }
-    });
   }, [
+    form,
     formFilter?.filterType,
     formFilter?.column,
     formFilter?.dataset?.value,
     JSON.stringify(formFilter?.adhoc_filters),
     formFilter?.time_range,
+    forceUpdate,
     filterId,
   ]);
+
+  useEffect(() => {
+    setNativeFilterFieldValues(form, filterId, {
+      defaultValue: formFilter?.defaultValue,
+    });
+    forceUpdate();
+  }, [form, formFilter?.defaultValue, forceUpdate, filterId]);
 };
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
index 015a2f1..61ef409 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
@@ -31,7 +31,7 @@
   filterId: string,
   values: object,
 ) => {
-  const formFilters = form.getFieldValue('filters');
+  const formFilters = form.getFieldValue('filters') || {};
   form.setFieldsValue({
     filters: {
       ...formFilters,