diff --git a/public/app/core/constants.ts b/public/app/core/constants.ts index c1afc61481e..39e9a66064e 100644 --- a/public/app/core/constants.ts +++ b/public/app/core/constants.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> = { - 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'; - }, -}; diff --git a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap index d527a15767d..ae474b91460 100644 --- a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap +++ b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap @@ -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, diff --git a/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap b/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap index 857cff96ae8..bdff0be2f4f 100644 --- a/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap +++ b/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap @@ -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, diff --git a/public/app/features/dashboard/state/DashboardMigrator.test.ts b/public/app/features/dashboard/state/DashboardMigrator.test.ts index d053b288a3b..93ecd137c95 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.test.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.test.ts @@ -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', () => { diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts index a16ffec20f1..16432bb4a89 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.ts @@ -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); + } +} diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index f97ef1d80a7..4c007eceb2d 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -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; + cachedPluginOptions: Record = {}; 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, diff --git a/public/app/features/dashboard/state/actions.ts b/public/app/features/dashboard/state/actions.ts index 30d718b8e19..05111cb5d08 100644 --- a/public/app/features/dashboard/state/actions.ts +++ b/public/app/features/dashboard/state/actions.ts @@ -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 { export function initDashboardPanel(panel: PanelModel): ThunkResult { 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 { } 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); } diff --git a/public/app/features/dashboard/utils/panel.ts b/public/app/features/dashboard/utils/panel.ts index 5bd9d101c8a..a434c03112b 100644 --- a/public/app/features/dashboard/utils/panel.ts +++ b/public/app/features/dashboard/utils/panel.ts @@ -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]; -}