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
This commit is contained in:
Haris Rozajac
2026-01-14 07:29:51 -07:00
committed by GitHub
parent d95c51b20e
commit ea2a0936df
4 changed files with 41 additions and 0 deletions
@@ -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"
@@ -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"
@@ -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)
@@ -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