Dashboard Migrations: V2 - legacy services.filter and graphite panel type (#112282)

* migrate to v2

* Fix tests

* graphite panels should be auto-migrated

* lint

* Provisioning: Fix dashboard export to preserve original API version

* Add error handling for the edge case where conversion fails but no
storedVersion is available.
This commit is contained in:
Haris Rozajac
2025-10-15 10:34:12 -06:00
committed by GitHub
parent 5b7e6ef2e1
commit d9067b27eb
13 changed files with 734 additions and 78 deletions
@@ -946,32 +946,13 @@ func applyPanelAutoMigration(panel map[string]interface{}) {
var newType string
// Graph needs special logic as it can be migrated to multiple panels
if panelType == "graph" {
// Including graphite which was previously migrated to graph in the schema version 2 migration in DashboardMigrator.ts
// but this was a bug because in there graphite was set to graph, but since those migrations run
// after PanelModel.restoreModel where autoMigrateFrom is set, this caused the graph migration to be skipped.
// And this resulted in a dashboard with invalid panels.
if panelType == "graph" || panelType == "graphite" {
// Check xaxis mode for special cases
if xaxis, ok := panel["xaxis"].(map[string]interface{}); ok {
if mode, ok := xaxis["mode"].(string); ok {
switch mode {
case "series":
// Check legend values for bargauge
if legend, ok := panel["legend"].(map[string]interface{}); ok {
if values, ok := legend["values"].(bool); ok && values {
newType = "bargauge"
} else {
newType = "barchart"
}
} else {
newType = "barchart"
}
case "histogram":
newType = "histogram"
}
}
}
// Default graph migration to timeseries
if newType == "" {
newType = "timeseries"
}
newType = getGraphAutoMigration(panel)
} else {
// Check autoMigrateAngular mapping
autoMigrateAngular := map[string]string{
@@ -995,6 +976,36 @@ func applyPanelAutoMigration(panel map[string]interface{}) {
}
}
func getGraphAutoMigration(panel map[string]interface{}) string {
newType := ""
if xaxis, ok := panel["xaxis"].(map[string]interface{}); ok {
if mode, ok := xaxis["mode"].(string); ok {
switch mode {
case "series":
// Check legend values for bargauge
if legend, ok := panel["legend"].(map[string]interface{}); ok {
if values, ok := legend["values"].(bool); ok && values {
newType = "bargauge"
} else {
newType = "barchart"
}
} else {
newType = "barchart"
}
case "histogram":
newType = "histogram"
}
}
}
// Default graph migration to timeseries
if newType == "" {
newType = "timeseries"
}
return newType
}
// removeNullValuesRecursively removes null values from nested objects and arrays
// This matches the frontend's JSON.stringify/parse behavior
func removeNullValuesRecursively(data interface{}) {