fix(filters): preserve backend metric-based sorting (#35152)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Elizabeth Thompson
2025-11-07 11:40:56 -08:00
committed by GitHub
parent 4d0fdba97a
commit 909bd877c9
2 changed files with 304 additions and 1 deletions

View File

@@ -379,4 +379,300 @@ describe('SelectFilterPlugin', () => {
userEvent.type(screen.getByRole('combobox'), 'new value');
expect(await screen.findByTitle('new value')).toBeInTheDocument();
});
test('preserves backend order when sortMetric is specified', () => {
const testData = [
{ gender: 'zebra' },
{ gender: 'alpha' },
{ gender: 'beta' },
];
const testProps = {
...selectMultipleProps,
formData: {
...selectMultipleProps.formData,
sortMetric: 'count',
sortAscending: true,
},
queriesData: [
{
rowcount: 3,
colnames: ['gender'],
coltypes: [1],
data: testData,
applied_filters: [{ column: 'gender' }],
rejected_filters: [],
},
],
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
};
render(
// @ts-ignore
<SelectFilterPlugin
// @ts-ignore
{...transformProps(testProps)}
setDataMask={jest.fn()}
showOverflow={false}
/>,
{
useRedux: true,
initialState: {
nativeFilters: {
filters: {
'test-filter': {
name: 'Test Filter',
},
},
},
dataMask: {
'test-filter': {
extraFormData: {},
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
},
},
},
},
);
const filterSelect = screen.getAllByRole('combobox')[0];
userEvent.click(filterSelect);
// When sortMetric is specified, options should appear in the original data order
// (zebra, alpha, beta) not alphabetically sorted
const options = screen.getAllByRole('option');
expect(options[0]).toHaveTextContent('zebra');
expect(options[1]).toHaveTextContent('alpha');
expect(options[2]).toHaveTextContent('beta');
});
test('applies alphabetical sorting when sortMetric is not specified', () => {
const testData = [
{ gender: 'zebra' },
{ gender: 'alpha' },
{ gender: 'beta' },
];
const testProps = {
...selectMultipleProps,
formData: {
...selectMultipleProps.formData,
sortMetric: undefined,
sortAscending: true,
},
queriesData: [
{
rowcount: 3,
colnames: ['gender'],
coltypes: [1],
data: testData,
applied_filters: [{ column: 'gender' }],
rejected_filters: [],
},
],
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
};
render(
// @ts-ignore
<SelectFilterPlugin
// @ts-ignore
{...transformProps(testProps)}
setDataMask={jest.fn()}
showOverflow={false}
/>,
{
useRedux: true,
initialState: {
nativeFilters: {
filters: {
'test-filter': {
name: 'Test Filter',
},
},
},
dataMask: {
'test-filter': {
extraFormData: {},
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
},
},
},
},
);
const filterSelect = screen.getAllByRole('combobox')[0];
userEvent.click(filterSelect);
// When sortMetric is not specified, options should be sorted alphabetically
// (alpha, beta, zebra)
const options = screen.getAllByRole('option');
expect(options[0]).toHaveTextContent('alpha');
expect(options[1]).toHaveTextContent('beta');
expect(options[2]).toHaveTextContent('zebra');
});
test('applies descending alphabetical sorting when sortAscending is false and no sortMetric', () => {
const testData = [
{ gender: 'zebra' },
{ gender: 'alpha' },
{ gender: 'beta' },
];
const testProps = {
...selectMultipleProps,
formData: {
...selectMultipleProps.formData,
sortMetric: undefined,
sortAscending: false,
},
queriesData: [
{
rowcount: 3,
colnames: ['gender'],
coltypes: [1],
data: testData,
applied_filters: [{ column: 'gender' }],
rejected_filters: [],
},
],
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
};
render(
// @ts-ignore
<SelectFilterPlugin
// @ts-ignore
{...transformProps(testProps)}
setDataMask={jest.fn()}
showOverflow={false}
/>,
{
useRedux: true,
initialState: {
nativeFilters: {
filters: {
'test-filter': {
name: 'Test Filter',
},
},
},
dataMask: {
'test-filter': {
extraFormData: {},
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
},
},
},
},
);
const filterSelect = screen.getAllByRole('combobox')[0];
userEvent.click(filterSelect);
// When sortAscending is false and no sortMetric, options should be sorted
// in descending alphabetical order (zebra, beta, alpha)
const options = screen.getAllByRole('option');
expect(options[0]).toHaveTextContent('zebra');
expect(options[1]).toHaveTextContent('beta');
expect(options[2]).toHaveTextContent('alpha');
});
test('preserves backend order even when sortAscending is false and sortMetric is specified', () => {
const testData = [
{ gender: 'zebra' },
{ gender: 'alpha' },
{ gender: 'beta' },
];
const testProps = {
...selectMultipleProps,
formData: {
...selectMultipleProps.formData,
sortMetric: 'count',
sortAscending: false,
},
queriesData: [
{
rowcount: 3,
colnames: ['gender'],
coltypes: [1],
data: testData,
applied_filters: [{ column: 'gender' }],
rejected_filters: [],
},
],
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
};
render(
// @ts-ignore
<SelectFilterPlugin
// @ts-ignore
{...transformProps(testProps)}
setDataMask={jest.fn()}
showOverflow={false}
/>,
{
useRedux: true,
initialState: {
nativeFilters: {
filters: {
'test-filter': {
name: 'Test Filter',
},
},
},
dataMask: {
'test-filter': {
extraFormData: {},
filterState: {
value: [],
label: '',
excludeFilterValues: true,
},
},
},
},
},
);
const filterSelect = screen.getAllByRole('combobox')[0];
userEvent.click(filterSelect);
// When sortMetric is specified, original order should be preserved regardless
// of sortAscending value (zebra, alpha, beta)
const options = screen.getAllByRole('option');
expect(options[0]).toHaveTextContent('zebra');
expect(options[1]).toHaveTextContent('alpha');
expect(options[2]).toHaveTextContent('beta');
});
});

View File

@@ -317,13 +317,20 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
const sortComparator = useCallback(
(a: LabeledValue, b: LabeledValue) => {
// When sortMetric is specified, the backend already sorted the data correctly
// Don't override the backend's metric-based sorting with frontend alphabetical sorting
if (formData.sortMetric) {
return 0; // Preserve the original order from the backend
}
// Only apply alphabetical sorting when no sortMetric is specified
const labelComparator = propertyComparator('label');
if (formData.sortAscending) {
return labelComparator(a, b);
}
return labelComparator(b, a);
},
[formData.sortAscending],
[formData.sortAscending, formData.sortMetric],
);
// Use effect for initialisation for filter plugin