DashboardSceneSerializerLike: Update interface to support initial version and snapshot url (#98206)

* Make dashboard prompt ignoreChanges schema version independent

* Serializer: add interface for snapshot url retrieval

* Revert "Make dashboard prompt ignoreChanges schema version independent"

This reverts commit 65466c2ef1.

* Add dashbaord version to scene metadata

* Add tracking info

* Revert "Add tracking info"

This reverts commit 4c58c6687b.

---------

Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com>
This commit is contained in:
Dominik Prokop 2024-12-19 16:09:19 +01:00 committed by GitHub
parent a37b6f455e
commit 746bde0fac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 60 additions and 19 deletions

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 {
@ -155,16 +155,12 @@ const getStyles = () => ({
export function ignoreChanges(scene: DashboardScene | null) { export function ignoreChanges(scene: DashboardScene | null) {
const original = scene?.getInitialSaveModel(); const original = scene?.getInitialSaveModel();
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 (scene?.state.meta.version === 0) {
return true; return true;
} }

View File

@ -168,6 +168,7 @@ describe('DashboardScene', () => {
expect(scene.state.isDirty).toBe(false); expect(scene.state.isDirty).toBe(false);
scene.exitEditMode({ skipConfirm: true }); scene.exitEditMode({ skipConfirm: true });
expect(scene.state.title).toEqual('Updated title'); expect(scene.state.title).toEqual('Updated title');
expect(scene.state.meta.version).toEqual(2);
}); });
it('Should start the detect changes worker', () => { it('Should start the detect changes worker', () => {

View File

@ -281,6 +281,7 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
slug: result.slug, slug: result.slug,
folderUid: folderUid, folderUid: folderUid,
isNew: false, isNew: false,
version: result.version,
}, },
}); });
@ -642,6 +643,10 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
return this._serializer.initialSaveModel; return this._serializer.initialSaveModel;
} }
public getSnapshotUrl = () => {
return this._serializer.getSnapshotUrl();
};
/** 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(saveModel?: Dashboard | DashboardV2Spec) {
this._serializer.initialSaveModel = saveModel; this._serializer.initialSaveModel = saveModel;

View File

@ -34,7 +34,7 @@ import { DashboardInteractions } from '../utils/interactions';
import { DynamicDashNavButtonModel, dynamicDashNavActions } from '../utils/registerDynamicDashNavAction'; import { DynamicDashNavButtonModel, dynamicDashNavActions } from '../utils/registerDynamicDashNavAction';
import { isLibraryPanel } from '../utils/utils'; import { isLibraryPanel } from '../utils/utils';
import { DashboardScene, isV2Dashboard } from './DashboardScene'; import { DashboardScene } from './DashboardScene';
import { GoToSnapshotOriginButton } from './GoToSnapshotOriginButton'; import { GoToSnapshotOriginButton } from './GoToSnapshotOriginButton';
interface Props { interface Props {
@ -140,17 +140,9 @@ export function ToolbarActions({ dashboard }: Props) {
toolbarActions.push({ toolbarActions.push({
group: 'icon-actions', group: 'icon-actions',
condition: meta.isSnapshot && !meta.dashboardNotFound && !isEditing, condition: meta.isSnapshot && !meta.dashboardNotFound && !isEditing,
render: () => { render: () => (
const saveModel = dashboard.getInitialSaveModel(); <GoToSnapshotOriginButton key="go-to-snapshot-origin" originalURL={dashboard.getSnapshotUrl() ?? ''} />
),
if (saveModel && isV2Dashboard(saveModel)) {
throw new Error('v2 schema not implemented');
}
return (
<GoToSnapshotOriginButton key="go-to-snapshot-origin" originalURL={saveModel?.snapshot?.originalUrl ?? ''} />
);
},
}); });
if (!isEditingPanel && !isEditing) { if (!isEditingPanel && !isEditing) {

View File

@ -326,6 +326,33 @@ describe('DashboardSceneSerializer', () => {
}); });
}); });
}); });
it('should allow retrieving snapshot url', () => {
const initialSaveModel: Dashboard = {
snapshot: {
originalUrl: 'originalUrl/snapshot',
created: '2023-01-01T00:00:00Z',
expires: '2023-12-31T23:59:59Z',
external: false,
externalUrl: '',
id: 1,
key: 'snapshot-key',
name: 'snapshot-name',
orgId: 1,
updated: '2023-01-01T00:00:00Z',
userId: 1,
},
title: 'hello',
uid: 'my-uid',
schemaVersion: 30,
version: 10,
};
const serializer = new V1DashboardSerializer();
serializer.initialSaveModel = initialSaveModel;
expect(serializer.getSnapshotUrl()).toBe('originalUrl/snapshot');
});
}); });
describe('v2 schema', () => { describe('v2 schema', () => {
@ -563,6 +590,11 @@ describe('DashboardSceneSerializer', () => {
}) })
).toThrow('Method not implemented.'); ).toThrow('Method not implemented.');
}); });
it('should throw on getSnapshotUrl', () => {
const serializer = new V2DashboardSerializer();
expect(() => serializer.getSnapshotUrl()).toThrow('Method not implemented.');
});
}); });
}); });

View File

@ -29,6 +29,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;
getSnapshotUrl: () => string | undefined;
} }
interface DashboardTrackingInfo { interface DashboardTrackingInfo {
@ -111,6 +112,10 @@ export class V1DashboardSerializer implements DashboardSceneSerializerLike<Dashb
} }
return undefined; return undefined;
} }
getSnapshotUrl() {
return this.initialSaveModel?.snapshot?.originalUrl;
}
} }
export class V2DashboardSerializer implements DashboardSceneSerializerLike<DashboardV2Spec> { export class V2DashboardSerializer implements DashboardSceneSerializerLike<DashboardV2Spec> {
@ -158,6 +163,11 @@ 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;
} }
getSnapshotUrl() {
throw new Error('v2 schema: Method not implemented.');
return undefined;
}
} }
export function getDashboardSceneSerializer(): DashboardSceneSerializerLike<Dashboard | DashboardV2Spec> { export function getDashboardSceneSerializer(): DashboardSceneSerializerLike<Dashboard | DashboardV2Spec> {

View File

@ -120,7 +120,9 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo<D
isDirty: false, isDirty: false,
links: dashboard.links, links: dashboard.links,
// TODO: Combine access and metadata to compose the V1 meta object // TODO: Combine access and metadata to compose the V1 meta object
meta: {}, meta: {
version: parseInt(metadata.resourceVersion, 10),
},
tags: dashboard.tags, tags: dashboard.tags,
title: dashboard.title, title: dashboard.title,
uid: metadata.name, uid: metadata.name,

View File

@ -118,6 +118,7 @@ export function ensureV1Response(
isFolder: false, isFolder: false,
uid: dashboard.metadata.name, uid: dashboard.metadata.name,
k8s: dashboard.metadata, k8s: dashboard.metadata,
version: parseInt(dashboard.metadata.resourceVersion, 10),
}, },
dashboard: spec, dashboard: spec,
}; };

View File

@ -88,6 +88,7 @@ export class K8sDashboardAPI implements DashboardAPI<DashboardDTO> {
isFolder: false, isFolder: false,
uid: dash.metadata.name, uid: dash.metadata.name,
k8s: dash.metadata, k8s: dash.metadata,
version: parseInt(dash.metadata.resourceVersion, 10),
}, },
dashboard: dash.spec, dashboard: dash.spec,
}; };

View File

@ -69,6 +69,7 @@ export interface DashboardMeta {
dashboardNotFound?: boolean; dashboardNotFound?: boolean;
isEmbedded?: boolean; isEmbedded?: boolean;
isNew?: boolean; isNew?: boolean;
version?: number;
// When loaded from kubernetes, we stick the raw metadata here // When loaded from kubernetes, we stick the raw metadata here
// yes weird, but this means all the editor structures can exist unchanged // yes weird, but this means all the editor structures can exist unchanged