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/05/20 16:52:38 UTC

[superset] branch master updated: chore: Improves the native filters UI/UX - iteration 1 (#14714)

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 d924223  chore: Improves the native filters UI/UX - iteration 1 (#14714)
d924223 is described below

commit d92422395013d7741a2052a8e93cb743f2dcafa5
Author: Michael S. Molina <70...@users.noreply.github.com>
AuthorDate: Thu May 20 13:52:01 2021 -0300

    chore: Improves the native filters UI/UX - iteration 1 (#14714)
---
 .../FilterScope/FilterScope.test.tsx               |  69 +--
 .../FiltersConfigForm/FilterScope/FilterScope.tsx  |   1 -
 .../FiltersConfigForm/FiltersConfigForm.tsx        | 477 +++++++++++----------
 .../FiltersConfigModal/FiltersConfigModal.tsx      |   1 +
 .../Footer/CancelConfirmationAlert.tsx             |  17 +-
 5 files changed, 306 insertions(+), 259 deletions(-)

diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
index ab19250..e9c35d1 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.test.tsx
@@ -18,7 +18,12 @@
  */
 import React from 'react';
 import { Provider } from 'react-redux';
-import { render, screen, fireEvent } from 'spec/helpers/testing-library';
+import {
+  render,
+  screen,
+  fireEvent,
+  waitFor,
+} from 'spec/helpers/testing-library';
 import { mockStoreWithChartsInTabsAndRoot } from 'spec/fixtures/mockStore';
 import { Form, FormInstance } from 'src/common/components';
 import { NativeFiltersForm } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/types';
@@ -34,7 +39,7 @@ describe('FilterScope', () => {
     save,
   };
 
-  const MockModal = ({ scope }: { scope: object | undefined }) => {
+  const MockModal = ({ scope }: { scope?: object }) => {
     const [newForm] = Form.useForm<NativeFiltersForm>();
     form = newForm;
     if (scope) {
@@ -55,56 +60,66 @@ describe('FilterScope', () => {
     );
   };
 
-  const getWrapper = (scope?: object) => {
-    render(<MockModal scope={scope} />);
-  };
-
   const getTreeSwitcher = (order = 0) =>
     document.querySelectorAll('.ant-tree-switcher')[order];
 
   it('renders "apply to all" filter scope', () => {
-    getWrapper();
-    expect(screen.queryByRole('tree')).toBe(null);
+    render(<MockModal />);
+    expect(screen.queryByRole('tree')).not.toBeInTheDocument();
   });
 
-  it('select tree values with 1 excluded', () => {
-    getWrapper();
+  it('select tree values with 1 excluded', async () => {
+    render(<MockModal />);
+    fireEvent.click(screen.getByText('Scoping'));
     fireEvent.click(screen.getByLabelText('Apply to specific panels'));
     expect(screen.getByRole('tree')).not.toBe(null);
     fireEvent.click(getTreeSwitcher(2));
     fireEvent.click(screen.getByText('CHART_ID2'));
-    expect(form.getFieldValue('filters')?.[mockedProps.filterId].scope).toEqual(
-      {
+    await waitFor(() =>
+      expect(
+        form.getFieldValue('filters')?.[mockedProps.filterId].scope,
+      ).toEqual({
         excluded: [20],
         rootPath: ['ROOT_ID'],
-      },
+      }),
     );
   });
 
-  it('select 1 value only', () => {
-    getWrapper();
+  it('select 1 value only', async () => {
+    render(<MockModal />);
+    fireEvent.click(screen.getByText('Scoping'));
     fireEvent.click(screen.getByLabelText('Apply to specific panels'));
     expect(screen.getByRole('tree')).not.toBe(null);
     fireEvent.click(getTreeSwitcher(2));
     fireEvent.click(screen.getByText('CHART_ID2'));
     fireEvent.click(screen.getByText('tab1'));
-    expect(form.getFieldValue('filters')?.[mockedProps.filterId].scope).toEqual(
-      {
+    await waitFor(() =>
+      expect(
+        form.getFieldValue('filters')?.[mockedProps.filterId].scope,
+      ).toEqual({
         excluded: [18, 20],
         rootPath: ['ROOT_ID'],
-      },
+      }),
     );
   });
 
-  it('correct init tree with values', () => {
-    getWrapper({
-      rootPath: ['TAB_ID'],
-      excluded: [],
-    });
-    fireEvent.click(screen.getByLabelText('Apply to specific panels'));
-    expect(screen.getByRole('tree')).not.toBe(null);
-    expect(document.querySelectorAll('.ant-tree-checkbox-checked').length).toBe(
-      1,
+  it('correct init tree with values', async () => {
+    render(
+      <MockModal
+        scope={{
+          rootPath: ['TAB_ID'],
+          excluded: [],
+        }}
+      />,
     );
+    fireEvent.click(screen.getByText('Scoping'));
+    fireEvent.click(screen.getByLabelText('Apply to specific panels'));
+
+    await waitFor(() => {
+      expect(screen.getByRole('tree')).toBeInTheDocument();
+      expect(
+        document.querySelectorAll('.ant-tree-checkbox-checked').length,
+      ).toBe(1);
+    });
   });
 });
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx
index 58d6434..e8ffde2 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx
@@ -64,7 +64,6 @@ const FilterScope: FC<FilterScopeProps> = ({
 
   return (
     <Wrapper>
-      <Typography.Title level={5}>{t('Scoping')}</Typography.Title>
       <CleanFormItem
         name={[...pathToFormValue, 'scoping']}
         initialValue={initialScoping}
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 fe5d048..47a0637 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -34,7 +34,7 @@ import {
 import { FormInstance } from 'antd/lib/form';
 import React, { useCallback, useEffect, useState } from 'react';
 import { useSelector } from 'react-redux';
-import { Checkbox, Form, Input, Typography } from 'src/common/components';
+import { Checkbox, Form, Input } from 'src/common/components';
 import { Select } from 'src/components/Select';
 import SupersetResourceSelect, {
   cachedSupersetGet,
@@ -48,6 +48,7 @@ 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 Tabs from 'src/components/Tabs';
 import { ColumnSelect } from './ColumnSelect';
 import { NativeFiltersForm } from '../types';
 import {
@@ -67,6 +68,8 @@ import {
   getFiltersConfigModalTestId,
 } from '../FiltersConfigModal';
 
+const { TabPane } = Tabs;
+
 const StyledContainer = styled.div`
   display: flex;
   flex-direction: row-reverse;
@@ -92,6 +95,17 @@ const CleanFormItem = styled(Form.Item)`
   margin-bottom: 0;
 `;
 
+const FilterTabs = {
+  configuration: {
+    key: 'configuration',
+    name: t('Configuration'),
+  },
+  scoping: {
+    key: 'scoping',
+    name: t('Scoping'),
+  },
+};
+
 export interface FiltersConfigFormProps {
   filterId: string;
   filterToEdit?: Filter;
@@ -264,254 +278,271 @@ export const FiltersConfigForm: React.FC<FiltersConfigFormProps> = ({
 
   return (
     <>
-      <Typography.Title level={5}>{t('Settings')}</Typography.Title>
-      <StyledContainer>
-        <StyledFormItem
-          name={['filters', filterId, 'name']}
-          label={<StyledLabel>{t('Filter name')}</StyledLabel>}
-          initialValue={filterToEdit?.name}
-          rules={[{ required: !removed, message: t('Name is required') }]}
+      <Tabs defaultActiveKey={FilterTabs.configuration.key} centered>
+        <TabPane
+          tab={FilterTabs.configuration.name}
+          key={FilterTabs.configuration.key}
+          forceRender
         >
-          <Input {...getFiltersConfigModalTestId('name-input')} />
-        </StyledFormItem>
-        <StyledFormItem
-          name={['filters', filterId, 'filterType']}
-          rules={[{ required: !removed, message: t('Name is required') }]}
-          initialValue={filterToEdit?.filterType || 'filter_select'}
-          label={<StyledLabel>{t('Filter Type')}</StyledLabel>}
-          {...getFiltersConfigModalTestId('filter-type')}
-        >
-          <Select
-            options={nativeFilterVizTypes.map(filterType => ({
-              value: filterType,
-              // @ts-ignore
-              label: nativeFilterItems[filterType]?.value.name,
-            }))}
-            onChange={({ value }: { value: string }) => {
-              setNativeFilterFieldValues(form, filterId, {
-                filterType: value,
-                defaultDataMask: null,
-              });
-              forceUpdate();
-            }}
-          />
-        </StyledFormItem>
-      </StyledContainer>
-      {hasDataset && (
-        <>
-          <StyledFormItem
-            name={['filters', filterId, 'dataset']}
-            initialValue={{ value: initialDatasetId }}
-            label={<StyledLabel>{t('Dataset')}</StyledLabel>}
-            rules={[{ required: !removed, message: t('Dataset is required') }]}
-            {...getFiltersConfigModalTestId('datasource-input')}
-          >
-            <SupersetResourceSelect
-              initialId={initialDatasetId}
-              resource="dataset"
-              searchColumn="table_name"
-              transformItem={datasetToSelectOption}
-              isMulti={false}
-              onError={onDatasetSelectError}
-              defaultOptions={Object.values(loadedDatasets).map(
-                datasetToSelectOption,
-              )}
-              onChange={e => {
-                // We need reset column when dataset changed
-                if (datasetId && e?.value !== datasetId) {
-                  setNativeFilterFieldValues(form, filterId, {
-                    defaultDataMask: null,
-                    column: null,
-                  });
-                }
-                forceUpdate();
-              }}
-            />
-          </StyledFormItem>
-          {hasColumn && (
+          <StyledContainer>
             <StyledFormItem
-              // don't show the column select unless we have a dataset
-              // style={{ display: datasetId == null ? undefined : 'none' }}
-              name={['filters', filterId, 'column']}
-              initialValue={initColumn}
-              label={<StyledLabel>{t('Column')}</StyledLabel>}
-              rules={[{ required: !removed, message: t('Field is required') }]}
-              data-test="field-input"
+              name={['filters', filterId, 'name']}
+              label={<StyledLabel>{t('Filter name')}</StyledLabel>}
+              initialValue={filterToEdit?.name}
+              rules={[{ required: !removed, message: t('Name is required') }]}
             >
-              <ColumnSelect
-                form={form}
-                filterId={filterId}
-                datasetId={datasetId}
-                onChange={() => {
-                  // We need reset default value when when column changed
+              <Input {...getFiltersConfigModalTestId('name-input')} />
+            </StyledFormItem>
+            <StyledFormItem
+              name={['filters', filterId, 'filterType']}
+              rules={[{ required: !removed, message: t('Name is required') }]}
+              initialValue={filterToEdit?.filterType || 'filter_select'}
+              label={<StyledLabel>{t('Filter Type')}</StyledLabel>}
+              {...getFiltersConfigModalTestId('filter-type')}
+            >
+              <Select
+                options={nativeFilterVizTypes.map(filterType => ({
+                  value: filterType,
+                  // @ts-ignore
+                  label: nativeFilterItems[filterType]?.value.name,
+                }))}
+                onChange={({ value }: { value: string }) => {
                   setNativeFilterFieldValues(form, filterId, {
+                    filterType: value,
                     defaultDataMask: null,
                   });
                   forceUpdate();
                 }}
               />
             </StyledFormItem>
-          )}
-          {hasAdditionalFilters && (
+          </StyledContainer>
+          {hasDataset && (
             <>
               <StyledFormItem
-                name={['filters', filterId, 'adhoc_filters']}
-                initialValue={filterToEdit?.adhoc_filters}
+                name={['filters', filterId, 'dataset']}
+                initialValue={{ value: initialDatasetId }}
+                label={<StyledLabel>{t('Dataset')}</StyledLabel>}
+                rules={[
+                  { required: !removed, message: t('Dataset is required') },
+                ]}
+                {...getFiltersConfigModalTestId('datasource-input')}
               >
-                <AdhocFilterControl
-                  columns={
-                    datasetDetails?.columns?.filter(
-                      (c: ColumnMeta) => c.filterable,
-                    ) || []
-                  }
-                  savedMetrics={datasetDetails?.metrics || []}
-                  datasource={datasetDetails}
-                  onChange={(filters: AdhocFilter[]) => {
-                    setNativeFilterFieldValues(form, filterId, {
-                      adhoc_filters: filters,
-                    });
+                <SupersetResourceSelect
+                  initialId={initialDatasetId}
+                  resource="dataset"
+                  searchColumn="table_name"
+                  transformItem={datasetToSelectOption}
+                  isMulti={false}
+                  onError={onDatasetSelectError}
+                  defaultOptions={Object.values(loadedDatasets).map(
+                    datasetToSelectOption,
+                  )}
+                  onChange={e => {
+                    // We need reset column when dataset changed
+                    if (datasetId && e?.value !== datasetId) {
+                      setNativeFilterFieldValues(form, filterId, {
+                        defaultDataMask: null,
+                        column: null,
+                      });
+                    }
                     forceUpdate();
                   }}
-                  label={<StyledLabel>{t('Adhoc filters')}</StyledLabel>}
                 />
               </StyledFormItem>
-              <StyledFormItem
-                name={['filters', filterId, 'time_range']}
-                label={<StyledLabel>{t('Time range')}</StyledLabel>}
-                initialValue={filterToEdit?.time_range || 'No filter'}
-              >
-                <DateFilterControl
-                  name="time_range"
-                  onChange={timeRange => {
+              {hasColumn && (
+                <StyledFormItem
+                  // don't show the column select unless we have a dataset
+                  // style={{ display: datasetId == null ? undefined : 'none' }}
+                  name={['filters', filterId, 'column']}
+                  initialValue={initColumn}
+                  label={<StyledLabel>{t('Column')}</StyledLabel>}
+                  rules={[
+                    { required: !removed, message: t('Field is required') },
+                  ]}
+                  data-test="field-input"
+                >
+                  <ColumnSelect
+                    form={form}
+                    filterId={filterId}
+                    datasetId={datasetId}
+                    onChange={() => {
+                      // We need reset default value when when column changed
+                      setNativeFilterFieldValues(form, filterId, {
+                        defaultDataMask: null,
+                      });
+                      forceUpdate();
+                    }}
+                  />
+                </StyledFormItem>
+              )}
+              {hasAdditionalFilters && (
+                <>
+                  <StyledFormItem
+                    name={['filters', filterId, 'adhoc_filters']}
+                    initialValue={filterToEdit?.adhoc_filters}
+                  >
+                    <AdhocFilterControl
+                      columns={
+                        datasetDetails?.columns?.filter(
+                          (c: ColumnMeta) => c.filterable,
+                        ) || []
+                      }
+                      savedMetrics={datasetDetails?.metrics || []}
+                      datasource={datasetDetails}
+                      onChange={(filters: AdhocFilter[]) => {
+                        setNativeFilterFieldValues(form, filterId, {
+                          adhoc_filters: filters,
+                        });
+                        forceUpdate();
+                      }}
+                      label={<StyledLabel>{t('Adhoc filters')}</StyledLabel>}
+                    />
+                  </StyledFormItem>
+                  <StyledFormItem
+                    name={['filters', filterId, 'time_range']}
+                    label={<StyledLabel>{t('Time range')}</StyledLabel>}
+                    initialValue={filterToEdit?.time_range || 'No filter'}
+                  >
+                    <DateFilterControl
+                      name="time_range"
+                      onChange={timeRange => {
+                        setNativeFilterFieldValues(form, filterId, {
+                          time_range: timeRange,
+                        });
+                        forceUpdate();
+                      }}
+                    />
+                  </StyledFormItem>
+                </>
+              )}
+            </>
+          )}
+          {hasFilledDataset && (
+            <CleanFormItem
+              name={['filters', filterId, 'defaultValueFormData']}
+              hidden
+              initialValue={newFormData}
+            />
+          )}
+          <CleanFormItem
+            name={['filters', filterId, 'defaultValueQueriesData']}
+            hidden
+            initialValue={null}
+          />
+          {isCascadingFilter && (
+            <StyledFormItem
+              name={['filters', filterId, 'parentFilter']}
+              label={<StyledLabel>{t('Parent filter')}</StyledLabel>}
+              initialValue={parentFilterOptions.find(
+                ({ value }) => value === filterToEdit?.cascadeParentIds[0],
+              )}
+              data-test="parent-filter-input"
+            >
+              <Select
+                placeholder={t('None')}
+                options={parentFilterOptions}
+                isClearable
+              />
+            </StyledFormItem>
+          )}
+          <StyledContainer>
+            <StyledFormItem className="bottom" label={<StyledLabel />}>
+              {hasDataset && hasFilledDataset && (
+                <Button onClick={refreshHandler}>
+                  {isDataDirty ? t('Populate') : t('Refresh')}
+                </Button>
+              )}
+            </StyledFormItem>
+            <StyledFormItem
+              name={['filters', filterId, 'defaultDataMask']}
+              initialValue={filterToEdit?.defaultDataMask}
+              data-test="default-input"
+              label={<StyledLabel>{t('Default Value')}</StyledLabel>}
+            >
+              {showDefaultValue ? (
+                <DefaultValue
+                  setDataMask={dataMask => {
                     setNativeFilterFieldValues(form, filterId, {
-                      time_range: timeRange,
+                      defaultDataMask: dataMask,
                     });
                     forceUpdate();
                   }}
+                  filterId={filterId}
+                  hasDataset={hasDataset}
+                  form={form}
+                  formData={newFormData}
                 />
-              </StyledFormItem>
-            </>
-          )}
-        </>
-      )}
-      {hasFilledDataset && (
-        <CleanFormItem
-          name={['filters', filterId, 'defaultValueFormData']}
-          hidden
-          initialValue={newFormData}
-        />
-      )}
-      <CleanFormItem
-        name={['filters', filterId, 'defaultValueQueriesData']}
-        hidden
-        initialValue={null}
-      />
-      {isCascadingFilter && (
-        <StyledFormItem
-          name={['filters', filterId, 'parentFilter']}
-          label={<StyledLabel>{t('Parent filter')}</StyledLabel>}
-          initialValue={parentFilterOptions.find(
-            ({ value }) => value === filterToEdit?.cascadeParentIds[0],
-          )}
-          data-test="parent-filter-input"
-        >
-          <Select
-            placeholder={t('None')}
-            options={parentFilterOptions}
-            isClearable
+              ) : hasFilledDataset ? (
+                t('Click "Populate" to get "Default Value" ->')
+              ) : (
+                t('Fill all required fields to enable "Default Value"')
+              )}
+            </StyledFormItem>
+          </StyledContainer>
+          <StyledCheckboxFormItem
+            name={['filters', filterId, 'isInstant']}
+            initialValue={filterToEdit?.isInstant || false}
+            valuePropName="checked"
+            colon={false}
+          >
+            <Checkbox data-test="apply-changes-instantly-checkbox">
+              {t('Apply changes instantly')}
+            </Checkbox>
+          </StyledCheckboxFormItem>
+          <ControlItems
+            disabled={!showDefaultValue}
+            filterToEdit={filterToEdit}
+            formFilter={formFilter}
+            filterId={filterId}
+            form={form}
+            forceUpdate={forceUpdate}
           />
-        </StyledFormItem>
-      )}
-      <StyledContainer>
-        <StyledFormItem className="bottom" label={<StyledLabel />}>
-          {hasDataset && hasFilledDataset && (
-            <Button onClick={refreshHandler}>
-              {isDataDirty ? t('Populate') : t('Refresh')}
-            </Button>
-          )}
-        </StyledFormItem>
-        <StyledFormItem
-          name={['filters', filterId, 'defaultDataMask']}
-          initialValue={filterToEdit?.defaultDataMask}
-          data-test="default-input"
-          label={<StyledLabel>{t('Default Value')}</StyledLabel>}
-        >
-          {showDefaultValue ? (
-            <DefaultValue
-              setDataMask={dataMask => {
-                setNativeFilterFieldValues(form, filterId, {
-                  defaultDataMask: dataMask,
-                });
-                forceUpdate();
-              }}
-              filterId={filterId}
-              hasDataset={hasDataset}
-              form={form}
-              formData={newFormData}
-            />
-          ) : hasFilledDataset ? (
-            t('Click "Populate" to get "Default Value" ->')
-          ) : (
-            t('Fill all required fields to enable "Default Value"')
+          {hasMetrics && (
+            <StyledFormItem
+              // don't show the column select unless we have a dataset
+              // style={{ display: datasetId == null ? undefined : 'none' }}
+              name={['filters', filterId, 'sortMetric']}
+              initialValue={filterToEdit?.sortMetric}
+              label={<StyledLabel>{t('Sort Metric')}</StyledLabel>}
+              data-test="field-input"
+            >
+              <SelectControl
+                form={form}
+                filterId={filterId}
+                name="sortMetric"
+                options={metrics.map((metric: Metric) => ({
+                  value: metric.metric_name,
+                  label: metric.verbose_name ?? metric.metric_name,
+                }))}
+                onChange={(value: string | null): void => {
+                  if (value !== undefined) {
+                    setNativeFilterFieldValues(form, filterId, {
+                      sortMetric: value,
+                    });
+                    forceUpdate();
+                  }
+                }}
+              />
+            </StyledFormItem>
           )}
-        </StyledFormItem>
-      </StyledContainer>
-      <StyledCheckboxFormItem
-        name={['filters', filterId, 'isInstant']}
-        initialValue={filterToEdit?.isInstant || false}
-        valuePropName="checked"
-        colon={false}
-      >
-        <Checkbox data-test="apply-changes-instantly-checkbox">
-          {t('Apply changes instantly')}
-        </Checkbox>
-      </StyledCheckboxFormItem>
-      <ControlItems
-        disabled={!showDefaultValue}
-        filterToEdit={filterToEdit}
-        formFilter={formFilter}
-        filterId={filterId}
-        form={form}
-        forceUpdate={forceUpdate}
-      />
-      {hasMetrics && (
-        <StyledFormItem
-          // don't show the column select unless we have a dataset
-          // style={{ display: datasetId == null ? undefined : 'none' }}
-          name={['filters', filterId, 'sortMetric']}
-          initialValue={filterToEdit?.sortMetric}
-          label={<StyledLabel>{t('Sort Metric')}</StyledLabel>}
-          data-test="field-input"
+        </TabPane>
+        <TabPane
+          tab={FilterTabs.scoping.name}
+          key={FilterTabs.scoping.key}
+          forceRender
         >
-          <SelectControl
-            form={form}
-            filterId={filterId}
-            name="sortMetric"
-            options={metrics.map((metric: Metric) => ({
-              value: metric.metric_name,
-              label: metric.verbose_name ?? metric.metric_name,
-            }))}
-            onChange={(value: string | null): void => {
-              if (value !== undefined) {
-                setNativeFilterFieldValues(form, filterId, {
-                  sortMetric: value,
-                });
-                forceUpdate();
-              }
-            }}
+          <FilterScope
+            updateFormValues={(values: any) =>
+              setNativeFilterFieldValues(form, filterId, values)
+            }
+            pathToFormValue={['filters', filterId]}
+            forceUpdate={forceUpdate}
+            scope={filterToEdit?.scope}
+            formScope={formFilter?.scope}
+            formScoping={formFilter?.scoping}
           />
-        </StyledFormItem>
-      )}
-      <FilterScope
-        updateFormValues={(values: any) =>
-          setNativeFilterFieldValues(form, filterId, values)
-        }
-        pathToFormValue={['filters', filterId]}
-        forceUpdate={forceUpdate}
-        scope={filterToEdit?.scope}
-        formScope={formFilter?.scope}
-        formScoping={formFilter?.scoping}
-      />
+        </TabPane>
+      </Tabs>
     </>
   );
 };
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
index d19538c..4b25bd5 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
@@ -39,6 +39,7 @@ import { useOpenModal, useRemoveCurrentFilter } from './state';
 
 export const StyledModalBody = styled.div`
   display: flex;
+  height: 500px;
   flex-direction: row;
   .filters-list {
     width: ${({ theme }) => theme.gridUnit * 50}px;
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx
index 5e2e896..ba48f69 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx
@@ -36,6 +36,7 @@ export function CancelConfirmationAlert({
 }: ConfirmationAlertProps) {
   return (
     <Alert
+      closable={false}
       type="warning"
       key="alert"
       message={title}
@@ -47,14 +48,6 @@ export function CancelConfirmationAlert({
       action={
         <div css={{ display: 'flex' }}>
           <Button
-            key="submit"
-            buttonSize="small"
-            buttonStyle="primary"
-            onClick={onConfirm}
-          >
-            {t('Yes, cancel')}
-          </Button>
-          <Button
             key="cancel"
             buttonSize="small"
             buttonStyle="secondary"
@@ -62,6 +55,14 @@ export function CancelConfirmationAlert({
           >
             {t('Keep editing')}
           </Button>
+          <Button
+            key="submit"
+            buttonSize="small"
+            buttonStyle="primary"
+            onClick={onConfirm}
+          >
+            {t('Yes, cancel')}
+          </Button>
         </div>
       }
     />