diff --git a/devenv/dev-dashboards/e2e-repeats/Repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel.json b/devenv/dev-dashboards/e2e-repeats/Repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel.json index 3a2e6bb18b5..2ca379c1d61 100644 --- a/devenv/dev-dashboards/e2e-repeats/Repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel.json +++ b/devenv/dev-dashboards/e2e-repeats/Repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel.json @@ -44,7 +44,7 @@ "id": 2, "panels": [], "repeat": "row", - "title": "Row title $row", + "title": "Row $row", "type": "row" }, { @@ -119,7 +119,7 @@ "sort": "none" } }, - "title": "Panel Title", + "title": "Row $row non-repeating panel", "type": "timeseries" }, { @@ -196,7 +196,7 @@ }, "repeat": "horizontal", "repeatDirection": "h", - "title": "Horizontal repeating $horizontal", + "title": "Row $row repeating panel $horizontal", "type": "timeseries" } ], diff --git a/e2e/dashboards-suite/Repeating_a_row_with_a_non_repeating_panel.spec.ts b/e2e/dashboards-suite/Repeating_a_row_with_a_non_repeating_panel.spec.ts new file mode 100644 index 00000000000..c47eb7fd096 --- /dev/null +++ b/e2e/dashboards-suite/Repeating_a_row_with_a_non_repeating_panel.spec.ts @@ -0,0 +1,39 @@ +import { e2e } from '@grafana/e2e'; +const PAGE_UNDER_TEST = 'k3PEoCpnk/repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel'; + +describe('Repeating a row with repeated panels and a non-repeating panel', () => { + beforeEach(() => { + e2e.flows.login('admin', 'admin'); + }); + + it('should be able to collapse and expand a repeated row without losing panels', () => { + e2e.flows.openDashboard({ uid: PAGE_UNDER_TEST }); + + const panelsToCheck = [ + 'Row 2 non-repeating panel', + 'Row 2 repeating panel 1', + 'Row 2 repeating panel 2', + 'Row 2 repeating panel 3', + ]; + + // Collapse Row 1 first so the Row 2 panels all fit on the screen + e2e.components.DashboardRow.title('Row 1').click(); + + // Rows are expanded by default, so check that all panels are visible + panelsToCheck.forEach((title) => { + e2e.components.Panels.Panel.title(title).should('be.visible'); + }); + + // Collapse the row and check panels are no longer visible + e2e.components.DashboardRow.title('Row 2').click(); + panelsToCheck.forEach((title) => { + e2e.components.Panels.Panel.title(title).should('not.exist'); + }); + + // Expand the row and check all panels are visible again + e2e.components.DashboardRow.title('Row 2').click(); + panelsToCheck.forEach((title) => { + e2e.components.Panels.Panel.title(title).should('be.visible'); + }); + }); +}); diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index 7398d9cd803..693efdcff95 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -546,7 +546,9 @@ export class DashboardModel implements TimeModel { } cleanUpRowRepeats(rowPanels: PanelModel[]) { - const panelsToRemove = rowPanels.filter((p) => !p.repeat && p.repeatPanelId); + const panelIds = rowPanels.map((row) => row.id); + // Remove repeated panels whose parent is in this row as these will be recreated later in processRowRepeats + const panelsToRemove = rowPanels.filter((p) => !p.repeat && p.repeatPanelId && panelIds.includes(p.repeatPanelId)); pull(rowPanels, ...panelsToRemove); pull(this.panels, ...panelsToRemove);