diff --git a/packages/grafana-ui/src/types/app.ts b/packages/grafana-ui/src/types/app.ts index 01dd6e1a40a..16302feefd9 100644 --- a/packages/grafana-ui/src/types/app.ts +++ b/packages/grafana-ui/src/types/app.ts @@ -26,6 +26,13 @@ export class AppPlugin extends GrafanaPlugin { // Old style pages angularPages?: { [component: string]: any }; + /** + * Called after the module has loaded, and before the app is used. + * This function may be called multiple times on the same instance. + * The first time, `this.meta` will be undefined + */ + init(meta: AppPluginMeta) {} + /** * Set the component displayed under: * /a/${plugin-id}/* diff --git a/public/app/features/plugins/plugin_loader.test.ts b/public/app/features/plugins/plugin_loader.test.ts new file mode 100644 index 00000000000..845a5dde62a --- /dev/null +++ b/public/app/features/plugins/plugin_loader.test.ts @@ -0,0 +1,68 @@ +// Use the real plugin_loader (stubbed by default) +jest.unmock('app/features/plugins/plugin_loader'); + +(global as any).ace = { + define: jest.fn(), +}; + +jest.mock('app/core/core', () => { + return { + coreModule: { + directive: jest.fn(), + }, + }; +}); + +/* tslint:disable:import-blacklist */ +import System from 'systemjs/dist/system.js'; + +import { AppPluginMeta, PluginMetaInfo, PluginType, AppPlugin } from '@grafana/ui'; +import { importAppPlugin } from './plugin_loader'; + +class MyCustomApp extends AppPlugin { + initWasCalled = false; + calledTwice = false; + + init(meta: AppPluginMeta) { + this.initWasCalled = true; + this.calledTwice = this.meta === meta; + } +} + +describe('Load App', () => { + const app = new MyCustomApp(); + const modulePath = 'my/custom/plugin/module'; + + beforeAll(() => { + System.set(modulePath, System.newModule({ plugin: app })); + }); + + afterAll(() => { + System.delete(modulePath); + }); + + it('should call init and set meta', async () => { + const meta: AppPluginMeta = { + id: 'test-app', + module: modulePath, + baseUrl: 'xxx', + info: {} as PluginMetaInfo, + type: PluginType.app, + name: 'test', + }; + + // Check that we mocked the import OK + const m = await System.import(modulePath); + expect(m.plugin).toBe(app); + + const loaded = await importAppPlugin(meta); + expect(loaded).toBe(app); + expect(app.meta).toBe(meta); + expect(app.initWasCalled).toBeTruthy(); + expect(app.calledTwice).toBeFalsy(); + + const again = await importAppPlugin(meta); + expect(again).toBe(app); + expect(app.calledTwice).toBeTruthy(); + }); +}); diff --git a/public/app/features/plugins/plugin_loader.ts b/public/app/features/plugins/plugin_loader.ts index 55531559d1d..9c3bc4ca553 100644 --- a/public/app/features/plugins/plugin_loader.ts +++ b/public/app/features/plugins/plugin_loader.ts @@ -181,8 +181,9 @@ export function importDataSourcePlugin(meta: DataSourcePluginMeta): Promise { return importPluginModule(meta.module).then(pluginExports => { const plugin = pluginExports.plugin ? (pluginExports.plugin as AppPlugin) : new AppPlugin(); - plugin.meta = meta; plugin.setComponentsFromLegacyExports(pluginExports); + plugin.init(meta); + plugin.meta = meta; return plugin; }); }