mirror of
https://github.com/apache/superset.git
synced 2026-04-20 08:34:37 +00:00
fix(filters): preserve backend metric-based sorting (#35152)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
4d0fdba97a
commit
909bd877c9
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user