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

diegopucci pushed a commit to branch feat/horizontal-filterbar-states
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 509dc08ddc795924a2f5db9c9e474b23c36b1514
Author: geido <[email protected]>
AuthorDate: Fri Nov 4 20:47:18 2022 +0200

    Separate components
---
 .../components/DropdownSelectableIcon/index.tsx    |   1 +
 .../DashboardBuilder/DashboardBuilder.tsx          |  95 ++--
 .../FilterBar/ActionButtons/ActionButtons.test.tsx |   2 +-
 .../FilterBar/ActionButtons/index.tsx              |  96 ++--
 .../nativeFilters/FilterBar/FilterBar.test.tsx     |  18 +-
 .../FilterBar/FilterBarLocationSelect/index.tsx    |   6 +-
 .../FilterBar/FilterConfigurationLink/index.tsx    |   2 +-
 .../FilterBar/FilterControls/FilterControl.tsx     |   2 +-
 .../FilterBar/FilterSets/EditSection.tsx           |   2 +-
 .../FilterBar/FilterSets/FilterSetUnit.tsx         |   2 +-
 .../FilterBar/FilterSets/FiltersHeader.tsx         |   2 +-
 .../nativeFilters/FilterBar/FilterSets/Footer.tsx  |   2 +-
 .../nativeFilters/FilterBar/FilterSets/index.tsx   |   2 +-
 .../nativeFilters/FilterBar/Header/index.tsx       |   8 +-
 .../FilterBar/{index.tsx => Horizontal.tsx}        | 342 ++++----------
 .../FilterBar/{index.tsx => Vertical.tsx}          |  27 +-
 .../components/nativeFilters/FilterBar/index.tsx   | 501 +--------------------
 .../components/nativeFilters/FilterBar/utils.ts    |   4 +
 18 files changed, 245 insertions(+), 869 deletions(-)

diff --git a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx 
b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx
index 228c6889a2..b6c5d89a2e 100644
--- a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx
+++ b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx
@@ -43,6 +43,7 @@ const StyledDropdownButton = styled(
     height: unset;
     padding: 0;
     border: none;
+    width: auto !important;
 
     .anticon {
       line-height: 0;
diff --git 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
index cd0cfdb3fc..d97410685b 100644
--- 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
+++ 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
@@ -40,7 +40,11 @@ import WithPopoverMenu from 
'src/dashboard/components/menu/WithPopoverMenu';
 import getDirectPathToTabIndex from 
'src/dashboard/util/getDirectPathToTabIndex';
 import { URL_PARAMS } from 'src/constants';
 import { getUrlParam } from 'src/utils/urlUtils';
-import { DashboardLayout, RootState } from 'src/dashboard/types';
+import {
+  DashboardLayout,
+  FilterBarLocation,
+  RootState,
+} from 'src/dashboard/types';
 import {
   setDirectPathToChild,
   setEditMode,
@@ -57,7 +61,10 @@ import {
   DASHBOARD_ROOT_DEPTH,
   DashboardStandaloneMode,
 } from 'src/dashboard/util/constants';
-import FilterBar from 'src/dashboard/components/nativeFilters/FilterBar';
+import {
+  VerticalFilterBar,
+  HorizontalFilterBar,
+} from 'src/dashboard/components/nativeFilters/FilterBar';
 import Loading from 'src/components/Loading';
 import { EmptyStateBig } from 'src/components/EmptyState';
 import { useUiConfig } from 'src/components/UiConfigContext';
@@ -241,6 +248,9 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
   const fullSizeChartId = useSelector<RootState, number | null>(
     state => state.dashboardState.fullSizeChartId,
   );
+  const filterBarLocation = useSelector<RootState, FilterBarLocation>(
+    ({ dashboardInfo }) => dashboardInfo.filterBarLocation,
+  );
 
   const handleChangeTab = useCallback(
     ({ pathToTabIndex }: { pathToTabIndex: string[] }) => {
@@ -354,6 +364,11 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
     ({ dropIndicatorProps }: { dropIndicatorProps: JsonObject }) => (
       <div>
         {!hideDashboardHeader && <DashboardHeader />}
+        {nativeFiltersEnabled &&
+          !editMode &&
+          filterBarLocation === FilterBarLocation.HORIZONTAL && (
+            <HorizontalFilterBar directPathToChild={directPathToChild} />
+          )}
         {dropIndicatorProps && <div {...dropIndicatorProps} />}
         {!isReport && topLevelTabs && !uiConfig.hideNav && (
           <WithPopoverMenu
@@ -382,6 +397,8 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
       </div>
     ),
     [
+      nativeFiltersEnabled,
+      filterBarLocation,
       editMode,
       handleChangeTab,
       handleDeleteTopLevelTabs,
@@ -394,42 +411,44 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => 
{
 
   return (
     <StyledDiv>
-      {nativeFiltersEnabled && !editMode && (
-        <>
-          <ResizableSidebar
-            id={`dashboard:${dashboardId}`}
-            enable={dashboardFiltersOpen}
-            minWidth={OPEN_FILTER_BAR_WIDTH}
-            maxWidth={OPEN_FILTER_BAR_MAX_WIDTH}
-            initialWidth={OPEN_FILTER_BAR_WIDTH}
-          >
-            {adjustedWidth => {
-              const filterBarWidth = dashboardFiltersOpen
-                ? adjustedWidth
-                : CLOSED_FILTER_BAR_WIDTH;
-              return (
-                <FiltersPanel
-                  width={filterBarWidth}
-                  data-test="dashboard-filters-panel"
-                >
-                  <StickyPanel ref={containerRef} width={filterBarWidth}>
-                    <ErrorBoundary>
-                      <FilterBar
-                        filtersOpen={dashboardFiltersOpen}
-                        toggleFiltersBar={toggleDashboardFiltersOpen}
-                        directPathToChild={directPathToChild}
-                        width={filterBarWidth}
-                        height={filterBarHeight}
-                        offset={filterBarOffset}
-                      />
-                    </ErrorBoundary>
-                  </StickyPanel>
-                </FiltersPanel>
-              );
-            }}
-          </ResizableSidebar>
-        </>
-      )}
+      {nativeFiltersEnabled &&
+        !editMode &&
+        filterBarLocation === FilterBarLocation.VERTICAL && (
+          <>
+            <ResizableSidebar
+              id={`dashboard:${dashboardId}`}
+              enable={dashboardFiltersOpen}
+              minWidth={OPEN_FILTER_BAR_WIDTH}
+              maxWidth={OPEN_FILTER_BAR_MAX_WIDTH}
+              initialWidth={OPEN_FILTER_BAR_WIDTH}
+            >
+              {adjustedWidth => {
+                const filterBarWidth = dashboardFiltersOpen
+                  ? adjustedWidth
+                  : CLOSED_FILTER_BAR_WIDTH;
+                return (
+                  <FiltersPanel
+                    width={filterBarWidth}
+                    data-test="dashboard-filters-panel"
+                  >
+                    <StickyPanel ref={containerRef} width={filterBarWidth}>
+                      <ErrorBoundary>
+                        <VerticalFilterBar
+                          filtersOpen={dashboardFiltersOpen}
+                          toggleFiltersBar={toggleDashboardFiltersOpen}
+                          directPathToChild={directPathToChild}
+                          width={filterBarWidth}
+                          height={filterBarHeight}
+                          offset={filterBarOffset}
+                        />
+                      </ErrorBoundary>
+                    </StickyPanel>
+                  </FiltersPanel>
+                );
+              }}
+            </ResizableSidebar>
+          </>
+        )}
       <StyledHeader ref={headerRef}>
         {/* @ts-ignore */}
         <DragDroppable
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx
index 3c3f838c4a..525f519632 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/ActionButtons.test.tsx
@@ -20,7 +20,7 @@ import React from 'react';
 import { OPEN_FILTER_BAR_WIDTH } from 'src/dashboard/constants';
 import userEvent from '@testing-library/user-event';
 import { render, screen } from 'spec/helpers/testing-library';
-import { ActionButtons } from './index';
+import ActionButtons from './index';
 
 const createProps = () => ({
   onApply: jest.fn(),
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx
index 5fca65c3ec..eac032eb70 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/ActionButtons/index.tsx
@@ -28,7 +28,8 @@ import {
 import Button from 'src/components/Button';
 import { OPEN_FILTER_BAR_WIDTH } from 'src/dashboard/constants';
 import { rgba } from 'emotion-rgba';
-import { getFilterBarTestId } from '../index';
+import { getFilterBarTestId } from '../utils';
+import { FilterBarLocation } from 'src/dashboard/types';
 
 interface ActionButtonsProps {
   width?: number;
@@ -37,38 +38,15 @@ interface ActionButtonsProps {
   dataMaskSelected: DataMaskState;
   dataMaskApplied: DataMaskStateWithId;
   isApplyDisabled: boolean;
+  orientation?: FilterBarLocation;
 }
 
-const ActionButtonsContainer = styled.div<{ width: number }>`
-  ${({ theme, width }) => css`
+const ActionButtonsContainer = styled.div<{
+  width: number;
+  orientation: FilterBarLocation;
+}>`
+  ${({ theme, width, orientation }) => css`
     display: flex;
-    flex-direction: column;
-    align-items: center;
-
-    position: fixed;
-    z-index: 100;
-
-    // filter bar width minus 1px for border
-    width: ${width - 1}px;
-    bottom: 0;
-
-    padding: ${theme.gridUnit * 4}px;
-    padding-top: ${theme.gridUnit * 6}px;
-
-    background: linear-gradient(
-      ${rgba(theme.colors.grayscale.light5, 0)},
-      ${theme.colors.grayscale.light5} ${theme.opacity.mediumLight}
-    );
-
-    pointer-events: none;
-
-    & > button {
-      pointer-events: auto;
-    }
-
-    & > .filter-apply-button {
-      margin-bottom: ${theme.gridUnit * 3}px;
-    }
 
     && > .filter-clear-all-button {
       color: ${theme.colors.grayscale.base};
@@ -82,16 +60,61 @@ const ActionButtonsContainer = styled.div<{ width: number 
}>`
         color: ${theme.colors.grayscale.light1};
       }
     }
+    ${orientation === FilterBarLocation.VERTICAL &&
+    `
+      flex-direction: column;
+      align-items: center;
+      pointer-events: none;
+      position: fixed;
+      z-index: 100;
+
+      // filter bar width minus 1px for border
+      width: ${width - 1}px;
+      bottom: 0;
+
+      padding: ${theme.gridUnit * 4}px;
+      padding-top: ${theme.gridUnit * 6}px;
+
+      background: linear-gradient(
+        ${rgba(theme.colors.grayscale.light5, 0)},
+        ${theme.colors.grayscale.light5} ${theme.opacity.mediumLight}
+      );
+
+      & > button {
+        pointer-events: auto;
+      }
+
+      & > .filter-apply-button {
+        margin-bottom: ${theme.gridUnit * 3}px;
+      }
+    `};
+
+    ${orientation === FilterBarLocation.HORIZONTAL &&
+    `
+      margin: 0 ${theme.gridUnit * 2}px;
+      && > .filter-clear-all-button {
+        text-transform: capitalize;
+        font-weight: ${theme.typography.weights.normal};
+      }
+      & > .filter-apply-button {
+        &[disabled],
+        &[disabled]:hover {
+          color: ${theme.colors.grayscale.light1};
+          background: ${theme.colors.grayscale.light3};
+        }
+      }
+    `};
   `};
 `;
 
-export const ActionButtons = ({
+const ActionButtons = ({
   width = OPEN_FILTER_BAR_WIDTH,
   onApply,
   onClearAll,
   dataMaskApplied,
   dataMaskSelected,
   isApplyDisabled,
+  orientation = FilterBarLocation.VERTICAL,
 }: ActionButtonsProps) => {
   const isClearAllEnabled = useMemo(
     () =>
@@ -103,9 +126,14 @@ export const ActionButtons = ({
       ),
     [dataMaskApplied, dataMaskSelected],
   );
+  const isVertical = orientation === FilterBarLocation.VERTICAL;
 
   return (
-    <ActionButtonsContainer data-test="filterbar-action-buttons" width={width}>
+    <ActionButtonsContainer
+      data-test="filterbar-action-buttons"
+      orientation={orientation}
+      width={width}
+    >
       <Button
         disabled={isApplyDisabled}
         buttonStyle="primary"
@@ -114,7 +142,7 @@ export const ActionButtons = ({
         onClick={onApply}
         {...getFilterBarTestId('apply-button')}
       >
-        {t('Apply filters')}
+        {isVertical ? t('Apply filters') : t('Apply')}
       </Button>
       <Button
         disabled={!isClearAllEnabled}
@@ -129,3 +157,5 @@ export const ActionButtons = ({
     </ActionButtonsContainer>
   );
 };
+
+export default ActionButtons;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx
index 871f2b4026..8a9bd48a12 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBar.test.tsx
@@ -29,7 +29,8 @@ import { TimeFilterPlugin, SelectFilterPlugin } from 
'src/filters/components';
 import { DATE_FILTER_TEST_KEY } from 
'src/explore/components/controls/DateFilterControl';
 import fetchMock from 'fetch-mock';
 import { waitFor } from '@testing-library/react';
-import FilterBar, { FILTER_BAR_TEST_ID } from '.';
+import { FILTER_BAR_TEST_ID } from './utils';
+import { VerticalFilterBar } from '.';
 import { FILTERS_CONFIG_MODAL_TEST_ID } from 
'../FiltersConfigModal/FiltersConfigModal';
 
 jest.useFakeTimers();
@@ -216,12 +217,15 @@ describe('FilterBar', () => {
   });
 
   const renderWrapper = (props = closedBarProps, state?: object) =>
-    render(<FilterBar {...props} width={280} height={400} offset={0} />, {
-      initialState: state,
-      useDnd: true,
-      useRedux: true,
-      useRouter: true,
-    });
+    render(
+      <VerticalFilterBar {...props} width={280} height={400} offset={0} />,
+      {
+        initialState: state,
+        useDnd: true,
+        useRedux: true,
+        useRouter: true,
+      },
+    );
 
   it('should render', () => {
     const { container } = renderWrapper();
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarLocationSelect/index.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarLocationSelect/index.tsx
index 82d4ba92e6..48260deb60 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarLocationSelect/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarLocationSelect/index.tsx
@@ -26,7 +26,7 @@ import { saveFilterBarLocation } from 
'src/dashboard/actions/dashboardInfo';
 import Icons from 'src/components/Icons';
 import DropdownSelectableIcon from 'src/components/DropdownSelectableIcon';
 
-export const FilterBarLocationSelect = () => {
+const FilterBarLocationSelect = () => {
   const dispatch = useDispatch();
   const theme = useTheme();
   const filterBarLocation = useSelector<RootState, FilterBarLocation>(
@@ -62,7 +62,7 @@ export const FilterBarLocationSelect = () => {
   return (
     <DropdownSelectableIcon
       onSelect={toggleFilterBarLocation}
-      info={t('Placement of filter bar')}
+      info={t('Orientation of filter bar')}
       icon={<Icons.Gear name="gear" iconColor={theme.colors.grayscale.base} />}
       menuItems={[
         {
@@ -78,3 +78,5 @@ export const FilterBarLocationSelect = () => {
     />
   );
 };
+
+export default FilterBarLocationSelect;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
index e99171c7e8..8319c3c9fb 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
@@ -22,7 +22,7 @@ import { setFilterConfiguration } from 
'src/dashboard/actions/nativeFilters';
 import Button from 'src/components/Button';
 import { FilterConfiguration, styled } from '@superset-ui/core';
 import FiltersConfigModal from 
'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal';
-import { getFilterBarTestId } from '..';
+import { getFilterBarTestId } from '../utils';
 
 export interface FCBProps {
   createNewOnOpen?: boolean;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx
index 986572c7f0..082111b94a 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx
@@ -24,7 +24,7 @@ import { checkIsMissingRequiredValue } from '../utils';
 import FilterValue from './FilterValue';
 import { FilterProps } from './types';
 import { FilterCard } from '../../FilterCard';
-import { FilterBarScrollContext } from '../index';
+import { FilterBarScrollContext } from '../Vertical';
 
 const StyledIcon = styled.div`
   position: absolute;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx
index 689eaa8266..c4807d751f 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/EditSection.tsx
@@ -27,7 +27,7 @@ import { ActionButtons } from './Footer';
 import { useNativeFiltersDataMask, useFilters, useFilterSets } from '../state';
 import { APPLY_FILTERS_HINT, findExistingFilterSet } from './utils';
 import { useFilterSetNameDuplicated } from './state';
-import { getFilterBarTestId } from '../index';
+import { getFilterBarTestId } from '../utils';
 
 const Wrapper = styled.div`
   display: grid;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx
index 53ea1c94c5..14e0c88b7e 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FilterSetUnit.tsx
@@ -31,7 +31,7 @@ import { CheckOutlined, EllipsisOutlined } from 
'@ant-design/icons';
 import Button from 'src/components/Button';
 import { Tooltip } from 'src/components/Tooltip';
 import FiltersHeader from './FiltersHeader';
-import { getFilterBarTestId } from '..';
+import { getFilterBarTestId } from '../utils';
 
 const HeaderButton = styled(Button)`
   padding: 0;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx
index 5a7bff6527..5982bf515a 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/FiltersHeader.tsx
@@ -30,7 +30,7 @@ import Icons from 'src/components/Icons';
 import { areObjectsEqual } from 'src/reduxUtils';
 import { getFilterValueForDisplay } from './utils';
 import { useFilters } from '../state';
-import { getFilterBarTestId } from '../index';
+import { getFilterBarTestId } from '../utils';
 
 const FilterHeader = styled.div`
   display: flex;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx
index df6c6ee44e..7847927ff5 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/Footer.tsx
@@ -22,7 +22,7 @@ import Button from 'src/components/Button';
 import { Tooltip } from 'src/components/Tooltip';
 import { APPLY_FILTERS_HINT } from './utils';
 import { useFilterSetNameDuplicated } from './state';
-import { getFilterBarTestId } from '..';
+import { getFilterBarTestId } from '../utils';
 
 export type FooterProps = {
   filterSetName: string;
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx
index 5fdfd48171..2c727f278f 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterSets/index.tsx
@@ -40,7 +40,7 @@ import { findExistingFilterSet } from './utils';
 import { useFilters, useNativeFiltersDataMask, useFilterSets } from '../state';
 import Footer from './Footer';
 import FilterSetUnit from './FilterSetUnit';
-import { getFilterBarTestId } from '..';
+import { getFilterBarTestId } from '../utils';
 import { TabIds } from '../utils';
 
 const FilterSetsWrapper = styled.div`
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx
index a20d6a61f7..77ec3203fb 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header/index.tsx
@@ -32,8 +32,8 @@ import { useSelector } from 'react-redux';
 import FilterConfigurationLink from 
'src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink';
 import { useFilters } from 
'src/dashboard/components/nativeFilters/FilterBar/state';
 import { RootState } from 'src/dashboard/types';
-import { getFilterBarTestId } from '..';
-import { FilterBarLocationSelect } from '../FilterBarLocationSelect';
+import { getFilterBarTestId } from '../utils';
+import FilterBarLocationSelect from '../FilterBarLocationSelect';
 
 const TitleArea = styled.h4`
   display: flex;
@@ -58,6 +58,10 @@ const HeaderButton = styled(Button)`
 const Wrapper = styled.div`
   padding: ${({ theme }) => theme.gridUnit}px
     ${({ theme }) => theme.gridUnit * 2}px;
+
+  .ant-dropdown-trigger span {
+    padding-right: ${({ theme }) => theme.gridUnit * 2}px;
+  }
 `;
 
 type HeaderProps = {
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
similarity index 50%
copy from 
superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
copy to 
superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
index 1b13f0583a..87aff179f9 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Horizontal.tsx
@@ -17,154 +17,90 @@
  * under the License.
  */
 
-/* eslint-disable no-param-reassign */
-import throttle from 'lodash/throttle';
-import React, {
-  useEffect,
-  useState,
-  useCallback,
-  useMemo,
-  useRef,
-  createContext,
-} from 'react';
+import React, { useEffect, useState, useCallback } from 'react';
 import { useDispatch, useSelector } from 'react-redux';
-import cx from 'classnames';
 import {
   DataMaskStateWithId,
   DataMaskWithId,
   Filter,
   DataMask,
-  HandlerFunction,
   styled,
   t,
   SLOW_DEBOUNCE,
   isNativeFilter,
 } from '@superset-ui/core';
 import Icons from 'src/components/Icons';
-import { AntdTabs } from 'src/components';
 import { useHistory } from 'react-router-dom';
 import { usePrevious } from 'src/hooks/usePrevious';
-import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
 import { updateDataMask, clearDataMask } from 'src/dataMask/actions';
 import { useImmer } from 'use-immer';
 import { isEmpty, isEqual, debounce } from 'lodash';
-import { testWithId } from 'src/utils/testUtils';
 import Loading from 'src/components/Loading';
 import { getInitialDataMask } from 'src/dataMask/reducer';
 import { URL_PARAMS } from 'src/constants';
 import { getUrlParam } from 'src/utils/urlUtils';
-import { EmptyStateSmall } from 'src/components/EmptyState';
 import { useTabId } from 'src/hooks/useTabId';
-import { RootState } from 'src/dashboard/types';
-import { checkIsApplyDisabled, TabIds } from './utils';
-import FilterSets from './FilterSets';
+import { FilterBarLocation, RootState } from 'src/dashboard/types';
+import { checkIsApplyDisabled } from './utils';
 import {
   useNativeFiltersDataMask,
   useFilters,
-  useFilterSets,
   useFilterUpdates,
   useInitialization,
 } from './state';
 import { createFilterKey, updateFilterKey } from './keyValue';
-import EditSection from './FilterSets/EditSection';
-import Header from './Header';
 import FilterControls from './FilterControls/FilterControls';
-import { ActionButtons } from './ActionButtons';
+import ActionButtons from './ActionButtons';
+import { getFilterBarTestId } from './utils';
+import FilterBarLocationSelect from './FilterBarLocationSelect';
+import FilterConfigurationLink from './FilterConfigurationLink';
 
-export const FILTER_BAR_TEST_ID = 'filter-bar';
-export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID);
-
-const BarWrapper = styled.div<{ width: number }>`
-  width: ${({ theme }) => theme.gridUnit * 8}px;
-
-  & .ant-tabs-top > .ant-tabs-nav {
-    margin: 0;
-  }
-  &.open {
-    width: ${({ width }) => width}px; // arbitrary...
-  }
-`;
-
-const Bar = styled.div<{ width: number }>`
-  & .ant-typography-edit-content {
-    left: 0;
-    margin-top: 0;
-    width: 100%;
-  }
-  position: absolute;
-  top: 0;
-  left: 0;
-  flex-direction: column;
-  flex-grow: 1;
-  width: ${({ width }) => width}px;
-  background: ${({ theme }) => theme.colors.grayscale.light5};
-  border-right: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
-  border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
-  min-height: 100%;
-  display: none;
-  &.open {
-    display: flex;
-  }
-`;
+export interface HorizontalFiltersBarProps {
+  directPathToChild?: string[];
+}
 
-const CollapsedBar = styled.div<{ offset: number }>`
-  position: absolute;
-  top: ${({ offset }) => offset}px;
-  left: 0;
-  height: 100%;
-  width: ${({ theme }) => theme.gridUnit * 8}px;
-  padding-top: ${({ theme }) => theme.gridUnit * 2}px;
-  display: none;
-  text-align: center;
-  &.open {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    padding: ${({ theme }) => theme.gridUnit * 2}px;
-  }
-  svg {
-    cursor: pointer;
-  }
+const HorizontalBar = styled.div`
+  ${({ theme }) => `
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: center;
+  justify-content: flex-start;
+  height: 48px;
+  background: ${theme.colors.grayscale.light5};
+  box-shadow: inset 0px -2px 2px -1px ${theme.colors.grayscale.light2};
+  padding: 0 ${theme.gridUnit * 4}px;
+`}
 `;
 
-const StyledCollapseIcon = styled(Icons.Collapse)`
-  color: ${({ theme }) => theme.colors.primary.base};
-  margin-bottom: ${({ theme }) => theme.gridUnit * 3}px;
+const FilterBarEmptyStateContainer = styled.div`
+  ${({ theme }) => `
+  margin: 0 ${theme.gridUnit * 2}px;
+  font-weight: ${theme.typography.weights.bold};
+`}
 `;
 
-const StyledFilterIcon = styled(Icons.Filter)`
-  color: ${({ theme }) => theme.colors.grayscale.base};
-`;
+const FiltersLinkContainer = styled.div<{ hasFilters: boolean }>`
+  ${({ theme, hasFilters }) => `
+  padding: 0 ${theme.gridUnit * 2}px;
+  border-right: ${
+    hasFilters ? `1px solid ${theme.colors.grayscale.light2}` : 0
+  };
 
-const StyledTabs = styled(AntdTabs)`
-  & .ant-tabs-nav-list {
-    width: 100%;
-  }
-  & .ant-tabs-tab {
+  button {
     display: flex;
-    justify-content: center;
-    margin: 0;
-    flex: 1;
-  }
-
-  & > .ant-tabs-nav .ant-tabs-nav-operations {
-    display: none;
+    align-items: center;
+    text-transform: capitalize;
+    font-weight: ${theme.typography.weights.normal};
+    color: ${theme.colors.primary.base};
+    > .anticon + span, > .anticon {
+        margin-right: 0;
+        margin-left: 0;
+      }
   }
+`}
 `;
 
-const FilterBarEmptyStateContainer = styled.div`
-  margin-top: ${({ theme }) => theme.gridUnit * 8}px;
-`;
-
-export interface FiltersBarProps {
-  filtersOpen: boolean;
-  toggleFiltersBar: any;
-  directPathToChild?: string[];
-  width: number;
-  height: number | string;
-  offset: number;
-}
-
 const EXCLUDED_URL_PARAMS: string[] = [
   URL_PARAMS.nativeFilters.name,
   URL_PARAMS.permalinkKey.name,
@@ -223,31 +159,21 @@ const publishDataMask = debounce(
   SLOW_DEBOUNCE,
 );
 
-export const FilterBarScrollContext = createContext(false);
-const FilterBar: React.FC<FiltersBarProps> = ({
-  filtersOpen,
-  toggleFiltersBar,
+const HorizontalFilterBar: React.FC<HorizontalFiltersBarProps> = ({
   directPathToChild,
-  width,
-  height,
-  offset,
 }) => {
   const history = useHistory();
   const dataMaskApplied: DataMaskStateWithId = useNativeFiltersDataMask();
-  const [editFilterSetId, setEditFilterSetId] = useState<number | null>(null);
   const [dataMaskSelected, setDataMaskSelected] =
     useImmer<DataMaskStateWithId>(dataMaskApplied);
   const dispatch = useDispatch();
   const [updateKey, setUpdateKey] = useState(0);
   const tabId = useTabId();
-  const filterSets = useFilterSets();
-  const filterSetFilterValues = Object.values(filterSets);
-  const [tab, setTab] = useState(TabIds.AllFilters);
   const filters = useFilters();
   const previousFilters = usePrevious(filters);
   const filterValues = Object.values(filters);
   const nativeFilterValues = filterValues.filter(isNativeFilter);
-  const dashboardId = useSelector<any, string>(
+  const dashboardId = useSelector<any, number>(
     ({ dashboardInfo }) => dashboardInfo?.id,
   );
   const previousDashboardId = usePrevious(dashboardId);
@@ -255,9 +181,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({
     ({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
   );
 
-  const [isScrolling, setIsScrolling] = useState(false);
-  const timeout = useRef<any>();
-
   const handleFilterSelectionChange = useCallback(
     (
       filter: Pick<Filter, 'id'> & Partial<Filter>,
@@ -352,29 +275,6 @@ const FilterBar: React.FC<FiltersBarProps> = ({
     });
   }, [dataMaskSelected, dispatch, setDataMaskSelected]);
 
-  const openFiltersBar = useCallback(
-    () => toggleFiltersBar(true),
-    [toggleFiltersBar],
-  );
-
-  const onScroll = useCallback(
-    throttle(() => {
-      clearTimeout(timeout.current);
-      setIsScrolling(true);
-      timeout.current = setTimeout(() => {
-        setIsScrolling(false);
-      }, 300);
-    }, 200),
-    [],
-  );
-
-  useEffect(() => {
-    document.onscroll = onScroll;
-    return () => {
-      document.onscroll = null;
-    };
-  }, [onScroll]);
-
   useFilterUpdates(dataMaskSelected, setDataMaskSelected);
   const isApplyDisabled = checkIsApplyDisabled(
     dataMaskSelected,
@@ -382,136 +282,48 @@ const FilterBar: React.FC<FiltersBarProps> = ({
     nativeFilterValues,
   );
   const isInitialized = useInitialization();
-  const tabPaneStyle = useMemo(
-    () => ({ overflow: 'auto', height, overscrollBehavior: 'contain' }),
-    [height],
-  );
-
-  const numberOfFilters = nativeFilterValues.length;
+  const hasFilters = filterValues.length > 0;
 
   return (
-    <FilterBarScrollContext.Provider value={isScrolling}>
-      <BarWrapper
-        {...getFilterBarTestId()}
-        className={cx({ open: filtersOpen })}
-        width={width}
-      >
-        <CollapsedBar
-          {...getFilterBarTestId('collapsable')}
-          className={cx({ open: !filtersOpen })}
-          onClick={openFiltersBar}
-          offset={offset}
-        >
-          <StyledCollapseIcon
-            {...getFilterBarTestId('expand-button')}
-            iconSize="l"
-          />
-          <StyledFilterIcon
-            {...getFilterBarTestId('filter-icon')}
-            iconSize="l"
-          />
-        </CollapsedBar>
-        <Bar className={cx({ open: filtersOpen })} width={width}>
-          <Header toggleFiltersBar={toggleFiltersBar} />
-          {!isInitialized ? (
-            <div css={{ height }}>
-              <Loading />
-            </div>
-          ) : isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) ? (
-            <StyledTabs
-              centered
-              onChange={setTab as HandlerFunction}
-              defaultActiveKey={TabIds.AllFilters}
-              activeKey={editFilterSetId ? TabIds.AllFilters : undefined}
-            >
-              <AntdTabs.TabPane
-                tab={t('All filters (%(filterCount)d)', {
-                  filterCount: numberOfFilters,
-                })}
-                key={TabIds.AllFilters}
-                css={tabPaneStyle}
-              >
-                {editFilterSetId && (
-                  <EditSection
-                    dataMaskSelected={dataMaskSelected}
-                    disabled={!isApplyDisabled}
-                    onCancel={() => setEditFilterSetId(null)}
-                    filterSetId={editFilterSetId}
-                  />
-                )}
-                {filterValues.length === 0 ? (
-                  <FilterBarEmptyStateContainer>
-                    <EmptyStateSmall
-                      title={t('No filters are currently added')}
-                      image="filter.svg"
-                      description={
-                        canEdit &&
-                        t(
-                          'Click the button above to add a filter to the 
dashboard',
-                        )
-                      }
-                    />
-                  </FilterBarEmptyStateContainer>
-                ) : (
-                  <FilterControls
-                    dataMaskSelected={dataMaskSelected}
-                    directPathToChild={directPathToChild}
-                    onFilterSelectionChange={handleFilterSelectionChange}
-                  />
-                )}
-              </AntdTabs.TabPane>
-              <AntdTabs.TabPane
-                disabled={!!editFilterSetId}
-                tab={t('Filter sets (%(filterSetCount)d)', {
-                  filterSetCount: filterSetFilterValues.length,
-                })}
-                key={TabIds.FilterSets}
-                css={tabPaneStyle}
+    <HorizontalBar {...getFilterBarTestId()}>
+      {!isInitialized ? (
+        <Loading position="inline-centered" />
+      ) : (
+        <>
+          {canEdit && <FilterBarLocationSelect />}
+          {!hasFilters && (
+            <FilterBarEmptyStateContainer>
+              {t('No filters are currently added to this dashboard.')}
+            </FilterBarEmptyStateContainer>
+          )}
+          {canEdit && (
+            <FiltersLinkContainer hasFilters={hasFilters}>
+              <FilterConfigurationLink
+                dashboardId={dashboardId}
+                createNewOnOpen={filterValues.length === 0}
               >
-                <FilterSets
-                  onEditFilterSet={setEditFilterSetId}
-                  disabled={!isApplyDisabled}
-                  dataMaskSelected={dataMaskSelected}
-                  tab={tab}
-                  onFilterSelectionChange={handleFilterSelectionChange}
-                />
-              </AntdTabs.TabPane>
-            </StyledTabs>
-          ) : (
-            <div css={tabPaneStyle} onScroll={onScroll}>
-              {filterValues.length === 0 ? (
-                <FilterBarEmptyStateContainer>
-                  <EmptyStateSmall
-                    title={t('No filters are currently added')}
-                    image="filter.svg"
-                    description={
-                      canEdit &&
-                      t(
-                        'Click the button above to add a filter to the 
dashboard',
-                      )
-                    }
-                  />
-                </FilterBarEmptyStateContainer>
-              ) : (
-                <FilterControls
-                  dataMaskSelected={dataMaskSelected}
-                  directPathToChild={directPathToChild}
-                  onFilterSelectionChange={handleFilterSelectionChange}
-                />
-              )}
-            </div>
+                <Icons.PlusSmall /> {t('Add/Edit Filters')}
+              </FilterConfigurationLink>
+            </FiltersLinkContainer>
+          )}
+          {hasFilters && (
+            <FilterControls
+              dataMaskSelected={dataMaskSelected}
+              directPathToChild={directPathToChild}
+              onFilterSelectionChange={handleFilterSelectionChange}
+            />
           )}
           <ActionButtons
-            width={width}
+            orientation={FilterBarLocation.HORIZONTAL}
             onApply={handleApply}
             onClearAll={handleClearAll}
             dataMaskSelected={dataMaskSelected}
             dataMaskApplied={dataMaskApplied}
             isApplyDisabled={isApplyDisabled}
           />
-        </Bar>
-      </BarWrapper>
-    </FilterBarScrollContext.Provider>
+        </>
+      )}
+    </HorizontalBar>
   );
 };
-export default React.memo(FilterBar);
+export default React.memo(HorizontalFilterBar);
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
similarity index 97%
copy from 
superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
copy to 
superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
index 1b13f0583a..569a9e3554 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
@@ -48,7 +48,6 @@ import { FeatureFlag, isFeatureEnabled } from 
'src/featureFlags';
 import { updateDataMask, clearDataMask } from 'src/dataMask/actions';
 import { useImmer } from 'use-immer';
 import { isEmpty, isEqual, debounce } from 'lodash';
-import { testWithId } from 'src/utils/testUtils';
 import Loading from 'src/components/Loading';
 import { getInitialDataMask } from 'src/dataMask/reducer';
 import { URL_PARAMS } from 'src/constants';
@@ -69,10 +68,17 @@ import { createFilterKey, updateFilterKey } from 
'./keyValue';
 import EditSection from './FilterSets/EditSection';
 import Header from './Header';
 import FilterControls from './FilterControls/FilterControls';
-import { ActionButtons } from './ActionButtons';
+import ActionButtons from './ActionButtons';
+import { getFilterBarTestId } from './utils';
 
-export const FILTER_BAR_TEST_ID = 'filter-bar';
-export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID);
+export interface VerticalFiltersBarProps {
+  filtersOpen: boolean;
+  toggleFiltersBar: any;
+  directPathToChild?: string[];
+  width: number;
+  height: number | string;
+  offset: number;
+}
 
 const BarWrapper = styled.div<{ width: number }>`
   width: ${({ theme }) => theme.gridUnit * 8}px;
@@ -156,15 +162,6 @@ const FilterBarEmptyStateContainer = styled.div`
   margin-top: ${({ theme }) => theme.gridUnit * 8}px;
 `;
 
-export interface FiltersBarProps {
-  filtersOpen: boolean;
-  toggleFiltersBar: any;
-  directPathToChild?: string[];
-  width: number;
-  height: number | string;
-  offset: number;
-}
-
 const EXCLUDED_URL_PARAMS: string[] = [
   URL_PARAMS.nativeFilters.name,
   URL_PARAMS.permalinkKey.name,
@@ -224,7 +221,7 @@ const publishDataMask = debounce(
 );
 
 export const FilterBarScrollContext = createContext(false);
-const FilterBar: React.FC<FiltersBarProps> = ({
+const VerticalFilterBar: React.FC<VerticalFiltersBarProps> = ({
   filtersOpen,
   toggleFiltersBar,
   directPathToChild,
@@ -514,4 +511,4 @@ const FilterBar: React.FC<FiltersBarProps> = ({
     </FilterBarScrollContext.Provider>
   );
 };
-export default React.memo(FilterBar);
+export default React.memo(VerticalFilterBar);
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
index 1b13f0583a..91644eda25 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
@@ -16,502 +16,5 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-/* eslint-disable no-param-reassign */
-import throttle from 'lodash/throttle';
-import React, {
-  useEffect,
-  useState,
-  useCallback,
-  useMemo,
-  useRef,
-  createContext,
-} from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import cx from 'classnames';
-import {
-  DataMaskStateWithId,
-  DataMaskWithId,
-  Filter,
-  DataMask,
-  HandlerFunction,
-  styled,
-  t,
-  SLOW_DEBOUNCE,
-  isNativeFilter,
-} from '@superset-ui/core';
-import Icons from 'src/components/Icons';
-import { AntdTabs } from 'src/components';
-import { useHistory } from 'react-router-dom';
-import { usePrevious } from 'src/hooks/usePrevious';
-import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
-import { updateDataMask, clearDataMask } from 'src/dataMask/actions';
-import { useImmer } from 'use-immer';
-import { isEmpty, isEqual, debounce } from 'lodash';
-import { testWithId } from 'src/utils/testUtils';
-import Loading from 'src/components/Loading';
-import { getInitialDataMask } from 'src/dataMask/reducer';
-import { URL_PARAMS } from 'src/constants';
-import { getUrlParam } from 'src/utils/urlUtils';
-import { EmptyStateSmall } from 'src/components/EmptyState';
-import { useTabId } from 'src/hooks/useTabId';
-import { RootState } from 'src/dashboard/types';
-import { checkIsApplyDisabled, TabIds } from './utils';
-import FilterSets from './FilterSets';
-import {
-  useNativeFiltersDataMask,
-  useFilters,
-  useFilterSets,
-  useFilterUpdates,
-  useInitialization,
-} from './state';
-import { createFilterKey, updateFilterKey } from './keyValue';
-import EditSection from './FilterSets/EditSection';
-import Header from './Header';
-import FilterControls from './FilterControls/FilterControls';
-import { ActionButtons } from './ActionButtons';
-
-export const FILTER_BAR_TEST_ID = 'filter-bar';
-export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID);
-
-const BarWrapper = styled.div<{ width: number }>`
-  width: ${({ theme }) => theme.gridUnit * 8}px;
-
-  & .ant-tabs-top > .ant-tabs-nav {
-    margin: 0;
-  }
-  &.open {
-    width: ${({ width }) => width}px; // arbitrary...
-  }
-`;
-
-const Bar = styled.div<{ width: number }>`
-  & .ant-typography-edit-content {
-    left: 0;
-    margin-top: 0;
-    width: 100%;
-  }
-  position: absolute;
-  top: 0;
-  left: 0;
-  flex-direction: column;
-  flex-grow: 1;
-  width: ${({ width }) => width}px;
-  background: ${({ theme }) => theme.colors.grayscale.light5};
-  border-right: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
-  border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
-  min-height: 100%;
-  display: none;
-  &.open {
-    display: flex;
-  }
-`;
-
-const CollapsedBar = styled.div<{ offset: number }>`
-  position: absolute;
-  top: ${({ offset }) => offset}px;
-  left: 0;
-  height: 100%;
-  width: ${({ theme }) => theme.gridUnit * 8}px;
-  padding-top: ${({ theme }) => theme.gridUnit * 2}px;
-  display: none;
-  text-align: center;
-  &.open {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    padding: ${({ theme }) => theme.gridUnit * 2}px;
-  }
-  svg {
-    cursor: pointer;
-  }
-`;
-
-const StyledCollapseIcon = styled(Icons.Collapse)`
-  color: ${({ theme }) => theme.colors.primary.base};
-  margin-bottom: ${({ theme }) => theme.gridUnit * 3}px;
-`;
-
-const StyledFilterIcon = styled(Icons.Filter)`
-  color: ${({ theme }) => theme.colors.grayscale.base};
-`;
-
-const StyledTabs = styled(AntdTabs)`
-  & .ant-tabs-nav-list {
-    width: 100%;
-  }
-  & .ant-tabs-tab {
-    display: flex;
-    justify-content: center;
-    margin: 0;
-    flex: 1;
-  }
-
-  & > .ant-tabs-nav .ant-tabs-nav-operations {
-    display: none;
-  }
-`;
-
-const FilterBarEmptyStateContainer = styled.div`
-  margin-top: ${({ theme }) => theme.gridUnit * 8}px;
-`;
-
-export interface FiltersBarProps {
-  filtersOpen: boolean;
-  toggleFiltersBar: any;
-  directPathToChild?: string[];
-  width: number;
-  height: number | string;
-  offset: number;
-}
-
-const EXCLUDED_URL_PARAMS: string[] = [
-  URL_PARAMS.nativeFilters.name,
-  URL_PARAMS.permalinkKey.name,
-];
-
-const publishDataMask = debounce(
-  async (
-    history,
-    dashboardId,
-    updateKey,
-    dataMaskSelected: DataMaskStateWithId,
-    tabId,
-  ) => {
-    const { location } = history;
-    const { search } = location;
-    const previousParams = new URLSearchParams(search);
-    const newParams = new URLSearchParams();
-    let dataMaskKey: string | null;
-    previousParams.forEach((value, key) => {
-      if (!EXCLUDED_URL_PARAMS.includes(key)) {
-        newParams.append(key, value);
-      }
-    });
-
-    const nativeFiltersCacheKey = getUrlParam(URL_PARAMS.nativeFiltersKey);
-    const dataMask = JSON.stringify(dataMaskSelected);
-    if (
-      updateKey &&
-      nativeFiltersCacheKey &&
-      (await updateFilterKey(
-        dashboardId,
-        dataMask,
-        nativeFiltersCacheKey,
-        tabId,
-      ))
-    ) {
-      dataMaskKey = nativeFiltersCacheKey;
-    } else {
-      dataMaskKey = await createFilterKey(dashboardId, dataMask, tabId);
-    }
-    if (dataMaskKey) {
-      newParams.set(URL_PARAMS.nativeFiltersKey.name, dataMaskKey);
-    }
-
-    // pathname could be updated somewhere else through window.history
-    // keep react router history in sync with window history
-    // replace params only when current page is /superset/dashboard
-    // this prevents a race condition between updating filters and navigating 
to Explore
-    if (window.location.pathname.includes('/superset/dashboard')) {
-      history.location.pathname = window.location.pathname;
-      history.replace({
-        search: newParams.toString(),
-      });
-    }
-  },
-  SLOW_DEBOUNCE,
-);
-
-export const FilterBarScrollContext = createContext(false);
-const FilterBar: React.FC<FiltersBarProps> = ({
-  filtersOpen,
-  toggleFiltersBar,
-  directPathToChild,
-  width,
-  height,
-  offset,
-}) => {
-  const history = useHistory();
-  const dataMaskApplied: DataMaskStateWithId = useNativeFiltersDataMask();
-  const [editFilterSetId, setEditFilterSetId] = useState<number | null>(null);
-  const [dataMaskSelected, setDataMaskSelected] =
-    useImmer<DataMaskStateWithId>(dataMaskApplied);
-  const dispatch = useDispatch();
-  const [updateKey, setUpdateKey] = useState(0);
-  const tabId = useTabId();
-  const filterSets = useFilterSets();
-  const filterSetFilterValues = Object.values(filterSets);
-  const [tab, setTab] = useState(TabIds.AllFilters);
-  const filters = useFilters();
-  const previousFilters = usePrevious(filters);
-  const filterValues = Object.values(filters);
-  const nativeFilterValues = filterValues.filter(isNativeFilter);
-  const dashboardId = useSelector<any, string>(
-    ({ dashboardInfo }) => dashboardInfo?.id,
-  );
-  const previousDashboardId = usePrevious(dashboardId);
-  const canEdit = useSelector<RootState, boolean>(
-    ({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
-  );
-
-  const [isScrolling, setIsScrolling] = useState(false);
-  const timeout = useRef<any>();
-
-  const handleFilterSelectionChange = useCallback(
-    (
-      filter: Pick<Filter, 'id'> & Partial<Filter>,
-      dataMask: Partial<DataMask>,
-    ) => {
-      setDataMaskSelected(draft => {
-        // force instant updating on initialization for filters with 
`requiredFirst` is true or instant filters
-        if (
-          // filterState.value === undefined - means that value not initialized
-          dataMask.filterState?.value !== undefined &&
-          dataMaskSelected[filter.id]?.filterState?.value === undefined &&
-          filter.requiredFirst
-        ) {
-          dispatch(updateDataMask(filter.id, dataMask));
-        }
-
-        draft[filter.id] = {
-          ...(getInitialDataMask(filter.id) as DataMaskWithId),
-          ...dataMask,
-        };
-      });
-    },
-    [dataMaskSelected, dispatch, setDataMaskSelected],
-  );
-
-  useEffect(() => {
-    if (previousFilters && dashboardId === previousDashboardId) {
-      const updates = {};
-      Object.values(filters).forEach(currentFilter => {
-        const previousFilter = previousFilters?.[currentFilter.id];
-        if (!previousFilter) {
-          return;
-        }
-        const currentType = currentFilter.filterType;
-        const currentTargets = currentFilter.targets;
-        const currentDataMask = currentFilter.defaultDataMask;
-        const previousType = previousFilter?.filterType;
-        const previousTargets = previousFilter?.targets;
-        const previousDataMask = previousFilter?.defaultDataMask;
-        const typeChanged = currentType !== previousType;
-        const targetsChanged = !isEqual(currentTargets, previousTargets);
-        const dataMaskChanged = !isEqual(currentDataMask, previousDataMask);
-
-        if (typeChanged || targetsChanged || dataMaskChanged) {
-          updates[currentFilter.id] = getInitialDataMask(currentFilter.id);
-        }
-      });
-
-      if (!isEmpty(updates)) {
-        setDataMaskSelected(draft => ({ ...draft, ...updates }));
-        Object.keys(updates).forEach(key => dispatch(clearDataMask(key)));
-      }
-    }
-  }, [
-    JSON.stringify(filters),
-    JSON.stringify(previousFilters),
-    previousDashboardId,
-  ]);
-
-  const dataMaskAppliedText = JSON.stringify(dataMaskApplied);
-
-  useEffect(() => {
-    setDataMaskSelected(() => dataMaskApplied);
-  }, [dataMaskAppliedText, setDataMaskSelected]);
-
-  useEffect(() => {
-    publishDataMask(history, dashboardId, updateKey, dataMaskApplied, tabId);
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [dashboardId, dataMaskAppliedText, history, updateKey, tabId]);
-
-  const handleApply = useCallback(() => {
-    const filterIds = Object.keys(dataMaskSelected);
-    setUpdateKey(1);
-    filterIds.forEach(filterId => {
-      if (dataMaskSelected[filterId]) {
-        dispatch(updateDataMask(filterId, dataMaskSelected[filterId]));
-      }
-    });
-  }, [dataMaskSelected, dispatch]);
-
-  const handleClearAll = useCallback(() => {
-    const filterIds = Object.keys(dataMaskSelected);
-    filterIds.forEach(filterId => {
-      if (dataMaskSelected[filterId]) {
-        dispatch(clearDataMask(filterId));
-        setDataMaskSelected(draft => {
-          if (draft[filterId].filterState?.value !== undefined) {
-            draft[filterId].filterState!.value = undefined;
-          }
-        });
-      }
-    });
-  }, [dataMaskSelected, dispatch, setDataMaskSelected]);
-
-  const openFiltersBar = useCallback(
-    () => toggleFiltersBar(true),
-    [toggleFiltersBar],
-  );
-
-  const onScroll = useCallback(
-    throttle(() => {
-      clearTimeout(timeout.current);
-      setIsScrolling(true);
-      timeout.current = setTimeout(() => {
-        setIsScrolling(false);
-      }, 300);
-    }, 200),
-    [],
-  );
-
-  useEffect(() => {
-    document.onscroll = onScroll;
-    return () => {
-      document.onscroll = null;
-    };
-  }, [onScroll]);
-
-  useFilterUpdates(dataMaskSelected, setDataMaskSelected);
-  const isApplyDisabled = checkIsApplyDisabled(
-    dataMaskSelected,
-    dataMaskApplied,
-    nativeFilterValues,
-  );
-  const isInitialized = useInitialization();
-  const tabPaneStyle = useMemo(
-    () => ({ overflow: 'auto', height, overscrollBehavior: 'contain' }),
-    [height],
-  );
-
-  const numberOfFilters = nativeFilterValues.length;
-
-  return (
-    <FilterBarScrollContext.Provider value={isScrolling}>
-      <BarWrapper
-        {...getFilterBarTestId()}
-        className={cx({ open: filtersOpen })}
-        width={width}
-      >
-        <CollapsedBar
-          {...getFilterBarTestId('collapsable')}
-          className={cx({ open: !filtersOpen })}
-          onClick={openFiltersBar}
-          offset={offset}
-        >
-          <StyledCollapseIcon
-            {...getFilterBarTestId('expand-button')}
-            iconSize="l"
-          />
-          <StyledFilterIcon
-            {...getFilterBarTestId('filter-icon')}
-            iconSize="l"
-          />
-        </CollapsedBar>
-        <Bar className={cx({ open: filtersOpen })} width={width}>
-          <Header toggleFiltersBar={toggleFiltersBar} />
-          {!isInitialized ? (
-            <div css={{ height }}>
-              <Loading />
-            </div>
-          ) : isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) ? (
-            <StyledTabs
-              centered
-              onChange={setTab as HandlerFunction}
-              defaultActiveKey={TabIds.AllFilters}
-              activeKey={editFilterSetId ? TabIds.AllFilters : undefined}
-            >
-              <AntdTabs.TabPane
-                tab={t('All filters (%(filterCount)d)', {
-                  filterCount: numberOfFilters,
-                })}
-                key={TabIds.AllFilters}
-                css={tabPaneStyle}
-              >
-                {editFilterSetId && (
-                  <EditSection
-                    dataMaskSelected={dataMaskSelected}
-                    disabled={!isApplyDisabled}
-                    onCancel={() => setEditFilterSetId(null)}
-                    filterSetId={editFilterSetId}
-                  />
-                )}
-                {filterValues.length === 0 ? (
-                  <FilterBarEmptyStateContainer>
-                    <EmptyStateSmall
-                      title={t('No filters are currently added')}
-                      image="filter.svg"
-                      description={
-                        canEdit &&
-                        t(
-                          'Click the button above to add a filter to the 
dashboard',
-                        )
-                      }
-                    />
-                  </FilterBarEmptyStateContainer>
-                ) : (
-                  <FilterControls
-                    dataMaskSelected={dataMaskSelected}
-                    directPathToChild={directPathToChild}
-                    onFilterSelectionChange={handleFilterSelectionChange}
-                  />
-                )}
-              </AntdTabs.TabPane>
-              <AntdTabs.TabPane
-                disabled={!!editFilterSetId}
-                tab={t('Filter sets (%(filterSetCount)d)', {
-                  filterSetCount: filterSetFilterValues.length,
-                })}
-                key={TabIds.FilterSets}
-                css={tabPaneStyle}
-              >
-                <FilterSets
-                  onEditFilterSet={setEditFilterSetId}
-                  disabled={!isApplyDisabled}
-                  dataMaskSelected={dataMaskSelected}
-                  tab={tab}
-                  onFilterSelectionChange={handleFilterSelectionChange}
-                />
-              </AntdTabs.TabPane>
-            </StyledTabs>
-          ) : (
-            <div css={tabPaneStyle} onScroll={onScroll}>
-              {filterValues.length === 0 ? (
-                <FilterBarEmptyStateContainer>
-                  <EmptyStateSmall
-                    title={t('No filters are currently added')}
-                    image="filter.svg"
-                    description={
-                      canEdit &&
-                      t(
-                        'Click the button above to add a filter to the 
dashboard',
-                      )
-                    }
-                  />
-                </FilterBarEmptyStateContainer>
-              ) : (
-                <FilterControls
-                  dataMaskSelected={dataMaskSelected}
-                  directPathToChild={directPathToChild}
-                  onFilterSelectionChange={handleFilterSelectionChange}
-                />
-              )}
-            </div>
-          )}
-          <ActionButtons
-            width={width}
-            onApply={handleApply}
-            onClearAll={handleClearAll}
-            dataMaskSelected={dataMaskSelected}
-            dataMaskApplied={dataMaskApplied}
-            isApplyDisabled={isApplyDisabled}
-          />
-        </Bar>
-      </BarWrapper>
-    </FilterBarScrollContext.Provider>
-  );
-};
-export default React.memo(FilterBar);
+export { default as VerticalFilterBar } from './Vertical';
+export { default as HorizontalFilterBar } from './Horizontal';
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts
index 842bb44054..1fa11db467 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts
@@ -19,6 +19,7 @@
 
 import { areObjectsEqual } from 'src/reduxUtils';
 import { DataMaskStateWithId, Filter, FilterState } from '@superset-ui/core';
+import { testWithId } from 'src/utils/testUtils';
 
 export enum TabIds {
   AllFilters = 'allFilters',
@@ -65,3 +66,6 @@ export const checkIsApplyDisabled = (
     )
   );
 };
+
+export const FILTER_BAR_TEST_ID = 'filter-bar';
+export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID);

Reply via email to