fix: empty panels

This commit is contained in:
konsalex 2025-10-04 01:38:13 +02:00
parent 45fe8c6612
commit df001f8041
No known key found for this signature in database
GPG Key ID: F39C38CAF93430A5
5 changed files with 817 additions and 806 deletions

View File

@ -158,8 +158,8 @@ func upgradeToGridLayout(dashboard map[string]interface{}) {
delete(panel, "span")
// Exact logic from lines 1082-1086 in TS
if rowPanel != nil && isCollapsed {
// Add to collapsed row's nested panels
// Condition matches line 1047 in TS
if rowPanel != nil && (isCollapsed || GetBoolValue(row, "showTitle")) {
if rowPanelPanels, ok := rowPanel["panels"].([]interface{}); ok {
rowPanel["panels"] = append(rowPanelPanels, panel)
}

View File

@ -35,26 +35,29 @@ func TestV16(t *testing.T) {
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
// and panels should be nested under it
map[string]interface{}{
"id": 3, // Next ID after max panel ID (2)
"type": "row",
"title": "Overview",
"collapsed": false,
"repeat": "",
"panels": []interface{}{},
"panels": []interface{}{
// The stat panel should be processed and added
// and nested under the row panel
map[string]interface{}{
"id": 2,
"type": "stat",
"title": "Customer Stats",
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 24,
"h": 7, // default height
},
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 0,
@ -240,30 +243,31 @@ func TestV16(t *testing.T) {
expected: map[string]interface{}{
"schemaVersion": 16,
"panels": []interface{}{
map[string]interface{}{
"id": 1,
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 12,
"h": 8,
},
},
map[string]interface{}{
"id": 2,
"gridPos": map[string]interface{}{
"x": 12,
"y": 1,
"w": 12,
"h": 8,
},
},
map[string]interface{}{
"id": 4, // Next ID after max panel ID (3)
"type": "row",
"title": "Row",
"repeat": "",
"panels": []interface{}{},
"panels": []interface{}{
map[string]interface{}{
"id": 1,
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 12,
"h": 8,
},
},
map[string]interface{}{
"id": 2,
"gridPos": map[string]interface{}{
"x": 12,
"y": 1,
"w": 12,
"h": 8,
},
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 0,
@ -1212,23 +1216,24 @@ func TestV16(t *testing.T) {
expected: map[string]interface{}{
"schemaVersion": 16,
"panels": []interface{}{
// Panel from first row
map[string]interface{}{
"id": 1,
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 12,
"h": 8,
},
},
// Repeated row panel (comes after its panels)
map[string]interface{}{
"id": 3,
"type": "row",
"title": "Row",
"repeat": "server",
"panels": []interface{}{},
"panels": []interface{}{
// Panel from first row should be nested
map[string]interface{}{
"id": 1,
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 12,
"h": 8,
},
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 0,
@ -1298,21 +1303,22 @@ func TestV16(t *testing.T) {
expected: map[string]interface{}{
"schemaVersion": 16,
"panels": []interface{}{
map[string]interface{}{
"id": 1,
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 12,
"h": 8,
},
},
map[string]interface{}{
"id": 3, // Next ID after max panel ID (2)
"type": "row",
"title": "Row1",
"repeat": "server",
"panels": []interface{}{},
"panels": []interface{}{
map[string]interface{}{
"id": 1,
"gridPos": map[string]interface{}{
"x": 0,
"y": 1,
"w": 12,
"h": 8,
},
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 0,
@ -1484,35 +1490,6 @@ func TestV16(t *testing.T) {
expected: map[string]interface{}{
"schemaVersion": 16,
"panels": []interface{}{
// First panel
map[string]interface{}{
"id": 1,
"type": "barchart",
"title": "Versions running",
"targets": []interface{}{
map[string]interface{}{
"expr": "up",
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 1, // After row panel
"w": 8, // 4 span * 2 = 8 width
"h": 19, // 700px parsed correctly: ceil(700/38) = 19
},
},
// Second panel
map[string]interface{}{
"id": 2,
"type": "barchart",
"title": "Deployment progress",
"gridPos": map[string]interface{}{
"x": 8, // Next to first panel
"y": 1,
"w": 8,
"h": 19,
},
},
// Row panel (created because showTitle is true)
map[string]interface{}{
"id": 3, // Next available ID
@ -1520,7 +1497,37 @@ func TestV16(t *testing.T) {
"title": "Rollout progress",
"collapsed": false, // Backend always sets this
"repeat": "", // Backend always sets this
"panels": []interface{}{},
"panels": []interface{}{
// First panel
map[string]interface{}{
"id": 1,
"type": "barchart",
"title": "Versions running",
"targets": []interface{}{
map[string]interface{}{
"expr": "up",
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 1, // After row panel
"w": 8, // 4 span * 2 = 8 width
"h": 19, // 700px parsed correctly: ceil(700/38) = 19
},
},
// Second panel
map[string]interface{}{
"id": 2,
"type": "barchart",
"title": "Deployment progress",
"gridPos": map[string]interface{}{
"x": 8, // Next to first panel
"y": 1,
"w": 8,
"h": 19,
},
},
},
"gridPos": map[string]interface{}{
"x": 0,
"y": 0,

View File

@ -214,7 +214,87 @@
"y": 17
},
"id": 15,
"panels": [],
"panels": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 6,
"w": 8,
"x": 0,
"y": 18
},
"id": 6,
"minSpan": 4,
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Temperature",
"type": "gauge"
},
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 6,
"w": 8,
"x": 8,
"y": 18
},
"id": 7,
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Uptime",
"type": "stat"
},
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 6,
"w": 8,
"x": 16,
"y": 18
},
"id": 8,
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Load Average",
"type": "bargauge"
}
],
"targets": [
{
"datasource": {
@ -228,85 +308,6 @@
"title": "Visible Row Title",
"type": "row"
},
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 6,
"w": 8,
"x": 0,
"y": 18
},
"id": 6,
"maxPerRow": 6,
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Temperature",
"type": "gauge"
},
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 6,
"w": 8,
"x": 8,
"y": 18
},
"id": 7,
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Uptime",
"type": "stat"
},
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"gridPos": {
"h": 6,
"w": 8,
"x": 16,
"y": 18
},
"id": 8,
"targets": [
{
"datasource": {
"apiVersion": "v1",
"type": "prometheus",
"uid": "default-ds-uid"
},
"refId": "A"
}
],
"title": "Load Average",
"type": "bargauge"
},
{
"datasource": {
"apiVersion": "v1",

View File

@ -113,44 +113,45 @@
"y": 17
},
"id": 15,
"panels": [],
"panels": [
{
"gridPos": {
"h": 6,
"w": 8,
"x": 0,
"y": 18
},
"id": 6,
"minSpan": 4,
"title": "Temperature",
"type": "gauge"
},
{
"gridPos": {
"h": 6,
"w": 8,
"x": 8,
"y": 18
},
"id": 7,
"title": "Uptime",
"type": "stat"
},
{
"gridPos": {
"h": 6,
"w": 8,
"x": 16,
"y": 18
},
"id": 8,
"title": "Load Average",
"type": "bargauge"
}
],
"title": "Visible Row Title",
"type": "row"
},
{
"gridPos": {
"h": 6,
"w": 8,
"x": 0,
"y": 18
},
"id": 6,
"minSpan": 4,
"title": "Temperature",
"type": "gauge"
},
{
"gridPos": {
"h": 6,
"w": 8,
"x": 8,
"y": 18
},
"id": 7,
"title": "Uptime",
"type": "stat"
},
{
"gridPos": {
"h": 6,
"w": 8,
"x": 16,
"y": 18
},
"id": 8,
"title": "Load Average",
"type": "bargauge"
},
{
"gridPos": {
"h": 4,