Make dashboard prompt ignoreChanges schema version independent

This commit is contained in:
Dominik Prokop 2024-12-18 16:33:41 +01:00
parent 30321a59a9
commit 65466c2ef1
9 changed files with 54 additions and 20 deletions

View File

@ -24,7 +24,7 @@ describe('DashboardPrompt', () => {
describe('when called without original dashboard', () => { describe('when called without original dashboard', () => {
it('then it should return true', () => { it('then it should return true', () => {
const scene = buildTestScene(); const scene = buildTestScene();
scene.setInitialSaveModel(undefined); scene.setInitialSaveModel(undefined, undefined);
expect(ignoreChanges(scene)).toBe(true); expect(ignoreChanges(scene)).toBe(true);
}); });
}); });
@ -59,7 +59,7 @@ describe('DashboardPrompt', () => {
}, },
}); });
const initialSaveModel = transformSceneToSaveModel(scene); const initialSaveModel = transformSceneToSaveModel(scene);
scene.setInitialSaveModel(initialSaveModel); scene.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
contextSrv.isEditor = false; contextSrv.isEditor = false;
@ -76,7 +76,7 @@ describe('DashboardPrompt', () => {
}, },
}); });
const initialSaveModel = transformSceneToSaveModel(scene); const initialSaveModel = transformSceneToSaveModel(scene);
scene.setInitialSaveModel(initialSaveModel); scene.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
contextSrv.isSignedIn = false; contextSrv.isSignedIn = false;
expect(ignoreChanges(scene)).toBe(true); expect(ignoreChanges(scene)).toBe(true);
@ -92,7 +92,7 @@ describe('DashboardPrompt', () => {
}, },
}); });
const initialSaveModel = transformSceneToSaveModel(scene); const initialSaveModel = transformSceneToSaveModel(scene);
scene.setInitialSaveModel(initialSaveModel); scene.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
expect(ignoreChanges(scene)).toBe(true); expect(ignoreChanges(scene)).toBe(true);
}); });
@ -108,7 +108,7 @@ describe('DashboardPrompt', () => {
}, },
}); });
const initialSaveModel = transformSceneToSaveModel(scene); const initialSaveModel = transformSceneToSaveModel(scene);
scene.setInitialSaveModel(initialSaveModel); scene.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
expect(ignoreChanges(scene)).toBe(true); expect(ignoreChanges(scene)).toBe(true);
}); });
@ -124,7 +124,7 @@ describe('DashboardPrompt', () => {
}, },
}); });
const initialSaveModel = transformSceneToSaveModel(scene); const initialSaveModel = transformSceneToSaveModel(scene);
scene.setInitialSaveModel(initialSaveModel); scene.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
expect(ignoreChanges(scene)).toBe(undefined); expect(ignoreChanges(scene)).toBe(undefined);
}); });

View File

@ -8,7 +8,7 @@ import { Prompt } from 'app/core/components/FormPrompt/Prompt';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import { SaveLibraryVizPanelModal } from '../panel-edit/SaveLibraryVizPanelModal'; import { SaveLibraryVizPanelModal } from '../panel-edit/SaveLibraryVizPanelModal';
import { DashboardScene, isV2Dashboard } from '../scene/DashboardScene'; import { DashboardScene } from '../scene/DashboardScene';
import { getLibraryPanelBehavior, isLibraryPanel } from '../utils/utils'; import { getLibraryPanelBehavior, isLibraryPanel } from '../utils/utils';
interface DashboardPromptProps { interface DashboardPromptProps {
@ -154,17 +154,14 @@ const getStyles = () => ({
*/ */
export function ignoreChanges(scene: DashboardScene | null) { export function ignoreChanges(scene: DashboardScene | null) {
const original = scene?.getInitialSaveModel(); const original = scene?.getInitialSaveModel();
const originalVersion = scene?.getInitialVersion();
if (original && isV2Dashboard(original)) {
throw new Error('isV2Dashboard is not implemented');
}
if (!original) { if (!original) {
return true; return true;
} }
// Ignore changes if original is unsaved // Ignore changes if original is unsaved
if (original.version === 0) { if (originalVersion === 0) {
return true; return true;
} }

View File

@ -215,7 +215,7 @@ function setup() {
dashboard.setState({ $data: undefined }); dashboard.setState({ $data: undefined });
const initialSaveModel = transformSceneToSaveModel(dashboard); const initialSaveModel = transformSceneToSaveModel(dashboard);
dashboard.setInitialSaveModel(initialSaveModel); dashboard.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
cleanUp(); cleanUp();
cleanUp = dashboard.activate(); cleanUp = dashboard.activate();

View File

@ -173,7 +173,7 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
private _prevScrollPos?: number; private _prevScrollPos?: number;
// TODO: use feature toggle to allow v2 serializer // TODO: use feature toggle to allow v2 serializer
private _serializer: DashboardSceneSerializerLike<Dashboard | DashboardV2Spec> = getDashboardSceneSerializer(true); private _serializer: DashboardSceneSerializerLike<Dashboard | DashboardV2Spec> = getDashboardSceneSerializer();
public constructor(state: Partial<DashboardSceneState>) { public constructor(state: Partial<DashboardSceneState>) {
super({ super({
@ -642,9 +642,14 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
return this._serializer.initialSaveModel; return this._serializer.initialSaveModel;
} }
public getInitialVersion = () => {
return this._serializer.getInitialVersion();
};
/** Hacky temp function until we refactor transformSaveModelToScene a bit */ /** Hacky temp function until we refactor transformSaveModelToScene a bit */
public setInitialSaveModel(saveModel?: Dashboard | DashboardV2Spec) { public setInitialSaveModel(version: number | undefined, saveModel?: Dashboard | DashboardV2Spec) {
this._serializer.initialSaveModel = saveModel; this._serializer.initialSaveModel = saveModel;
this._serializer.initialVersion = version;
} }
public getTrackingInformation() { public getTrackingInformation() {

View File

@ -17,6 +17,21 @@ import { findVizPanelByKey } from '../utils/utils';
import { V1DashboardSerializer, V2DashboardSerializer } from './DashboardSceneSerializer'; import { V1DashboardSerializer, V2DashboardSerializer } from './DashboardSceneSerializer';
describe('DashboardSceneSerializer', () => { describe('DashboardSceneSerializer', () => {
it('should allow retrieving initial dashboard version', () => {
const dashboard = transformSaveModelToScene({
dashboard: {
title: 'hello',
uid: 'my-uid',
schemaVersion: 30,
version: 10,
},
meta: {},
});
const initialSaveModel = transformSceneToSaveModel(dashboard);
dashboard.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
expect(dashboard.getInitialVersion()).toBe(10);
});
describe('v1 schema', () => { describe('v1 schema', () => {
it('Can detect no changes', () => { it('Can detect no changes', () => {
const dashboard = setup(); const dashboard = setup();
@ -160,7 +175,7 @@ describe('DashboardSceneSerializer', () => {
meta: {}, meta: {},
}); });
const initialSaveModel = transformSceneToSaveModel(dashboard); const initialSaveModel = transformSceneToSaveModel(dashboard);
dashboard.setInitialSaveModel(initialSaveModel); dashboard.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
const variable = sceneGraph.lookupVariable('GroupBy', dashboard) as GroupByVariable; const variable = sceneGraph.lookupVariable('GroupBy', dashboard) as GroupByVariable;
variable.setState({ defaultOptions: [{ text: 'Host', value: 'host' }] }); variable.setState({ defaultOptions: [{ text: 'Host', value: 'host' }] });
@ -217,7 +232,7 @@ describe('DashboardSceneSerializer', () => {
}); });
const initialSaveModel = transformSceneToSaveModel(dashboard); const initialSaveModel = transformSceneToSaveModel(dashboard);
dashboard.setInitialSaveModel(initialSaveModel); dashboard.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
const variable = sceneGraph.lookupVariable('adhoc', dashboard) as AdHocFiltersVariable; const variable = sceneGraph.lookupVariable('adhoc', dashboard) as AdHocFiltersVariable;
variable.setState({ defaultKeys: [{ text: 'Host', value: 'host' }] }); variable.setState({ defaultKeys: [{ text: 'Host', value: 'host' }] });
@ -378,7 +393,7 @@ function setup(options: ScenarioOptions = {}) {
}); });
const initialSaveModel = transformSceneToSaveModel(dashboard); const initialSaveModel = transformSceneToSaveModel(dashboard);
dashboard.setInitialSaveModel(initialSaveModel); dashboard.setInitialSaveModel(initialSaveModel.version, initialSaveModel);
return dashboard; return dashboard;
} }

View File

@ -17,6 +17,7 @@ export interface DashboardSceneSerializerLike<T> {
* The save model which the dashboard scene was originally created from * The save model which the dashboard scene was originally created from
*/ */
initialSaveModel?: T; initialSaveModel?: T;
initialVersion?: number;
getSaveModel: (s: DashboardScene) => T; getSaveModel: (s: DashboardScene) => T;
getSaveAsModel: (s: DashboardScene, options: SaveDashboardAsOptions) => T; getSaveAsModel: (s: DashboardScene, options: SaveDashboardAsOptions) => T;
getDashboardChangesFromScene: ( getDashboardChangesFromScene: (
@ -29,6 +30,7 @@ export interface DashboardSceneSerializerLike<T> {
) => DashboardChangeInfo; ) => DashboardChangeInfo;
onSaveComplete(saveModel: T, result: SaveDashboardResponseDTO): void; onSaveComplete(saveModel: T, result: SaveDashboardResponseDTO): void;
getTrackingInformation: () => DashboardTrackingInfo | undefined; getTrackingInformation: () => DashboardTrackingInfo | undefined;
getInitialVersion: () => number | undefined;
} }
interface DashboardTrackingInfo { interface DashboardTrackingInfo {
@ -43,6 +45,7 @@ interface DashboardTrackingInfo {
export class V1DashboardSerializer implements DashboardSceneSerializerLike<Dashboard> { export class V1DashboardSerializer implements DashboardSceneSerializerLike<Dashboard> {
initialSaveModel?: Dashboard; initialSaveModel?: Dashboard;
initialVersion?: number | undefined;
getSaveModel(s: DashboardScene) { getSaveModel(s: DashboardScene) {
return transformSceneToSaveModel(s); return transformSceneToSaveModel(s);
@ -111,10 +114,15 @@ export class V1DashboardSerializer implements DashboardSceneSerializerLike<Dashb
} }
return undefined; return undefined;
} }
getInitialVersion() {
return this.initialVersion;
}
} }
export class V2DashboardSerializer implements DashboardSceneSerializerLike<DashboardV2Spec> { export class V2DashboardSerializer implements DashboardSceneSerializerLike<DashboardV2Spec> {
initialSaveModel?: DashboardV2Spec; initialSaveModel?: DashboardV2Spec;
initialVersion?: number | undefined;
getSaveModel(s: DashboardScene) { getSaveModel(s: DashboardScene) {
return transformSceneToSaveModelSchemaV2(s); return transformSceneToSaveModelSchemaV2(s);
@ -140,6 +148,10 @@ export class V2DashboardSerializer implements DashboardSceneSerializerLike<Dashb
throw new Error('v2 schema: Method not implemented.'); throw new Error('v2 schema: Method not implemented.');
return undefined; return undefined;
} }
getInitialVersion() {
return this.initialVersion;
}
} }
export function getDashboardSceneSerializer( export function getDashboardSceneSerializer(

View File

@ -176,6 +176,11 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo<D
}), }),
}); });
dashboardScene.setInitialSaveModel(
dto.metadata.resourceVersion ? parseInt(dto.metadata.resourceVersion, 10) : undefined,
dto.spec
);
return dashboardScene; return dashboardScene;
} }

View File

@ -71,7 +71,7 @@ export function transformSaveModelToScene(rsp: DashboardDTO): DashboardScene {
const scene = createDashboardSceneFromDashboardModel(oldModel, rsp.dashboard); const scene = createDashboardSceneFromDashboardModel(oldModel, rsp.dashboard);
// TODO: refactor createDashboardSceneFromDashboardModel to work on Dashboard schema model // TODO: refactor createDashboardSceneFromDashboardModel to work on Dashboard schema model
scene.setInitialSaveModel(rsp.dashboard); scene.setInitialSaveModel(rsp.dashboard.version, rsp.dashboard);
return scene; return scene;
} }

View File

@ -73,7 +73,7 @@ export class JsonModelEditView extends SceneObjectBase<JsonModelEditViewState> i
const newState = sceneUtils.cloneSceneObjectState(newDashboardScene.state); const newState = sceneUtils.cloneSceneObjectState(newDashboardScene.state);
dashboard.pauseTrackingChanges(); dashboard.pauseTrackingChanges();
dashboard.setInitialSaveModel(rsp.dashboard); dashboard.setInitialSaveModel(rsp.dashboard.version, rsp.dashboard);
dashboard.setState(newState); dashboard.setState(newState);
this.setState({ jsonText: this.getJsonText() }); this.setState({ jsonText: this.getJsonText() });