From 20b9dc84449969706efb94210bc11b2e43cc9a0f Mon Sep 17 00:00:00 2001 From: Shubham Sinha Date: Mon, 10 Oct 2022 18:57:43 +0530 Subject: [PATCH] feat(embedded-dashboard): Share Switchboard State for Sending Events from Plugins (#21319) --- .../superset-ui-switchboard/src/index.ts | 3 ++ .../src/switchboard.test.ts | 27 +++++++++++++- .../src/switchboard.ts | 36 +++++++++++++++++-- superset-frontend/src/embedded/index.tsx | 14 ++++---- 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/superset-frontend/packages/superset-ui-switchboard/src/index.ts b/superset-frontend/packages/superset-ui-switchboard/src/index.ts index adbd7450fc..8e6bef5ff7 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/index.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/index.ts @@ -17,4 +17,7 @@ * under the License. */ +import Switchboard from './switchboard'; + export * from './switchboard'; +export default Switchboard; diff --git a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts index fc9ed46b21..9e36f541e1 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Switchboard } from './switchboard'; +import SingletonSwitchboard, { Switchboard } from './switchboard'; type EventHandler = (event: MessageEvent) => void; @@ -114,6 +114,7 @@ describe('comms', () => { beforeEach(() => { console.debug = jest.fn(); // silencio bruno + console.error = jest.fn(); }); afterEach(() => { @@ -128,6 +129,30 @@ describe('comms', () => { expect(sb).toHaveProperty('debugMode'); }); + it('singleton', async () => { + SingletonSwitchboard.start(); + expect(console.error).toHaveBeenCalledWith( + '[]', + 'Switchboard not initialised', + ); + SingletonSwitchboard.emit('someEvent', 42); + expect(console.error).toHaveBeenCalledWith( + '[]', + 'Switchboard not initialised', + ); + await expect(SingletonSwitchboard.get('failing')).rejects.toThrow( + 'Switchboard not initialised', + ); + SingletonSwitchboard.init({ port: new MessageChannel().port1 }); + expect(SingletonSwitchboard).toHaveProperty('name'); + expect(SingletonSwitchboard).toHaveProperty('debugMode'); + SingletonSwitchboard.init({ port: new MessageChannel().port1 }); + expect(console.error).toHaveBeenCalledWith( + '[switchboard]', + 'already initialized', + ); + }); + describe('emit', () => { it('triggers the method', async () => { const channel = new MessageChannel(); diff --git a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts index f12c9b6482..2a870e7b69 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.ts @@ -90,7 +90,7 @@ function isError(message: Message): message is ErrorMessage { export class Switchboard { port: MessagePort; - name: string; + name = ''; methods: Record> = {}; @@ -99,7 +99,23 @@ export class Switchboard { debugMode: boolean; - constructor({ port, name = 'switchboard', debug = false }: Params) { + private isInitialised: boolean; + + constructor(params?: Params) { + if (!params) { + return; + } + this.init(params); + } + + init(params: Params) { + if (this.isInitialised) { + this.logError('already initialized'); + return; + } + + const { port, name = 'switchboard', debug = false } = params; + this.port = port; this.name = name; this.debugMode = debug; @@ -122,6 +138,8 @@ export class Switchboard { } } }); + + this.isInitialised = true; } private async getMethodResult({ @@ -178,6 +196,10 @@ export class Switchboard { */ get(method: string, args: unknown = undefined): Promise { return new Promise((resolve, reject) => { + if (!this.isInitialised) { + reject(new Error('Switchboard not initialised')); + return; + } // In order to "call a method" on the other side of the port, // we will send a message with a unique id const messageId = this.getNewMessageId(); @@ -215,6 +237,10 @@ export class Switchboard { * @param args */ emit(method: string, args: unknown = undefined) { + if (!this.isInitialised) { + this.logError('Switchboard not initialised'); + return; + } const message: EmitMessage = { switchboardAction: Actions.EMIT, method, @@ -224,6 +250,10 @@ export class Switchboard { } start() { + if (!this.isInitialised) { + this.logError('Switchboard not initialised'); + return; + } this.port.start(); } @@ -242,3 +272,5 @@ export class Switchboard { return `m_${this.name}_${this.incrementor++}`; } } + +export default new Switchboard(); diff --git a/superset-frontend/src/embedded/index.tsx b/superset-frontend/src/embedded/index.tsx index df673f24e7..832c76a767 100644 --- a/superset-frontend/src/embedded/index.tsx +++ b/superset-frontend/src/embedded/index.tsx @@ -20,7 +20,7 @@ import React, { lazy, Suspense } from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router, Route } from 'react-router-dom'; import { makeApi, t, logging } from '@superset-ui/core'; -import { Switchboard } from '@superset-ui/switchboard'; +import Switchboard from '@superset-ui/switchboard'; import { bootstrapData } from 'src/preamble'; import setupClient from 'src/setup/setupClient'; import { RootContextProviders } from 'src/views/RootContextProviders'; @@ -176,7 +176,7 @@ window.addEventListener('message', function embeddedPageInitializer(event) { if (event.data.handshake === 'port transfer' && port) { log('message port received', event); - const switchboard = new Switchboard({ + Switchboard.init({ port, name: 'superset', debug: debugMode, @@ -184,7 +184,7 @@ window.addEventListener('message', function embeddedPageInitializer(event) { let started = false; - switchboard.defineMethod( + Switchboard.defineMethod( 'guestToken', ({ guestToken }: { guestToken: string }) => { setupGuestClient(guestToken); @@ -195,13 +195,13 @@ window.addEventListener('message', function embeddedPageInitializer(event) { }, ); - switchboard.defineMethod('getScrollSize', embeddedApi.getScrollSize); - switchboard.defineMethod( + Switchboard.defineMethod('getScrollSize', embeddedApi.getScrollSize); + Switchboard.defineMethod( 'getDashboardPermalink', embeddedApi.getDashboardPermalink, ); - switchboard.defineMethod('getActiveTabs', embeddedApi.getActiveTabs); - switchboard.start(); + Switchboard.defineMethod('getActiveTabs', embeddedApi.getActiveTabs); + Switchboard.start(); } });