@thoughtspot/visual-embed-sdk 1.41.1 → 1.42.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/cjs/package.json +9 -9
  2. package/cjs/src/api-intercept.d.ts +25 -0
  3. package/cjs/src/api-intercept.d.ts.map +1 -0
  4. package/cjs/src/api-intercept.js +115 -0
  5. package/cjs/src/api-intercept.js.map +1 -0
  6. package/cjs/src/css-variables.d.ts +52 -14
  7. package/cjs/src/css-variables.d.ts.map +1 -1
  8. package/cjs/src/embed/app.d.ts.map +1 -1
  9. package/cjs/src/embed/app.js +7 -2
  10. package/cjs/src/embed/app.js.map +1 -1
  11. package/cjs/src/embed/app.spec.js +20 -0
  12. package/cjs/src/embed/app.spec.js.map +1 -1
  13. package/cjs/src/embed/bodyless-conversation.d.ts +1 -0
  14. package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
  15. package/cjs/src/embed/bodyless-conversation.js +7 -3
  16. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  17. package/cjs/src/embed/conversation.d.ts +1 -0
  18. package/cjs/src/embed/conversation.d.ts.map +1 -1
  19. package/cjs/src/embed/conversation.js +7 -2
  20. package/cjs/src/embed/conversation.js.map +1 -1
  21. package/cjs/src/embed/hostEventClient/contracts.d.ts +11 -1
  22. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  23. package/cjs/src/embed/hostEventClient/contracts.js +1 -0
  24. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  25. package/cjs/src/embed/liveboard.d.ts +1 -0
  26. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  27. package/cjs/src/embed/liveboard.js +10 -2
  28. package/cjs/src/embed/liveboard.js.map +1 -1
  29. package/cjs/src/embed/liveboard.spec.js +35 -0
  30. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  31. package/cjs/src/embed/sage.d.ts +1 -0
  32. package/cjs/src/embed/sage.d.ts.map +1 -1
  33. package/cjs/src/embed/sage.js +10 -6
  34. package/cjs/src/embed/sage.js.map +1 -1
  35. package/cjs/src/embed/search-bar.d.ts +1 -0
  36. package/cjs/src/embed/search-bar.d.ts.map +1 -1
  37. package/cjs/src/embed/search-bar.js +11 -7
  38. package/cjs/src/embed/search-bar.js.map +1 -1
  39. package/cjs/src/embed/search.d.ts +1 -0
  40. package/cjs/src/embed/search.d.ts.map +1 -1
  41. package/cjs/src/embed/search.js +10 -9
  42. package/cjs/src/embed/search.js.map +1 -1
  43. package/cjs/src/embed/ts-embed.d.ts +21 -4
  44. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  45. package/cjs/src/embed/ts-embed.js +115 -34
  46. package/cjs/src/embed/ts-embed.js.map +1 -1
  47. package/cjs/src/embed/ts-embed.spec.js +83 -0
  48. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  49. package/cjs/src/errors.d.ts +1 -0
  50. package/cjs/src/errors.d.ts.map +1 -1
  51. package/cjs/src/errors.js +1 -0
  52. package/cjs/src/errors.js.map +1 -1
  53. package/cjs/src/index.d.ts +2 -2
  54. package/cjs/src/index.d.ts.map +1 -1
  55. package/cjs/src/index.js +2 -1
  56. package/cjs/src/index.js.map +1 -1
  57. package/cjs/src/react/all-types-export.d.ts +1 -1
  58. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  59. package/cjs/src/react/all-types-export.js +2 -1
  60. package/cjs/src/react/all-types-export.js.map +1 -1
  61. package/cjs/src/react/all-types-export.spec.js +1 -1
  62. package/cjs/src/react/all-types-export.spec.js.map +1 -1
  63. package/cjs/src/react/util.js.map +1 -1
  64. package/cjs/src/react/util.spec.d.ts +2 -0
  65. package/cjs/src/react/util.spec.d.ts.map +1 -0
  66. package/cjs/src/react/util.spec.js +78 -0
  67. package/cjs/src/react/util.spec.js.map +1 -0
  68. package/cjs/src/types.d.ts +135 -8
  69. package/cjs/src/types.d.ts.map +1 -1
  70. package/cjs/src/types.js +73 -4
  71. package/cjs/src/types.js.map +1 -1
  72. package/cjs/src/utils/processData.d.ts +1 -1
  73. package/cjs/src/utils/processData.d.ts.map +1 -1
  74. package/cjs/src/utils/processData.js +8 -8
  75. package/cjs/src/utils/processData.js.map +1 -1
  76. package/dist/index-BEzW4MDA.js +7371 -0
  77. package/dist/{index-DQueHwfQ.js → index-DvNA626T.js} +1 -1
  78. package/dist/src/api-intercept.d.ts +25 -0
  79. package/dist/src/api-intercept.d.ts.map +1 -0
  80. package/dist/src/css-variables.d.ts +52 -14
  81. package/dist/src/css-variables.d.ts.map +1 -1
  82. package/dist/src/embed/app.d.ts.map +1 -1
  83. package/dist/src/embed/bodyless-conversation.d.ts +1 -0
  84. package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
  85. package/dist/src/embed/conversation.d.ts +1 -0
  86. package/dist/src/embed/conversation.d.ts.map +1 -1
  87. package/dist/src/embed/hostEventClient/contracts.d.ts +11 -1
  88. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  89. package/dist/src/embed/liveboard.d.ts +1 -0
  90. package/dist/src/embed/liveboard.d.ts.map +1 -1
  91. package/dist/src/embed/sage.d.ts +1 -0
  92. package/dist/src/embed/sage.d.ts.map +1 -1
  93. package/dist/src/embed/search-bar.d.ts +1 -0
  94. package/dist/src/embed/search-bar.d.ts.map +1 -1
  95. package/dist/src/embed/search.d.ts +1 -0
  96. package/dist/src/embed/search.d.ts.map +1 -1
  97. package/dist/src/embed/ts-embed.d.ts +21 -4
  98. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  99. package/dist/src/errors.d.ts +1 -0
  100. package/dist/src/errors.d.ts.map +1 -1
  101. package/dist/src/index.d.ts +2 -2
  102. package/dist/src/index.d.ts.map +1 -1
  103. package/dist/src/react/all-types-export.d.ts +1 -1
  104. package/dist/src/react/all-types-export.d.ts.map +1 -1
  105. package/dist/src/react/util.spec.d.ts +2 -0
  106. package/dist/src/react/util.spec.d.ts.map +1 -0
  107. package/dist/src/types.d.ts +135 -8
  108. package/dist/src/types.d.ts.map +1 -1
  109. package/dist/src/utils/processData.d.ts +1 -1
  110. package/dist/src/utils/processData.d.ts.map +1 -1
  111. package/dist/tsembed-react.es.js +370 -90
  112. package/dist/tsembed-react.js +369 -89
  113. package/dist/tsembed.es.js +371 -91
  114. package/dist/tsembed.js +369 -89
  115. package/dist/visual-embed-sdk-react-full.d.ts +9431 -9915
  116. package/dist/visual-embed-sdk-react.d.ts +9301 -9922
  117. package/dist/visual-embed-sdk.d.ts +9470 -9532
  118. package/lib/package.json +9 -9
  119. package/lib/src/api-intercept.d.ts +25 -0
  120. package/lib/src/api-intercept.d.ts.map +1 -0
  121. package/lib/src/api-intercept.js +108 -0
  122. package/lib/src/api-intercept.js.map +1 -0
  123. package/lib/src/css-variables.d.ts +52 -14
  124. package/lib/src/css-variables.d.ts.map +1 -1
  125. package/lib/src/embed/app.d.ts.map +1 -1
  126. package/lib/src/embed/app.js +7 -2
  127. package/lib/src/embed/app.js.map +1 -1
  128. package/lib/src/embed/app.spec.js +20 -0
  129. package/lib/src/embed/app.spec.js.map +1 -1
  130. package/lib/src/embed/bodyless-conversation.d.ts +1 -0
  131. package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
  132. package/lib/src/embed/bodyless-conversation.js +7 -3
  133. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  134. package/lib/src/embed/conversation.d.ts +1 -0
  135. package/lib/src/embed/conversation.d.ts.map +1 -1
  136. package/lib/src/embed/conversation.js +7 -2
  137. package/lib/src/embed/conversation.js.map +1 -1
  138. package/lib/src/embed/hostEventClient/contracts.d.ts +11 -1
  139. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  140. package/lib/src/embed/hostEventClient/contracts.js +1 -0
  141. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  142. package/lib/src/embed/liveboard.d.ts +1 -0
  143. package/lib/src/embed/liveboard.d.ts.map +1 -1
  144. package/lib/src/embed/liveboard.js +10 -2
  145. package/lib/src/embed/liveboard.js.map +1 -1
  146. package/lib/src/embed/liveboard.spec.js +35 -0
  147. package/lib/src/embed/liveboard.spec.js.map +1 -1
  148. package/lib/src/embed/sage.d.ts +1 -0
  149. package/lib/src/embed/sage.d.ts.map +1 -1
  150. package/lib/src/embed/sage.js +10 -6
  151. package/lib/src/embed/sage.js.map +1 -1
  152. package/lib/src/embed/search-bar.d.ts +1 -0
  153. package/lib/src/embed/search-bar.d.ts.map +1 -1
  154. package/lib/src/embed/search-bar.js +11 -7
  155. package/lib/src/embed/search-bar.js.map +1 -1
  156. package/lib/src/embed/search.d.ts +1 -0
  157. package/lib/src/embed/search.d.ts.map +1 -1
  158. package/lib/src/embed/search.js +10 -9
  159. package/lib/src/embed/search.js.map +1 -1
  160. package/lib/src/embed/ts-embed.d.ts +21 -4
  161. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  162. package/lib/src/embed/ts-embed.js +115 -34
  163. package/lib/src/embed/ts-embed.js.map +1 -1
  164. package/lib/src/embed/ts-embed.spec.js +83 -0
  165. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  166. package/lib/src/errors.d.ts +1 -0
  167. package/lib/src/errors.d.ts.map +1 -1
  168. package/lib/src/errors.js +1 -0
  169. package/lib/src/errors.js.map +1 -1
  170. package/lib/src/index.d.ts +2 -2
  171. package/lib/src/index.d.ts.map +1 -1
  172. package/lib/src/index.js +2 -2
  173. package/lib/src/index.js.map +1 -1
  174. package/lib/src/react/all-types-export.d.ts +1 -1
  175. package/lib/src/react/all-types-export.d.ts.map +1 -1
  176. package/lib/src/react/all-types-export.js +1 -1
  177. package/lib/src/react/all-types-export.js.map +1 -1
  178. package/lib/src/react/all-types-export.spec.js +1 -1
  179. package/lib/src/react/all-types-export.spec.js.map +1 -1
  180. package/lib/src/react/util.js.map +1 -1
  181. package/lib/src/react/util.spec.d.ts +2 -0
  182. package/lib/src/react/util.spec.d.ts.map +1 -0
  183. package/lib/src/react/util.spec.js +76 -0
  184. package/lib/src/react/util.spec.js.map +1 -0
  185. package/lib/src/types.d.ts +135 -8
  186. package/lib/src/types.d.ts.map +1 -1
  187. package/lib/src/types.js +72 -3
  188. package/lib/src/types.js.map +1 -1
  189. package/lib/src/utils/processData.d.ts +1 -1
  190. package/lib/src/utils/processData.d.ts.map +1 -1
  191. package/lib/src/utils/processData.js +8 -8
  192. package/lib/src/utils/processData.js.map +1 -1
  193. package/package.json +9 -9
  194. package/src/api-intercept.ts +134 -0
  195. package/src/css-variables.ts +53 -16
  196. package/src/embed/app.spec.ts +28 -0
  197. package/src/embed/app.ts +9 -1
  198. package/src/embed/bodyless-conversation.ts +8 -3
  199. package/src/embed/conversation.ts +17 -2
  200. package/src/embed/hostEventClient/contracts.ts +10 -0
  201. package/src/embed/liveboard.spec.ts +44 -0
  202. package/src/embed/liveboard.ts +12 -1
  203. package/src/embed/sage.ts +14 -9
  204. package/src/embed/search-bar.tsx +14 -7
  205. package/src/embed/search.ts +21 -8
  206. package/src/embed/ts-embed.spec.ts +116 -5
  207. package/src/embed/ts-embed.ts +152 -50
  208. package/src/errors.ts +1 -0
  209. package/src/index.ts +2 -0
  210. package/src/react/all-types-export.spec.ts +1 -1
  211. package/src/react/all-types-export.ts +1 -0
  212. package/src/react/util.spec.tsx +88 -0
  213. package/src/react/util.ts +3 -3
  214. package/src/types.ts +195 -64
  215. package/src/utils/processData.ts +11 -11
  216. package/lib/src/visual-embed-sdk.d.ts +0 -9779
@@ -71,6 +71,7 @@ import { getEmbedConfig } from './embedConfig';
71
71
  import { ERROR_MESSAGE } from '../errors';
72
72
  import { getPreauthInfo } from '../utils/sessionInfoService';
73
73
  import { HostEventClient } from './hostEventClient/host-event-client';
74
+ import { getInterceptInitData, handleInterceptEvent, processLegacyInterceptResponse } from '../api-intercept';
74
75
 
75
76
  const { version } = pkgInfo;
76
77
 
@@ -199,11 +200,11 @@ export class TsEmbed {
199
200
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_EMBED_CREATE, {
200
201
  ...viewConfig,
201
202
  });
202
- this.hostEventClient = new HostEventClient(this.iFrame);
203
+ const embedConfig = getEmbedConfig();
204
+ this.embedConfig = embedConfig;
203
205
 
206
+ this.hostEventClient = new HostEventClient(this.iFrame);
204
207
  this.isReadyForRenderPromise = getInitPromise().then(async () => {
205
- const embedConfig = getEmbedConfig();
206
- this.embedConfig = embedConfig;
207
208
  if (!embedConfig.authTriggerContainer && !embedConfig.useEventForSAMLPopup) {
208
209
  this.embedConfig.authTriggerContainer = domSelector;
209
210
  }
@@ -312,31 +313,11 @@ export class TsEmbed {
312
313
  private subscribedListeners: Record<string, any> = {};
313
314
 
314
315
  /**
315
- * Adds a global event listener to window for "message" events.
316
- * ThoughtSpot detects if a particular event is targeted to this
317
- * embed instance through an identifier contained in the payload,
318
- * and executes the registered callbacks accordingly.
316
+ * Subscribe to network events (online/offline) that should
317
+ * work regardless of auth status
319
318
  */
320
- private subscribeToEvents() {
321
- this.unsubscribeToEvents();
322
- const messageEventListener = (event: MessageEvent<any>) => {
323
- const eventType = this.getEventType(event);
324
- const eventPort = this.getEventPort(event);
325
- const eventData = this.formatEventData(event, eventType);
326
- if (event.source === this.iFrame.contentWindow) {
327
- this.executeCallbacks(
328
- eventType,
329
- processEventData(
330
- eventType,
331
- eventData,
332
- this.thoughtSpotHost,
333
- this.isPreRendered ? this.preRenderWrapper : this.el,
334
- ),
335
- eventPort,
336
- );
337
- }
338
- };
339
- window.addEventListener('message', messageEventListener);
319
+ private subscribeToNetworkEvents() {
320
+ this.unsubscribeToNetworkEvents();
340
321
 
341
322
  const onlineEventListener = (e: Event) => {
342
323
  this.trigger(HostEvent.Reload);
@@ -344,7 +325,7 @@ export class TsEmbed {
344
325
  window.addEventListener('online', onlineEventListener);
345
326
 
346
327
  const offlineEventListener = (e: Event) => {
347
- const offlineWarning = 'Network not Detected. Embed is offline. Please reconnect and refresh';
328
+ const offlineWarning = ERROR_MESSAGE.OFFLINE_WARNING;
348
329
  this.executeCallbacks(EmbedEvent.Error, {
349
330
  offlineWarning,
350
331
  });
@@ -352,11 +333,84 @@ export class TsEmbed {
352
333
  };
353
334
  window.addEventListener('offline', offlineEventListener);
354
335
 
355
- this.subscribedListeners = {
356
- message: messageEventListener,
357
- online: onlineEventListener,
358
- offline: offlineEventListener,
359
- };
336
+ this.subscribedListeners.online = onlineEventListener;
337
+ this.subscribedListeners.offline = offlineEventListener;
338
+ }
339
+
340
+ private messageEventListener = async (event: MessageEvent<any>) => {
341
+ const eventType = this.getEventType(event);
342
+ const eventPort = this.getEventPort(event);
343
+ const eventData = this.formatEventData(event, eventType);
344
+ if (event.source === this.iFrame.contentWindow) {
345
+ const processedEventData = await processEventData(
346
+ eventType,
347
+ eventData,
348
+ this.thoughtSpotHost,
349
+ this.isPreRendered ? this.preRenderWrapper : this.el,
350
+ );
351
+
352
+ const executeEvent = (_eventType: EmbedEvent, data: any) => {
353
+ this.executeCallbacks(_eventType, data, eventPort);
354
+ }
355
+
356
+ if (eventType === EmbedEvent.ApiIntercept && this.viewConfig.enableApiIntercept) {
357
+ const getUnsavedAnswerTml = async (props: { sessionId?: string, vizId?: string }) => {
358
+ const response = await this.triggerUIPassThrough(UIPassthroughEvent.GetUnsavedAnswerTML, props);
359
+ return response[0]?.value;
360
+ }
361
+ handleInterceptEvent({ eventData: processedEventData, executeEvent, embedConfig: this.embedConfig, viewConfig: this.viewConfig, getUnsavedAnswerTml });
362
+ return;
363
+ }
364
+
365
+ this.executeCallbacks(
366
+ eventType,
367
+ processedEventData,
368
+ eventPort,
369
+ );
370
+ }
371
+ };
372
+ /**
373
+ * Subscribe to message events that depend on successful iframe setup
374
+ */
375
+ private subscribeToMessageEvents() {
376
+ this.unsubscribeToMessageEvents();
377
+
378
+ window.addEventListener('message', this.messageEventListener);
379
+
380
+ this.subscribedListeners.message = this.messageEventListener;
381
+ }
382
+
383
+
384
+ /**
385
+ * Adds event listeners for both network and message events.
386
+ * This maintains backward compatibility with the existing method.
387
+ * Adds a global event listener to window for "message" events.
388
+ * ThoughtSpot detects if a particular event is targeted to this
389
+ * embed instance through an identifier contained in the payload,
390
+ * and executes the registered callbacks accordingly.
391
+ */
392
+ private subscribeToEvents() {
393
+ this.subscribeToNetworkEvents();
394
+ this.subscribeToMessageEvents();
395
+ }
396
+
397
+
398
+ private unsubscribeToNetworkEvents() {
399
+ if (this.subscribedListeners.online) {
400
+ window.removeEventListener('online', this.subscribedListeners.online);
401
+ delete this.subscribedListeners.online;
402
+ }
403
+ if (this.subscribedListeners.offline) {
404
+ window.removeEventListener('offline', this.subscribedListeners.offline);
405
+ delete this.subscribedListeners.offline;
406
+ }
407
+ }
408
+
409
+ private unsubscribeToMessageEvents() {
410
+ if (this.subscribedListeners.message) {
411
+ window.removeEventListener('message', this.subscribedListeners.message);
412
+ delete this.subscribedListeners.message;
413
+ }
360
414
  }
361
415
 
362
416
  private unsubscribeToEvents() {
@@ -391,7 +445,7 @@ export class TsEmbed {
391
445
  message: customActionsResult.errors,
392
446
  });
393
447
  }
394
- return {
448
+ const baseInitData = {
395
449
  customisations: getCustomisations(this.embedConfig, this.viewConfig),
396
450
  authToken,
397
451
  runtimeFilterParams: this.viewConfig.excludeRuntimeFiltersfromURL
@@ -410,7 +464,10 @@ export class TsEmbed {
410
464
  this.embedConfig.customVariablesForThirdPartyTools || {},
411
465
  hiddenListColumns: this.viewConfig.hiddenListColumns || [],
412
466
  customActions: customActionsResult.actions,
467
+ ...getInterceptInitData(this.embedConfig, this.viewConfig),
413
468
  };
469
+
470
+ return baseInitData;
414
471
  }
415
472
 
416
473
  protected async getAppInitData() {
@@ -494,10 +551,10 @@ export class TsEmbed {
494
551
  this.on(EmbedEvent.APP_INIT, this.appInitCb, { start: false }, true);
495
552
  this.on(EmbedEvent.AuthExpire, this.updateAuthToken, { start: false }, true);
496
553
  this.on(EmbedEvent.IdleSessionTimeout, this.idleSessionTimeout, { start: false }, true);
497
-
498
- const embedListenerReadyHandler = this.createEmbedContainerHandler(EmbedEvent.EmbedListenerReady);
554
+
555
+ const embedListenerReadyHandler = this.createEmbedContainerHandler(EmbedEvent.EmbedListenerReady);
499
556
  this.on(EmbedEvent.EmbedListenerReady, embedListenerReadyHandler, { start: false }, true);
500
-
557
+
501
558
  const authInitHandler = this.createEmbedContainerHandler(EmbedEvent.AuthInit);
502
559
  this.on(EmbedEvent.AuthInit, authInitHandler, { start: false }, true);
503
560
  };
@@ -520,6 +577,12 @@ export class TsEmbed {
520
577
  return `${basePath}#`;
521
578
  }
522
579
 
580
+ protected getUpdateEmbedParamsObject() {
581
+ let queryParams = this.getEmbedParamsObject();
582
+ queryParams = { ...this.viewConfig, ...queryParams };
583
+ return queryParams;
584
+ }
585
+
523
586
  /**
524
587
  * Common query params set for all the embed modes.
525
588
  * @param queryParams
@@ -702,10 +765,15 @@ export class TsEmbed {
702
765
  }
703
766
 
704
767
  protected getEmbedParams() {
705
- const queryParams = this.getBaseQueryParams();
768
+ const queryParams = this.getEmbedParamsObject();
706
769
  return getQueryParamString(queryParams);
707
770
  }
708
771
 
772
+ protected getEmbedParamsObject() {
773
+ const params = this.getBaseQueryParams();
774
+ return params;
775
+ }
776
+
709
777
  protected getRootIframeSrc() {
710
778
  const query = this.getEmbedParams();
711
779
  return this.getEmbedBasePath(query);
@@ -787,6 +855,9 @@ export class TsEmbed {
787
855
 
788
856
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_RENDER_START);
789
857
 
858
+ // Always subscribe to network events, regardless of auth status
859
+ this.subscribeToNetworkEvents();
860
+
790
861
  return getAuthPromise()
791
862
  ?.then((isLoggedIn: boolean) => {
792
863
  if (!isLoggedIn) {
@@ -832,7 +903,9 @@ export class TsEmbed {
832
903
  el.remove();
833
904
  });
834
905
  }
835
- this.subscribeToEvents();
906
+ // Subscribe to message events only after successful
907
+ // auth and iframe setup
908
+ this.subscribeToMessageEvents();
836
909
  })
837
910
  .catch((error) => {
838
911
  nextInQueue();
@@ -972,6 +1045,21 @@ export class TsEmbed {
972
1045
  this.iFrame.style.height = getCssDimension(height);
973
1046
  }
974
1047
 
1048
+ protected createEmbedEventResponder = (eventPort: MessagePort | void, eventType: EmbedEvent) => {
1049
+
1050
+ const { enableApiIntercept } = getInterceptInitData(this.embedConfig, this.viewConfig);
1051
+ if (eventType === EmbedEvent.OnBeforeGetVizDataIntercept && enableApiIntercept) {
1052
+ return (payload: any) => {
1053
+ const payloadToSend = processLegacyInterceptResponse(payload);
1054
+ this.triggerEventOnPort(eventPort, payloadToSend);
1055
+ }
1056
+ }
1057
+
1058
+ return (payload: any) => {
1059
+ this.triggerEventOnPort(eventPort, payload);
1060
+ }
1061
+ }
1062
+
975
1063
  /**
976
1064
  * Executes all registered event handlers for a particular event type
977
1065
  * @param eventType The event type
@@ -996,9 +1084,8 @@ export class TsEmbed {
996
1084
  // payload
997
1085
  || (!callbackObj.options.start && dataStatus === embedEventStatus.END)
998
1086
  ) {
999
- callbackObj.callback(data, (payload) => {
1000
- this.triggerEventOnPort(eventPort, payload);
1001
- });
1087
+ const responder = this.createEmbedEventResponder(eventPort, eventType);
1088
+ callbackObj.callback(data, responder);
1002
1089
  }
1003
1090
  });
1004
1091
  }
@@ -1141,10 +1228,10 @@ export class TsEmbed {
1141
1228
  }
1142
1229
 
1143
1230
  /**
1144
- * @hidden
1145
- * Internal state to track if the embed container is loaded.
1146
- * This is used to trigger events after the embed container is loaded.
1147
- */
1231
+ * @hidden
1232
+ * Internal state to track if the embed container is loaded.
1233
+ * This is used to trigger events after the embed container is loaded.
1234
+ */
1148
1235
  public isEmbedContainerLoaded = false;
1149
1236
 
1150
1237
  /**
@@ -1191,7 +1278,7 @@ export class TsEmbed {
1191
1278
  } else {
1192
1279
  logger.debug('pushing callback to embedContainerReadyCallbacks', callback);
1193
1280
  this.embedContainerReadyCallbacks.push(callback);
1194
- }
1281
+ }
1195
1282
  }
1196
1283
 
1197
1284
  protected createEmbedContainerHandler = (source: EmbedEvent.AuthInit | EmbedEvent.EmbedListenerReady) => () => {
@@ -1232,6 +1319,16 @@ export class TsEmbed {
1232
1319
  this.handleError('Host event type is undefined');
1233
1320
  return null;
1234
1321
  }
1322
+
1323
+ // Check if iframe exists before triggering -
1324
+ // this prevents the error when auth fails
1325
+ if (!this.iFrame) {
1326
+ logger.debug(
1327
+ `Cannot trigger ${messageType} - iframe not available (likely due to auth failure)`,
1328
+ );
1329
+ return null;
1330
+ }
1331
+
1235
1332
  // send an empty object, this is needed for liveboard default handlers
1236
1333
  return this.hostEventClient.triggerHostEvent(messageType, data);
1237
1334
  }
@@ -1279,6 +1376,7 @@ export class TsEmbed {
1279
1376
  * Creates the preRender shell
1280
1377
  * @param showPreRenderByDefault - Show the preRender after render, hidden by default
1281
1378
  */
1379
+
1282
1380
  public async preRender(showPreRenderByDefault = false, replaceExistingPreRender = false): Promise<TsEmbed> {
1283
1381
  if (!this.viewConfig.preRenderId) {
1284
1382
  logger.error(ERROR_MESSAGE.PRERENDER_ID_MISSING);
@@ -1286,7 +1384,7 @@ export class TsEmbed {
1286
1384
  }
1287
1385
  this.isPreRendered = true;
1288
1386
  this.showPreRenderByDefault = showPreRenderByDefault;
1289
-
1387
+
1290
1388
  const isAlreadyRendered = this.connectPreRendered();
1291
1389
  if (isAlreadyRendered && !replaceExistingPreRender) {
1292
1390
  return this;
@@ -1413,8 +1511,14 @@ export class TsEmbed {
1413
1511
  return this.preRender(true);
1414
1512
  }
1415
1513
  this.validatePreRenderViewConfig(this.viewConfig);
1514
+ logger.debug('triggering UpdateEmbedParams', this.viewConfig);
1515
+ this.executeAfterEmbedContainerLoaded(() => {
1516
+ this.trigger(HostEvent.UpdateEmbedParams, this.getUpdateEmbedParamsObject());
1517
+ });
1416
1518
  }
1417
1519
 
1520
+ this.beforePrerenderVisible();
1521
+
1418
1522
  if (this.el) {
1419
1523
  this.syncPreRenderStyle();
1420
1524
  if (!this.viewConfig.doNotTrackPreRenderSize) {
@@ -1432,8 +1536,6 @@ export class TsEmbed {
1432
1536
  }
1433
1537
  }
1434
1538
 
1435
- this.beforePrerenderVisible();
1436
-
1437
1539
  removeStyleProperties(this.preRenderWrapper, ['z-index', 'opacity', 'pointer-events']);
1438
1540
 
1439
1541
  this.subscribeToEvents();
package/src/errors.ts CHANGED
@@ -19,6 +19,7 @@ export const ERROR_MESSAGE = {
19
19
  MISSING_REPORTING_OBSERVER: 'ReportingObserver not supported',
20
20
  RENDER_CALLED_BEFORE_INIT: 'Looks like render was called before calling init, the render won\'t start until init is called.\nFor more info check\n1. https://developers.thoughtspot.com/docs/Function_init#_init\n2.https://developers.thoughtspot.com/docs/getting-started#initSdk',
21
21
  SPOTTER_AGENT_NOT_INITIALIZED: 'SpotterAgent not initialized',
22
+ OFFLINE_WARNING : 'Network not Detected. Embed is offline. Please reconnect and refresh',
22
23
  };
23
24
 
24
25
  export const CUSTOM_ACTIONS_ERROR_MESSAGE = {
package/src/index.ts CHANGED
@@ -64,6 +64,7 @@ import {
64
64
  ListPageColumns,
65
65
  CustomActionsPosition,
66
66
  CustomActionTarget,
67
+ InterceptedApiType,
67
68
  } from './types';
68
69
  import { CustomCssVariables } from './css-variables';
69
70
  import { SageEmbed, SageViewConfig } from './embed/sage';
@@ -152,6 +153,7 @@ export {
152
153
  DataPanelCustomColumnGroupsAccordionState,
153
154
  CustomActionsPosition,
154
155
  CustomActionTarget,
156
+ InterceptedApiType,
155
157
  };
156
158
 
157
159
  export { resetCachedAuthToken } from './authToken';
@@ -6,6 +6,6 @@ describe('Exports', () => {
6
6
  });
7
7
 
8
8
  it('should not have undefined exports', () => {
9
- Object.keys(Exports).forEach((exportKey) => expect(Boolean(Exports[exportKey])).toBe(true));
9
+ Object.entries(Exports).forEach(([, exportValue]) => {expect(Boolean(exportValue)).toBe(true);});
10
10
  });
11
11
  });
@@ -59,4 +59,5 @@ export {
59
59
  resetCachedAuthToken,
60
60
  UIPassthroughEvent,
61
61
  DataPanelCustomColumnGroupsAccordionState,
62
+ InterceptedApiType,
62
63
  } from '../index';
@@ -0,0 +1,88 @@
1
+ import { getViewPropsAndListeners } from './util';
2
+ import { EmbedEvent, MessageCallback } from '../types';
3
+
4
+ describe('React util functions', () => {
5
+ describe('getViewPropsAndListeners', () => {
6
+ test('should return empty viewConfig and listeners for empty props', () => {
7
+ const props = {};
8
+ const result = getViewPropsAndListeners(props);
9
+
10
+ expect(result.viewConfig).toEqual({});
11
+ expect(result.listeners).toEqual({});
12
+ });
13
+
14
+ test('should separate view config properties from props', () => {
15
+ const props = {
16
+ frameParams: { width: 100, height: 200 },
17
+ showLiveboardTitle: true,
18
+ liveboardId: 'test-liveboard-id',
19
+ vizId: 'test-viz-id',
20
+ className: 'test-class',
21
+ style: { color: 'red' },
22
+ };
23
+
24
+ const result = getViewPropsAndListeners(props);
25
+
26
+ expect(result.viewConfig).toEqual({
27
+ frameParams: { width: 100, height: 200 },
28
+ showLiveboardTitle: true,
29
+ liveboardId: 'test-liveboard-id',
30
+ vizId: 'test-viz-id',
31
+ className: 'test-class',
32
+ style: { color: 'red' },
33
+ });
34
+ expect(result.listeners).toEqual({});
35
+ });
36
+
37
+ test('should separate event handlers from props', () => {
38
+ const onInit: MessageCallback = jest.fn();
39
+ const onLoad: MessageCallback = jest.fn();
40
+ const onData: MessageCallback = jest.fn();
41
+
42
+ const props = {
43
+ onInit,
44
+ onLoad,
45
+ onData,
46
+ };
47
+
48
+ const result = getViewPropsAndListeners(props);
49
+
50
+ expect(result.viewConfig).toEqual({});
51
+ expect(result.listeners).toEqual({
52
+ [EmbedEvent.Init]: onInit,
53
+ [EmbedEvent.Load]: onLoad,
54
+ [EmbedEvent.Data]: onData,
55
+ });
56
+ });
57
+
58
+ test('should handle both view config and event handlers', () => {
59
+ const onInit: MessageCallback = jest.fn();
60
+ const onAuthInit: MessageCallback = jest.fn();
61
+ const onQueryChanged: MessageCallback = jest.fn();
62
+
63
+ const props = {
64
+ liveboardId: 'test-liveboard-id',
65
+ showLiveboardTitle: false,
66
+ frameParams: { height: 500 },
67
+ onInit,
68
+ onAuthInit,
69
+ onQueryChanged,
70
+ className: 'embed-container',
71
+ };
72
+
73
+ const result = getViewPropsAndListeners(props);
74
+
75
+ expect(result.viewConfig).toEqual({
76
+ liveboardId: 'test-liveboard-id',
77
+ showLiveboardTitle: false,
78
+ frameParams: { height: 500 },
79
+ className: 'embed-container',
80
+ });
81
+ expect(result.listeners).toEqual({
82
+ [EmbedEvent.Init]: onInit,
83
+ [EmbedEvent.AuthInit]: onAuthInit,
84
+ [EmbedEvent.QueryChanged]: onQueryChanged,
85
+ });
86
+ });
87
+ });
88
+ });
package/src/react/util.ts CHANGED
@@ -24,10 +24,10 @@ export function getViewPropsAndListeners<
24
24
  return Object.keys(props).reduce(
25
25
  (accu, key) => {
26
26
  if (key.startsWith('on')) {
27
- const eventName = key.substr(2);
28
- accu.listeners[EmbedEvent[eventName]] = props[key];
27
+ const eventName = key.substr(2) as any;
28
+ (accu.listeners as any)[EmbedEvent[eventName as keyof typeof EmbedEvent] as any] = props[key as keyof T];
29
29
  } else {
30
- accu.viewConfig[key] = props[key];
30
+ (accu.viewConfig as any)[key] = props[key as keyof T];
31
31
  }
32
32
  return accu;
33
33
  },