import { PanelPlugin, PanelProps } from '@grafana/data'; import { config } from '@grafana/runtime'; import { SceneObject, SceneObjectBase, SceneObjectState, sceneUtils, VizPanel, VizPanelState } from '@grafana/scenes'; import { LibraryPanel } from '@grafana/schema'; import { Stack } from '@grafana/ui'; import { Trans } from 'app/core/internationalization'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { getLibraryPanel } from 'app/features/library-panels/state/api'; import { createPanelDataProvider } from '../utils/createPanelDataProvider'; import { VizPanelLinks, VizPanelLinksMenu } from './PanelLinks'; import { panelLinksBehavior } from './PanelMenuBehavior'; import { PanelNotices } from './PanelNotices'; import { PanelTimeRange } from './PanelTimeRange'; import { AngularDeprecation } from './angular/AngularDeprecation'; import { DashboardGridItem } from './layout-default/DashboardGridItem'; export interface LibraryPanelBehaviorState extends SceneObjectState { uid: string; name: string; isLoaded?: boolean; _loadedPanel?: LibraryPanel; } export class LibraryPanelBehavior extends SceneObjectBase { public static LOADING_VIZ_PANEL_PLUGIN_ID = 'library-panel-loading-plugin'; public constructor(state: LibraryPanelBehaviorState) { super(state); this.addActivationHandler(() => this._activationHandler()); } private _activationHandler() { if (!this.state.isLoaded) { this.loadLibraryPanelFromPanelModel(); } } public setPanelFromLibPanel(libPanel: LibraryPanel) { if (this.state._loadedPanel?.version === libPanel.version) { return; } const vizPanel = this.parent; if (!(vizPanel instanceof VizPanel)) { return; } const libPanelModel = new PanelModel(libPanel.model); const titleItems: SceneObject[] = []; if (config.featureToggles.angularDeprecationUI) { titleItems.push(new AngularDeprecation()); } titleItems.push( new VizPanelLinks({ rawLinks: libPanelModel.links, menu: new VizPanelLinksMenu({ $behaviors: [panelLinksBehavior] }), }) ); titleItems.push(new PanelNotices()); const vizPanelState: VizPanelState = { title: vizPanel.state.title ?? libPanelModel.title, options: libPanelModel.options ?? {}, fieldConfig: libPanelModel.fieldConfig, pluginId: libPanelModel.type, pluginVersion: libPanelModel.pluginVersion, displayMode: libPanelModel.transparent ? 'transparent' : undefined, description: libPanelModel.description, titleItems: titleItems, $data: createPanelDataProvider(libPanelModel), }; if (libPanelModel.timeFrom || libPanelModel.timeShift) { vizPanelState.$timeRange = new PanelTimeRange({ timeFrom: libPanelModel.timeFrom, timeShift: libPanelModel.timeShift, hideTimeOverride: libPanelModel.hideTimeOverride, }); } vizPanel.setState(vizPanelState); vizPanel.changePluginType(libPanelModel.type, vizPanelState.options, vizPanelState.fieldConfig); this.setState({ _loadedPanel: libPanel, isLoaded: true, name: libPanel.name }); const layoutElement = vizPanel.parent!; // Migrate repeat options to layout element if (libPanelModel.repeat && layoutElement instanceof DashboardGridItem) { layoutElement.setState({ variableName: libPanelModel.repeat, repeatDirection: libPanelModel.repeatDirection === 'h' ? 'h' : 'v', maxPerRow: libPanelModel.maxPerRow, itemHeight: layoutElement.state.height ?? 10, }); layoutElement.performRepeat(); } } /** * Removes itself from the parent panel's behaviors array */ public unlink() { const panel = this.parent; if (panel instanceof VizPanel) { panel.setState({ $behaviors: panel.state.$behaviors?.filter((b) => b !== this) }); } } private async loadLibraryPanelFromPanelModel() { let vizPanel = this.parent; if (!(vizPanel instanceof VizPanel)) { return; } try { const libPanel = await getLibraryPanel(this.state.uid, true); this.setPanelFromLibPanel(libPanel); } catch (err) { vizPanel.setState({ _pluginLoadError: `Unable to load library panel: ${this.state.uid}`, }); } } } const LoadingVizPanelPlugin = new PanelPlugin(LoadingVizPanel); function LoadingVizPanel(props: PanelProps) { return ( Loading library panel ); } sceneUtils.registerRuntimePanelPlugin({ pluginId: LibraryPanelBehavior.LOADING_VIZ_PANEL_PLUGIN_ID, plugin: LoadingVizPanelPlugin, });