From ae8dd737704bb6232c52e19090e593d9165f5e77 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Fri, 10 Jun 2022 17:12:56 -0700 Subject: [PATCH] Graph Panel: Add feature toggle that will allow automatic migration to timeseries panel (#50631) --- .../src/types/featureToggles.gen.ts | 1 + pkg/services/featuremgmt/registry.go | 6 +++ pkg/services/featuremgmt/toggles_gen.go | 4 ++ .../features/dashboard/state/PanelModel.ts | 40 ++++++++++++++++--- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index ef1da04661a9e..8b75df36d374c 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -55,6 +55,7 @@ export interface FeatureToggles { traceToMetrics?: boolean; prometheusStreamingJSONParser?: boolean; validateDashboardsOnSave?: boolean; + autoMigrateGraphPanels?: boolean; prometheusWideSeries?: boolean; canvasPanelNesting?: boolean; cloudMonitoringExperimentalUI?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index b913a3384e880..cbd439bcf74cb 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -221,6 +221,12 @@ var ( State: FeatureStateAlpha, RequiresRestart: true, }, + { + Name: "autoMigrateGraphPanels", + Description: "Replace the angular graph panel with timeseries", + State: FeatureStateBeta, + FrontendOnly: true, + }, { Name: "prometheusWideSeries", Description: "Enable wide series responses in the Prometheus datasource", diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index f73b679a30d6f..9a530e78b6a4f 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -163,6 +163,10 @@ const ( // Validate dashboard JSON POSTed to api/dashboards/db FlagValidateDashboardsOnSave = "validateDashboardsOnSave" + // FlagAutoMigrateGraphPanels + // Replace the angular graph panel with timeseries + FlagAutoMigrateGraphPanels = "autoMigrateGraphPanels" + // FlagPrometheusWideSeries // Enable wide series responses in the Prometheus datasource FlagPrometheusWideSeries = "prometheusWideSeries" diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index b4a64914493d1..817b9d76c5f4e 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -163,6 +163,8 @@ export class PanelModel implements DataConfigSource, IPanelModel { libraryPanel?: { uid: undefined; name: string } | PanelModelLibraryPanel; + autoMigrateFrom?: string; + // non persisted isViewing = false; isEditing = false; @@ -222,6 +224,12 @@ export class PanelModel implements DataConfigSource, IPanelModel { (this as any)[property] = model[property]; } + // Special 'graph' migration logic + if (this.type === 'graph' && config?.featureToggles?.autoMigrateGraphPanels) { + this.autoMigrateFrom = this.type; + this.type = 'timeseries'; + } + // defaults defaultsDeep(this, cloneDeep(defaults)); @@ -368,6 +376,18 @@ export class PanelModel implements DataConfigSource, IPanelModel { this.plugin = plugin; const version = getPluginVersion(plugin); + if (this.autoMigrateFrom) { + const wasAngular = this.autoMigrateFrom === 'graph'; + this.callPanelTypeChangeHandler( + plugin, + this.autoMigrateFrom, + this.getOptionsToRemember(), // old options + wasAngular + ); + + delete this.autoMigrateFrom; + } + if (plugin.onPanelMigration) { if (version !== this.pluginVersion) { this.options = plugin.onPanelMigration(this); @@ -401,6 +421,19 @@ export class PanelModel implements DataConfigSource, IPanelModel { }; } + // Let panel plugins inspect options from previous panel and keep any that it can use + private callPanelTypeChangeHandler( + newPlugin: PanelPlugin, + oldPluginId: string, + oldOptions: any, + wasAngular: boolean + ) { + if (newPlugin.onPanelTypeChanged) { + const prevOptions = wasAngular ? { angular: oldOptions } : oldOptions.options; + Object.assign(this.options, newPlugin.onPanelTypeChanged(this, oldPluginId, prevOptions, this.fieldConfig)); + } + } + changePlugin(newPlugin: PanelPlugin) { const pluginId = newPlugin.meta.id; const oldOptions: any = this.getOptionsToRemember(); @@ -415,11 +448,8 @@ export class PanelModel implements DataConfigSource, IPanelModel { this.clearPropertiesBeforePluginChange(); this.restorePanelOptions(pluginId); - // Let panel plugins inspect options from previous panel and keep any that it can use - if (newPlugin.onPanelTypeChanged) { - const prevOptions = wasAngular ? { angular: oldOptions } : oldOptions.options; - Object.assign(this.options, newPlugin.onPanelTypeChanged(this, oldPluginId, prevOptions, prevFieldConfig)); - } + // Potentially modify current options + this.callPanelTypeChangeHandler(newPlugin, oldPluginId, oldOptions, wasAngular); // switch this.type = pluginId;