Skip to content

Commit 9680f58

Browse files
harsh-vadorclaude
andcommitted
fix(ui-core): resync staged FilterSelect state on controlled open
Staged selections were only reset inside react-aria's onOpenChange, which never fires for a programmatic open via the controlled isOpen prop. Move the resync into an effect on the resolved open state so both paths refresh staged from selectedValues. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent b2d9679 commit 9680f58

2 files changed

Lines changed: 29 additions & 4 deletions

File tree

openmetadata-ui-core-components/src/main/resources/ui/src/components/application/filter-select/filter-select.test.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,24 @@ describe('FilterSelect', () => {
9696
);
9797
});
9898

99+
it('resyncs staged selections on a controlled programmatic open', () => {
100+
const onChange = vi.fn();
101+
const props = {
102+
commitMode: 'staged' as const,
103+
label: 'Service',
104+
options: OPTIONS,
105+
onChange,
106+
};
107+
const { rerender } = render(
108+
<FilterSelect {...props} isOpen={false} selectedValues={['redshift']} />
109+
);
110+
111+
rerender(<FilterSelect {...props} isOpen selectedValues={['snowflake']} />);
112+
fireEvent.click(screen.getByTestId('apply-filter-btn'));
113+
114+
expect(onChange).toHaveBeenCalledWith(['snowflake']);
115+
});
116+
99117
it('does not commit staged toggles on cancel', () => {
100118
const { onChange } = renderFilter({ commitMode: 'staged' });
101119

openmetadata-ui-core-components/src/main/resources/ui/src/components/application/filter-select/filter-select.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { useCoreTranslation } from '@/i18n/useCoreTranslation';
1818
import { cx } from '@/utils/cx';
1919
import { borderAfter } from '@/utils/tailwindClasses';
2020
import { Check, ChevronDown, SearchLg } from '@untitledui/icons';
21-
import { useMemo, useState, type HTMLAttributes } from 'react';
21+
import { useEffect, useMemo, useState, type HTMLAttributes } from 'react';
2222
import { Button as AriaButton, type Selection } from 'react-aria-components';
2323
import type {
2424
FilterSelectOption,
@@ -231,13 +231,20 @@ export const FilterSelect = ({
231231

232232
const commit = isStaged ? setStaged : onChange;
233233

234+
// Resync staged whenever the dropdown transitions open — including a
235+
// programmatic open via the controlled `isOpen` prop, which never goes
236+
// through react-aria's onOpenChange.
237+
useEffect(() => {
238+
if (isOpen && isStaged) {
239+
setStaged(selectedValues);
240+
}
241+
// eslint-disable-next-line react-hooks/exhaustive-deps
242+
}, [isOpen]);
243+
234244
const handleOpenChange = (open: boolean) => {
235245
setInternalOpen(open);
236246
onOpenChange?.(open);
237247
setQuery('');
238-
if (open) {
239-
setStaged(selectedValues);
240-
}
241248
};
242249

243250
const handleSearch = (search: string) => {

0 commit comments

Comments
 (0)