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

sadpandajoe pushed a commit to branch fix-dashboard-filterbar-section-spacing
in repository https://gitbox.apache.org/repos/asf/superset.git

commit ed770ace5518f6f22fc8cb5e7d1a07ad51377fe2
Author: sadpandajoe <[email protected]>
AuthorDate: Sat Oct 3 17:41:03 2026 +0000

    fix(dashboard): remove redundant margin causing extra space around filter 
bar out-of-scope section
    
    SectionContainer's margin-bottom stacked additively on top of
    FilterControlsWrapper's flex gap, doubling the vertical space before
    the "Filters out of scope" collapsible (and other sections) in the
    vertical filter bar. Spacing between sections is already handled by
    the wrapper's flex gap, so the extra margin is removed.
    
    Co-Authored-By: Claude Sonnet 5 <[email protected]>
---
 .../FilterControls/FilterControls.test.tsx         | 62 ++++++++++++++++++++++
 .../FilterBar/FilterControls/FilterControls.tsx    | 12 ++---
 2 files changed, 66 insertions(+), 8 deletions(-)

diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.test.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.test.tsx
index 935928bada0..268129a7ee7 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.test.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.test.tsx
@@ -26,6 +26,7 @@ import {
   ChartCustomizationType,
   ChartCustomizationDivider,
 } from '@superset-ui/core';
+import { styled } from '@apache-superset/core/theme';
 import { FilterBarOrientation } from 'src/dashboard/types';
 import FilterControls from './FilterControls';
 
@@ -422,3 +423,64 @@ test('FilterControls overflowedByIndex updates when 
filters change scope', () =>
 
   expect(container).toBeInTheDocument();
 });
+
+// Mirrors FilterControlsWrapper in ../Vertical.tsx, which wraps FilterControls
+// in production and supplies the flex `gap` between vertical sections.
+const FilterControlsWrapper = styled.div`
+  display: flex;
+  flex-direction: column;
+  gap: ${({ theme }) => theme.sizeUnit * 2}px;
+`;
+
+test('out-of-scope section does not add margin on top of the wrapper flex 
gap', () => {
+  const state = getDefaultState(FilterBarOrientation.Vertical);
+  state.dashboardLayout.present['CHART-1'].parents = [
+    'ROOT_ID',
+    'TABS-1',
+    'TAB-1',
+  ];
+  state.dashboardLayout.present['CHART-2'].parents = [
+    'ROOT_ID',
+    'TABS-1',
+    'TAB-2',
+  ];
+  state.nativeFilters.filters['filter-1'].chartsInScope = [1];
+  state.nativeFilters.filters['filter-2'].chartsInScope = [1];
+  // filter-3 lives under the inactive TAB-2, so it renders out of scope.
+  state.nativeFilters.filters['filter-3'].chartsInScope = [2];
+  (state as any).dashboardInfo = {
+    ...state.dashboardInfo,
+    metadata: {
+      native_filter_configuration: Object.values(state.nativeFilters.filters),
+    },
+  };
+
+  const { useSelector } = jest.requireMock('react-redux');
+  useSelector.mockImplementation((selector: (s: typeof state) => unknown) =>
+    selector(state),
+  );
+
+  const store = mockStore(state) as Store;
+  const { container } = render(
+    <Provider store={store}>
+      <FilterControlsWrapper>
+        <FilterControls
+          dataMaskSelected={{}}
+          onFilterSelectionChange={jest.fn()}
+          onPendingCustomizationDataMaskChange={jest.fn()}
+          chartCustomizationValues={[]}
+        />
+      </FilterControlsWrapper>
+    </Provider>,
+  );
+
+  expect(screen.getByText('Filters out of scope (1)')).toBeInTheDocument();
+
+  // The "Filters" section is the out-of-scope collapsible's previous sibling
+  // inside the flex column. The parent already adds spacing via `gap`, so this
+  // section must not add its own margin-bottom on top of it.
+  const outOfScopeCollapse = container.querySelector('.ant-collapse');
+  const filtersSection = outOfScopeCollapse?.previousElementSibling as Element;
+  const { marginBottom } = getComputedStyle(filtersSection);
+  expect(parseInt(marginBottom, 10) || 0).toBe(0);
+});
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
index 2d5bc878768..ebf554d9390 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx
@@ -101,10 +101,6 @@ type FilterControlsProps = {
   hideHeader?: boolean;
 };
 
-const SectionContainer = styled.div`
-  margin-bottom: ${({ theme }) => theme.sizeUnit * 3}px;
-`;
-
 const SectionHeader = styled.button`
   appearance: none;
   border: none;
@@ -321,7 +317,7 @@ const FilterControls: FC<FilterControlsProps> = ({
     () => (
       <>
         {filtersInScope.length > 0 && (
-          <SectionContainer>
+          <div>
             {!hideHeader && (
               <SectionHeader
                 type="button"
@@ -347,7 +343,7 @@ const FilterControls: FC<FilterControlsProps> = ({
               <SectionContent>{filtersInScope.map(renderer)}</SectionContent>
             )}
             {(hideHeader || sectionsOpen.filters) && <StyledDivider />}
-          </SectionContainer>
+          </div>
         )}
 
         {showFiltersOutOfScope && (
@@ -359,7 +355,7 @@ const FilterControls: FC<FilterControlsProps> = ({
         )}
 
         {customizationsInScope.length > 0 && (
-          <SectionContainer>
+          <div>
             {!hideHeader && (
               <SectionHeader
                 type="button"
@@ -396,7 +392,7 @@ const FilterControls: FC<FilterControlsProps> = ({
             {(hideHeader || sectionsOpen.chartCustomization) && (
               <StyledDivider />
             )}
-          </SectionContainer>
+          </div>
         )}
 
         {showCustomizationCollapsePanel &&

Reply via email to