diff --git a/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx b/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx index 753a504de5c..66cde096744 100644 --- a/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/css'; import React, { useMemo } from 'react'; +import { Unsubscribable } from 'rxjs'; import { config } from '@grafana/runtime'; import { @@ -39,6 +40,7 @@ interface DashboardGridItemState extends SceneGridItemStateLike { export type RepeatDirection = 'v' | 'h'; export class DashboardGridItem extends SceneObjectBase implements SceneGridItemLike { + private _libPanelSubscription: Unsubscribable | undefined; protected _variableDependency = new VariableDependencyConfig(this, { variableNames: this.state.variableName ? [this.state.variableName] : [], onVariableUpdateCompleted: this._onVariableUpdateCompleted.bind(this), @@ -55,6 +57,46 @@ export class DashboardGridItem extends SceneObjectBase i this._subs.add(this.subscribeToState((newState, prevState) => this._handleGridResize(newState, prevState))); this._performRepeat(); } + + // Subscriptions that handles body updates, i.e. VizPanel -> LibraryVizPanel, AddLibPanelWidget -> LibraryVizPanel + this._subs.add( + this.subscribeToState((newState, prevState) => { + if (newState.body !== prevState.body) { + if (newState.body instanceof LibraryVizPanel) { + this.setupLibraryPanelChangeSubscription(newState.body); + } + } + }) + ); + + // Initial setup of the lbrary panel subscription. Lib panels are lazy laded, so only then we can subscribe to the repeat config changes + if (this.state.body instanceof LibraryVizPanel) { + this.setupLibraryPanelChangeSubscription(this.state.body); + } + + return () => { + this._libPanelSubscription?.unsubscribe(); + this._libPanelSubscription = undefined; + }; + } + + private setupLibraryPanelChangeSubscription(panel: LibraryVizPanel) { + if (this._libPanelSubscription) { + this._libPanelSubscription.unsubscribe(); + this._libPanelSubscription = undefined; + } + + this._libPanelSubscription = panel.subscribeToState((newState) => { + if (newState._loadedPanel?.model.repeat) { + this._variableDependency.setVariableNames([newState._loadedPanel.model.repeat]); + this.setState({ + variableName: newState._loadedPanel.model.repeat, + repeatDirection: newState._loadedPanel.model.repeatDirection, + maxPerRow: newState._loadedPanel.model.maxPerRow, + }); + this._performRepeat(); + } + }); } private _onVariableUpdateCompleted(): void { diff --git a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx index 53b9c2ddc42..76e70db37cc 100644 --- a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx +++ b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { SceneComponentProps, - SceneGridLayout, SceneObjectBase, SceneObjectState, VizPanel, @@ -78,29 +77,6 @@ export class LibraryVizPanel extends SceneObjectBase { }; const panel = new VizPanel(vizPanelState); - const gridItem = this.parent; - - if (libPanelModel.repeat && gridItem instanceof DashboardGridItem && gridItem.parent instanceof SceneGridLayout) { - this._parent = undefined; - const repeater = new DashboardGridItem({ - key: gridItem.state.key, - x: gridItem.state.x, - y: gridItem.state.y, - width: libPanelModel.repeatDirection === 'h' ? 24 : gridItem.state.width, - height: gridItem.state.height, - itemHeight: gridItem.state.height, - body: this, - variableName: libPanelModel.repeat, - repeatedPanels: [], - repeatDirection: libPanelModel.repeatDirection === 'h' ? 'h' : 'v', - maxPerRow: libPanelModel.maxPerRow, - }); - gridItem.parent.setState({ - children: gridItem.parent.state.children.map((child) => - child.state.key === gridItem.state.key ? repeater : child - ), - }); - } this.setState({ panel, _loadedPanel: libPanel, isLoaded: true, name: libPanel.name }); }