Dashboard Migrations: v12 - template variables (#110253)
* migrate to v19 * migrate to v18 * Migration to be verified: v17 Convert minSpan to maxPerRow in panels * Migration to be verified: 16 Grid layout migration * Refactor v17 and v19 migrations to use shared helper functions * Migration to be verified: 15 No-op migration for schema consistency * Migration to be verified: 14 Shared crosshair to graph tooltip migration * cleanup * wip * complete migration * fix lint issues * refactor and test with minimal graph config * update tests * migrate to v12 * extract defaults outside the func * lint * lint * add missing showValues prop * update * add context and fix latest version * add context * generate snapshots * v13 should be no-op * clean up * fix tests * fix test * remove v28 * remove singlestat migraiton from frontend migrator because this is an automigration * remove unused function * Remove v24 table plugin logic * cleanup * remove plugin version for automigrate as it was used only in v24 and v28 that have been removed * cleanup * es int --------- Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
co-authored by
Dominik Prokop
parent
6af50482a1
commit
5c815a1733
@@ -2,6 +2,8 @@ package migration
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
)
|
||||
|
||||
// applyFrontendDefaults applies all DashboardModel constructor defaults
|
||||
@@ -793,10 +795,12 @@ func cleanupVariable(variable map[string]interface{}) {
|
||||
if variableType, ok := variable["type"].(string); ok {
|
||||
switch variableType {
|
||||
case "query":
|
||||
// Query variables: keep options: [] if refresh !== never
|
||||
// Since refresh is not specified in the input, it defaults to not "never"
|
||||
if _, hasOptions := variable["options"]; !hasOptions {
|
||||
variable["options"] = []interface{}{}
|
||||
// Query variables: keep options: [] if refresh !== never (matches frontend getSaveModel logic)
|
||||
refresh := schemaversion.GetIntValue(variable, "refresh", 1) // Default to 1 (onDashboardLoad) if not specified
|
||||
if refresh != 0 { // 0 = VariableRefreshNever
|
||||
if _, hasOptions := variable["options"]; !hasOptions {
|
||||
variable["options"] = []interface{}{}
|
||||
}
|
||||
}
|
||||
case "constant":
|
||||
// Constant variables: remove options completely
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MIN_VERSION = 12
|
||||
MIN_VERSION = 11
|
||||
LATEST_VERSION = 42
|
||||
)
|
||||
|
||||
@@ -35,6 +35,7 @@ type PanelPluginInfo struct {
|
||||
|
||||
func GetMigrations(dsInfoProvider DataSourceInfoProvider) map[int]SchemaVersionMigrationFunc {
|
||||
return map[int]SchemaVersionMigrationFunc{
|
||||
12: V12,
|
||||
13: V13,
|
||||
14: V14,
|
||||
15: V15,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V12 migrates template variables to update their refresh and hide properties.
|
||||
// This migration ensures that:
|
||||
// 1. Variables with refresh=true get refresh=1, and variables with refresh=false get refresh=0
|
||||
// 2. Variables with hideVariable=true get hide=2 (hide variable)
|
||||
// 3. Variables with hideLabel=true get hide=1 (hide label)
|
||||
//
|
||||
// Example before migration:
|
||||
//
|
||||
// "templating": {
|
||||
// "list": [
|
||||
// { "type": "query", "name": "var1", "refresh": true, "hideVariable": true },
|
||||
// { "type": "query", "name": "var2", "refresh": false, "hideLabel": true }
|
||||
// ]
|
||||
// }
|
||||
//
|
||||
// Example after migration:
|
||||
//
|
||||
// "templating": {
|
||||
// "list": [
|
||||
// { "type": "query", "name": "var1", "refresh": 1, "hide": 2 },
|
||||
// { "type": "query", "name": "var2", "refresh": 0, "hide": 1 }
|
||||
// ]
|
||||
// }
|
||||
func V12(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 12
|
||||
|
||||
templating, ok := dashboard["templating"].(map[string]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
list, ok := templating["list"].([]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, v := range list {
|
||||
variable, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Update refresh property
|
||||
if _, hasRefresh := variable["refresh"]; hasRefresh {
|
||||
if GetBoolValue(variable, "refresh") {
|
||||
variable["refresh"] = 1
|
||||
} else {
|
||||
variable["refresh"] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Update hide property based on hideVariable and hideLabel
|
||||
// hideVariable takes priority over hideLabel
|
||||
if GetBoolValue(variable, "hideVariable") {
|
||||
variable["hide"] = 2
|
||||
} else if GetBoolValue(variable, "hideLabel") {
|
||||
variable["hide"] = 1
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
package schemaversion_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
)
|
||||
|
||||
func TestV12(t *testing.T) {
|
||||
tests := []migrationTestCase{
|
||||
{
|
||||
name: "variable with refresh=true gets refresh=1",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Refresh True Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "refresh_true_var",
|
||||
"refresh": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Refresh True Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "refresh_true_var",
|
||||
"refresh": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with refresh=false gets refresh=0",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Refresh False Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "refresh_false_var",
|
||||
"refresh": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Refresh False Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "refresh_false_var",
|
||||
"refresh": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with hideVariable=true gets hide=2",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Hide Variable Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "hide_variable_var",
|
||||
"hideVariable": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Hide Variable Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "hide_variable_var",
|
||||
"hideVariable": true,
|
||||
"hide": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with hideLabel=true gets hide=1",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Hide Label Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "hide_label_var",
|
||||
"hideLabel": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Hide Label Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "hide_label_var",
|
||||
"hideLabel": true,
|
||||
"hide": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with both hideVariable and hideLabel prioritizes hideVariable",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Hide Priority Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "priority_var",
|
||||
"hideVariable": true,
|
||||
"hideLabel": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Hide Priority Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "priority_var",
|
||||
"hideVariable": true,
|
||||
"hideLabel": true,
|
||||
"hide": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with no refresh or hide properties is unchanged",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 No Properties Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "no_properties_var",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 No Properties Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "no_properties_var",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard without templating is unchanged",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 No Templating Test",
|
||||
"schemaVersion": 11,
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 No Templating Test",
|
||||
"schemaVersion": 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dashboard with empty templating list is unchanged",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Empty Templating Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Empty Templating Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variables with hideVariable=false and hideLabel=false do not get hide property",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 False Hide Properties Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "false_hide_var",
|
||||
"hideVariable": false,
|
||||
"hideLabel": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 False Hide Properties Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "false_hide_var",
|
||||
"hideVariable": false,
|
||||
"hideLabel": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with hideVariable=false but hideLabel=true gets hide=1",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 Mixed Hide Properties Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "mixed_hide_var",
|
||||
"hideVariable": false,
|
||||
"hideLabel": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 Mixed Hide Properties Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "mixed_hide_var",
|
||||
"hideVariable": false,
|
||||
"hideLabel": true,
|
||||
"hide": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "variable with all properties gets all migrations applied",
|
||||
input: map[string]interface{}{
|
||||
"title": "V12 All Properties Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "all_properties_var",
|
||||
"refresh": true,
|
||||
"hideVariable": true,
|
||||
"hideLabel": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"title": "V12 All Properties Test",
|
||||
"schemaVersion": 12,
|
||||
"templating": map[string]interface{}{
|
||||
"list": []interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "query",
|
||||
"name": "all_properties_var",
|
||||
"refresh": 1,
|
||||
"hideVariable": true,
|
||||
"hideLabel": false,
|
||||
"hide": 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runMigrationTests(t, tests, schemaversion.V12)
|
||||
}
|
||||
@@ -139,7 +139,8 @@ func migrateTemplateVariables(dashboard map[string]interface{}, datasources []Da
|
||||
|
||||
ds, exists := varMap["datasource"]
|
||||
// Handle null datasource variables by setting to default (matches frontend behavior)
|
||||
if !exists || ds == nil {
|
||||
// Only add datasource if it's explicitly null, not if it doesn't exist
|
||||
if exists && ds == nil {
|
||||
varMap["datasource"] = GetDataSourceRef(defaultDS)
|
||||
}
|
||||
// Note: Frontend v36 migration only converts null datasources to default objects
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"title": "V12 Template Variables Migration Test",
|
||||
"schemaVersion": 11,
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"type": "query",
|
||||
"name": "refresh_true_var",
|
||||
"refresh": true
|
||||
},
|
||||
{
|
||||
"type": "query",
|
||||
"name": "refresh_false_var",
|
||||
"refresh": false
|
||||
},
|
||||
{
|
||||
"type": "query",
|
||||
"name": "hide_variable_var",
|
||||
"hideVariable": true
|
||||
},
|
||||
{
|
||||
"type": "query",
|
||||
"name": "hide_label_var",
|
||||
"hideLabel": true
|
||||
},
|
||||
{
|
||||
"type": "query",
|
||||
"name": "priority_var",
|
||||
"hideVariable": true,
|
||||
"hideLabel": true
|
||||
},
|
||||
{
|
||||
"type": "query",
|
||||
"name": "no_properties_var"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [],
|
||||
"refresh": "",
|
||||
"schemaVersion": 42,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"name": "refresh_true_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"name": "refresh_false_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 2,
|
||||
"hideVariable": true,
|
||||
"name": "hide_variable_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 1,
|
||||
"hideLabel": true,
|
||||
"name": "hide_label_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 2,
|
||||
"hideLabel": true,
|
||||
"hideVariable": true,
|
||||
"name": "priority_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"name": "no_properties_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "V12 Template Variables Migration Test",
|
||||
"weekStart": ""
|
||||
}
|
||||
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations \u0026 Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [],
|
||||
"schemaVersion": 12,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"name": "refresh_true_var",
|
||||
"options": [],
|
||||
"refresh": 1,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"name": "refresh_false_var",
|
||||
"refresh": 0,
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 2,
|
||||
"hideVariable": true,
|
||||
"name": "hide_variable_var",
|
||||
"options": [],
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 1,
|
||||
"hideLabel": true,
|
||||
"name": "hide_label_var",
|
||||
"options": [],
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"hide": 2,
|
||||
"hideLabel": true,
|
||||
"hideVariable": true,
|
||||
"name": "priority_var",
|
||||
"options": [],
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"name": "no_properties_var",
|
||||
"options": [],
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "V12 Template Variables Migration Test",
|
||||
"weekStart": ""
|
||||
}
|
||||
@@ -2544,7 +2544,7 @@
|
||||
"count": 2
|
||||
},
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 20
|
||||
"count": 19
|
||||
}
|
||||
},
|
||||
"public/app/features/dashboard/state/DashboardModel.repeat.test.ts": {
|
||||
|
||||
@@ -347,57 +347,6 @@ export class DashboardMigrator {
|
||||
});
|
||||
}
|
||||
|
||||
if (oldVersion < 12 && finalTargetVersion >= 12) {
|
||||
// update graph yaxes changes
|
||||
panelUpgrades.push((panel: any) => {
|
||||
if (panel.type !== 'graph') {
|
||||
return panel;
|
||||
}
|
||||
if (!panel.grid) {
|
||||
return panel;
|
||||
}
|
||||
|
||||
if (!panel.yaxes) {
|
||||
panel.yaxes = [
|
||||
{
|
||||
show: panel['y-axis'],
|
||||
min: panel.grid.leftMin,
|
||||
max: panel.grid.leftMax,
|
||||
logBase: panel.grid.leftLogBase,
|
||||
format: panel.y_formats[0],
|
||||
label: panel.leftYAxisLabel,
|
||||
},
|
||||
{
|
||||
show: panel['y-axis'],
|
||||
min: panel.grid.rightMin,
|
||||
max: panel.grid.rightMax,
|
||||
logBase: panel.grid.rightLogBase,
|
||||
format: panel.y_formats[1],
|
||||
label: panel.rightYAxisLabel,
|
||||
},
|
||||
];
|
||||
|
||||
panel.xaxis = {
|
||||
show: panel['x-axis'],
|
||||
};
|
||||
|
||||
delete panel.grid.leftMin;
|
||||
delete panel.grid.leftMax;
|
||||
delete panel.grid.leftLogBase;
|
||||
delete panel.grid.rightMin;
|
||||
delete panel.grid.rightMax;
|
||||
delete panel.grid.rightLogBase;
|
||||
delete panel.y_formats;
|
||||
delete panel.leftYAxisLabel;
|
||||
delete panel.rightYAxisLabel;
|
||||
delete panel['y-axis'];
|
||||
delete panel['x-axis'];
|
||||
}
|
||||
|
||||
return panel;
|
||||
});
|
||||
}
|
||||
|
||||
if (oldVersion < 13 && finalTargetVersion >= 13) {
|
||||
// graph panel auto migrates to either barchart, bargauge, histogram or timeseries (all standard Grafana plugins)
|
||||
// see public/app/features/dashboard/state/getPanelPluginToMigrateTo.ts
|
||||
|
||||
Reference in New Issue
Block a user