From ea2a0936df07b48b0cc61392d21fe4745c62294b Mon Sep 17 00:00:00 2001 From: Haris Rozajac <58232930+harisrozajac@users.noreply.github.com> Date: Wed, 14 Jan 2026 07:29:51 -0700 Subject: [PATCH] Dashboard Conversion: Preserve repeat property when converting tabs to rows (#116180) * preserve repeat property * fix test * preserve repeat when converting panels in tabs or rows with autogrid layout * fix v1 serialization of autogrid --- ...beta1.tabs-and-rows-repeated.v0alpha1.json | 4 ++++ ...2beta1.tabs-and-rows-repeated.v1beta1.json | 4 ++++ .../conversion/v2alpha1_to_v1beta1.go | 20 +++++++++++++++++++ .../transformSceneToSaveModel.ts | 13 ++++++++++++ 4 files changed, 41 insertions(+) diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json index 716b476f825..40b4fff030e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json @@ -586,6 +586,7 @@ }, "id": -1, "panels": [], + "repeat": "custom_var_tab", "title": "Repeated Tab by \"$custom_var_tab\"", "type": "row" }, @@ -610,8 +611,11 @@ "y": 22 }, "id": 6, + "maxPerRow": 3, "options": {}, "pluginVersion": "12.4.0-19736337744", + "repeat": "custom_var_panel", + "repeatDirection": "h", "targets": [ { "refId": "A" diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json index f915142fd14..ff1e2d42e20 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json @@ -586,6 +586,7 @@ }, "id": -1, "panels": [], + "repeat": "custom_var_tab", "title": "Repeated Tab by \"$custom_var_tab\"", "type": "row" }, @@ -610,8 +611,11 @@ "y": 22 }, "id": 6, + "maxPerRow": 3, "options": {}, "pluginVersion": "12.4.0-19736337744", + "repeat": "custom_var_panel", + "repeatDirection": "h", "targets": [ { "refId": "A" diff --git a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go index 857af7ca866..f9f953f965d 100644 --- a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go +++ b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go @@ -439,6 +439,11 @@ func processTabItem(elements map[string]dashv2alpha1.DashboardElement, tab *dash rowPanel["title"] = *tab.Spec.Title } + if tab.Spec.Repeat != nil && tab.Spec.Repeat.Value != "" { + // We only use value here as V1 doesn't support mode + rowPanel["repeat"] = tab.Spec.Repeat.Value + } + rowPanel["gridPos"] = map[string]interface{}{ "x": 0, "y": currentY, @@ -819,6 +824,21 @@ func convertAutoGridLayoutToPanelsWithOffset(elements map[string]dashv2alpha1.Da }, } + // Convert AutoGridRepeatOptions to RepeatOptions if present + // AutoGridRepeatOptions only has mode and value; infer direction and maxPerRow from AutoGrid settings: + // - direction: always "h" (AutoGrid flows horizontally, left-to-right then wraps) + // - maxPerRow: from AutoGrid's maxColumnCount + if item.Spec.Repeat != nil { + directionH := dashv2alpha1.DashboardRepeatOptionsDirectionH + maxPerRow := int64(maxColumnCount) + gridItem.Spec.Repeat = &dashv2alpha1.DashboardRepeatOptions{ + Mode: item.Spec.Repeat.Mode, + Value: item.Spec.Repeat.Value, + Direction: &directionH, + MaxPerRow: &maxPerRow, + } + } + panel, err := convertPanelFromElement(&element, &gridItem) if err != nil { return nil, fmt.Errorf("failed to convert panel %s: %w", item.Spec.Element.Name, err) diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index c5d01b433e3..4b0e109e864 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -781,6 +781,10 @@ export function tabItemToSaveModel( panels: [], }; + if (tab.state.repeatByVariable) { + rowPanel.repeat = tab.state.repeatByVariable; + } + panelsArray.push(rowPanel); // The base Y position for panels in this tab (after the row panel) @@ -912,6 +916,15 @@ function autoGridLayoutToPanels(layout: AutoGridLayoutManager, isSnapshot = fals }, isSnapshot ); + + // Handle repeat properties for AutoGridItem + // AutoGrid always uses horizontal direction, and maxPerRow is derived from maxColumnCount + if (item.state.variableName) { + panel.repeat = item.state.variableName; + panel.repeatDirection = 'h'; + panel.maxPerRow = maxColumnCount; + } + panels.push(panel); // Move to next position