diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.span_zero_demo.v42.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.span_zero_demo.v42.v0alpha1.json index f68749927e5..9b1312fb8eb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.span_zero_demo.v42.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.span_zero_demo.v42.v0alpha1.json @@ -77,7 +77,7 @@ "x": 0, "y": 0 }, - "id": 23, + "id": 24, "panels": [], "targets": [ { diff --git a/apps/dashboard/pkg/migration/schemaversion/v16.go b/apps/dashboard/pkg/migration/schemaversion/v16.go index 779498e864a..c33ee1a09f4 100644 --- a/apps/dashboard/pkg/migration/schemaversion/v16.go +++ b/apps/dashboard/pkg/migration/schemaversion/v16.go @@ -46,7 +46,8 @@ func upgradeToGridLayout(dashboard map[string]interface{}) { widthFactor := gridColumnCount / 12.0 // Find max panel ID (lines 1014-1021 in TS) - maxPanelID := getMaxPanelID(rows) + // Also check top-level panels which may have been assigned IDs by ensurePanelsHaveUniqueIds + maxPanelID := getMaxPanelID(dashboard, rows) nextRowID := maxPanelID + 1 // Match frontend: dashboard.panels already exists with top-level panels @@ -269,10 +270,25 @@ func (r *rowArea) getPanelPosition(panelHeight int, panelWidth int) map[string]i return r.getPanelPosition(panelHeight, panelWidth) } -func getMaxPanelID(rows []interface{}) int { +func getMaxPanelID(dashboard map[string]interface{}, rows []interface{}) int { maxID := 0 hasValidID := false + // Check top-level panels first (these may have been assigned IDs by ensurePanelsHaveUniqueIds) + if panels, ok := dashboard["panels"].([]interface{}); ok { + for _, panelInterface := range panels { + if panel, ok := panelInterface.(map[string]interface{}); ok { + if id := GetIntValue(panel, "id", 0); id > 0 { + hasValidID = true + if id > maxID { + maxID = id + } + } + } + } + } + + // Also check panels inside rows for _, rowInterface := range rows { if row, ok := rowInterface.(map[string]interface{}); ok { if panels, ok := row["panels"].([]interface{}); ok { diff --git a/apps/dashboard/pkg/migration/testdata/output/latest_version/v16.span_zero_demo.v42.json b/apps/dashboard/pkg/migration/testdata/output/latest_version/v16.span_zero_demo.v42.json index 2b565a7117c..fbc1867f078 100644 --- a/apps/dashboard/pkg/migration/testdata/output/latest_version/v16.span_zero_demo.v42.json +++ b/apps/dashboard/pkg/migration/testdata/output/latest_version/v16.span_zero_demo.v42.json @@ -71,7 +71,7 @@ "x": 0, "y": 0 }, - "id": 23, + "id": 24, "panels": [], "targets": [ { diff --git a/apps/dashboard/pkg/migration/testdata/output/single_version/v16.span_zero_demo.v16.json b/apps/dashboard/pkg/migration/testdata/output/single_version/v16.span_zero_demo.v16.json index 473a1bfe023..129028d5931 100644 --- a/apps/dashboard/pkg/migration/testdata/output/single_version/v16.span_zero_demo.v16.json +++ b/apps/dashboard/pkg/migration/testdata/output/single_version/v16.span_zero_demo.v16.json @@ -51,7 +51,7 @@ "x": 0, "y": 0 }, - "id": 23, + "id": 24, "panels": [], "title": "Application Service", "type": "row" diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts index 7355f7575b7..4c9a0197782 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.ts @@ -816,14 +816,17 @@ export class DashboardMigrator { let yPos = 0; const widthFactor = GRID_COLUMN_COUNT / 12; - const maxPanelId = - max( - flattenDeep( - map(old.rows, (row) => { - return map(row.panels, 'id'); - }) - ).filter((id) => id != null) - ) || 0; + // Find max panel ID from both rows and existing top-level panels + // Top-level panels may have been assigned IDs by ensurePanelsHaveUniqueIds + const rowPanelIds = flattenDeep( + map(old.rows, (row) => { + return map(row.panels, 'id'); + }) + ).filter((id) => id != null); + + const topLevelPanelIds = map(this.dashboard.panels, 'id').filter((id) => id != null); + + const maxPanelId = max([...rowPanelIds, ...topLevelPanelIds]) || 0; let nextRowId = maxPanelId + 1; if (!old.rows) {