@thoughtspot/visual-embed-sdk
Version:
ThoughtSpot Embed SDK
363 lines • 15.9 kB
JavaScript
"use strict";
/**
* Copyright (c) 2022
*
* Embed a ThoughtSpot Liveboard or visualization
* https://developers.thoughtspot.com/docs/?pageid=embed-pinboard
* https://developers.thoughtspot.com/docs/?pageid=embed-a-viz
* @summary Liveboard & visualization embed
* @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PinboardEmbed = exports.LiveboardEmbed = void 0;
const preview_service_1 = require("../utils/graphql/preview-service");
const errors_1 = require("../errors");
const types_1 = require("../types");
const utils_1 = require("../utils");
const ts_embed_1 = require("./ts-embed");
const global_styles_1 = require("../utils/global-styles");
const logger_1 = require("../utils/logger");
/**
* Embed a ThoughtSpot Liveboard or visualization. When rendered it already
* waits for the authentication to complete, so you need not wait for
* `AuthStatus.SUCCESS`.
* @example
* ```js
* import { .. } from '@thoughtspot/visual-embed-sdk';
* init({ ... });
* const embed = new LiveboardEmbed("#container", {
* liveboardId: <your-id-here>,
* // .. other params here.
* })
* ```
* @group Embed components
*/
class LiveboardEmbed extends ts_embed_1.V1Embed {
constructor(domSelector, viewConfig) {
viewConfig.embedComponentType = 'LiveboardEmbed';
super(domSelector, viewConfig);
this.defaultHeight = 500;
this.sendFullHeightLazyLoadData = () => {
const data = (0, utils_1.calculateVisibleElementData)(this.iFrame);
this.trigger(types_1.HostEvent.VisibleEmbedCoordinates, data);
};
/**
* This is a handler for the RequestVisibleEmbedCoordinates event.
* It is used to send the visible coordinates data to the host application.
* @param data The event payload
* @param responder The responder function
*/
this.requestVisibleEmbedCoordinatesHandler = (data, responder) => {
logger_1.logger.info('Sending RequestVisibleEmbedCoordinates', data);
const visibleCoordinatesData = (0, utils_1.calculateVisibleElementData)(this.iFrame);
responder({ type: types_1.EmbedEvent.RequestVisibleEmbedCoordinates, data: visibleCoordinatesData });
};
/**
* Set the iframe height as per the computed height received
* from the ThoughtSpot app.
* @param data The event payload
*/
this.updateIFrameHeight = (data) => {
this.setIFrameHeight(Math.max(data.data, this.defaultHeight));
this.sendFullHeightLazyLoadData();
};
this.embedIframeCenter = (data, responder) => {
const obj = this.getIframeCenter();
responder({ type: types_1.EmbedEvent.EmbedIframeCenter, data: obj });
};
this.setIframeHeightForNonEmbedLiveboard = (data) => {
const { height: frameHeight } = this.viewConfig.frameParams || {};
const liveboardRelatedRoutes = [
'/pinboard/',
'/insights/pinboard/',
'/schedules/',
'/embed/viz/',
'/embed/insights/viz/',
'/liveboard/',
'/insights/liveboard/',
'/tsl-editor/PINBOARD_ANSWER_BOOK/',
'/import-tsl/PINBOARD_ANSWER_BOOK/',
];
if (liveboardRelatedRoutes.some((path) => data.data.currentPath.startsWith(path))) {
// Ignore the height reset of the frame, if the navigation is
// only within the liveboard page.
return;
}
this.setIFrameHeight(frameHeight || this.defaultHeight);
};
/**
* @hidden
* Internal state to track the current liveboard id.
* This is used to navigate to the correct liveboard when the prerender is visible.
*/
this.currentLiveboardState = {
liveboardId: this.viewConfig.liveboardId,
vizId: this.viewConfig.vizId,
activeTabId: this.viewConfig.activeTabId,
};
if (this.viewConfig.fullHeight === true) {
if (this.viewConfig.vizId) {
logger_1.logger.warn('Full height is currently only supported for Liveboard embeds.' +
'Using full height with vizId might lead to unexpected behavior.');
}
this.on(types_1.EmbedEvent.RouteChange, this.setIframeHeightForNonEmbedLiveboard);
this.on(types_1.EmbedEvent.EmbedHeight, this.updateIFrameHeight);
this.on(types_1.EmbedEvent.EmbedIframeCenter, this.embedIframeCenter);
this.on(types_1.EmbedEvent.RequestVisibleEmbedCoordinates, this.requestVisibleEmbedCoordinatesHandler);
}
}
/**
* Construct a map of params to be passed on to the
* embedded Liveboard or visualization.
*/
getEmbedParams() {
let params = {};
params = this.getBaseQueryParams(params);
const { enableVizTransformations, fullHeight, defaultHeight, visibleVizs, liveboardV2, vizId, hideTabPanel, activeTabId, hideLiveboardHeader, showLiveboardDescription, showLiveboardTitle, isLiveboardHeaderSticky = true, isLiveboardCompactHeaderEnabled = false, showLiveboardVerifiedBadge = true, showLiveboardReverifyBanner = true, hideIrrelevantChipsInLiveboardTabs = false, enableAskSage, enable2ColumnLayout, dataPanelV2 = true, enableCustomColumnGroups = false, oAuthPollingInterval, isForceRedirect, dataSourceId, coverAndFilterOptionInPDF = false, liveboardXLSXCSVDownload = false, isLiveboardStylingAndGroupingEnabled, isPNGInScheduledEmailsEnabled = false, showSpotterLimitations, } = this.viewConfig;
const preventLiveboardFilterRemoval = this.viewConfig.preventLiveboardFilterRemoval
|| this.viewConfig.preventPinboardFilterRemoval;
if (fullHeight === true) {
params[types_1.Param.fullHeight] = true;
if (this.viewConfig.lazyLoadingForFullHeight) {
params[types_1.Param.IsLazyLoadingForEmbedEnabled] = true;
params[types_1.Param.RootMarginForLazyLoad] = this.viewConfig.lazyLoadingMargin;
}
}
if (defaultHeight) {
this.defaultHeight = defaultHeight;
}
if (enableVizTransformations !== undefined) {
params[types_1.Param.EnableVizTransformations] = enableVizTransformations.toString();
}
if (preventLiveboardFilterRemoval) {
params[types_1.Param.preventLiveboardFilterRemoval] = true;
}
if (visibleVizs) {
params[types_1.Param.visibleVizs] = visibleVizs;
}
params[types_1.Param.livedBoardEmbed] = true;
if (vizId) {
params[types_1.Param.vizEmbed] = true;
}
if (liveboardV2 !== undefined) {
params[types_1.Param.LiveboardV2Enabled] = liveboardV2;
}
if (enable2ColumnLayout !== undefined) {
params[types_1.Param.Enable2ColumnLayout] = enable2ColumnLayout;
}
if (hideTabPanel) {
params[types_1.Param.HideTabPanel] = hideTabPanel;
}
if (hideLiveboardHeader) {
params[types_1.Param.HideLiveboardHeader] = hideLiveboardHeader;
}
if (showLiveboardDescription) {
params[types_1.Param.ShowLiveboardDescription] = showLiveboardDescription;
}
if (showLiveboardTitle) {
params[types_1.Param.ShowLiveboardTitle] = showLiveboardTitle;
}
if (enableAskSage) {
params[types_1.Param.enableAskSage] = enableAskSage;
}
if (oAuthPollingInterval !== undefined) {
params[types_1.Param.OauthPollingInterval] = oAuthPollingInterval;
}
if (isForceRedirect) {
params[types_1.Param.IsForceRedirect] = isForceRedirect;
}
if (dataSourceId !== undefined) {
params[types_1.Param.DataSourceId] = dataSourceId;
}
if (isLiveboardStylingAndGroupingEnabled !== undefined) {
params[types_1.Param.IsLiveboardStylingAndGroupingEnabled] = isLiveboardStylingAndGroupingEnabled;
}
if (isPNGInScheduledEmailsEnabled !== undefined) {
params[types_1.Param.isPNGInScheduledEmailsEnabled] = isPNGInScheduledEmailsEnabled;
}
if (showSpotterLimitations !== undefined) {
params[types_1.Param.ShowSpotterLimitations] = showSpotterLimitations;
}
params[types_1.Param.LiveboardHeaderSticky] = isLiveboardHeaderSticky;
params[types_1.Param.LiveboardHeaderV2] = isLiveboardCompactHeaderEnabled;
params[types_1.Param.ShowLiveboardVerifiedBadge] = showLiveboardVerifiedBadge;
params[types_1.Param.ShowLiveboardReverifyBanner] = showLiveboardReverifyBanner;
params[types_1.Param.HideIrrelevantFiltersInTab] = hideIrrelevantChipsInLiveboardTabs;
params[types_1.Param.DataPanelV2Enabled] = dataPanelV2;
params[types_1.Param.EnableCustomColumnGroups] = enableCustomColumnGroups;
params[types_1.Param.CoverAndFilterOptionInPDF] = coverAndFilterOptionInPDF;
params[types_1.Param.LiveboardXLSXCSVDownload] = !!liveboardXLSXCSVDownload;
const queryParams = (0, utils_1.getQueryParamString)(params, true);
return queryParams;
}
getIframeSuffixSrc(liveboardId, vizId, activeTabId) {
let suffix = `/embed/viz/${liveboardId}`;
if (activeTabId) {
suffix = `${suffix}/tab/${activeTabId} `;
}
if (vizId) {
suffix = `${suffix}/${vizId}`;
}
const tsPostHashParams = this.getThoughtSpotPostUrlParams();
suffix = `${suffix}${tsPostHashParams}`;
return suffix;
}
/**
* Construct the URL of the embedded ThoughtSpot Liveboard or visualization
* to be loaded within the iFrame.
*/
getIFrameSrc() {
var _a;
const { vizId, activeTabId } = this.viewConfig;
const liveboardId = (_a = this.viewConfig.liveboardId) !== null && _a !== void 0 ? _a : this.viewConfig.pinboardId;
if (!liveboardId) {
this.handleError(errors_1.ERROR_MESSAGE.LIVEBOARD_VIZ_ID_VALIDATION);
}
return `${this.getRootIframeSrc()}${this.getIframeSuffixSrc(liveboardId, vizId, activeTabId)}`;
}
setActiveTab(data) {
if (!this.viewConfig.vizId) {
const prefixPath = this.iFrame.src.split('#/')[1].split('/tab')[0];
const path = `${prefixPath}/tab/${data.tabId}`;
super.trigger(types_1.HostEvent.Navigate, path);
}
}
async showPreviewLoader() {
if (!this.viewConfig.showPreviewLoader || !this.viewConfig.vizId) {
return;
}
try {
const preview = await (0, preview_service_1.getPreview)(this.thoughtSpotHost, this.viewConfig.vizId, this.viewConfig.liveboardId);
if (!preview.vizContent) {
return;
}
(0, global_styles_1.addPreviewStylesIfNotPresent)();
const div = document.createElement('div');
div.innerHTML = `
<div class=ts-viz-preview-loader>
${preview.vizContent}
</div>
`;
const previewDiv = div.firstElementChild;
this.el.appendChild(previewDiv);
this.el.style.position = 'relative';
this.on(types_1.EmbedEvent.Data, () => {
previewDiv.remove();
});
}
catch (error) {
console.error('Error fetching preview', error);
}
}
beforePrerenderVisible() {
const embedObj = this.getPreRenderObj();
this.executeAfterEmbedContainerLoaded(() => {
this.navigateToLiveboard(this.viewConfig.liveboardId, this.viewConfig.vizId, this.viewConfig.activeTabId);
if (embedObj) {
embedObj.currentLiveboardState = {
liveboardId: this.viewConfig.liveboardId,
vizId: this.viewConfig.vizId,
activeTabId: this.viewConfig.activeTabId,
};
}
});
}
async handleRenderForPrerender() {
if ((0, utils_1.isUndefined)(this.viewConfig.liveboardId)) {
return this.prerenderGeneric();
}
return super.handleRenderForPrerender();
}
/**
* Triggers an event to the embedded app
* @param {HostEvent} messageType The event type
* @param {any} data The payload to send with the message
* @returns A promise that resolves with the response from the embedded app
*/
trigger(messageType, data = {}) {
const dataWithVizId = data;
if (messageType === types_1.HostEvent.SetActiveTab) {
this.setActiveTab(data);
return Promise.resolve(null);
}
if (typeof dataWithVizId === 'object' && this.viewConfig.vizId) {
dataWithVizId.vizId = this.viewConfig.vizId;
}
return super.trigger(messageType, dataWithVizId);
}
/**
* Destroys the ThoughtSpot embed, and remove any nodes from the DOM.
* @version SDK: 1.39.0 | ThoughtSpot: 10.10.0.cl
*/
destroy() {
super.destroy();
this.unregisterLazyLoadEvents();
}
postRender() {
this.registerLazyLoadEvents();
}
registerLazyLoadEvents() {
if (this.viewConfig.fullHeight && this.viewConfig.lazyLoadingForFullHeight) {
// TODO: Use passive: true, install modernizr to check for passive
window.addEventListener('resize', this.sendFullHeightLazyLoadData);
window.addEventListener('scroll', this.sendFullHeightLazyLoadData, true);
}
}
unregisterLazyLoadEvents() {
if (this.viewConfig.fullHeight && this.viewConfig.lazyLoadingForFullHeight) {
window.removeEventListener('resize', this.sendFullHeightLazyLoadData);
window.removeEventListener('scroll', this.sendFullHeightLazyLoadData);
}
}
/**
* Render an embedded ThoughtSpot Liveboard or visualization
* @param renderOptions An object specifying the Liveboard ID,
* visualization ID and the runtime filters.
*/
async render() {
await super.render();
const src = this.getIFrameSrc();
await this.renderV1Embed(src);
this.showPreviewLoader();
this.postRender();
return this;
}
navigateToLiveboard(liveboardId, vizId, activeTabId) {
const path = this.getIframeSuffixSrc(liveboardId, vizId, activeTabId);
this.viewConfig.liveboardId = liveboardId;
this.viewConfig.activeTabId = activeTabId;
this.viewConfig.vizId = vizId;
if (this.isRendered) {
this.trigger(types_1.HostEvent.Navigate, path.substring(1));
}
else if (this.viewConfig.preRenderId) {
this.preRender(true);
}
else {
this.render();
}
}
/**
* Returns the full url of the Liveboard/visualization which can be used to open
* this Liveboard inside the full ThoughtSpot application in a new tab.
* @returns url string
*/
getLiveboardUrl() {
let url = `${this.thoughtSpotHost}/#/pinboard/${this.viewConfig.liveboardId}`;
if (this.viewConfig.activeTabId) {
url = `${url}/tab/${this.viewConfig.activeTabId}`;
}
if (this.viewConfig.vizId) {
url = `${url}/${this.viewConfig.vizId}`;
}
return url;
}
}
exports.LiveboardEmbed = LiveboardEmbed;
/**
* @hidden
*/
class PinboardEmbed extends LiveboardEmbed {
}
exports.PinboardEmbed = PinboardEmbed;
//# sourceMappingURL=liveboard.js.map