@thoughtspot/visual-embed-sdk 1.44.0 → 1.44.1-test

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 (148) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/api-intercept.d.ts.map +1 -1
  3. package/cjs/src/api-intercept.js +8 -3
  4. package/cjs/src/api-intercept.js.map +1 -1
  5. package/cjs/src/api-intercept.spec.js +19 -3
  6. package/cjs/src/api-intercept.spec.js.map +1 -1
  7. package/cjs/src/embed/app.d.ts +17 -0
  8. package/cjs/src/embed/app.d.ts.map +1 -1
  9. package/cjs/src/embed/app.js +6 -4
  10. package/cjs/src/embed/app.js.map +1 -1
  11. package/cjs/src/embed/app.spec.js +84 -1
  12. package/cjs/src/embed/app.spec.js.map +1 -1
  13. package/cjs/src/embed/base.d.ts +7 -0
  14. package/cjs/src/embed/base.d.ts.map +1 -1
  15. package/cjs/src/embed/base.js +16 -1
  16. package/cjs/src/embed/base.js.map +1 -1
  17. package/cjs/src/embed/base.spec.js +21 -0
  18. package/cjs/src/embed/base.spec.js.map +1 -1
  19. package/cjs/src/embed/conversation.d.ts.map +1 -1
  20. package/cjs/src/embed/conversation.js +6 -1
  21. package/cjs/src/embed/conversation.js.map +1 -1
  22. package/cjs/src/embed/conversation.spec.js +6 -1
  23. package/cjs/src/embed/conversation.spec.js.map +1 -1
  24. package/cjs/src/embed/liveboard.d.ts +18 -0
  25. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  26. package/cjs/src/embed/liveboard.js +10 -5
  27. package/cjs/src/embed/liveboard.js.map +1 -1
  28. package/cjs/src/embed/liveboard.spec.js +86 -0
  29. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  30. package/cjs/src/embed/ts-embed.d.ts +3 -2
  31. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  32. package/cjs/src/embed/ts-embed.js +51 -17
  33. package/cjs/src/embed/ts-embed.js.map +1 -1
  34. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  35. package/cjs/src/embed/ts-embed.spec.js +93 -5
  36. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  37. package/cjs/src/errors.d.ts +7 -0
  38. package/cjs/src/errors.d.ts.map +1 -1
  39. package/cjs/src/errors.js +7 -0
  40. package/cjs/src/errors.js.map +1 -1
  41. package/cjs/src/index.d.ts +2 -2
  42. package/cjs/src/index.d.ts.map +1 -1
  43. package/cjs/src/index.js +2 -1
  44. package/cjs/src/index.js.map +1 -1
  45. package/cjs/src/react/all-types-export.d.ts +1 -1
  46. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  47. package/cjs/src/react/all-types-export.js +2 -1
  48. package/cjs/src/react/all-types-export.js.map +1 -1
  49. package/cjs/src/types.d.ts +248 -6
  50. package/cjs/src/types.d.ts.map +1 -1
  51. package/cjs/src/types.js +134 -2
  52. package/cjs/src/types.js.map +1 -1
  53. package/dist/{index-B2QPwxuL.js → index-BXCUJ09L.js} +1 -1
  54. package/dist/src/api-intercept.d.ts.map +1 -1
  55. package/dist/src/embed/app.d.ts +17 -0
  56. package/dist/src/embed/app.d.ts.map +1 -1
  57. package/dist/src/embed/base.d.ts +7 -0
  58. package/dist/src/embed/base.d.ts.map +1 -1
  59. package/dist/src/embed/conversation.d.ts.map +1 -1
  60. package/dist/src/embed/liveboard.d.ts +18 -0
  61. package/dist/src/embed/liveboard.d.ts.map +1 -1
  62. package/dist/src/embed/ts-embed.d.ts +3 -2
  63. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  64. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  65. package/dist/src/errors.d.ts +7 -0
  66. package/dist/src/errors.d.ts.map +1 -1
  67. package/dist/src/index.d.ts +2 -2
  68. package/dist/src/index.d.ts.map +1 -1
  69. package/dist/src/react/all-types-export.d.ts +1 -1
  70. package/dist/src/react/all-types-export.d.ts.map +1 -1
  71. package/dist/src/types.d.ts +248 -6
  72. package/dist/src/types.d.ts.map +1 -1
  73. package/dist/tsembed-react.es.js +293 -104
  74. package/dist/tsembed-react.js +292 -103
  75. package/dist/tsembed.es.js +307 -105
  76. package/dist/tsembed.js +306 -103
  77. package/dist/visual-embed-sdk-react-full.d.ts +245 -7
  78. package/dist/visual-embed-sdk-react.d.ts +238 -7
  79. package/dist/visual-embed-sdk.d.ts +245 -7
  80. package/lib/package.json +1 -1
  81. package/lib/src/api-intercept.d.ts.map +1 -1
  82. package/lib/src/api-intercept.js +9 -4
  83. package/lib/src/api-intercept.js.map +1 -1
  84. package/lib/src/api-intercept.spec.js +20 -4
  85. package/lib/src/api-intercept.spec.js.map +1 -1
  86. package/lib/src/embed/app.d.ts +17 -0
  87. package/lib/src/embed/app.d.ts.map +1 -1
  88. package/lib/src/embed/app.js +6 -4
  89. package/lib/src/embed/app.js.map +1 -1
  90. package/lib/src/embed/app.spec.js +84 -1
  91. package/lib/src/embed/app.spec.js.map +1 -1
  92. package/lib/src/embed/base.d.ts +7 -0
  93. package/lib/src/embed/base.d.ts.map +1 -1
  94. package/lib/src/embed/base.js +14 -0
  95. package/lib/src/embed/base.js.map +1 -1
  96. package/lib/src/embed/base.spec.js +21 -0
  97. package/lib/src/embed/base.spec.js.map +1 -1
  98. package/lib/src/embed/conversation.d.ts.map +1 -1
  99. package/lib/src/embed/conversation.js +7 -2
  100. package/lib/src/embed/conversation.js.map +1 -1
  101. package/lib/src/embed/conversation.spec.js +7 -2
  102. package/lib/src/embed/conversation.spec.js.map +1 -1
  103. package/lib/src/embed/liveboard.d.ts +18 -0
  104. package/lib/src/embed/liveboard.d.ts.map +1 -1
  105. package/lib/src/embed/liveboard.js +11 -6
  106. package/lib/src/embed/liveboard.js.map +1 -1
  107. package/lib/src/embed/liveboard.spec.js +86 -0
  108. package/lib/src/embed/liveboard.spec.js.map +1 -1
  109. package/lib/src/embed/ts-embed.d.ts +3 -2
  110. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  111. package/lib/src/embed/ts-embed.js +52 -18
  112. package/lib/src/embed/ts-embed.js.map +1 -1
  113. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  114. package/lib/src/embed/ts-embed.spec.js +94 -6
  115. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  116. package/lib/src/errors.d.ts +7 -0
  117. package/lib/src/errors.d.ts.map +1 -1
  118. package/lib/src/errors.js +7 -0
  119. package/lib/src/errors.js.map +1 -1
  120. package/lib/src/index.d.ts +2 -2
  121. package/lib/src/index.d.ts.map +1 -1
  122. package/lib/src/index.js +2 -2
  123. package/lib/src/index.js.map +1 -1
  124. package/lib/src/react/all-types-export.d.ts +1 -1
  125. package/lib/src/react/all-types-export.d.ts.map +1 -1
  126. package/lib/src/react/all-types-export.js +1 -1
  127. package/lib/src/react/all-types-export.js.map +1 -1
  128. package/lib/src/types.d.ts +248 -6
  129. package/lib/src/types.d.ts.map +1 -1
  130. package/lib/src/types.js +133 -1
  131. package/lib/src/types.js.map +1 -1
  132. package/package.json +1 -1
  133. package/src/api-intercept.spec.ts +23 -10
  134. package/src/api-intercept.ts +9 -4
  135. package/src/embed/app.spec.ts +116 -2
  136. package/src/embed/app.ts +26 -2
  137. package/src/embed/base.spec.ts +28 -0
  138. package/src/embed/base.ts +15 -0
  139. package/src/embed/conversation.spec.ts +7 -2
  140. package/src/embed/conversation.ts +7 -2
  141. package/src/embed/liveboard.spec.ts +107 -0
  142. package/src/embed/liveboard.ts +32 -4
  143. package/src/embed/ts-embed.spec.ts +107 -15
  144. package/src/embed/ts-embed.ts +56 -19
  145. package/src/errors.ts +7 -0
  146. package/src/index.ts +2 -0
  147. package/src/react/all-types-export.ts +1 -0
  148. package/src/types.ts +259 -6
package/src/embed/base.ts CHANGED
@@ -35,6 +35,7 @@ import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
35
35
  import { getEmbedConfig, setEmbedConfig } from './embedConfig';
36
36
  import { getQueryParamString, getValueFromWindow, storeValueInWindow } from '../utils';
37
37
  import { resetAllCachedServices } from '../utils/resetServices';
38
+ import { reload } from '../utils/processTrigger';
38
39
 
39
40
  const CONFIG_DEFAULTS: Partial<EmbedConfig> = {
40
41
  loginFailedMessage: 'Not logged in',
@@ -459,3 +460,17 @@ export function reset(): void {
459
460
  setAuthEE(null);
460
461
  authPromise = null;
461
462
  }
463
+
464
+ /**
465
+ * Reloads the ThoughtSpot iframe.
466
+ * @param iFrame
467
+ * @group Global methods
468
+ * @version SDK: 1.43.1
469
+ */
470
+ export const reloadIframe = (iFrame: HTMLIFrameElement) => {
471
+ if (!iFrame) {
472
+ logger.warn('reloadIframe called with no iFrame element.');
473
+ return;
474
+ }
475
+ reload(iFrame);
476
+ };
@@ -2,7 +2,7 @@ import { SpotterEmbed, SpotterEmbedViewConfig, ConversationEmbed } from './conve
2
2
  import { TsEmbed } from './ts-embed';
3
3
  import * as authInstance from '../auth';
4
4
  import { Action, init } from '../index';
5
- import { AuthType, Param, RuntimeFilterOp } from '../types';
5
+ import { AuthType, Param, RuntimeFilterOp, ErrorDetailsTypes, EmbedErrorCodes } from '../types';
6
6
  import {
7
7
  getDocumentBody,
8
8
  getIFrameSrc,
@@ -120,7 +120,12 @@ describe('ConversationEmbed', () => {
120
120
  (conversationEmbed as any).handleError = jest.fn();
121
121
  await conversationEmbed.render();
122
122
  expect((conversationEmbed as any).handleError).toHaveBeenCalledWith(
123
- ERROR_MESSAGE.SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND,
123
+ {
124
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
125
+ message: ERROR_MESSAGE.SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND,
126
+ code: EmbedErrorCodes.WORKSHEET_ID_NOT_FOUND,
127
+ error: ERROR_MESSAGE.SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND,
128
+ },
124
129
  );
125
130
  });
126
131
 
@@ -1,6 +1,6 @@
1
1
  import isUndefined from 'lodash/isUndefined';
2
2
  import { ERROR_MESSAGE } from '../errors';
3
- import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter } from '../types';
3
+ import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter, ErrorDetailsTypes, EmbedErrorCodes } from '../types';
4
4
  import { TsEmbed } from './ts-embed';
5
5
  import { getQueryParamString, getFilterQuery, getRuntimeParameters } from '../utils';
6
6
 
@@ -246,7 +246,12 @@ export class SpotterEmbed extends TsEmbed {
246
246
  } = this.viewConfig;
247
247
 
248
248
  if (!worksheetId) {
249
- this.handleError(ERROR_MESSAGE.SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND);
249
+ this.handleError({
250
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
251
+ message: ERROR_MESSAGE.SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND,
252
+ code: EmbedErrorCodes.WORKSHEET_ID_NOT_FOUND,
253
+ error: ERROR_MESSAGE.SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND,
254
+ });
250
255
  }
251
256
  const queryParams = this.getBaseQueryParams();
252
257
  queryParams[Param.SpotterEnabled] = true;
@@ -407,6 +407,70 @@ describe('Liveboard/viz embed tests', () => {
407
407
  });
408
408
  });
409
409
 
410
+ test('Should add showMaskedFilterChip flag set to true to the iframe src', async () => {
411
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
412
+ ...defaultViewConfig,
413
+ liveboardId,
414
+ showMaskedFilterChip: true,
415
+ } as LiveboardViewConfig);
416
+
417
+ liveboardEmbed.render();
418
+ await executeAfterWait(() => {
419
+ expectUrlMatchesWithParams(
420
+ getIFrameSrc(),
421
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showMaskedFilterChip=true${prefixParams}#/embed/viz/${liveboardId}`,
422
+ );
423
+ });
424
+ });
425
+
426
+ test('Should add showMaskedFilterChip flag set to false to the iframe src', async () => {
427
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
428
+ ...defaultViewConfig,
429
+ liveboardId,
430
+ showMaskedFilterChip: false,
431
+ } as LiveboardViewConfig);
432
+
433
+ liveboardEmbed.render();
434
+ await executeAfterWait(() => {
435
+ expectUrlMatchesWithParams(
436
+ getIFrameSrc(),
437
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showMaskedFilterChip=false${prefixParams}#/embed/viz/${liveboardId}`,
438
+ );
439
+ });
440
+ });
441
+
442
+ test('Should add isLiveboardMasterpiecesEnabled flag set to true to the iframe src', async () => {
443
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
444
+ ...defaultViewConfig,
445
+ liveboardId,
446
+ isLiveboardMasterpiecesEnabled: true,
447
+ } as LiveboardViewConfig);
448
+
449
+ liveboardEmbed.render();
450
+ await executeAfterWait(() => {
451
+ expectUrlMatchesWithParams(
452
+ getIFrameSrc(),
453
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardMasterpiecesEnabled=true${prefixParams}#/embed/viz/${liveboardId}`,
454
+ );
455
+ });
456
+ });
457
+
458
+ test('Should add isLiveboardMasterpiecesEnabled flag set to false to the iframe src', async () => {
459
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
460
+ ...defaultViewConfig,
461
+ liveboardId,
462
+ isLiveboardMasterpiecesEnabled: false,
463
+ } as LiveboardViewConfig);
464
+
465
+ liveboardEmbed.render();
466
+ await executeAfterWait(() => {
467
+ expectUrlMatchesWithParams(
468
+ getIFrameSrc(),
469
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardMasterpiecesEnabled=false${prefixParams}#/embed/viz/${liveboardId}`,
470
+ );
471
+ });
472
+ });
473
+
410
474
  test('Should add hideIrrelevantFiltersAtTabLevel flag to the iframe src', async () => {
411
475
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
412
476
  ...defaultViewConfig,
@@ -1587,4 +1651,47 @@ describe('Liveboard/viz embed tests', () => {
1587
1651
  expect(navigateToLiveboardSpy).toHaveBeenCalledWith(liveboardId, undefined, undefined);
1588
1652
  });
1589
1653
  });
1654
+
1655
+ describe('Liveboard Embed Default Height and Minimum Height Handling', () => {
1656
+ test('should set default height to 800 when minimum height is provided', async () => {
1657
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1658
+ liveboardId,
1659
+ ...defaultViewConfig,
1660
+ fullHeight: true,
1661
+ defaultHeight: 700,
1662
+ minimumHeight: 800,
1663
+ });
1664
+ await liveboardEmbed.render();
1665
+ expect(liveboardEmbed['defaultHeight']).toBe(800);
1666
+ });
1667
+ test('should set default height to 700 when default height is provided', async () => {
1668
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1669
+ liveboardId,
1670
+ ...defaultViewConfig,
1671
+ fullHeight: true,
1672
+ defaultHeight: 700,
1673
+ });
1674
+ await liveboardEmbed.render();
1675
+ expect(liveboardEmbed['defaultHeight']).toBe(700);
1676
+ });
1677
+ test('should set default height to 800 when minimum height is provided but default height is not', async () => {
1678
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1679
+ liveboardId,
1680
+ ...defaultViewConfig,
1681
+ fullHeight: true,
1682
+ minimumHeight: 800,
1683
+ });
1684
+ await liveboardEmbed.render();
1685
+ expect(liveboardEmbed['defaultHeight']).toBe(800);
1686
+ });
1687
+ test('should set default height to 500 when neither default height nor minimum height is provided', async () => {
1688
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1689
+ liveboardId,
1690
+ ...defaultViewConfig,
1691
+ fullHeight: true,
1692
+ });
1693
+ await liveboardEmbed.render();
1694
+ expect(liveboardEmbed['defaultHeight']).toBe(500);
1695
+ });
1696
+ });
1590
1697
  });
@@ -20,6 +20,8 @@ import {
20
20
  SearchLiveboardCommonViewConfig as LiveboardOtherViewConfig,
21
21
  BaseViewConfig,
22
22
  LiveboardAppEmbedViewConfig,
23
+ ErrorDetailsTypes,
24
+ EmbedErrorCodes,
23
25
  } from '../types';
24
26
  import { calculateVisibleElementData, getQueryParamString, isUndefined } from '../utils';
25
27
  import { getAuthPromise } from './base';
@@ -65,6 +67,7 @@ export interface LiveboardViewConfig extends BaseViewConfig, LiveboardOtherViewC
65
67
  * Supported embed types: `LiveboardEmbed`
66
68
  * @version SDK: 1.5.0 | ThoughtSpot: ts7.oct.cl, 7.2.1
67
69
  * @default 500
70
+ * @deprecated Use `minimumHeight` instead.
68
71
  * @example
69
72
  * ```js
70
73
  * const embed = new LiveboardEmbed('#embed', {
@@ -75,6 +78,23 @@ export interface LiveboardViewConfig extends BaseViewConfig, LiveboardOtherViewC
75
78
  * ```
76
79
  */
77
80
  defaultHeight?: number;
81
+ /**
82
+ * This is the minimum height (in pixels) for a full-height Liveboard.
83
+ * Setting this height helps resolve issues with empty Liveboards and
84
+ * other screens navigable from a Liveboard.
85
+ *
86
+ * @version SDK: 1.44.2 | ThoughtSpot: 26.0.2.cl
87
+ * @default 500
88
+ * @example
89
+ * ```js
90
+ * const embed = new LiveboardEmbed('#embed', {
91
+ * ... // other liveboard view config
92
+ * fullHeight: true,
93
+ * minimumHeight: 600,
94
+ * });
95
+ * ```
96
+ */
97
+ minimumHeight?: number;
78
98
  /**
79
99
  * @Deprecated If set to true, the context menu in visualizations will be enabled.
80
100
  * @example
@@ -467,6 +487,7 @@ export class LiveboardEmbed extends V1Embed {
467
487
  enableVizTransformations,
468
488
  fullHeight,
469
489
  defaultHeight,
490
+ minimumHeight,
470
491
  visibleVizs,
471
492
  liveboardV2,
472
493
  vizId,
@@ -480,6 +501,8 @@ export class LiveboardEmbed extends V1Embed {
480
501
  showLiveboardVerifiedBadge = true,
481
502
  showLiveboardReverifyBanner = true,
482
503
  hideIrrelevantChipsInLiveboardTabs = false,
504
+ showMaskedFilterChip = false,
505
+ isLiveboardMasterpiecesEnabled = false,
483
506
  isEnhancedFilterInteractivityEnabled = false,
484
507
  enableAskSage,
485
508
  enable2ColumnLayout,
@@ -508,9 +531,7 @@ export class LiveboardEmbed extends V1Embed {
508
531
  params[Param.RootMarginForLazyLoad] = this.viewConfig.lazyLoadingMargin;
509
532
  }
510
533
  }
511
- if (defaultHeight) {
512
- this.defaultHeight = defaultHeight;
513
- }
534
+ this.defaultHeight = minimumHeight || defaultHeight || this.defaultHeight;
514
535
  if (enableVizTransformations !== undefined) {
515
536
  params[Param.EnableVizTransformations] = enableVizTransformations.toString();
516
537
  }
@@ -589,6 +610,8 @@ export class LiveboardEmbed extends V1Embed {
589
610
  params[Param.ShowLiveboardVerifiedBadge] = showLiveboardVerifiedBadge;
590
611
  params[Param.ShowLiveboardReverifyBanner] = showLiveboardReverifyBanner;
591
612
  params[Param.HideIrrelevantFiltersInTab] = hideIrrelevantChipsInLiveboardTabs;
613
+ params[Param.ShowMaskedFilterChip] = showMaskedFilterChip;
614
+ params[Param.IsLiveboardMasterpiecesEnabled] = isLiveboardMasterpiecesEnabled;
592
615
  params[Param.IsEnhancedFilterInteractivityEnabled] = isEnhancedFilterInteractivityEnabled;
593
616
  params[Param.DataPanelV2Enabled] = dataPanelV2;
594
617
  params[Param.EnableCustomColumnGroups] = enableCustomColumnGroups;
@@ -642,7 +665,12 @@ export class LiveboardEmbed extends V1Embed {
642
665
  const liveboardId = this.viewConfig.liveboardId ?? this.viewConfig.pinboardId;
643
666
 
644
667
  if (!liveboardId) {
645
- this.handleError(ERROR_MESSAGE.LIVEBOARD_VIZ_ID_VALIDATION);
668
+ this.handleError({
669
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
670
+ message: ERROR_MESSAGE.LIVEBOARD_VIZ_ID_VALIDATION,
671
+ code: EmbedErrorCodes.LIVEBOARD_ID_MISSING,
672
+ error: ERROR_MESSAGE.LIVEBOARD_VIZ_ID_VALIDATION,
673
+ });
646
674
  }
647
675
  return `${this.getRootIframeSrc()}${this.getIframeSuffixSrc(
648
676
  liveboardId,
@@ -29,6 +29,8 @@ import {
29
29
  CustomActionTarget,
30
30
  CustomActionsPosition,
31
31
  DefaultAppInitData,
32
+ ErrorDetailsTypes,
33
+ EmbedErrorCodes,
32
34
  } from '../types';
33
35
  import {
34
36
  executeAfterWait,
@@ -1613,9 +1615,12 @@ describe('Unit test case for ts embed', () => {
1613
1615
  } as LiveboardViewConfig);
1614
1616
  await pinboardEmbed.render();
1615
1617
  expect(pinboardEmbed['isError']).toBe(true);
1616
- expect(logger.error).toHaveBeenCalledWith(
1617
- 'You cannot have both hidden actions and visible actions',
1618
- );
1618
+ expect(logger.error).toHaveBeenCalledWith({
1619
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1620
+ message: ERROR_MESSAGE.CONFLICTING_ACTIONS_CONFIG,
1621
+ code: EmbedErrorCodes.CONFLICTING_ACTIONS_CONFIG,
1622
+ error: ERROR_MESSAGE.CONFLICTING_ACTIONS_CONFIG,
1623
+ });
1619
1624
  });
1620
1625
  test('should not throw error when there are only visible or hidden actions - pinboard', async () => {
1621
1626
  const pinboardEmbed = new PinboardEmbed(getRootEl(), {
@@ -1645,9 +1650,12 @@ describe('Unit test case for ts embed', () => {
1645
1650
  } as LiveboardViewConfig);
1646
1651
  await liveboardEmbed.render();
1647
1652
  expect(liveboardEmbed['isError']).toBe(true);
1648
- expect(logger.error).toHaveBeenCalledWith(
1649
- 'You cannot have both hidden actions and visible actions',
1650
- );
1653
+ expect(logger.error).toHaveBeenCalledWith({
1654
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1655
+ message: ERROR_MESSAGE.CONFLICTING_ACTIONS_CONFIG,
1656
+ code: EmbedErrorCodes.CONFLICTING_ACTIONS_CONFIG,
1657
+ error: ERROR_MESSAGE.CONFLICTING_ACTIONS_CONFIG,
1658
+ });
1651
1659
  }
1652
1660
  test('should throw error when there are both visible and hidden action arrays', async () => {
1653
1661
  await testActionsForLiveboards([Action.DownloadAsCsv], [Action.DownloadAsCsv]);
@@ -1690,9 +1698,12 @@ describe('Unit test case for ts embed', () => {
1690
1698
  } as LiveboardViewConfig);
1691
1699
  await pinboardEmbed.render();
1692
1700
  expect(pinboardEmbed['isError']).toBe(true);
1693
- expect(logger.error).toHaveBeenCalledWith(
1694
- 'You cannot have both hidden Tabs and visible Tabs',
1695
- );
1701
+ expect(logger.error).toHaveBeenCalledWith({
1702
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1703
+ message: ERROR_MESSAGE.CONFLICTING_TABS_CONFIG,
1704
+ code: EmbedErrorCodes.CONFLICTING_TABS_CONFIG,
1705
+ error: ERROR_MESSAGE.CONFLICTING_TABS_CONFIG,
1706
+ });
1696
1707
  });
1697
1708
  test('should not throw error when there are only visible or hidden Tabs - pinboard', async () => {
1698
1709
  const pinboardEmbed = new PinboardEmbed(getRootEl(), {
@@ -1722,9 +1733,12 @@ describe('Unit test case for ts embed', () => {
1722
1733
  } as LiveboardViewConfig);
1723
1734
  await liveboardEmbed.render();
1724
1735
  expect(liveboardEmbed['isError']).toBe(true);
1725
- expect(logger.error).toHaveBeenCalledWith(
1726
- 'You cannot have both hidden Tabs and visible Tabs',
1727
- );
1736
+ expect(logger.error).toHaveBeenCalledWith({
1737
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1738
+ message: ERROR_MESSAGE.CONFLICTING_TABS_CONFIG,
1739
+ code: EmbedErrorCodes.CONFLICTING_TABS_CONFIG,
1740
+ error: ERROR_MESSAGE.CONFLICTING_TABS_CONFIG,
1741
+ });
1728
1742
  }
1729
1743
  test('should throw error when there are both visible and hidden Tab arrays', async () => {
1730
1744
  await testTabsForLiveboards([tabId1], [tabId2]);
@@ -1770,9 +1784,12 @@ describe('Unit test case for ts embed', () => {
1770
1784
  const tsEmbed = new SearchEmbed(getRootEl(), {});
1771
1785
  await tsEmbed.render();
1772
1786
  expect(tsEmbed['isError']).toBe(true);
1773
- expect(logger.error).toHaveBeenCalledWith(
1774
- 'You need to init the ThoughtSpot SDK module first',
1775
- );
1787
+ expect(logger.error).toHaveBeenCalledWith({
1788
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1789
+ message: ERROR_MESSAGE.INIT_SDK_REQUIRED,
1790
+ code: EmbedErrorCodes.INIT_ERROR,
1791
+ error: ERROR_MESSAGE.INIT_SDK_REQUIRED,
1792
+ });
1776
1793
  });
1777
1794
  });
1778
1795
 
@@ -3829,3 +3846,78 @@ describe('Unit test case for ts embed', () => {
3829
3846
  });
3830
3847
  });
3831
3848
  });
3849
+
3850
+
3851
+ describe('Additional Coverage Tests', () => {
3852
+ beforeAll(() => {
3853
+ init({
3854
+ thoughtSpotHost: 'tshost',
3855
+ authType: AuthType.None,
3856
+ });
3857
+ });
3858
+
3859
+ test('should handle getAuthTokenForCookielessInit with non-cookieless auth', async () => {
3860
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3861
+ const token = await searchEmbed['getAuthTokenForCookielessInit']();
3862
+ expect(token).toBe('');
3863
+ });
3864
+
3865
+ test('should call setIFrameHeight', async () => {
3866
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3867
+ await searchEmbed.render();
3868
+ await executeAfterWait(() => {
3869
+ searchEmbed['setIFrameHeight'](500);
3870
+ expect(getIFrameEl().style.height).toBe('500px');
3871
+ });
3872
+ });
3873
+
3874
+ test('should test getIframeCenter calculation', async () => {
3875
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3876
+ await searchEmbed.render();
3877
+ await executeAfterWait(() => {
3878
+ const center = searchEmbed['getIframeCenter']();
3879
+ expect(center).toHaveProperty('iframeCenter');
3880
+ expect(center).toHaveProperty('iframeHeight');
3881
+ expect(center).toHaveProperty('viewPortHeight');
3882
+ });
3883
+ });
3884
+
3885
+ test('should handle preRender with replaceExistingPreRender=true', async () => {
3886
+ createRootEleForEmbed();
3887
+ const embed1 = new LiveboardEmbed('#tsEmbedDiv', {
3888
+ preRenderId: 'test-replace',
3889
+ liveboardId: 'lb1',
3890
+ });
3891
+ await embed1.preRender();
3892
+ const embed2 = new LiveboardEmbed('#tsEmbedDiv', {
3893
+ preRenderId: 'test-replace',
3894
+ liveboardId: 'lb2',
3895
+ });
3896
+ await embed2.preRender(false, true);
3897
+ expect(document.getElementById('tsEmbed-pre-render-wrapper-test-replace')).toBeTruthy();
3898
+ });
3899
+
3900
+ test('should test getIframeSrc base implementation', () => {
3901
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3902
+ expect(searchEmbed.getIframeSrc()).toBe('');
3903
+ });
3904
+
3905
+ test('should handle createEmbedEventResponder with OnBeforeGetVizDataIntercept', async () => {
3906
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3907
+ const mockPort: any = { postMessage: jest.fn() };
3908
+ const responder = searchEmbed['createEmbedEventResponder'](
3909
+ mockPort,
3910
+ EmbedEvent.OnBeforeGetVizDataIntercept,
3911
+ );
3912
+ responder({ data: 'test' });
3913
+ expect(mockPort.postMessage).toHaveBeenCalled();
3914
+ });
3915
+
3916
+ test('should clean up message event listeners', async () => {
3917
+ const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
3918
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3919
+ await searchEmbed.render();
3920
+ searchEmbed['unsubscribeToMessageEvents']();
3921
+ expect(removeEventListenerSpy).toHaveBeenCalledWith('message', expect.any(Function));
3922
+ });
3923
+ });
@@ -57,6 +57,9 @@ import {
57
57
  ContextMenuTriggerOptions,
58
58
  DefaultAppInitData,
59
59
  AllEmbedViewConfig as ViewConfig,
60
+ EmbedErrorDetailsEvent,
61
+ ErrorDetailsTypes,
62
+ EmbedErrorCodes,
60
63
  } from '../types';
61
64
  import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
62
65
  import { processEventData, processAuthFailure } from '../utils/processData';
@@ -218,20 +221,24 @@ export class TsEmbed {
218
221
  * Throws error encountered during initialization.
219
222
  */
220
223
  private throwInitError() {
221
- this.handleError('You need to init the ThoughtSpot SDK module first');
224
+ this.handleError({
225
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
226
+ message: ERROR_MESSAGE.INIT_SDK_REQUIRED,
227
+ code: EmbedErrorCodes.INIT_ERROR,
228
+ error : ERROR_MESSAGE.INIT_SDK_REQUIRED,
229
+ });
222
230
  }
223
231
 
224
232
  /**
225
233
  * Handles errors within the SDK
226
234
  * @param error The error message or object
235
+ * @param errorDetails The error details
227
236
  */
228
- protected handleError(error: string | Record<string, unknown>) {
237
+ protected handleError(errorDetails: EmbedErrorDetailsEvent) {
229
238
  this.isError = true;
230
- this.executeCallbacks(EmbedEvent.Error, {
231
- error,
232
- });
239
+ this.executeCallbacks(EmbedEvent.Error, errorDetails);
233
240
  // Log error
234
- logger.error(error);
241
+ logger.error(errorDetails);
235
242
  }
236
243
 
237
244
  /**
@@ -325,11 +332,14 @@ export class TsEmbed {
325
332
  window.addEventListener('online', onlineEventListener);
326
333
 
327
334
  const offlineEventListener = (e: Event) => {
328
- const offlineWarning = ERROR_MESSAGE.OFFLINE_WARNING;
329
- this.executeCallbacks(EmbedEvent.Error, {
330
- offlineWarning,
331
- });
332
- logger.warn(offlineWarning);
335
+ const errorDetails = {
336
+ errorType: ErrorDetailsTypes.NETWORK,
337
+ message: ERROR_MESSAGE.OFFLINE_WARNING,
338
+ code: EmbedErrorCodes.NETWORK_ERROR,
339
+ offlineWarning : ERROR_MESSAGE.OFFLINE_WARNING,
340
+ };
341
+ this.executeCallbacks(EmbedEvent.Error, errorDetails);
342
+ logger.warn(errorDetails);
333
343
  };
334
344
  window.addEventListener('offline', offlineEventListener);
335
345
 
@@ -444,9 +454,11 @@ export class TsEmbed {
444
454
  ]);
445
455
  if (customActionsResult.errors.length > 0) {
446
456
  this.handleError({
447
- type: 'CUSTOM_ACTION_VALIDATION',
448
- message: customActionsResult.errors,
449
- });
457
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
458
+ message: customActionsResult.errors,
459
+ code: EmbedErrorCodes.CUSTOM_ACTION_VALIDATION,
460
+ error : { type: EmbedErrorCodes.CUSTOM_ACTION_VALIDATION, message: customActionsResult.errors }
461
+ });
450
462
  }
451
463
  const baseInitData = {
452
464
  customisations: getCustomisations(this.embedConfig, this.viewConfig),
@@ -658,12 +670,22 @@ export class TsEmbed {
658
670
  };
659
671
 
660
672
  if (Array.isArray(visibleActions) && Array.isArray(hiddenActions)) {
661
- this.handleError('You cannot have both hidden actions and visible actions');
673
+ this.handleError({
674
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
675
+ message: ERROR_MESSAGE.CONFLICTING_ACTIONS_CONFIG,
676
+ code: EmbedErrorCodes.CONFLICTING_ACTIONS_CONFIG,
677
+ error : ERROR_MESSAGE.CONFLICTING_ACTIONS_CONFIG,
678
+ });
662
679
  return queryParams;
663
680
  }
664
681
 
665
682
  if (Array.isArray(visibleTabs) && Array.isArray(hiddenTabs)) {
666
- this.handleError('You cannot have both hidden Tabs and visible Tabs');
683
+ this.handleError({
684
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
685
+ message: ERROR_MESSAGE.CONFLICTING_TABS_CONFIG,
686
+ code: EmbedErrorCodes.CONFLICTING_TABS_CONFIG,
687
+ error : ERROR_MESSAGE.CONFLICTING_TABS_CONFIG,
688
+ });
667
689
  return queryParams;
668
690
  }
669
691
  if (primaryAction) {
@@ -916,7 +938,12 @@ export class TsEmbed {
916
938
  error: JSON.stringify(error),
917
939
  });
918
940
  this.handleInsertionIntoDOM(this.embedConfig.loginFailedMessage);
919
- this.handleError(error);
941
+ this.handleError({
942
+ errorType: ErrorDetailsTypes.API,
943
+ message: error.message || ERROR_MESSAGE.LOGIN_FAILED,
944
+ code: EmbedErrorCodes.LOGIN_FAILED,
945
+ error : error,
946
+ });
920
947
  });
921
948
  });
922
949
  }
@@ -1323,12 +1350,22 @@ export class TsEmbed {
1323
1350
  uploadMixpanelEvent(`${MIXPANEL_EVENT.VISUAL_SDK_TRIGGER}-${messageType}`);
1324
1351
 
1325
1352
  if (!this.isRendered) {
1326
- this.handleError('Please call render before triggering events');
1353
+ this.handleError({
1354
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1355
+ message: ERROR_MESSAGE.RENDER_BEFORE_EVENTS_REQUIRED,
1356
+ code: EmbedErrorCodes.RENDER_NOT_CALLED,
1357
+ error: ERROR_MESSAGE.RENDER_BEFORE_EVENTS_REQUIRED,
1358
+ });
1327
1359
  return null;
1328
1360
  }
1329
1361
 
1330
1362
  if (!messageType) {
1331
- this.handleError('Host event type is undefined');
1363
+ this.handleError({
1364
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
1365
+ message: ERROR_MESSAGE.HOST_EVENT_TYPE_UNDEFINED,
1366
+ code: EmbedErrorCodes.HOST_EVENT_TYPE_UNDEFINED,
1367
+ error: ERROR_MESSAGE.HOST_EVENT_TYPE_UNDEFINED,
1368
+ });
1332
1369
  return null;
1333
1370
  }
1334
1371
 
package/src/errors.ts CHANGED
@@ -20,6 +20,13 @@ export const ERROR_MESSAGE = {
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
22
  OFFLINE_WARNING : 'Network not Detected. Embed is offline. Please reconnect and refresh',
23
+ INIT_SDK_REQUIRED: 'You need to init the ThoughtSpot SDK module first',
24
+ CONFLICTING_ACTIONS_CONFIG: 'You cannot have both hidden actions and visible actions',
25
+ CONFLICTING_TABS_CONFIG: 'You cannot have both hidden Tabs and visible Tabs',
26
+ RENDER_BEFORE_EVENTS_REQUIRED: 'Please call render before triggering events',
27
+ HOST_EVENT_TYPE_UNDEFINED: 'Host event type is undefined',
28
+ LOGIN_FAILED: 'Login failed',
29
+ ERROR_PARSING_API_INTERCEPT_BODY: 'Error parsing api intercept body',
23
30
  };
24
31
 
25
32
  export const CUSTOM_ACTIONS_ERROR_MESSAGE = {
package/src/index.ts CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  exportTML,
27
27
  executeTMLInput,
28
28
  exportTMLInput,
29
+ reloadIframe,
29
30
  } from './embed/base';
30
31
  import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/liveboard';
31
32
  import { SearchEmbed, SearchViewConfig } from './embed/search';
@@ -83,6 +84,7 @@ export {
83
84
  executeTML,
84
85
  exportTML,
85
86
  executeTMLInput,
87
+ reloadIframe,
86
88
  exportTMLInput,
87
89
  getEmbedConfig as getInitConfig,
88
90
  getSessionInfo,
@@ -22,6 +22,7 @@ export {
22
22
  init,
23
23
  logout,
24
24
  prefetch,
25
+ reloadIframe,
25
26
  getInitConfig,
26
27
  getSessionInfo,
27
28
  uploadMixpanelEvent,