Skip to content

Commit

Permalink
feat: Introduce a library for embedded iframe <-> host communication (#…
Browse files Browse the repository at this point in the history
…18652)

* improved logging

* switchboard, and window size

* lint

* tsconfig

* fix path

* fix release script

* tests, debug mode, and error handling

* moar debug mode

* package lock

* formatting

* comment

* wording

* appease the coverage gods

* Async assertions must be awaited or returned
  • Loading branch information
suddjian committed Feb 12, 2022
1 parent 40ab26d commit 225015f
Show file tree
Hide file tree
Showing 14 changed files with 737 additions and 29 deletions.
2 changes: 1 addition & 1 deletion superset-embedded-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"module": "lib/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc & babel src --out-dir lib --extensions '.ts,.tsx' & webpack --mode production",
"build": "tsc ; babel src --out-dir lib --extensions '.ts,.tsx' ; webpack --mode production",
"ci:release": "node ./release-if-necessary.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
Expand Down
29 changes: 22 additions & 7 deletions superset-embedded-sdk/release-if-necessary.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@ const { execSync } = require('child_process');
const axios = require('axios');
const { name, version } = require('./package.json');

function log(...args) {
console.log('[embedded-sdk-release]', ...args);
}

function logError(...args) {
console.error('[embedded-sdk-release]', ...args);
}

(async () => {
console.log(`checking if ${name}@${version} needs releasing`);
log(`checking if ${name}@${version} needs releasing`);

const packageUrl = `https://registry.npmjs.org/${name}/${version}`;
// npm commands output a bunch of garbage in the edge cases,
Expand All @@ -33,14 +41,21 @@ const { name, version } = require('./package.json');
});

if (status === 200) {
console.log('version already exists on npm, exiting');
log('version already exists on npm, exiting');
} else if (status === 404) {
console.log('release required, building');
execSync('npm run build');
execSync('npm publish --access public');
console.log(`published ${version} to npm`);
log('release required, building');
try {
execSync('npm run build', { stdio: 'pipe' });
log('build successful, publishing')
execSync('npm publish --access public', { stdio: 'pipe' });
log(`published ${version} to npm`);
} catch (err) {
console.error(String(err.stdout));
logError('Encountered an error, details should be above');
process.exitCode = 1;
}
} else {
console.error(`ERROR: Received unexpected http status code ${status} from GET ${packageUrl}
logError(`ERROR: Received unexpected http status code ${status} from GET ${packageUrl}
The embedded sdk release script might need to be fixed, or maybe you just need to try again later.`);
process.exitCode = 1;
}
Expand Down
36 changes: 28 additions & 8 deletions superset-embedded-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

import { IFRAME_COMMS_MESSAGE_TYPE } from './const';

// We can swap this out for the actual switchboard package once it gets published
import { Switchboard } from '../../superset-frontend/packages/superset-ui-switchboard/src/switchboard';

/**
* The function to fetch a guest token from your Host App's backend server.
* The Host App backend must supply an API endpoint
Expand All @@ -35,6 +38,17 @@ export type EmbedDashboardParams = {
mountPoint: HTMLElement
/** A function to fetch a guest token from the Host App's backend server */
fetchGuestToken: GuestTokenFetchFn
/** Are we in debug mode? */
debug?: boolean
}

export type Size = {
width: number, height: number
}

export type EmbeddedDashboard = {
getScrollSize: () => Promise<Size>
unmount: () => void
}

/**
Expand All @@ -44,15 +58,18 @@ export async function embedDashboard({
id,
supersetDomain,
mountPoint,
fetchGuestToken
}: EmbedDashboardParams) {
fetchGuestToken,
debug = false
}: EmbedDashboardParams): Promise<EmbeddedDashboard> {
function log(...info: unknown[]) {
console.debug(`[superset-embedded-sdk][dashboard ${id}]`, ...info);
if (debug) {
console.debug(`[superset-embedded-sdk][dashboard ${id}]`, ...info);
}
}

log('embedding');

async function mountIframe(): Promise<MessagePort> {
async function mountIframe(): Promise<Switchboard> {
return new Promise(resolve => {
const iframe = document.createElement('iframe');

Expand Down Expand Up @@ -83,7 +100,7 @@ export async function embedDashboard({
log('sent message channel to the iframe');

// return our port from the promise
resolve(ourPort);
resolve(new Switchboard({ port: ourPort, name: 'superset-embedded-sdk', debug }));
});

iframe.src = `${supersetDomain}/dashboard/${id}/embedded`;
Expand All @@ -94,18 +111,21 @@ export async function embedDashboard({

const [guestToken, ourPort] = await Promise.all([
fetchGuestToken(),
mountIframe()
mountIframe(),
]);

ourPort.postMessage({ guestToken });
ourPort.emit('guestToken', { guestToken });
log('sent guest token');

function unmount() {
log('unmounting');
mountPoint.replaceChildren();
}

const getScrollSize = () => ourPort.get<Size>('getScrollSize');

return {
unmount
getScrollSize,
unmount,
};
}
4 changes: 2 additions & 2 deletions superset-embedded-sdk/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module.exports = {
module: {
rules: [
{
test: /\.ts$/,
test: /\.[tj]s$/,
// babel-loader is faster than ts-loader because it ignores types.
// We do type checking in a separate process, so that's fine.
use: 'babel-loader',
Expand All @@ -44,6 +44,6 @@ module.exports = {
],
},
resolve: {
extensions: ['.ts'],
extensions: ['.ts', '.js'],
},
};
13 changes: 13 additions & 0 deletions superset-frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions superset-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
"@superset-ui/plugin-chart-table": "file:./plugins/plugin-chart-table",
"@superset-ui/plugin-chart-word-cloud": "file:./plugins/plugin-chart-word-cloud",
"@superset-ui/preset-chart-xy": "file:./plugins/preset-chart-xy",
"@superset-ui/switchboard": "file:./packages/superset-ui-switchboard",
"@vx/responsive": "^0.0.195",
"abortcontroller-polyfill": "^1.1.9",
"antd": "^4.9.4",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions superset-frontend/packages/superset-ui-switchboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@superset-ui/switchboard",
"version": "0.18.25",
"description": "Switchboard is a library to make it easier to communicate across browser windows using the MessageChannel API",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"files": [
"esm",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/apache/superset.git"
},
"keywords": [
"switchboard",
"iframe",
"communication",
"messagechannel",
"messageport",
"postmessage"
],
"author": "Superset",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/apache/superset/issues"
},
"homepage": "https://github.com/apache/superset#readme",
"publishConfig": {
"access": "public"
}
}
20 changes: 20 additions & 0 deletions superset-frontend/packages/superset-ui-switchboard/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export * from './switchboard';

0 comments on commit 225015f

Please sign in to comment.