@mongodb-js/charts-embed-dom
Version:
JavaScript library for embedding MongoDB Charts
166 lines (165 loc) • 6.47 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chatty_1 = require("@looker/chatty");
const dom_1 = require("./dom");
const types_1 = require("./types");
const utils_1 = require("./utils");
const MAX_QUERY_EXECUTION_MS = 10 * 60 * 1000; // 10 minutes
class BaseEmbedItem {
/**
* Renders an embeddable item into the given `container`.
*
* This method should only be called once, and successive attempts to call `render`
* will fail with an error.
*
* @returns a promise that will resolve once the item has successfully been embedded
*/
async render(container) {
if (this.iframe) {
throw new Error(this.ERRORS.IFRAME);
}
// Create styled container
const embedRoot = this._configureEmbedRoot((0, dom_1.createElement)('div', {
style: {
position: 'relative',
overflow: 'hidden',
minHeight: Boolean(this.options.height) ? 0 : '15px',
width: (0, utils_1.parseCSSMeasurement)(this.options.width) || '100%',
height: (0, utils_1.parseCSSMeasurement)(this.options.height) || '100%',
},
}));
// Create host
const host = this._configureHost(chatty_1.Chatty.createHost(this.getEmbedUrl())
.withDefaultTimeout(MAX_QUERY_EXECUTION_MS)
.withSandboxAttribute('allow-scripts')
.withSandboxAttribute('allow-same-origin')
.withSandboxAttribute('allow-popups')
.withSandboxAttribute('allow-popups-to-escape-sandbox')
.appendTo(embedRoot)).build();
// Customise IFrame styles
host.iframe.setAttribute('aria-label', this.name);
Object.assign(host.iframe.style, {
position: 'absolute',
top: 0,
left: 0,
border: 0,
width: '100%',
height: '100%',
});
// Remove any existing nodes in our target container
while (container.firstChild)
container.removeChild(container.firstChild);
container.appendChild(embedRoot);
// connect to iframe
this.connection = await host.connect();
this.iframe = host.iframe;
this._setBackground(this.options.background, this.options.theme);
// configure token if needed
await this._retrieveAndSetToken();
}
/**
* @returns whether auto refreshing is enabled
*/
async isAutoRefresh() {
const [result] = await this._send('get', 'autoRefresh');
// autoRefresh from embed chart may be a number when refreshInterval is set
return typeof result === 'number' || typeof result === 'boolean'
? Boolean(result)
: Promise.reject('unexpected response received from iframe');
}
/**
* Enable/Disable auto refreshing.
*/
async setAutoRefresh(value) {
if (typeof value !== 'boolean') {
return Promise.reject('autoRefresh property value should be a boolean');
}
await this._send('set', 'autoRefresh', value);
}
/**
* @returns the number of seconds before a chart or dashboard's data expires
*/
async getMaxDataAge() {
const [result] = await this._send('get', 'maxDataAge');
return typeof result === 'number'
? result
: Promise.reject('unexpected response received from iframe');
}
/**
* Set the number of seconds a chart or dashboard's data expires.
*/
async setMaxDataAge(value) {
if (typeof value !== 'number') {
return Promise.reject('maxDataAge property value should be a number');
}
await this._send('set', 'maxDataAge', value);
}
/**
* Sets the color scheme to apply to the chart or dashboard.
*
* If the theme is set to 'dark' and you have specified a custom background color, you should ensure that your background color has appropriate contrast.
*/
async setTheme(value) {
if (typeof value !== 'string') {
return Promise.reject('theme property value should be a string');
}
// if invalid theme string is provided, default it to light
const newTheme = Object.values(types_1.THEME).includes(value)
? value
: types_1.THEME.LIGHT;
await this._send('set', 'theme', newTheme);
this._setBackground(this.options.background, newTheme);
}
/**
* @returns the current theme applied to the chart or dashboard
*/
async getTheme() {
const [result] = await this._send('get', 'theme');
return typeof result === 'string'
? result
: Promise.reject('unexpected response received from iframe');
}
_configureHost(hostBuilder) {
return hostBuilder.on('refreshToken', () => this._retrieveAndSetToken());
}
_configureEmbedRoot(embedRoot) {
return embedRoot;
}
_setBackground(background, theme) {
this.iframe.style.backgroundColor = (0, utils_1.getBackground)(background, theme, this.COLOUR.LIGHT, this.COLOUR.DARK);
}
async _retrieveAndSetToken() {
if (this.options.getUserToken) {
const token = await this.options.getUserToken();
await this._send('set', 'token', token);
}
}
/**
* Send message to embedded app.
*/
_send(eventName, ...payload) {
if (this.connection) {
return this.connection.sendAndReceive(eventName, ...payload);
}
return Promise.reject(this.ERRORS.SEND);
}
/**
* Get the image data of embeded entity in base64 or binary encoding
* @param {GetImageOptions} options options for image generation
* @returns {string | Blob} image encoded with base64 or binary
*/
async getImage(options) {
const { encoding } = options || {};
if (encoding !== types_1.ENCODING.BASE64 && encoding !== types_1.ENCODING.BINARY) {
return Promise.reject('Encoding must be either "base64" or "binary"');
}
const [result] = await this._send('get', 'image', {
background: this.options.background,
encoding,
});
return typeof result === 'string' || result instanceof Blob
? result
: Promise.reject('unexpected response received from iframe');
}
}
exports.default = BaseEmbedItem;