@thoughtspot/visual-embed-sdk
Version:
ThoughtSpot Embed SDK
437 lines • 19.9 kB
JavaScript
"use strict";
/**
* Copyright (c) 2022
*
* Full application embedding
* https://developers.thoughtspot.com/docs/?pageid=full-embed
* @summary Full app embed
* @module
* @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppEmbed = exports.ListPage = exports.HomePage = exports.PrimaryNavbarVersion = exports.HomePageSearchBarMode = exports.DataPanelCustomColumnGroupsAccordionState = exports.Page = void 0;
const logger_1 = require("../utils/logger");
const utils_1 = require("../utils");
const types_1 = require("../types");
const ts_embed_1 = require("./ts-embed");
/**
* Pages within the ThoughtSpot app that can be embedded.
*/
var Page;
(function (Page) {
/**
* Home page
*/
Page["Home"] = "home";
/**
* Search page
*/
Page["Search"] = "search";
/**
* Saved answers listing page
*/
Page["Answers"] = "answers";
/**
* Liveboards listing page
*/
Page["Liveboards"] = "liveboards";
/**
* @hidden
*/
Page["Pinboards"] = "pinboards";
/**
* Data management page
*/
Page["Data"] = "data";
/**
* SpotIQ listing page
*/
Page["SpotIQ"] = "insights";
/**
* Monitor Alerts Page
*/
Page["Monitor"] = "monitor";
})(Page = exports.Page || (exports.Page = {}));
/**
* Define the initial state os column custom group accordions
* in data panel v2.
*/
var DataPanelCustomColumnGroupsAccordionState;
(function (DataPanelCustomColumnGroupsAccordionState) {
/**
* Expand all the accordion initially in data panel v2.
*/
DataPanelCustomColumnGroupsAccordionState["EXPAND_ALL"] = "EXPAND_ALL";
/**
* Collapse all the accordions initially in data panel v2.
*/
DataPanelCustomColumnGroupsAccordionState["COLLAPSE_ALL"] = "COLLAPSE_ALL";
/**
* Expand the first accordion and collapse the rest.
*/
DataPanelCustomColumnGroupsAccordionState["EXPAND_FIRST"] = "EXPAND_FIRST";
})(DataPanelCustomColumnGroupsAccordionState = exports.DataPanelCustomColumnGroupsAccordionState || (exports.DataPanelCustomColumnGroupsAccordionState = {}));
var HomePageSearchBarMode;
(function (HomePageSearchBarMode) {
HomePageSearchBarMode["OBJECT_SEARCH"] = "objectSearch";
HomePageSearchBarMode["AI_ANSWER"] = "aiAnswer";
HomePageSearchBarMode["NONE"] = "none";
})(HomePageSearchBarMode = exports.HomePageSearchBarMode || (exports.HomePageSearchBarMode = {}));
/**
* Define the version of the primary navbar
* @version SDK: 1.40.0 | ThoughtSpot: 10.11.0.cl
*/
var PrimaryNavbarVersion;
(function (PrimaryNavbarVersion) {
/**
* Sliding (v3) introduces a new left-side navigation hub featuring a tab switcher,
* along with updates to the top navigation bar.
* It serves as the foundational version of the PrimaryNavBar.
*/
PrimaryNavbarVersion["Sliding"] = "v3";
})(PrimaryNavbarVersion = exports.PrimaryNavbarVersion || (exports.PrimaryNavbarVersion = {}));
/**
* Define the version of the home page
* @version SDK: 1.40.0 | ThoughtSpot: 10.11.0.cl
*/
var HomePage;
(function (HomePage) {
/**
* Modular (v2) introduces the updated Modular Home Experience.
* It serves as the foundational version of the home page.
*/
HomePage["Modular"] = "v2";
/**
* ModularWithStylingChanges (v3) introduces Modular Home Experience
* with styling changes.
*/
HomePage["ModularWithStylingChanges"] = "v3";
})(HomePage = exports.HomePage || (exports.HomePage = {}));
/**
* Define the version of the list page
* @version SDK: 1.40.0 | ThoughtSpot: 10.12.0.cl
*/
var ListPage;
(function (ListPage) {
/**
* List (v2) is the traditional List Experience.
* It serves as the foundational version of the list page.
*/
ListPage["List"] = "v2";
/**
* ListWithUXChanges (v3) introduces the new updated list page with UX changes.
*/
ListPage["ListWithUXChanges"] = "v3";
})(ListPage = exports.ListPage || (exports.ListPage = {}));
/**
* Embeds full ThoughtSpot experience in a host application.
* @group Embed components
*/
class AppEmbed extends ts_embed_1.V1Embed {
constructor(domSelector, viewConfig) {
viewConfig.embedComponentType = 'AppEmbed';
super(domSelector, viewConfig);
this.defaultHeight = '100%';
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) => {
var _a;
this.setIFrameHeight(Math.max(data.data, (_a = this.iFrame) === null || _a === void 0 ? void 0 : _a.scrollHeight));
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);
};
if (this.viewConfig.fullHeight === true) {
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);
}
}
/**
* Constructs a map of parameters to be passed on to the
* embedded Liveboard or visualization.
*/
getEmbedParams() {
const { tag, hideObjects, liveboardV2, showPrimaryNavbar, disableProfileAndHelp, hideHamburger, hideObjectSearch, hideNotification, hideApplicationSwitcher, hideOrgSwitcher, enableSearchAssist, fullHeight, dataPanelV2 = true, hideLiveboardHeader = false, showLiveboardTitle = true, showLiveboardDescription = true, hideHomepageLeftNav = false, modularHomeExperience = false, isLiveboardHeaderSticky = true, enableAskSage, collapseSearchBarInitially = false, enable2ColumnLayout, enableCustomColumnGroups = false, isOnBeforeGetVizDataInterceptEnabled = false, dataPanelCustomGroupsAccordionInitialState = DataPanelCustomColumnGroupsAccordionState.EXPAND_ALL, collapseSearchBar = true, isLiveboardCompactHeaderEnabled = false, showLiveboardVerifiedBadge = true, showLiveboardReverifyBanner = true, hideIrrelevantChipsInLiveboardTabs = false, homePageSearchBarMode, isUnifiedSearchExperienceEnabled = true, enablePendoHelp = true, discoveryExperience, coverAndFilterOptionInPDF = false, liveboardXLSXCSVDownload = false, isLiveboardStylingAndGroupingEnabled, isPNGInScheduledEmailsEnabled = false, } = this.viewConfig;
let params = {};
params[types_1.Param.PrimaryNavHidden] = !showPrimaryNavbar;
params[types_1.Param.HideProfleAndHelp] = !!disableProfileAndHelp;
params[types_1.Param.HideApplicationSwitcher] = !!hideApplicationSwitcher;
params[types_1.Param.HideOrgSwitcher] = !!hideOrgSwitcher;
params[types_1.Param.HideLiveboardHeader] = hideLiveboardHeader;
params[types_1.Param.ShowLiveboardTitle] = showLiveboardTitle;
params[types_1.Param.ShowLiveboardDescription] = !!showLiveboardDescription;
params[types_1.Param.LiveboardHeaderSticky] = isLiveboardHeaderSticky;
params[types_1.Param.IsFullAppEmbed] = true;
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.IsUnifiedSearchExperienceEnabled] = isUnifiedSearchExperienceEnabled;
params[types_1.Param.CoverAndFilterOptionInPDF] = !!coverAndFilterOptionInPDF;
params[types_1.Param.LiveboardXLSXCSVDownload] = !!liveboardXLSXCSVDownload;
params = this.getBaseQueryParams(params);
if (hideObjectSearch) {
params[types_1.Param.HideObjectSearch] = !!hideObjectSearch;
}
if (hideHamburger) {
params[types_1.Param.HideHamburger] = !!hideHamburger;
}
if (hideNotification) {
params[types_1.Param.HideNotification] = !!hideNotification;
}
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 (tag) {
params[types_1.Param.Tag] = tag;
}
if (hideObjects && hideObjects.length) {
params[types_1.Param.HideObjects] = JSON.stringify(hideObjects);
}
if (liveboardV2 !== undefined) {
params[types_1.Param.LiveboardV2Enabled] = liveboardV2;
}
if (enableSearchAssist !== undefined) {
params[types_1.Param.EnableSearchAssist] = enableSearchAssist;
}
if (enable2ColumnLayout !== undefined) {
params[types_1.Param.Enable2ColumnLayout] = enable2ColumnLayout;
}
if (enableAskSage) {
params[types_1.Param.enableAskSage] = enableAskSage;
}
if (isOnBeforeGetVizDataInterceptEnabled) {
params[types_1.Param.IsOnBeforeGetVizDataInterceptEnabled] = isOnBeforeGetVizDataInterceptEnabled;
}
if (homePageSearchBarMode) {
params[types_1.Param.HomePageSearchBarMode] = homePageSearchBarMode;
}
if (enablePendoHelp !== undefined) {
params[types_1.Param.EnablePendoHelp] = enablePendoHelp;
}
if (isLiveboardStylingAndGroupingEnabled !== undefined) {
params[types_1.Param.IsLiveboardStylingAndGroupingEnabled] = isLiveboardStylingAndGroupingEnabled;
}
if (isPNGInScheduledEmailsEnabled !== undefined) {
params[types_1.Param.isPNGInScheduledEmailsEnabled] = isPNGInScheduledEmailsEnabled;
}
params[types_1.Param.DataPanelV2Enabled] = dataPanelV2;
params[types_1.Param.HideHomepageLeftNav] = hideHomepageLeftNav;
params[types_1.Param.ModularHomeExperienceEnabled] = modularHomeExperience;
params[types_1.Param.CollapseSearchBarInitially] = collapseSearchBarInitially || collapseSearchBar;
params[types_1.Param.EnableCustomColumnGroups] = enableCustomColumnGroups;
if (dataPanelCustomGroupsAccordionInitialState
=== DataPanelCustomColumnGroupsAccordionState.COLLAPSE_ALL
|| dataPanelCustomGroupsAccordionInitialState
=== DataPanelCustomColumnGroupsAccordionState.EXPAND_FIRST) {
params[types_1.Param.DataPanelCustomGroupsAccordionInitialState] = dataPanelCustomGroupsAccordionInitialState;
}
else {
params[types_1.Param.DataPanelCustomGroupsAccordionInitialState] = DataPanelCustomColumnGroupsAccordionState.EXPAND_ALL;
}
// Set navigation to v2 by default to avoid problems like the app
// switcher (9-dot menu) not showing when v3 navigation is turned on
// at the cluster level.
// To use v3 navigation, we must manually set the discoveryExperience
// settings.
params[types_1.Param.NavigationVersion] = 'v2';
// Set homePageVersion to v2 by default to reset the LD flag value
// for the homepageVersion.
params[types_1.Param.HomepageVersion] = 'v2';
// Set listpageVersion to v2 by default to reset the LD flag value
// for the listpageVersion.
params[types_1.Param.ListPageVersion] = ListPage.List;
if (discoveryExperience) {
// primaryNavbarVersion v3 will enabled the new left navigation
if (discoveryExperience.primaryNavbarVersion === PrimaryNavbarVersion.Sliding) {
params[types_1.Param.NavigationVersion] = discoveryExperience.primaryNavbarVersion;
// Enable the modularHomeExperience when Sliding is enabled.
params[types_1.Param.ModularHomeExperienceEnabled] = true;
}
// homePage v2 will enable the modular home page
// and it will override the modularHomeExperience value
if (discoveryExperience.homePage === HomePage.Modular) {
params[types_1.Param.ModularHomeExperienceEnabled] = true;
}
// ModularWithStylingChanges (v3) introduces the styling changes
// to the Modular Homepage.
// v3 will be the base version of homePageVersion.
if (discoveryExperience.homePage === HomePage.ModularWithStylingChanges) {
params[types_1.Param.HomepageVersion] = HomePage.ModularWithStylingChanges;
}
// listPageVersion v3 will enable the new list page
if (discoveryExperience.listPageVersion === ListPage.ListWithUXChanges) {
params[types_1.Param.ListPageVersion] = discoveryExperience.listPageVersion;
}
}
const queryParams = (0, utils_1.getQueryParamString)(params, true);
return queryParams;
}
/**
* Constructs the URL of the ThoughtSpot app page to be rendered.
* @param pageId The ID of the page to be embedded.
*/
getIFrameSrc() {
const { pageId, path, modularHomeExperience } = this.viewConfig;
const pageRoute = this.formatPath(path) || this.getPageRoute(pageId, modularHomeExperience);
let url = `${this.getRootIframeSrc()}/${pageRoute}`;
const tsPostHashParams = this.getThoughtSpotPostUrlParams();
url = `${url}${tsPostHashParams}`;
return url;
}
/**
* Gets the ThoughtSpot route of the page for a particular page ID.
* @param pageId The identifier for a page in the ThoughtSpot app.
* @param modularHomeExperience
*/
getPageRoute(pageId, modularHomeExperience = false) {
switch (pageId) {
case Page.Search:
return 'answer';
case Page.Answers:
return modularHomeExperience ? 'home/answers' : 'answers';
case Page.Liveboards:
return modularHomeExperience ? 'home/liveboards' : 'pinboards';
case Page.Pinboards:
return modularHomeExperience ? 'home/liveboards' : 'pinboards';
case Page.Data:
return 'data/tables';
case Page.SpotIQ:
return modularHomeExperience ? 'home/spotiq-analysis' : 'insights/results';
case Page.Monitor:
return modularHomeExperience ? 'home/monitor-alerts' : 'insights/monitor-alerts';
case Page.Home:
default:
return 'home';
}
}
/**
* Formats the path provided by the user.
* @param path The URL path.
* @returns The URL path that the embedded app understands.
*/
formatPath(path) {
if (!path) {
return null;
}
// remove leading slash
if (path.indexOf('/') === 0) {
return path.substring(1);
}
return path;
}
/**
* Navigate to particular page for app embed. eg:answers/pinboards/home
* This is used for embedding answers, pinboards, visualizations and full application
* only.
* @param path string | number The string, set to iframe src and navigate to new page
* eg: appEmbed.navigateToPage('pinboards')
* When used with `noReload` (default: true) this can also be a number
* like 1/-1 to go forward/back.
* @param noReload boolean Trigger the navigation without reloading the page
* @version SDK: 1.12.0 | ThoughtSpot: 8.4.0.cl, 8.4.1-sw
*/
navigateToPage(path, noReload = false) {
if (!this.iFrame) {
logger_1.logger.log('Please call render before invoking this method');
return;
}
if (noReload) {
this.trigger(types_1.HostEvent.Navigate, path);
}
else {
if (typeof path !== 'string') {
logger_1.logger.warn('Path can only by a string when triggered without noReload');
return;
}
const iframeSrc = this.iFrame.src;
const embedPath = '#/embed';
const currentPath = iframeSrc.includes(embedPath) ? embedPath : '#';
this.iFrame.src = `${iframeSrc.split(currentPath)[0]}${currentPath}/${path.replace(/^\/?#?\//, '')}`;
}
}
/**
* 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);
}
}
/**
* Renders the embedded application pages in the ThoughtSpot app.
* @param renderOptions An object containing the page ID
* to be embedded.
*/
async render() {
await super.render();
const src = this.getIFrameSrc();
await this.renderV1Embed(src);
this.postRender();
return this;
}
}
exports.AppEmbed = AppEmbed;
//# sourceMappingURL=app.js.map