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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user