Dashboard: Improve diffing by handling the Infinity value (#105037)
* convert infinity values to 0 * convert infinity in V1 transformer * update test
This commit is contained in:
@@ -19,6 +19,22 @@ describe('objects', () => {
|
||||
world: {
|
||||
deeper: 10,
|
||||
arr: [null, 1, 'hello'],
|
||||
value: -Infinity,
|
||||
},
|
||||
simple: 'A',
|
||||
});
|
||||
expect(value.hello).toBeNull();
|
||||
expect(value.world.foo).toBeNull();
|
||||
expect(value.bar).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns a clean copy with Infinity converted to 0', () => {
|
||||
const copy = sortedDeepCloneWithoutNulls(value, true);
|
||||
expect(copy).toMatchObject({
|
||||
world: {
|
||||
deeper: 10,
|
||||
arr: [null, 1, 'hello'],
|
||||
value: 0,
|
||||
},
|
||||
simple: 'A',
|
||||
});
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
import { isArray, isPlainObject } from 'lodash';
|
||||
|
||||
/** @returns a deep clone of the object, but with any null value removed */
|
||||
export function sortedDeepCloneWithoutNulls<T>(value: T): T {
|
||||
/**
|
||||
* @returns A deep clone of the object, but with any null value removed.
|
||||
* @param value - The object to be cloned and cleaned.
|
||||
* @param convertInfinity - If true, -Infinity or Infinity is converted to 0.
|
||||
* This is because Infinity is not a valid JSON value, and sometimes we want to convert it to 0 instead of default null.
|
||||
*/
|
||||
export function sortedDeepCloneWithoutNulls<T>(value: T, convertInfinity?: boolean): T {
|
||||
if (isArray(value)) {
|
||||
return value.map(sortedDeepCloneWithoutNulls) as unknown as T;
|
||||
return value.map((item) => sortedDeepCloneWithoutNulls(item, convertInfinity)) as unknown as T;
|
||||
}
|
||||
if (isPlainObject(value)) {
|
||||
return Object.keys(value as { [key: string]: any })
|
||||
.sort()
|
||||
.reduce((acc: any, key) => {
|
||||
const v = (value as any)[key];
|
||||
// Remove null values and also -Infinity which is not a valid JSON value
|
||||
if (v != null && v !== -Infinity) {
|
||||
acc[key] = sortedDeepCloneWithoutNulls(v);
|
||||
// Remove null values
|
||||
if (v != null) {
|
||||
acc[key] = sortedDeepCloneWithoutNulls(v, convertInfinity);
|
||||
}
|
||||
|
||||
if (convertInfinity && (v === Infinity || v === -Infinity)) {
|
||||
acc[key] = 0;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
|
||||
scopeMeta: state.scopeMeta,
|
||||
};
|
||||
|
||||
return sortedDeepCloneWithoutNulls(dashboard);
|
||||
return sortedDeepCloneWithoutNulls(dashboard, true);
|
||||
}
|
||||
|
||||
export function gridItemToPanel(gridItem: DashboardGridItem, isSnapshot = false): Panel {
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ export function transformSceneToSaveModelSchemaV2(scene: DashboardScene, isSnaps
|
||||
try {
|
||||
// validateDashboardSchemaV2 will throw an error if the dashboard is not valid
|
||||
if (validateDashboardSchemaV2(dashboardSchemaV2)) {
|
||||
return sortedDeepCloneWithoutNulls(dashboardSchemaV2);
|
||||
return sortedDeepCloneWithoutNulls(dashboardSchemaV2, true);
|
||||
}
|
||||
// should never reach this point, validation should throw an error
|
||||
throw new Error('Error we could transform the dashboard to schema v2: ' + dashboardSchemaV2);
|
||||
|
||||
Reference in New Issue
Block a user