mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboards: Unify angular auto-migration code (#63915)
This commit is contained in:
parent
f948482386
commit
36e8ca7f13
@ -85,7 +85,9 @@ it('handles a default datasource in a template variable', async () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const dashboardModel = new DashboardModel(dashboard, {}, () => dashboard.templating.list);
|
const dashboardModel = new DashboardModel(dashboard, undefined, {
|
||||||
|
getVariablesFromState: () => dashboard.templating.list,
|
||||||
|
});
|
||||||
const exporter = new DashboardExporter();
|
const exporter = new DashboardExporter();
|
||||||
const exported: any = await exporter.makeExportable(dashboardModel);
|
const exported: any = await exporter.makeExportable(dashboardModel);
|
||||||
expect(exported.templating.list[0].datasource.uid).toBe('${DS_GFDB}');
|
expect(exported.templating.list[0].datasource.uid).toBe('${DS_GFDB}');
|
||||||
@ -105,7 +107,9 @@ it('If a panel queries has no datasource prop ignore it', async () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const dashboardModel = new DashboardModel(dashboard, {}, () => []);
|
const dashboardModel = new DashboardModel(dashboard, undefined, {
|
||||||
|
getVariablesFromState: () => [],
|
||||||
|
});
|
||||||
const exporter = new DashboardExporter();
|
const exporter = new DashboardExporter();
|
||||||
const exported: any = await exporter.makeExportable(dashboardModel);
|
const exported: any = await exporter.makeExportable(dashboardModel);
|
||||||
expect(exported.panels[0].datasource).toEqual({ uid: '${DS_OTHER}', type: 'other' });
|
expect(exported.panels[0].datasource).toEqual({ uid: '${DS_OTHER}', type: 'other' });
|
||||||
@ -230,7 +234,13 @@ describe('given dashboard with repeated panels', () => {
|
|||||||
info: { version: '1.1.2' },
|
info: { version: '1.1.2' },
|
||||||
} as PanelPluginMeta;
|
} as PanelPluginMeta;
|
||||||
|
|
||||||
dash = new DashboardModel(dash, {}, () => dash.templating.list);
|
dash = new DashboardModel(
|
||||||
|
dash,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
getVariablesFromState: () => dash.templating.list,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// init library panels
|
// init library panels
|
||||||
dash.getPanelById(17).initLibraryPanel({
|
dash.getPanelById(17).initLibraryPanel({
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
TimeZone,
|
TimeZone,
|
||||||
UrlQueryValue,
|
UrlQueryValue,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { RefreshEvent, TimeRangeUpdatedEvent } from '@grafana/runtime';
|
import { RefreshEvent, TimeRangeUpdatedEvent, config } from '@grafana/runtime';
|
||||||
import { Dashboard } from '@grafana/schema';
|
import { Dashboard } from '@grafana/schema';
|
||||||
import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
|
import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
|
||||||
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, REPEAT_DIR_VERTICAL } from 'app/core/constants';
|
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, REPEAT_DIR_VERTICAL } from 'app/core/constants';
|
||||||
@ -41,7 +41,7 @@ import { getTimeSrv } from '../services/TimeSrv';
|
|||||||
import { mergePanels, PanelMergeInfo } from '../utils/panelMerge';
|
import { mergePanels, PanelMergeInfo } from '../utils/panelMerge';
|
||||||
|
|
||||||
import { DashboardMigrator } from './DashboardMigrator';
|
import { DashboardMigrator } from './DashboardMigrator';
|
||||||
import { GridPos, PanelModel } from './PanelModel';
|
import { GridPos, PanelModel, autoMigrateAngular } from './PanelModel';
|
||||||
import { TimeModel } from './TimeModel';
|
import { TimeModel } from './TimeModel';
|
||||||
import { deleteScopeVars, isOnTheSameGridRow } from './utils';
|
import { deleteScopeVars, isOnTheSameGridRow } from './utils';
|
||||||
|
|
||||||
@ -108,6 +108,7 @@ export class DashboardModel implements TimeModel {
|
|||||||
// repeat process cycles
|
// repeat process cycles
|
||||||
declare meta: DashboardMeta;
|
declare meta: DashboardMeta;
|
||||||
events: EventBusExtended;
|
events: EventBusExtended;
|
||||||
|
private getVariablesFromState: GetVariables;
|
||||||
|
|
||||||
static nonPersistedProperties: { [str: string]: boolean } = {
|
static nonPersistedProperties: { [str: string]: boolean } = {
|
||||||
events: true,
|
events: true,
|
||||||
@ -126,7 +127,18 @@ export class DashboardModel implements TimeModel {
|
|||||||
lastRefresh: true,
|
lastRefresh: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(data: Dashboard, meta?: DashboardMeta, private getVariablesFromState: GetVariables = getVariablesByKey) {
|
constructor(
|
||||||
|
data: Dashboard,
|
||||||
|
meta?: DashboardMeta,
|
||||||
|
options?: {
|
||||||
|
// By default this uses variables from redux state
|
||||||
|
getVariablesFromState?: GetVariables;
|
||||||
|
|
||||||
|
// Force the loader to migrate panels
|
||||||
|
autoMigrateOldPanels?: boolean;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
this.getVariablesFromState = options?.getVariablesFromState ?? getVariablesByKey;
|
||||||
this.events = new EventBusSrv();
|
this.events = new EventBusSrv();
|
||||||
this.id = data.id || null;
|
this.id = data.id || null;
|
||||||
// UID is not there for newly created dashboards
|
// UID is not there for newly created dashboards
|
||||||
@ -162,6 +174,17 @@ export class DashboardModel implements TimeModel {
|
|||||||
this.initMeta(meta);
|
this.initMeta(meta);
|
||||||
this.updateSchema(data);
|
this.updateSchema(data);
|
||||||
|
|
||||||
|
// Auto-migrate old angular panels
|
||||||
|
if (options?.autoMigrateOldPanels || !config.angularSupportEnabled || config.featureToggles.autoMigrateOldPanels) {
|
||||||
|
this.panels.forEach((p) => {
|
||||||
|
const newType = autoMigrateAngular[p.type];
|
||||||
|
if (!p.autoMigrateFrom && newType) {
|
||||||
|
p.autoMigrateFrom = p.type;
|
||||||
|
p.type = newType;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.addBuiltInAnnotationQuery();
|
this.addBuiltInAnnotationQuery();
|
||||||
this.sortPanelsByGridPos();
|
this.sortPanelsByGridPos();
|
||||||
this.panelsAffectedByVariableChange = null;
|
this.panelsAffectedByVariableChange = null;
|
||||||
|
@ -132,6 +132,19 @@ const defaults: any = {
|
|||||||
title: '',
|
title: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const autoMigrateAngular: Record<string, string> = {
|
||||||
|
graph: 'timeseries',
|
||||||
|
'table-old': 'table',
|
||||||
|
singlestat: 'stat', // also automigrated if dashboard schemaVerion < 27
|
||||||
|
'grafana-singlestat-panel': 'stat',
|
||||||
|
'grafana-piechart-panel': 'piechart',
|
||||||
|
'grafana-worldmap-panel': 'geomap',
|
||||||
|
};
|
||||||
|
|
||||||
|
const autoMigratePanelType: Record<string, string> = {
|
||||||
|
'heatmap-new': 'heatmap', // this was a temporary development panel that is now standard
|
||||||
|
};
|
||||||
|
|
||||||
export class PanelModel implements DataConfigSource, IPanelModel {
|
export class PanelModel implements DataConfigSource, IPanelModel {
|
||||||
/* persisted id, used in URL to identify a panel */
|
/* persisted id, used in URL to identify a panel */
|
||||||
id!: number;
|
id!: number;
|
||||||
@ -235,23 +248,10 @@ export class PanelModel implements DataConfigSource, IPanelModel {
|
|||||||
(this as any)[property] = model[property];
|
(this as any)[property] = model[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this.type) {
|
const newType = autoMigratePanelType[this.type];
|
||||||
case 'graph':
|
if (newType) {
|
||||||
if (config.featureToggles?.autoMigrateOldPanels || !config.angularSupportEnabled) {
|
this.autoMigrateFrom = this.type;
|
||||||
this.autoMigrateFrom = this.type;
|
this.type = newType;
|
||||||
this.type = 'timeseries';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'table-old':
|
|
||||||
if (config.featureToggles?.autoMigrateOldPanels || !config.angularSupportEnabled) {
|
|
||||||
this.autoMigrateFrom = this.type;
|
|
||||||
this.type = 'table';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'heatmap-new':
|
|
||||||
this.autoMigrateFrom = this.type;
|
|
||||||
this.type = 'heatmap';
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
@ -427,7 +427,7 @@ export class PanelModel implements DataConfigSource, IPanelModel {
|
|||||||
const version = getPluginVersion(plugin);
|
const version = getPluginVersion(plugin);
|
||||||
|
|
||||||
if (this.autoMigrateFrom) {
|
if (this.autoMigrateFrom) {
|
||||||
const wasAngular = this.autoMigrateFrom === 'graph' || this.autoMigrateFrom === 'table-old';
|
const wasAngular = autoMigrateAngular[this.autoMigrateFrom] != null;
|
||||||
this.callPanelTypeChangeHandler(
|
this.callPanelTypeChangeHandler(
|
||||||
plugin,
|
plugin,
|
||||||
this.autoMigrateFrom,
|
this.autoMigrateFrom,
|
||||||
|
@ -27,7 +27,7 @@ export function createDashboardModelFixture(
|
|||||||
...dashboardInput,
|
...dashboardInput,
|
||||||
};
|
};
|
||||||
|
|
||||||
return new DashboardModel(dashboardJson, meta, getVariablesFromState);
|
return new DashboardModel(dashboardJson, meta, { getVariablesFromState });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createPanelJSONFixture(panelInput: Partial<Panel | GraphPanel | RowPanel> = {}): Panel {
|
export function createPanelJSONFixture(panelInput: Partial<Panel | GraphPanel | RowPanel> = {}): Panel {
|
||||||
|
@ -25,7 +25,6 @@ import {
|
|||||||
import { StateManagerBase } from 'app/core/services/StateManagerBase';
|
import { StateManagerBase } from 'app/core/services/StateManagerBase';
|
||||||
import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
|
import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
|
||||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||||
import { graphToTimeseriesOptions } from 'app/plugins/panel/timeseries/migrations';
|
|
||||||
import { DashboardDTO } from 'app/types';
|
import { DashboardDTO } from 'app/types';
|
||||||
|
|
||||||
import { DashboardScene } from './DashboardScene';
|
import { DashboardScene } from './DashboardScene';
|
||||||
@ -63,7 +62,9 @@ export class DashboardLoader extends StateManagerBase<DashboardLoaderState> {
|
|||||||
|
|
||||||
private initDashboard(rsp: DashboardDTO) {
|
private initDashboard(rsp: DashboardDTO) {
|
||||||
// Just to have migrations run
|
// Just to have migrations run
|
||||||
const oldModel = new DashboardModel(rsp.dashboard, rsp.meta);
|
const oldModel = new DashboardModel(rsp.dashboard, rsp.meta, {
|
||||||
|
autoMigrateOldPanels: true,
|
||||||
|
});
|
||||||
|
|
||||||
const dashboard = createDashboardSceneFromDashboardModel(oldModel);
|
const dashboard = createDashboardSceneFromDashboardModel(oldModel);
|
||||||
|
|
||||||
@ -262,14 +263,6 @@ export function createVizPanelFromPanelModel(panel: PanelModel) {
|
|||||||
maxDataPoints: panel.maxDataPoints ?? undefined,
|
maxDataPoints: panel.maxDataPoints ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Migrate graph to timeseries
|
|
||||||
if (panel.type === 'graph') {
|
|
||||||
const { fieldConfig, options } = graphToTimeseriesOptions(panel);
|
|
||||||
panel.fieldConfig = fieldConfig;
|
|
||||||
panel.options = options;
|
|
||||||
panel.type = 'timeseries';
|
|
||||||
}
|
|
||||||
|
|
||||||
return new VizPanel({
|
return new VizPanel({
|
||||||
title: panel.title,
|
title: panel.title,
|
||||||
pluginId: panel.type,
|
pluginId: panel.type,
|
||||||
|
@ -60,13 +60,13 @@ describe('PieChart -> PieChartV2 migrations', () => {
|
|||||||
expect(options).toMatchObject({ displayLabels: [PieChartLabels.Name, PieChartLabels.Value] });
|
expect(options).toMatchObject({ displayLabels: [PieChartLabels.Name, PieChartLabels.Value] });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the legend when no legend values are selected', () => {
|
it('hides the legend when show is false', () => {
|
||||||
const panel = { options: {} } as PanelModel;
|
const panel = { options: {} } as PanelModel;
|
||||||
|
|
||||||
const oldPieChartOptions = {
|
const oldPieChartOptions = {
|
||||||
angular: {
|
angular: {
|
||||||
legendType: 'On graph',
|
legendType: 'On graph',
|
||||||
legend: {},
|
legend: { show: false },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const options = PieChartPanelChangedHandler(panel, 'grafana-piechart-panel', oldPieChartOptions);
|
const options = PieChartPanelChangedHandler(panel, 'grafana-piechart-panel', oldPieChartOptions);
|
||||||
|
@ -102,10 +102,6 @@ export const PieChartPanelChangedHandler = (
|
|||||||
if (angular.legend.percentage) {
|
if (angular.legend.percentage) {
|
||||||
options.legend.values.push(PieChartLegendValues.Percent);
|
options.legend.values.push(PieChartLegendValues.Percent);
|
||||||
}
|
}
|
||||||
if (!angular.legend.percentage && !angular.legend.values) {
|
|
||||||
// If you deselect both value and percentage in the old pie chart plugin, the legend is hidden.
|
|
||||||
options.legend.showLegend = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up labels when the old piechart is using 'on graph', for the legend option.
|
// Set up labels when the old piechart is using 'on graph', for the legend option.
|
||||||
|
@ -3,5 +3,5 @@ import { DashboardMeta } from '../../app/types/dashboard';
|
|||||||
|
|
||||||
export const getDashboardModel = (json: any, meta: DashboardMeta = {}) => {
|
export const getDashboardModel = (json: any, meta: DashboardMeta = {}) => {
|
||||||
const getVariablesFromState = () => json.templating.list;
|
const getVariablesFromState = () => json.templating.list;
|
||||||
return new DashboardModel(json, meta, getVariablesFromState);
|
return new DashboardModel(json, meta, { getVariablesFromState });
|
||||||
};
|
};
|
||||||
|
43
yarn.lock
43
yarn.lock
@ -15644,45 +15644,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001271, caniuse-lite@npm:^1.0.30001286, caniuse-lite@npm:^1.0.30001317":
|
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001271, caniuse-lite@npm:^1.0.30001286, caniuse-lite@npm:^1.0.30001317, caniuse-lite@npm:^1.0.30001332, caniuse-lite@npm:^1.0.30001335, caniuse-lite@npm:^1.0.30001400, caniuse-lite@npm:^1.0.30001426, caniuse-lite@npm:^1.0.30001449":
|
||||||
version: 1.0.30001332
|
version: 1.0.30001469
|
||||||
resolution: "caniuse-lite@npm:1.0.30001332"
|
resolution: "caniuse-lite@npm:1.0.30001469"
|
||||||
checksum: e54182ea42ab3d2ff1440f9a6480292f7ab23c00c188df7ad65586312e4da567e8bedd5cb5fb8f0ff4193dc027a54e17e0b3c0b6db5d5a3fb61c7726ff9c45b3
|
checksum: 8e496509d7e9ff189c72205675b5db0c5f1b6a09917027441e835efae0848a468a8c4e7d2b409ffc202438fcd23ae53e017f976a03c22c04d12d3c0e1e33e5de
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001449":
|
|
||||||
version: 1.0.30001467
|
|
||||||
resolution: "caniuse-lite@npm:1.0.30001467"
|
|
||||||
checksum: c7df36ddb8050fb366a4bedd278f4b639c1dde94b6ba62bacf960f26d488395632a0630b7932ebc52d3d04b57940d12dcb4a7d3bb744ff64c249b61fb3e0c238
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.30001332":
|
|
||||||
version: 1.0.30001335
|
|
||||||
resolution: "caniuse-lite@npm:1.0.30001335"
|
|
||||||
checksum: fe08b49ec6cb76cc69958ff001cf89d0a8ef9f35e0c8028b65981585046384f76e007d64dea372a34ca56d91caa83cc614c00779fe2b4d378aa0e68696374f67
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.30001335":
|
|
||||||
version: 1.0.30001341
|
|
||||||
resolution: "caniuse-lite@npm:1.0.30001341"
|
|
||||||
checksum: 7262b093fb0bf49dbc5328418f5ce4e3dbb0b13e39c015f986ba1807634c123ac214efc94df7d095a336f57f86852b4b63ee61838f18dcc3a4a35f87b390c8f5
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.30001400":
|
|
||||||
version: 1.0.30001402
|
|
||||||
resolution: "caniuse-lite@npm:1.0.30001402"
|
|
||||||
checksum: 6068ccccd64b357f75388cb2303cf351b686b20800571d0a845bff5c0e0d24f83df0133afbbdd8177a33eb087c93d39ecf359035a52b2feac5f182c946f706ee
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.30001426":
|
|
||||||
version: 1.0.30001429
|
|
||||||
resolution: "caniuse-lite@npm:1.0.30001429"
|
|
||||||
checksum: d1658080248ef5ef0f5157423b2766026e6aa45642ce3b2cc74859b6a54e39881dd902397a2368324ed30ed0cd40250f11a4a4f3773453cd57b88db5e5e5c76a
|
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user