mirror of
https://github.com/apache/superset.git
synced 2026-06-30 03:45:33 +00:00
Compare commits
1 Commits
fix/105973
...
fix/107166
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70843d668a |
@@ -57,6 +57,7 @@ import { SearchOption, SortByItem } from '../types';
|
||||
import getInitialSortState, { shouldSort } from '../utils/getInitialSortState';
|
||||
import getInitialFilterModel from '../utils/getInitialFilterModel';
|
||||
import reconcileColumnState from '../utils/reconcileColumnState';
|
||||
import getColumnStateSignature from '../utils/getColumnStateSignature';
|
||||
import { PAGE_SIZE_OPTIONS } from '../consts';
|
||||
import { getCompleteFilterState } from '../utils/filterStateManager';
|
||||
|
||||
@@ -337,11 +338,11 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
const stateHash = JSON.stringify({
|
||||
columnOrder: columnState.map(c => c.colId),
|
||||
sorts: sortModel,
|
||||
filters: filterModel,
|
||||
});
|
||||
const stateHash = getColumnStateSignature(
|
||||
columnState,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
|
||||
if (stateHash !== lastCapturedStateRef.current) {
|
||||
lastCapturedStateRef.current = stateHash;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { ColumnState } from '@superset-ui/core/components/ThemedAgGridReact';
|
||||
|
||||
type SortModelEntry = {
|
||||
colId: string;
|
||||
sort: 'asc' | 'desc';
|
||||
sortIndex: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a stable signature of the parts of AG Grid column state that must be
|
||||
* persisted (and therefore must trigger an `onColumnStateChange` when they
|
||||
* change): column order, per-column value aggregation, sorts and filters.
|
||||
*
|
||||
* The value aggregation (`aggFunc`) is normalized so that "no aggregation"
|
||||
* (the AG Grid "None" option, represented as `null`/`undefined`) produces a
|
||||
* distinct, stable signature. Without this, switching a column's Value
|
||||
* Aggregation to "None" did not change the signature, so the change was never
|
||||
* captured and the column reverted to its default aggregation on reload.
|
||||
*/
|
||||
export default function getColumnStateSignature(
|
||||
columnState: ColumnState[],
|
||||
sortModel: SortModelEntry[],
|
||||
filterModel: Record<string, unknown>,
|
||||
): string {
|
||||
return JSON.stringify({
|
||||
columnOrder: columnState.map(col => col.colId),
|
||||
aggregations: columnState.map(col => ({
|
||||
colId: col.colId,
|
||||
// Normalize falsy "None" (null/undefined) to an explicit sentinel so it
|
||||
// is preserved and distinguishable from a real aggregation function.
|
||||
aggFunc: col.aggFunc ?? null,
|
||||
})),
|
||||
sorts: sortModel,
|
||||
filters: filterModel,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import getColumnStateSignature from '../../src/utils/getColumnStateSignature';
|
||||
|
||||
const sortModel: any[] = [];
|
||||
const filterModel = {};
|
||||
|
||||
test('signature changes when a column value aggregation changes', () => {
|
||||
const before = getColumnStateSignature(
|
||||
[{ colId: 'sales', aggFunc: 'sum' }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
const after = getColumnStateSignature(
|
||||
[{ colId: 'sales', aggFunc: 'avg' }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
expect(after).not.toEqual(before);
|
||||
});
|
||||
|
||||
test('switching value aggregation to "None" (null/undefined) changes the signature', () => {
|
||||
// Regression test for #107166: selecting "None" must be captured so it
|
||||
// persists instead of reverting to the default Sum aggregation on reload.
|
||||
const sumState = getColumnStateSignature(
|
||||
[{ colId: 'sales', aggFunc: 'sum' }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
const noneNull = getColumnStateSignature(
|
||||
[{ colId: 'sales', aggFunc: null }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
const noneUndefined = getColumnStateSignature(
|
||||
[{ colId: 'sales' }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
|
||||
expect(noneNull).not.toEqual(sumState);
|
||||
expect(noneUndefined).not.toEqual(sumState);
|
||||
// null and undefined both represent "None" and must be treated identically.
|
||||
expect(noneNull).toEqual(noneUndefined);
|
||||
});
|
||||
|
||||
test('signature is stable when nothing changes', () => {
|
||||
const a = getColumnStateSignature(
|
||||
[{ colId: 'sales', aggFunc: 'sum' }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
const b = getColumnStateSignature(
|
||||
[{ colId: 'sales', aggFunc: 'sum' }] as any,
|
||||
sortModel,
|
||||
filterModel,
|
||||
);
|
||||
expect(a).toEqual(b);
|
||||
});
|
||||
Reference in New Issue
Block a user