DashboardScene: Support auto migration for angular panels (#76100)

* DashboardScene: Support auto migration for angular panels

* minor tweak

* Update scenes

* Review fix

* Update
This commit is contained in:
Torkel Ödegaard 2023-10-10 14:33:58 +02:00 committed by GitHub
parent ea741dda6b
commit 42218fbdbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 86 additions and 22 deletions

View File

@ -3007,6 +3007,10 @@ exports[`better eslint`] = {
"public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
"public/app/features/dashboard-scene/serialization/angularMigration.test.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
@ -3579,18 +3583,19 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "9"],
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
[0, 0, 0, "Do not use any type assertions.", "12"],
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
[0, 0, 0, "Do not use any type assertions.", "14"],
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
[0, 0, 0, "Do not use any type assertions.", "13"],
[0, 0, 0, "Unexpected any. Specify a different type.", "14"],
[0, 0, 0, "Do not use any type assertions.", "15"],
[0, 0, 0, "Unexpected any. Specify a different type.", "16"],
[0, 0, 0, "Unexpected any. Specify a different type.", "17"],
[0, 0, 0, "Do not use any type assertions.", "18"],
[0, 0, 0, "Unexpected any. Specify a different type.", "19"],
[0, 0, 0, "Do not use any type assertions.", "20"],
[0, 0, 0, "Unexpected any. Specify a different type.", "21"],
[0, 0, 0, "Unexpected any. Specify a different type.", "18"],
[0, 0, 0, "Do not use any type assertions.", "19"],
[0, 0, 0, "Unexpected any. Specify a different type.", "20"],
[0, 0, 0, "Do not use any type assertions.", "21"],
[0, 0, 0, "Unexpected any. Specify a different type.", "22"],
[0, 0, 0, "Unexpected any. Specify a different type.", "23"]
[0, 0, 0, "Unexpected any. Specify a different type.", "23"],
[0, 0, 0, "Unexpected any. Specify a different type.", "24"]
],
"public/app/features/dashboard/state/TimeModel.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],

View File

@ -250,7 +250,7 @@
"@grafana/lezer-traceql": "0.0.6",
"@grafana/monaco-logql": "^0.0.7",
"@grafana/runtime": "workspace:*",
"@grafana/scenes": "^1.13.0",
"@grafana/scenes": "^1.15.0",
"@grafana/schema": "workspace:*",
"@grafana/ui": "workspace:*",
"@kusto/monaco-kusto": "^7.4.0",

View File

@ -0,0 +1,35 @@
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
import { PanelModel } from 'app/features/dashboard/state';
import { getAngularPanelMigrationHandler } from './angularMigration';
describe('getAngularPanelMigrationHandler', () => {
describe('Given an old angular panel', () => {
it('Should call migration handler', () => {
const onPanelTypeChanged = (panel: PanelModel, prevPluginId: string, prevOptions: Record<string, any>) => {
panel.fieldConfig = { defaults: { unit: 'bytes' }, overrides: [] };
return { name: prevOptions.angular.oldOptionProp };
};
const reactPlugin = getPanelPlugin({ id: 'timeseries' }).setPanelChangeHandler(onPanelTypeChanged as any);
const oldModel = new PanelModel({
autoMigrateFrom: 'graph',
oldOptionProp: 'old name',
type: 'timeseries',
});
const mutatedModel = {
id: 1,
type: 'timeseries',
options: {},
fieldConfig: { defaults: {}, overrides: [] },
};
getAngularPanelMigrationHandler(oldModel)(mutatedModel, reactPlugin);
expect(mutatedModel.options).toEqual({ name: 'old name' });
expect(mutatedModel.fieldConfig).toEqual({ defaults: { unit: 'bytes' }, overrides: [] });
});
});
});

View File

@ -0,0 +1,22 @@
import { PanelModel as PanelModelFromData, PanelPlugin } from '@grafana/data';
import { autoMigrateAngular, PanelModel } from 'app/features/dashboard/state/PanelModel';
export function getAngularPanelMigrationHandler(oldModel: PanelModel) {
return function handleAngularPanelMigrations(panel: PanelModelFromData, plugin: PanelPlugin) {
if (plugin.angularPanelCtrl) {
panel.options = { angularOptions: oldModel.getOptionsToRemember() };
return;
}
if (oldModel.autoMigrateFrom) {
const wasAngular = autoMigrateAngular[oldModel.autoMigrateFrom] != null;
const oldOptions = oldModel.getOptionsToRemember();
const prevPluginId = oldModel.autoMigrateFrom;
if (plugin.onPanelTypeChanged) {
const prevOptions = wasAngular ? { angular: oldOptions } : oldOptions.options;
Object.assign(panel.options, plugin.onPanelTypeChanged(panel, prevPluginId, prevOptions, panel.fieldConfig));
}
}
};
}

View File

@ -122,7 +122,6 @@ describe('sceneVariablesSetToVariables', () => {
"query": "query",
"refresh": 1,
"regex": "",
"sort": 1,
}
`);
});

View File

@ -46,6 +46,8 @@ import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
import { getVizPanelKeyForPanelId } from '../utils/utils';
import { getAngularPanelMigrationHandler } from './angularMigration';
export interface DashboardLoaderState {
dashboard?: DashboardScene;
isLoading?: boolean;
@ -338,6 +340,7 @@ export function buildGridItemForPanel(panel: PanelModel): SceneGridItemLike {
menu: new VizPanelMenu({
$behaviors: [panelMenuBehavior],
}),
_UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel),
};
if (panel.timeFrom || panel.timeShift) {

View File

@ -394,7 +394,7 @@ export class PanelModel implements DataConfigSource, IPanelModel {
}
}
private getOptionsToRemember() {
public getOptionsToRemember(): any {
return Object.keys(this).reduce((acc, property) => {
if (notPersistedProperties[property] || mustKeepProps[property]) {
return acc;

View File

@ -50,7 +50,7 @@ export function getVariablesDefinitions() {
new QueryVariable({
name: 'instance',
datasource: { uid: 'gdev-prometheus' },
query: { query: 'label_values(grafana_http_request_duration_seconds_sum, instance)' },
query: { query: 'label_values(grafana_http_request_duration_seconds_sum, instance)', refId: 'A' },
}),
],
});

View File

@ -31,19 +31,19 @@ export function getQueryVariableDemo(): DashboardScene {
new QueryVariable({
name: 'instance (using datasource variable)',
refresh: VariableRefresh.onTimeRangeChanged,
query: { query: 'label_values(go_gc_duration_seconds, ${metric})' },
query: { query: 'label_values(go_gc_duration_seconds, ${metric})', refId: 'A' },
datasource: { uid: '${datasource}' },
}),
new QueryVariable({
name: 'label values (on time range refresh)',
refresh: VariableRefresh.onTimeRangeChanged,
query: { query: 'label_values(go_gc_duration_seconds, ${metric})' },
query: { query: 'label_values(go_gc_duration_seconds, ${metric})', refId: 'B' },
datasource: { uid: 'gdev-prometheus', type: 'prometheus' },
}),
new QueryVariable({
name: 'legacy (graphite)',
refresh: VariableRefresh.onTimeRangeChanged,
query: { queryType: 'Default', target: 'stats.response.*' },
query: { queryType: 'Default', target: 'stats.response.*', refId: 'C' },
datasource: { uid: 'gdev-graphite', type: 'graphite' },
}),
],

View File

@ -79,7 +79,7 @@ export function getRepeatingPanelsDemo(): DashboardScene {
function changeVariable(variable: TestVariable) {
const sub = variable.subscribeToState((state, old) => {
if (!state.loading && old.loading) {
if (variable.state.optionsToReturn.length === 2) {
if (variable.state.optionsToReturn?.length === 2) {
variable.setState({
query: 'ABC',
optionsToReturn: [

View File

@ -3343,9 +3343,9 @@ __metadata:
languageName: unknown
linkType: soft
"@grafana/scenes@npm:^1.13.0":
version: 1.13.0
resolution: "@grafana/scenes@npm:1.13.0"
"@grafana/scenes@npm:^1.15.0":
version: 1.15.0
resolution: "@grafana/scenes@npm:1.15.0"
dependencies:
"@grafana/e2e-selectors": 10.0.2
react-grid-layout: 1.3.4
@ -3357,7 +3357,7 @@ __metadata:
"@grafana/runtime": 10.0.3
"@grafana/schema": 10.0.3
"@grafana/ui": 10.0.3
checksum: 3a6c4419ee324d49f41b9569dc86ca7ffa926438eedd762aa79c3327c39cd16b9671047ad02f5de3c52190a81b4139cdb75653a4b3741753f851ca0c9155b9bf
checksum: 8416327ad9a0e3be35d5a106788248d5886f6aa220777cf0772ef73a3f64ecac889f58a8e804beea0de339acd571d6e49a10278180cf1c50a2a51f44e03bf93e
languageName: node
linkType: hard
@ -17654,7 +17654,7 @@ __metadata:
"@grafana/lezer-traceql": 0.0.6
"@grafana/monaco-logql": ^0.0.7
"@grafana/runtime": "workspace:*"
"@grafana/scenes": ^1.13.0
"@grafana/scenes": ^1.15.0
"@grafana/schema": "workspace:*"
"@grafana/tsconfig": ^1.3.0-rc1
"@grafana/ui": "workspace:*"