feat(embedded-dashboard): Share Switchboard State for Sending Events from Plugins (#21319)

This commit is contained in:
Shubham Sinha 2022-10-10 18:57:43 +05:30 committed by GitHub
parent d1a6f0ebc4
commit 20b9dc8444
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 10 deletions

View File

@ -17,4 +17,7 @@
* under the License. * under the License.
*/ */
import Switchboard from './switchboard';
export * from './switchboard'; export * from './switchboard';
export default Switchboard;

View File

@ -17,7 +17,7 @@
* under the License. * under the License.
*/ */
import { Switchboard } from './switchboard'; import SingletonSwitchboard, { Switchboard } from './switchboard';
type EventHandler = (event: MessageEvent) => void; type EventHandler = (event: MessageEvent) => void;
@ -114,6 +114,7 @@ describe('comms', () => {
beforeEach(() => { beforeEach(() => {
console.debug = jest.fn(); // silencio bruno console.debug = jest.fn(); // silencio bruno
console.error = jest.fn();
}); });
afterEach(() => { afterEach(() => {
@ -128,6 +129,30 @@ describe('comms', () => {
expect(sb).toHaveProperty('debugMode'); 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', () => { describe('emit', () => {
it('triggers the method', async () => { it('triggers the method', async () => {
const channel = new MessageChannel(); const channel = new MessageChannel();

View File

@ -90,7 +90,7 @@ function isError(message: Message): message is ErrorMessage {
export class Switchboard { export class Switchboard {
port: MessagePort; port: MessagePort;
name: string; name = '';
methods: Record<string, Method<any, unknown>> = {}; methods: Record<string, Method<any, unknown>> = {};
@ -99,7 +99,23 @@ export class Switchboard {
debugMode: boolean; 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.port = port;
this.name = name; this.name = name;
this.debugMode = debug; this.debugMode = debug;
@ -122,6 +138,8 @@ export class Switchboard {
} }
} }
}); });
this.isInitialised = true;
} }
private async getMethodResult({ private async getMethodResult({
@ -178,6 +196,10 @@ export class Switchboard {
*/ */
get<T = unknown>(method: string, args: unknown = undefined): Promise<T> { get<T = unknown>(method: string, args: unknown = undefined): Promise<T> {
return new Promise((resolve, reject) => { 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, // In order to "call a method" on the other side of the port,
// we will send a message with a unique id // we will send a message with a unique id
const messageId = this.getNewMessageId(); const messageId = this.getNewMessageId();
@ -215,6 +237,10 @@ export class Switchboard {
* @param args * @param args
*/ */
emit(method: string, args: unknown = undefined) { emit(method: string, args: unknown = undefined) {
if (!this.isInitialised) {
this.logError('Switchboard not initialised');
return;
}
const message: EmitMessage = { const message: EmitMessage = {
switchboardAction: Actions.EMIT, switchboardAction: Actions.EMIT,
method, method,
@ -224,6 +250,10 @@ export class Switchboard {
} }
start() { start() {
if (!this.isInitialised) {
this.logError('Switchboard not initialised');
return;
}
this.port.start(); this.port.start();
} }
@ -242,3 +272,5 @@ export class Switchboard {
return `m_${this.name}_${this.incrementor++}`; return `m_${this.name}_${this.incrementor++}`;
} }
} }
export default new Switchboard();

View File

@ -20,7 +20,7 @@ import React, { lazy, Suspense } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom'; import { BrowserRouter as Router, Route } from 'react-router-dom';
import { makeApi, t, logging } from '@superset-ui/core'; 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 { bootstrapData } from 'src/preamble';
import setupClient from 'src/setup/setupClient'; import setupClient from 'src/setup/setupClient';
import { RootContextProviders } from 'src/views/RootContextProviders'; import { RootContextProviders } from 'src/views/RootContextProviders';
@ -176,7 +176,7 @@ window.addEventListener('message', function embeddedPageInitializer(event) {
if (event.data.handshake === 'port transfer' && port) { if (event.data.handshake === 'port transfer' && port) {
log('message port received', event); log('message port received', event);
const switchboard = new Switchboard({ Switchboard.init({
port, port,
name: 'superset', name: 'superset',
debug: debugMode, debug: debugMode,
@ -184,7 +184,7 @@ window.addEventListener('message', function embeddedPageInitializer(event) {
let started = false; let started = false;
switchboard.defineMethod( Switchboard.defineMethod(
'guestToken', 'guestToken',
({ guestToken }: { guestToken: string }) => { ({ guestToken }: { guestToken: string }) => {
setupGuestClient(guestToken); setupGuestClient(guestToken);
@ -195,13 +195,13 @@ window.addEventListener('message', function embeddedPageInitializer(event) {
}, },
); );
switchboard.defineMethod('getScrollSize', embeddedApi.getScrollSize); Switchboard.defineMethod('getScrollSize', embeddedApi.getScrollSize);
switchboard.defineMethod( Switchboard.defineMethod(
'getDashboardPermalink', 'getDashboardPermalink',
embeddedApi.getDashboardPermalink, embeddedApi.getDashboardPermalink,
); );
switchboard.defineMethod('getActiveTabs', embeddedApi.getActiveTabs); Switchboard.defineMethod('getActiveTabs', embeddedApi.getActiveTabs);
switchboard.start(); Switchboard.start();
} }
}); });