diff --git a/packages/scenes/src/components/VizPanel/VizPanel.test.tsx b/packages/scenes/src/components/VizPanel/VizPanel.test.tsx index be1717e3d..fb2dc9914 100644 --- a/packages/scenes/src/components/VizPanel/VizPanel.test.tsx +++ b/packages/scenes/src/components/VizPanel/VizPanel.test.tsx @@ -24,6 +24,7 @@ import { SeriesVisibilityChangeMode } from '@grafana/ui'; import { SceneTimeRange } from '../../core/SceneTimeRange'; import { act, render, screen } from '@testing-library/react'; import { RefreshEvent } from '@grafana/runtime'; +import { SceneDeactivationHandler } from '../../core/types'; let pluginToLoad: PanelPlugin | undefined; @@ -289,6 +290,7 @@ describe('VizPanel', () => { describe('When changing plugin', () => { let panel: VizPanel; + let deactivate: SceneDeactivationHandler; beforeEach(async () => { panel = new VizPanel({ @@ -300,7 +302,11 @@ describe('VizPanel', () => { }); pluginToLoad = getTestPlugin1(); - panel.activate(); + deactivate = panel.activate(); + }); + + afterEach(() => { + deactivate(); }); it('Should successfully change from one viz type to another', async () => { @@ -365,6 +371,18 @@ describe('VizPanel', () => { expect(panel.state.options.showThresholds).toBe(true); expect(panel.state.options.option2).toBe('hello'); }); + + it('Should detect plugin change on activation', async () => { + pluginToLoad = getTestPlugin2(); + deactivate(); + + panel.setState({ pluginId: pluginToLoad.meta.id }); + deactivate = panel.activate(); + + await Promise.resolve(); + + expect(panel.getPlugin()).toBe(pluginToLoad); + }); }); describe('getLegacyPanelId', () => { diff --git a/packages/scenes/src/components/VizPanel/VizPanel.tsx b/packages/scenes/src/components/VizPanel/VizPanel.tsx index 2f498fd09..b0424489e 100644 --- a/packages/scenes/src/components/VizPanel/VizPanel.tsx +++ b/packages/scenes/src/components/VizPanel/VizPanel.tsx @@ -122,12 +122,17 @@ export class VizPanel extends Scene } private _onActivate() { - if (!this._plugin) { + if (!this._plugin || this.state.pluginId !== this._plugin.meta.id) { this._loadPlugin(this.state.pluginId); } } - private async _loadPlugin(pluginId: string, overwriteOptions?: DeepPartial<{}>, overwriteFieldConfig?: FieldConfigSource, isAfterPluginChange?: boolean) { + private async _loadPlugin( + pluginId: string, + overwriteOptions?: DeepPartial<{}>, + overwriteFieldConfig?: FieldConfigSource, + isAfterPluginChange?: boolean + ) { const plugin = loadPanelPluginSync(pluginId); if (plugin) { @@ -157,7 +162,12 @@ export class VizPanel extends Scene return panelId; } - private async _pluginLoaded(plugin: PanelPlugin, overwriteOptions?: DeepPartial<{}>, overwriteFieldConfig?: FieldConfigSource, isAfterPluginChange?: boolean) { + private async _pluginLoaded( + plugin: PanelPlugin, + overwriteOptions?: DeepPartial<{}>, + overwriteFieldConfig?: FieldConfigSource, + isAfterPluginChange?: boolean + ) { const { options, fieldConfig, title, pluginVersion, _UNSAFE_customMigrationHandler } = this.state; const panel: PanelModel = { @@ -217,6 +227,10 @@ export class VizPanel extends Scene return this._plugin; } + public getPluginAsync(): PanelPlugin | undefined { + return this._plugin; + } + public getPanelContext(): PanelContext { this._panelContext ??= this.buildPanelContext(); @@ -257,11 +271,7 @@ export class VizPanel extends Scene }; public async changePluginType(pluginId: string, newOptions?: DeepPartial<{}>, newFieldConfig?: FieldConfigSource) { - const { - options: prevOptions, - fieldConfig: prevFieldConfig, - pluginId: prevPluginId, - } = this.state; + const { options: prevOptions, fieldConfig: prevFieldConfig, pluginId: prevPluginId } = this.state; //clear field config cache to update it later this._dataWithFieldConfig = undefined; @@ -276,8 +286,8 @@ export class VizPanel extends Scene type: pluginId, }; - // onPanelTypeChanged is mainly used by plugins to migrate from Angular to React. - // For example, this will migrate options from 'graph' to 'timeseries' if the previous and new plugin ID matches. + // onPanelTypeChanged is mainly used by plugins to migrate from Angular to React. + // For example, this will migrate options from 'graph' to 'timeseries' if the previous and new plugin ID matches. const updatedOptions = this._plugin?.onPanelTypeChanged?.(panel, prevPluginId, prevOptions, prevFieldConfig); if (updatedOptions && !isEmpty(updatedOptions)) {