Singlstat: Fixes all the singlestat migration issues by moving it to DashboardMigration (#33349)

* Singlstat: Fixes all the singlestat migration issues by doing during DashboardMigration

* fixes

* Updated snapshot
pull/33411/head
Torkel Ödegaard 4 years ago committed by GitHub
parent ca85012865
commit 759a501564
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      public/app/core/constants.ts
  2. 28
      public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap
  3. 80
      public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap
  4. 35
      public/app/features/dashboard/state/DashboardMigrator.test.ts
  5. 43
      public/app/features/dashboard/state/DashboardMigrator.ts
  6. 18
      public/app/features/dashboard/state/PanelModel.ts
  7. 15
      public/app/features/dashboard/state/actions.ts
  8. 6
      public/app/features/dashboard/utils/panel.ts

@ -1,6 +1,3 @@
import { PanelModel } from '../features/dashboard/state';
import { config } from '@grafana/runtime';
export const GRID_CELL_HEIGHT = 30;
export const GRID_CELL_VMARGIN = 8;
export const GRID_COLUMN_COUNT = 24;
@ -17,18 +14,3 @@ export const PANEL_BORDER = 2;
export const EDIT_PANEL_ID = 23763571993;
export const DEFAULT_PER_PAGE_PAGINATION = 8;
export const DEPRECATED_PANELS: Record<string, (panel: PanelModel) => string> = {
singlestat: (panel: PanelModel) => {
// If 'grafana-singlestat-panel' exists, move to that
if (config.panels['grafana-singlestat-panel']) {
return 'grafana-singlestat-panel';
}
// Otheriwse use gauge or stat panel
if ((panel as any).gauge && (panel as any).gauge.show) {
return 'gauge';
}
return 'stat';
},
};

@ -64,6 +64,10 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,
@ -196,6 +200,10 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,
@ -298,6 +306,10 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,
@ -422,6 +434,10 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,
@ -554,6 +570,10 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,
@ -656,6 +676,10 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,
@ -762,6 +786,10 @@ exports[`DashboardPage When dashboard has editview url state should render setti
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 1,
"w": 1,

@ -111,6 +111,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 24,
@ -142,6 +146,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -173,6 +181,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 100,
"w": 25,
@ -204,6 +216,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -260,6 +276,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 24,
@ -352,6 +372,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 24,
@ -383,6 +407,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -414,6 +442,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 100,
"w": 25,
@ -445,6 +477,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -501,6 +537,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -593,6 +633,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 24,
@ -624,6 +668,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -655,6 +703,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 100,
"w": 25,
@ -686,6 +738,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -742,6 +798,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 100,
"w": 25,
@ -834,6 +894,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 24,
@ -865,6 +929,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -896,6 +964,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 100,
"w": 25,
@ -927,6 +999,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,
@ -983,6 +1059,10 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
"_eventsCount": 0,
},
},
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"gridPos": Object {
"h": 10,
"w": 25,

@ -5,6 +5,8 @@ import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
import { expect } from 'test/lib/common';
import { DataLinkBuiltInVars } from '@grafana/data';
import { VariableHide } from '../../variables/types';
import { config } from 'app/core/config';
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
jest.mock('app/core/services/context_srv', () => ({}));
@ -14,6 +16,12 @@ describe('DashboardModel', () => {
let graph: any;
let singlestat: any;
let table: any;
let singlestatGauge: any;
config.panels = {
stat: getPanelPlugin({ id: 'stat' }).meta,
gauge: getPanelPlugin({ id: 'gauge' }).meta,
};
beforeEach(() => {
model = new DashboardModel({
@ -49,10 +57,22 @@ describe('DashboardModel', () => {
type: 'singlestat',
legend: true,
thresholds: '10,20,30',
colors: ['#FF0000', 'green', 'orange'],
aliasYAxis: { test: 2 },
grid: { min: 1, max: 10 },
targets: [{ refId: 'A' }, {}],
},
{
type: 'singlestat',
thresholds: '10,20,30',
colors: ['#FF0000', 'green', 'orange'],
gauge: {
show: true,
thresholdMarkers: true,
thresholdLabels: false,
},
grid: { min: 1, max: 10 },
},
{
type: 'table',
legend: true,
@ -64,7 +84,8 @@ describe('DashboardModel', () => {
graph = model.panels[0];
singlestat = model.panels[1];
table = model.panels[2];
singlestatGauge = model.panels[2];
table = model.panels[3];
});
it('should have title', () => {
@ -84,8 +105,16 @@ describe('DashboardModel', () => {
expect(graph.type).toBe('graph');
});
it('single stat panel should have two thresholds', () => {
expect(singlestat.thresholds).toBe('20,30');
it('singlestat panel should be mapped to stat panel', () => {
expect(singlestat.type).toBe('stat');
expect(singlestat.fieldConfig.defaults.thresholds.steps[2].value).toBe(30);
expect(singlestat.fieldConfig.defaults.thresholds.steps[0].color).toBe('#FF0000');
});
it('singlestat panel should be mapped to gauge panel', () => {
expect(singlestatGauge.type).toBe('gauge');
expect(singlestatGauge.options.showThresholdMarkers).toBe(true);
expect(singlestatGauge.options.showThresholdLabels).toBe(false);
});
it('queries without refId should get it', () => {

@ -6,7 +6,14 @@ import kbn from 'app/core/utils/kbn';
// Types
import { PanelModel } from './PanelModel';
import { DashboardModel } from './DashboardModel';
import { DataLink, DataLinkBuiltInVars, urlUtil } from '@grafana/data';
import {
DataLink,
DataLinkBuiltInVars,
PanelPlugin,
standardEditorsRegistry,
standardFieldConfigEditorRegistry,
urlUtil,
} from '@grafana/data';
// Constants
import {
DEFAULT_PANEL_SPAN,
@ -19,6 +26,13 @@ import {
import { isConstant, isMulti } from 'app/features/variables/guard';
import { alignCurrentWithMulti } from 'app/features/variables/shared/multiOptions';
import { VariableHide } from '../../variables/types';
import { config } from 'app/core/config';
import { plugin as statPanelPlugin } from 'app/plugins/panel/stat/module';
import { plugin as gaugePanelPlugin } from 'app/plugins/panel/gauge/module';
import { getStandardFieldConfigs, getStandardOptionEditors } from '@grafana/ui';
standardEditorsRegistry.setInit(getStandardOptionEditors);
standardFieldConfigEditorRegistry.setInit(getStandardFieldConfigs);
export class DashboardMigrator {
dashboard: DashboardModel;
@ -555,6 +569,12 @@ export class DashboardMigrator {
}
if (oldVersion < 28) {
panelUpgrades.push((panel: PanelModel) => {
if (panel.type === 'singlestat') {
migrateSinglestat(panel);
}
});
for (const variable of this.dashboard.templating.list) {
if (variable.tags) {
delete variable.tags;
@ -828,3 +848,24 @@ function updateVariablesSyntax(text: string) {
return match;
});
}
function migrateSinglestat(panel: PanelModel) {
// If 'grafana-singlestat-panel' exists, move to that
if (config.panels['grafana-singlestat-panel']) {
panel.type = 'grafana-singlestat-panel';
return;
}
// To make sure PanelModel.isAngularPlugin logic thinks the current panel is angular
// And since this plugin no longer exist we just fake it here
panel.plugin = { angularPanelCtrl: {} } as PanelPlugin;
// Otheriwse use gauge or stat panel
if ((panel as any).gauge?.show) {
gaugePanelPlugin.meta = config.panels['gauge'];
panel.changePlugin(gaugePanelPlugin);
} else {
statPanelPlugin.meta = config.panels['stat'];
panel.changePlugin(statPanelPlugin);
}
}

@ -39,7 +39,6 @@ import {
} from './getPanelOptionsWithDefaults';
import { QueryGroupOptions } from 'app/types';
import { PanelModelLibraryPanel } from '../../library-panels/types';
import { isDeprecatedPanel } from '../utils/panel';
export interface GridPos {
x: number;
@ -116,6 +115,10 @@ const defaults: any = {
cachedPluginOptions: {},
transparent: false,
options: {},
fieldConfig: {
defaults: {},
overrides: [],
},
datasource: null,
title: '',
};
@ -166,11 +169,10 @@ export class PanelModel implements DataConfigSource {
isEditing = false;
isInView = false;
configRev = 0; // increments when configs change
hasRefreshed?: boolean;
events: EventBus;
cacheTimeout?: any;
declare cachedPluginOptions: Record<string, PanelOptionsCache>;
cachedPluginOptions: Record<string, PanelOptionsCache> = {};
legend?: { show: boolean; sort?: string; sortDesc?: boolean };
plugin?: PanelPlugin;
dataSupport?: PanelPluginDataSupport;
@ -232,10 +234,6 @@ export class PanelModel implements DataConfigSource {
return this.options;
}
getFieldConfig() {
return this.fieldConfig;
}
get hasChanged(): boolean {
return this.configRev > 0;
}
@ -317,10 +315,6 @@ export class PanelModel implements DataConfigSource {
}
private restorePanelOptions(pluginId: string) {
if (!this.cachedPluginOptions) {
return;
}
const prevOptions = this.cachedPluginOptions[pluginId];
if (!prevOptions) {
@ -389,7 +383,7 @@ export class PanelModel implements DataConfigSource {
const oldOptions: any = this.getOptionsToRemember();
const prevFieldConfig = this.fieldConfig;
const oldPluginId = this.type;
const wasAngular = this.isAngularPlugin() || isDeprecatedPanel(this.type);
const wasAngular = this.isAngularPlugin();
this.cachedPluginOptions[oldPluginId] = {
properties: oldOptions,
fieldConfig: prevFieldConfig,

@ -15,8 +15,6 @@ import { loadPanelPlugin } from 'app/features/plugins/state/actions';
import { DashboardAcl, DashboardAclUpdateDTO, NewDashboardAclItem, PermissionLevel, ThunkResult } from 'app/types';
import { PanelModel } from './PanelModel';
import { cancelVariables } from '../../variables/state/actions';
import { isDeprecatedPanel } from '../utils/panel';
import { DEPRECATED_PANELS } from '../../../core/constants';
import { getPanelPluginNotFound } from '../dashgrid/PanelPluginError';
import { getTimeSrv } from '../services/TimeSrv';
@ -124,9 +122,6 @@ export function removeDashboard(uri: string): ThunkResult<void> {
export function initDashboardPanel(panel: PanelModel): ThunkResult<void> {
return async (dispatch, getStore) => {
let pluginToLoad = panel.type;
const isDeprecated = isDeprecatedPanel(panel.type);
let notFound = false;
let plugin = getStore().plugins.panels[pluginToLoad];
if (!plugin) {
@ -135,19 +130,9 @@ export function initDashboardPanel(panel: PanelModel): ThunkResult<void> {
} catch (e) {
// When plugin not found
plugin = getPanelPluginNotFound(pluginToLoad, pluginToLoad === 'row');
if (pluginToLoad !== 'row') {
notFound = true;
}
}
}
// if there isn't an "external" plugin with the same name as deprecated one, load the deprecated panel replacement
if (notFound && isDeprecated) {
pluginToLoad = DEPRECATED_PANELS[panel.type](panel);
plugin = await dispatch(loadPanelPlugin(pluginToLoad));
await dispatch(changePanelPlugin(panel, pluginToLoad));
}
if (!panel.plugin) {
panel.pluginLoaded(plugin);
}

@ -15,7 +15,7 @@ import config from 'app/core/config';
import { getTemplateSrv } from '@grafana/runtime';
// Constants
import { DEPRECATED_PANELS, LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
import { LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
import { ShowConfirmModalEvent, ShowModalReactEvent } from '../../../types/events';
@ -187,7 +187,3 @@ export function calculateInnerPanelHeight(panel: PanelModel, containerHeight: nu
const headerHeight = panel.hasTitle() ? config.theme.panelHeaderHeight : 0;
return containerHeight - headerHeight - chromePadding - PANEL_BORDER;
}
export function isDeprecatedPanel(panelType: string) {
return !!DEPRECATED_PANELS[panelType];
}

Loading…
Cancel
Save