diff --git a/public/app/features/dashboard-scene/scene/DashboardGridItem.test.tsx b/public/app/features/dashboard-scene/scene/DashboardGridItem.test.tsx index fc045edfa16..6a710357cdf 100644 --- a/public/app/features/dashboard-scene/scene/DashboardGridItem.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardGridItem.test.tsx @@ -1,6 +1,7 @@ import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks'; import { setPluginImportUtils } from '@grafana/runtime'; -import { SceneGridLayout, VizPanel } from '@grafana/scenes'; +import { SceneGridLayout, TestVariable, VizPanel } from '@grafana/scenes'; +import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from 'app/features/variables/constants'; import { activateFullSceneTree, buildPanelRepeaterScene } from '../utils/test-utils'; @@ -40,7 +41,7 @@ describe('PanelRepeaterGridItem', () => { expect(repeater.state.repeatedPanels?.length).toBe(5); }); - it('Should adjust container height to fit panels direction is horizontal', async () => { + it('Should adjust container height to fit panels if direction is horizontal', async () => { const { scene, repeater } = buildPanelRepeaterScene({ variableQueryTime: 0, maxPerRow: 2, itemHeight: 10 }); const layoutForceRender = jest.fn(); @@ -144,4 +145,56 @@ describe('PanelRepeaterGridItem', () => { expect(gridItem.getClassName()).toBe(''); }); + + it('should have correct height after repeat is performed', () => { + const { scene, repeater } = buildPanelRepeaterScene({ + variableQueryTime: 0, + height: 4, + maxPerRow: 4, + repeatDirection: 'h', + numberOfOptions: 5, + }); + + activateFullSceneTree(scene); + + expect(repeater.state.height).toBe(4); + }); + + it('should have same item height if number of repititions changes', async () => { + const { scene, repeater } = buildPanelRepeaterScene({ + variableQueryTime: 0, + height: 4, + maxPerRow: 4, + repeatDirection: 'h', + numberOfOptions: 5, + }); + activateFullSceneTree(scene); + + scene.state.$variables!.setState({ + variables: [ + new TestVariable({ + name: 'server', + query: 'A.*', + value: ALL_VARIABLE_VALUE, + text: ALL_VARIABLE_TEXT, + isMulti: true, + includeAll: true, + delayMs: 0, + optionsToReturn: [ + { label: 'A', value: '1' }, + { label: 'B', value: '2' }, + { label: 'C', value: '3' }, + { label: 'D', value: '4' }, + { label: 'E', value: '5' }, + { label: 'F', value: '6' }, + { label: 'G', value: '7' }, + { label: 'H', value: '8' }, + { label: 'I', value: '9' }, + { label: 'J', value: '10' }, + ], + }), + ], + }); + expect(repeater.state.height).toBe(6); + }); }); diff --git a/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx b/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx index d1fb47776ed..99d91083efc 100644 --- a/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx @@ -163,6 +163,8 @@ export class DashboardGridItem extends SceneObjectBase i return; } + // Needed to calculate item height + const prevRepeatCount = this._prevRepeatValues?.length ?? values.length; this._prevRepeatValues = values; const panelToRepeat = this.state.body instanceof LibraryVizPanel ? this.state.body.state.panel! : this.state.body; const repeatedPanels: VizPanel[] = []; @@ -188,16 +190,15 @@ export class DashboardGridItem extends SceneObjectBase i const direction = this.getRepeatDirection(); const stateChange: Partial = { repeatedPanels: repeatedPanels }; - const itemHeight = this.state.itemHeight ?? 10; - const prevHeight = this.state.height; - const maxPerRow = this.getMaxPerRow(); + const prevHeight = this.state.height ?? 0; + const maxPerRow = direction === 'h' ? this.getMaxPerRow() : 1; + const prevRowCount = Math.ceil(prevRepeatCount / maxPerRow); + const newRowCount = Math.ceil(repeatedPanels.length / maxPerRow); - if (direction === 'h') { - const rowCount = Math.ceil(repeatedPanels.length / maxPerRow); - stateChange.height = rowCount * itemHeight; - } else { - stateChange.height = repeatedPanels.length * itemHeight; - } + // If item height is not defined, calculate based on total height and row count + const itemHeight = this.state.itemHeight ?? prevHeight / prevRowCount; + stateChange.itemHeight = itemHeight; + stateChange.height = Math.ceil(newRowCount * itemHeight); this.setState(stateChange); diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index 2d76314a1cb..121ee9d8c74 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -437,7 +437,6 @@ export function buildGridItemForLibPanel(panel: PanelModel) { x: panel.gridPos.x, width: panel.gridPos.w, height: panel.gridPos.h, - itemHeight: panel.gridPos.h, body, }); } @@ -502,7 +501,6 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem { y: panel.gridPos.y, width: repeatOptions.repeatDirection === 'h' ? 24 : panel.gridPos.w, height: panel.gridPos.h, - itemHeight: panel.gridPos.h, body, maxPerRow: panel.maxPerRow, ...repeatOptions, diff --git a/public/app/features/dashboard-scene/utils/test-utils.ts b/public/app/features/dashboard-scene/utils/test-utils.ts index 235dae85035..b8f284622d0 100644 --- a/public/app/features/dashboard-scene/utils/test-utils.ts +++ b/public/app/features/dashboard-scene/utils/test-utils.ts @@ -96,6 +96,7 @@ interface SceneOptions { variableQueryTime: number; maxPerRow?: number; itemHeight?: number; + height?: number; repeatDirection?: RepeatDirection; x?: number; y?: number; @@ -113,6 +114,7 @@ export function buildPanelRepeaterScene(options: SceneOptions, source?: VizPanel repeatDirection: options.repeatDirection, maxPerRow: options.maxPerRow, itemHeight: options.itemHeight, + height: options.height, body: source ?? new VizPanel({