Dashboard: Improve diffing by handling the Infinity value (#105037)

* convert infinity values to 0

* convert infinity in V1 transformer

* update test
pull/105283/head
Haris Rozajac 1 week ago committed by GitHub
parent cc4d151487
commit 82f0a58490
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 16
      public/app/core/utils/object.test.ts
  2. 22
      public/app/core/utils/object.ts
  3. 2
      public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
  4. 2
      public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts

@ -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 {

@ -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);

Loading…
Cancel
Save