DashboardMigration: V16 was removing panels when repeatInteration is null (#110151)

This commit is contained in:
Ivan Ortega Alba
2025-08-26 14:20:22 +02:00
committed by GitHub
parent 6e3ded8432
commit a7e4447d0e
10 changed files with 19951 additions and 2 deletions
@@ -66,7 +66,7 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
}
// Skip repeated rows (line 1031-1033 in TS)
if _, hasRepeatIteration := row["repeatIteration"]; hasRepeatIteration {
if repeatIteration, hasRepeatIteration := row["repeatIteration"]; hasRepeatIteration && repeatIteration != nil {
continue
}
@@ -283,7 +283,11 @@ func getMaxPanelID(rows []interface{}) int {
func shouldShowRows(rows []interface{}) bool {
for _, rowInterface := range rows {
if row, ok := rowInterface.(map[string]interface{}); ok {
if GetBoolValue(row, "collapse") || GetBoolValue(row, "showTitle") || GetStringValue(row, "repeat") != "" {
collapse := GetBoolValue(row, "collapse")
showTitle := GetBoolValue(row, "showTitle")
repeat := GetStringValue(row, "repeat")
if collapse || showTitle || repeat != "" {
return true
}
}
@@ -8,6 +8,63 @@ import (
func TestV16(t *testing.T) {
tests := []migrationTestCase{
{
name: "should handle repeatIteration null",
input: map[string]interface{}{
"schemaVersion": 15,
"rows": []interface{}{
map[string]interface{}{
"collapse": false,
"showTitle": true,
"title": "Overview",
"type": "row",
"repeat": nil,
"repeatIteration": nil,
"repeatRowId": nil,
"panels": []interface{}{
map[string]interface{}{
"id": 2,
"type": "stat",
"span": 12,
"title": "Customer Stats",
},
},
},
},
},
expected: map[string]interface{}{
"schemaVersion": 16,
"panels": []interface{}{
// The stat panel should be processed and added
map[string]interface{}{
"id": 2,
"type": "stat",
"title": "Customer Stats",
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 24,
"h": 7, // default height
},
},
// The row panel should be created because showTitle is true
map[string]interface{}{
"id": 3, // Next ID after max panel ID (2)
"type": "row",
"title": "Overview",
"collapsed": false,
"repeat": "",
"panels": []interface{}{},
"gridPos": map[string]interface{}{
"x": 0,
"y": 0,
"w": 24,
"h": 7, // default height
},
},
},
},
},
{
name: "should create proper grid",
input: map[string]interface{}{
@@ -0,0 +1,118 @@
{
"annotations": {
"list": [
]
},
"editable": false,
"gnetId": null,
"graphTooltip": 1,
"hideControls": false,
"id": 22815,
"links": [
],
"refresh": "1m",
"rows": [
{
"collapse": false,
"collapsed": false,
"panels": [
{
"datasource": "$datasource",
"fieldConfig": {
"defaults": {
"links": [],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [{ "color": "green", "value": 0 }]
},
"unit": "none"
}
},
"gridPos": { "h": 9, "w": 12, "x": 0, "y": 0 },
"id": 2,
"links": [],
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["mean"],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "7",
"targets": [
{
"expr": "sum(rate(http_requests_total{environment=\"$env\", region=\"$region\", service=\"webapp\"}[5m]))",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "Requests/sec",
"refId": "A"
},
{
"expr": "avg(memory_usage_bytes{environment=\"$env\", region=\"$region\", service=\"webapp\"}) / 1024 / 1024",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "Memory (MB)",
"refId": "B"
},
{
"expr": "histogram_quantile(0.95, rate(response_time_bucket{environment=\"$env\", region=\"$region\", service=\"webapp\"}[5m]))",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "95th percentile latency",
"refId": "C"
}
],
"title": "Service Stats",
"transparent": false,
"type": "stat"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": true,
"title": "Overview",
"titleSize": "h6",
"type": "row"
}
],
"schemaVersion": 14,
"style": "dark",
"tags": ["example-service", "as-code"],
"templating": {
"list": [
]
},
"time": { "from": "now-2h", "to": "now" },
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
},
"timezone": "browser",
"title": "Service Overview Dashboard",
"uid": "ba9b93e998e09d254266b11192894a8d",
"version": 1
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,159 @@
{
"annotations": {
"list": []
},
"editable": false,
"gnetId": null,
"graphTooltip": 1,
"hideControls": false,
"id": 22815,
"links": [],
"panels": [
{
"datasource": {
"uid": "$datasource"
},
"fieldConfig": {
"defaults": {
"links": [],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
}
]
},
"unit": "none"
}
},
"gridPos": {
"h": 7,
"w": 8,
"x": 0,
"y": 1
},
"id": 2,
"links": [],
"options": {
"colorMode": "value",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"mean"
],
"fields": "",
"values": false
},
"showPercentChange": false,
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "7",
"targets": [
{
"datasource": {
"uid": "$datasource"
},
"expr": "sum(rate(http_requests_total{environment=\"$env\", region=\"$region\", service=\"webapp\"}[5m]))",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "Requests/sec",
"refId": "A"
},
{
"datasource": {
"uid": "$datasource"
},
"expr": "avg(memory_usage_bytes{environment=\"$env\", region=\"$region\", service=\"webapp\"}) / 1024 / 1024",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "Memory (MB)",
"refId": "B"
},
{
"datasource": {
"uid": "$datasource"
},
"expr": "histogram_quantile(0.95, rate(response_time_bucket{environment=\"$env\", region=\"$region\", service=\"webapp\"}[5m]))",
"format": "time_series",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "95th percentile latency",
"refId": "C"
}
],
"title": "Service Stats",
"transparent": false,
"type": "stat"
},
{
"collapsed": false,
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 0
},
"id": 3,
"panels": [],
"repeat": "",
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Overview",
"type": "row"
}
],
"refresh": "1m",
"schemaVersion": 41,
"style": "dark",
"tags": [
"example-service",
"as-code"
],
"templating": {
"list": []
},
"time": {
"from": "now-2h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "browser",
"title": "Service Overview Dashboard",
"uid": "ba9b93e998e09d254266b11192894a8d",
"version": 1
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff