diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ConfigModalSidebar/ConfigModalSidebar.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ConfigModalSidebar/ConfigModalSidebar.tsx index 9d542be04e3..58a06691a25 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ConfigModalSidebar/ConfigModalSidebar.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ConfigModalSidebar/ConfigModalSidebar.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { FC, ReactNode } from 'react'; +import { FC, ReactNode, useCallback } from 'react'; import { t } from '@apache-superset/core'; import { NativeFilterType, ChartCustomizationType } from '@superset-ui/core'; import { styled } from '@apache-superset/core/ui'; @@ -77,6 +77,7 @@ export interface ConfigModalSidebarProps { sourceType: 'filter' | 'customization', targetType: 'filter' | 'customization', ) => void; + itemTitles?: Record; } const ConfigModalSidebar: FC = ({ @@ -99,7 +100,13 @@ const ConfigModalSidebar: FC = ({ restoreItem, onCollapseChange, onCrossListDrop, + itemTitles, }) => { + const getTitle = useCallback( + (id: string) => itemTitles?.[id] ?? getItemTitle(id), + [itemTitles, getItemTitle], + ); + const handleFilterCrossListDrop = ( sourceId: string, targetIndex: number, @@ -150,7 +157,7 @@ const ConfigModalSidebar: FC = ({ items={filterOrderedIds} removedItems={filterRemovedItems} erroredItems={filterErroredItems} - getItemTitle={getItemTitle} + getItemTitle={getTitle} onChange={onChange} onRearrange={onRearrange} onRemove={onRemove} @@ -172,7 +179,7 @@ const ConfigModalSidebar: FC = ({ items={customizationOrderedIds} removedItems={customizationRemovedItems} erroredItems={customizationErroredItems} - getItemTitle={getItemTitle} + getItemTitle={getTitle} onChange={onChange} onRearrange={onRearrange} onRemove={onRemove} 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 58dba03d08b..2e8a9226886 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx @@ -630,6 +630,45 @@ test('rearranges three filters and deletes one of them', async () => { ); }); +test('updates sidebar title when filter name changes', async () => { + const nativeFilterConfig = [ + buildNativeFilter('NATIVE_FILTER-1', 'state', []), + buildNativeFilter('NATIVE_FILTER-2', 'country', []), + ]; + + const state = { + ...defaultState(), + dashboardInfo: { + metadata: { + native_filter_configuration: nativeFilterConfig, + }, + }, + dashboardLayout, + }; + + defaultRender(state, { + ...props, + createNewOnOpen: false, + }); + + const filterNameInput = screen.getByRole('textbox', { + name: FILTER_NAME_REGEX, + }); + + const filterContainer = screen.getByTestId('filter-title-container'); + const tabsBeforeChange = within(filterContainer).getAllByRole('tab'); + + expect(tabsBeforeChange[0]).not.toHaveTextContent('New Filter Name'); + + await userEvent.clear(filterNameInput); + await userEvent.type(filterNameInput, 'New Filter Name'); + + await waitFor(() => { + const tabsAfterChange = within(filterContainer).getAllByRole('tab'); + expect(tabsAfterChange[0]).toHaveTextContent('New Filter Name'); + }); +}); + test('modifies the name of a filter', async () => { jest.useFakeTimers(); try { diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx index 659f0154c87..23cdb356448 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx @@ -450,7 +450,17 @@ function FiltersConfigModal({ ? Icons.FullscreenExitOutlined : Icons.FullscreenOutlined; - const handleValuesChange = useMemo( + const [formValuesVersion, setFormValuesVersion] = useState(0); + + const itemTitles = useMemo(() => { + const titles: Record = {}; + [...filterIds, ...chartCustomizationIds].forEach(id => { + titles[id] = modalSaveLogic.getItemTitle(id); + }); + return titles; + }, [filterIds, chartCustomizationIds, modalSaveLogic, formValuesVersion]); + + const debouncedErrorHandling = useMemo( () => debounce(() => { setSaveAlertVisible(false); @@ -459,6 +469,11 @@ function FiltersConfigModal({ [modalSaveLogic], ); + const handleValuesChange = useCallback(() => { + setFormValuesVersion(prev => prev + 1); + debouncedErrorHandling(); + }, [debouncedErrorHandling]); + const handleActiveFilterPanelChange = useCallback( (key: string | string[]) => setActiveFilterPanelKey(key), [], @@ -557,6 +572,7 @@ function FiltersConfigModal({ customizationErroredItems={customizationState.erroredIds} activeCollapseKeys={activeCollapseKeys} getItemTitle={modalSaveLogic.getItemTitle} + itemTitles={itemTitles} onAddFilter={filterOperations.addFilter} onAddCustomization={ customizationOperations.addChartCustomization