You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by so...@apache.org on 2026/06/05 18:37:02 UTC

(superset) branch master updated: fix(dashboard): prevent divider display controls from reverting on second save (#40696)

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

yousoph 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 e956f82224b fix(dashboard): prevent divider display controls from reverting on second save (#40696)
e956f82224b is described below

commit e956f82224b3352562542e8d5514a898c60251e2
Author: yousoph <so...@gmail.com>
AuthorDate: Fri Jun 5 11:36:55 2026 -0700

    fix(dashboard): prevent divider display controls from reverting on second save (#40696)
    
    Co-authored-by: Claude Sonnet 4.6 <no...@anthropic.com>
---
 .../FiltersConfigModal/FiltersConfigModal.test.tsx | 133 +++++++++++++++++++++
 .../FiltersConfigModal/FiltersConfigModal.tsx      |  18 ++-
 2 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
index 3583671ad59..ebdd0038077 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
@@ -800,6 +800,139 @@ test('does not auto-create a filter when createNewOnOpen is false', () => {
   expect(screen.queryByText(DATASET_REGEX)).not.toBeInTheDocument();
 });
 
+test('enables save button and includes updated title when editing an existing divider', async () => {
+  jest.useFakeTimers();
+
+  const nativeFilterDividerConfig = [
+    {
+      id: 'NATIVE_FILTER_DIVIDER-1',
+      type: 'DIVIDER' as const,
+      title: 'First Edit',
+      description: '',
+      scope: { rootPath: ['ROOT'], excluded: [] },
+    },
+  ];
+
+  const state = {
+    ...defaultState(),
+    dashboardInfo: {
+      metadata: {
+        native_filter_configuration: nativeFilterDividerConfig,
+      },
+    },
+    dashboardLayout,
+  };
+
+  const onSave = jest.fn();
+
+  defaultRender(state, {
+    ...props,
+    createNewOnOpen: false,
+    initialFilterId: 'NATIVE_FILTER_DIVIDER-1',
+    onSave,
+  });
+
+  // Save button should be disabled when no changes have been made
+  expect(screen.getByRole('button', { name: SAVE_REGEX })).toBeDisabled();
+
+  // Editing the title field should mark the divider modified and enable save
+  const titleInput = screen.getByRole('textbox', { name: /^title$/i });
+  await userEvent.clear(titleInput);
+  await userEvent.type(titleInput, 'Second Edit');
+
+  jest.advanceTimersByTime(500);
+  jest.useRealTimers();
+
+  await waitFor(() =>
+    expect(
+      screen.getByRole('button', { name: SAVE_REGEX }),
+    ).not.toBeDisabled(),
+  );
+
+  await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
+
+  await waitFor(() =>
+    expect(onSave).toHaveBeenCalledWith(
+      expect.objectContaining({
+        filterChanges: expect.objectContaining({
+          modified: expect.arrayContaining([
+            expect.objectContaining({
+              id: 'NATIVE_FILTER_DIVIDER-1',
+              title: 'Second Edit',
+            }),
+          ]),
+        }),
+      }),
+    ),
+  );
+}, 30000);
+
+test('enables save button and includes updated title when editing an existing chart customization divider', async () => {
+  jest.useFakeTimers();
+
+  const chartCustomizationDividerConfig = [
+    {
+      id: 'CHART_CUSTOMIZATION_DIVIDER-1',
+      type: 'CHART_CUSTOMIZATION_DIVIDER' as const,
+      title: 'First Edit',
+      description: '',
+    },
+  ];
+
+  const state = {
+    ...defaultState(),
+    dashboardInfo: {
+      metadata: {
+        chart_customization_config: chartCustomizationDividerConfig,
+      },
+    },
+    dashboardLayout,
+  };
+
+  const onSave = jest.fn();
+
+  defaultRender(state, {
+    ...props,
+    createNewOnOpen: false,
+    initialFilterId: 'CHART_CUSTOMIZATION_DIVIDER-1',
+    onSave,
+  });
+
+  // Save button should be disabled when no changes have been made
+  expect(screen.getByRole('button', { name: SAVE_REGEX })).toBeDisabled();
+
+  // Editing the title field should mark the divider modified and enable save
+  const titleInput = screen.getByRole('textbox', { name: /^title$/i });
+  await userEvent.clear(titleInput);
+  await userEvent.type(titleInput, 'Second Edit');
+
+  jest.advanceTimersByTime(500);
+  jest.useRealTimers();
+
+  await waitFor(() =>
+    expect(
+      screen.getByRole('button', { name: SAVE_REGEX }),
+    ).not.toBeDisabled(),
+  );
+
+  await userEvent.click(screen.getByRole('button', { name: SAVE_REGEX }));
+
+  await waitFor(() =>
+    expect(onSave).toHaveBeenCalledWith(
+      expect.objectContaining({
+        customizationChanges: expect.objectContaining({
+          modified: expect.arrayContaining([
+            expect.objectContaining({
+              id: 'CHART_CUSTOMIZATION_DIVIDER-1',
+              title: 'Second Edit',
+            }),
+          ]),
+        }),
+      }),
+    ),
+  );
+}, 30000);
+
 test('empty state disappears when a filter is added via dropdown', async () => {
   defaultRender(defaultState(), {
     ...props,
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
index 3cfe83434fe..44ba434ab66 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
@@ -57,6 +57,7 @@ import {
   isFilterId,
   isChartCustomizationId,
   transformDividerId,
+  isDivider,
 } from './utils';
 import { ConfigModalContent } from './ConfigModalContent';
 import ConfigModalSidebar from './ConfigModalSidebar';
@@ -470,9 +471,20 @@ function FiltersConfigModal({
     [modalSaveLogic, setSaveAlertVisible],
   );
 
-  const handleValuesChange = useMemo(
-    () => debouncedHandleErroredItems,
-    [debouncedHandleErroredItems],
+  const handleValuesChange = useCallback(
+    (changedValues: Partial<NativeFiltersForm>) => {
+      debouncedHandleErroredItems();
+      // DividerConfigForm doesn't call handleModifyItem on change the way
+      // FiltersConfigForm does, so detect divider field changes here and mark
+      // the divider as modified so canSave becomes true and the save payload
+      // includes the updated divider values.
+      Object.keys(changedValues?.filters ?? {}).forEach(id => {
+        if (isDivider(id)) {
+          handleModifyItem(id);
+        }
+      });
+    },
+    [debouncedHandleErroredItems, handleModifyItem],
   );
 
   const handleActiveFilterPanelChange = useCallback(