@thoughtspot/visual-embed-sdk 1.44.1 → 1.44.3

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 (246) hide show
  1. package/cjs/package.json +6 -5
  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/auth.spec.js +43 -42
  8. package/cjs/src/auth.spec.js.map +1 -1
  9. package/cjs/src/authToken.spec.js +3 -3
  10. package/cjs/src/authToken.spec.js.map +1 -1
  11. package/cjs/src/embed/app.d.ts +17 -0
  12. package/cjs/src/embed/app.d.ts.map +1 -1
  13. package/cjs/src/embed/app.js +9 -5
  14. package/cjs/src/embed/app.js.map +1 -1
  15. package/cjs/src/embed/app.spec.js +96 -6
  16. package/cjs/src/embed/app.spec.js.map +1 -1
  17. package/cjs/src/embed/base.d.ts +1 -1
  18. package/cjs/src/embed/base.d.ts.map +1 -1
  19. package/cjs/src/embed/base.js +4 -0
  20. package/cjs/src/embed/base.js.map +1 -1
  21. package/cjs/src/embed/base.spec.js +71 -15
  22. package/cjs/src/embed/base.spec.js.map +1 -1
  23. package/cjs/src/embed/bodyless-conversation.spec.js +2 -2
  24. package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
  25. package/cjs/src/embed/conversation.d.ts.map +1 -1
  26. package/cjs/src/embed/conversation.js +6 -1
  27. package/cjs/src/embed/conversation.js.map +1 -1
  28. package/cjs/src/embed/conversation.spec.js +8 -3
  29. package/cjs/src/embed/conversation.spec.js.map +1 -1
  30. package/cjs/src/embed/embed.spec.js +101 -2
  31. package/cjs/src/embed/embed.spec.js.map +1 -1
  32. package/cjs/src/embed/events.spec.js +2 -2
  33. package/cjs/src/embed/events.spec.js.map +1 -1
  34. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +1 -1
  35. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  36. package/cjs/src/embed/liveboard.d.ts +18 -0
  37. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  38. package/cjs/src/embed/liveboard.js +13 -6
  39. package/cjs/src/embed/liveboard.js.map +1 -1
  40. package/cjs/src/embed/liveboard.spec.js +114 -26
  41. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  42. package/cjs/src/embed/pinboard.spec.js +1 -1
  43. package/cjs/src/embed/pinboard.spec.js.map +1 -1
  44. package/cjs/src/embed/sage.spec.js +2 -2
  45. package/cjs/src/embed/sage.spec.js.map +1 -1
  46. package/cjs/src/embed/search.spec.js +118 -2
  47. package/cjs/src/embed/search.spec.js.map +1 -1
  48. package/cjs/src/embed/ts-embed-trigger.spec.js +2 -3
  49. package/cjs/src/embed/ts-embed-trigger.spec.js.map +1 -1
  50. package/cjs/src/embed/ts-embed.d.ts +3 -2
  51. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  52. package/cjs/src/embed/ts-embed.js +51 -17
  53. package/cjs/src/embed/ts-embed.js.map +1 -1
  54. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  55. package/cjs/src/embed/ts-embed.spec.js +335 -71
  56. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  57. package/cjs/src/errors.d.ts +8 -0
  58. package/cjs/src/errors.d.ts.map +1 -1
  59. package/cjs/src/errors.js +8 -0
  60. package/cjs/src/errors.js.map +1 -1
  61. package/cjs/src/mixpanel-service.spec.js +1 -1
  62. package/cjs/src/mixpanel-service.spec.js.map +1 -1
  63. package/cjs/src/react/index.spec.js +3 -4
  64. package/cjs/src/react/index.spec.js.map +1 -1
  65. package/cjs/src/test/test-utils.js +1 -1
  66. package/cjs/src/test/test-utils.js.map +1 -1
  67. package/cjs/src/types.d.ts +194 -1
  68. package/cjs/src/types.d.ts.map +1 -1
  69. package/cjs/src/types.js +94 -2
  70. package/cjs/src/types.js.map +1 -1
  71. package/cjs/src/utils/authService/authService.spec.js +8 -8
  72. package/cjs/src/utils/authService/authService.spec.js.map +1 -1
  73. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  74. package/cjs/src/utils/graphql/answerService/answerService.spec.js +1 -1
  75. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  76. package/cjs/src/utils/graphql/graphql-request.spec.js +1 -1
  77. package/cjs/src/utils/graphql/graphql-request.spec.js.map +1 -1
  78. package/cjs/src/utils/graphql/sourceService.spec.js +1 -1
  79. package/cjs/src/utils/graphql/sourceService.spec.js.map +1 -1
  80. package/cjs/src/utils/logger.spec.d.ts +5 -20
  81. package/cjs/src/utils/logger.spec.d.ts.map +1 -1
  82. package/cjs/src/utils/processData.spec.js +17 -17
  83. package/cjs/src/utils/processData.spec.js.map +1 -1
  84. package/cjs/src/utils/processTrigger.spec.js +8 -8
  85. package/cjs/src/utils/processTrigger.spec.js.map +1 -1
  86. package/cjs/src/utils.d.ts +16 -3
  87. package/cjs/src/utils.d.ts.map +1 -1
  88. package/cjs/src/utils.js +60 -5
  89. package/cjs/src/utils.js.map +1 -1
  90. package/cjs/src/utils.spec.js +72 -10
  91. package/cjs/src/utils.spec.js.map +1 -1
  92. package/dist/{index-BE9gGzRX.js → index-D0n5LIka.js} +1 -1
  93. package/dist/src/api-intercept.d.ts.map +1 -1
  94. package/dist/src/embed/app.d.ts +17 -0
  95. package/dist/src/embed/app.d.ts.map +1 -1
  96. package/dist/src/embed/base.d.ts +1 -1
  97. package/dist/src/embed/base.d.ts.map +1 -1
  98. package/dist/src/embed/conversation.d.ts.map +1 -1
  99. package/dist/src/embed/liveboard.d.ts +18 -0
  100. package/dist/src/embed/liveboard.d.ts.map +1 -1
  101. package/dist/src/embed/ts-embed.d.ts +3 -2
  102. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  103. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  104. package/dist/src/errors.d.ts +8 -0
  105. package/dist/src/errors.d.ts.map +1 -1
  106. package/dist/src/types.d.ts +194 -1
  107. package/dist/src/types.d.ts.map +1 -1
  108. package/dist/src/utils/logger.spec.d.ts +5 -20
  109. package/dist/src/utils/logger.spec.d.ts.map +1 -1
  110. package/dist/src/utils.d.ts +16 -3
  111. package/dist/src/utils.d.ts.map +1 -1
  112. package/dist/tsembed-react.es.js +282 -74
  113. package/dist/tsembed-react.js +281 -73
  114. package/dist/tsembed.es.js +282 -74
  115. package/dist/tsembed.js +281 -73
  116. package/dist/visual-embed-sdk-react-full.d.ts +185 -3
  117. package/dist/visual-embed-sdk-react.d.ts +184 -2
  118. package/dist/visual-embed-sdk.d.ts +185 -3
  119. package/lib/package.json +6 -5
  120. package/lib/src/api-intercept.d.ts.map +1 -1
  121. package/lib/src/api-intercept.js +9 -4
  122. package/lib/src/api-intercept.js.map +1 -1
  123. package/lib/src/api-intercept.spec.js +20 -4
  124. package/lib/src/api-intercept.spec.js.map +1 -1
  125. package/lib/src/auth.spec.js +43 -42
  126. package/lib/src/auth.spec.js.map +1 -1
  127. package/lib/src/authToken.spec.js +3 -3
  128. package/lib/src/authToken.spec.js.map +1 -1
  129. package/lib/src/embed/app.d.ts +17 -0
  130. package/lib/src/embed/app.d.ts.map +1 -1
  131. package/lib/src/embed/app.js +10 -6
  132. package/lib/src/embed/app.js.map +1 -1
  133. package/lib/src/embed/app.spec.js +96 -6
  134. package/lib/src/embed/app.spec.js.map +1 -1
  135. package/lib/src/embed/base.d.ts +1 -1
  136. package/lib/src/embed/base.d.ts.map +1 -1
  137. package/lib/src/embed/base.js +5 -1
  138. package/lib/src/embed/base.js.map +1 -1
  139. package/lib/src/embed/base.spec.js +72 -16
  140. package/lib/src/embed/base.spec.js.map +1 -1
  141. package/lib/src/embed/bodyless-conversation.spec.js +2 -2
  142. package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
  143. package/lib/src/embed/conversation.d.ts.map +1 -1
  144. package/lib/src/embed/conversation.js +7 -2
  145. package/lib/src/embed/conversation.js.map +1 -1
  146. package/lib/src/embed/conversation.spec.js +9 -4
  147. package/lib/src/embed/conversation.spec.js.map +1 -1
  148. package/lib/src/embed/embed.spec.js +103 -4
  149. package/lib/src/embed/embed.spec.js.map +1 -1
  150. package/lib/src/embed/events.spec.js +2 -2
  151. package/lib/src/embed/events.spec.js.map +1 -1
  152. package/lib/src/embed/hostEventClient/host-event-client.spec.js +2 -2
  153. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  154. package/lib/src/embed/liveboard.d.ts +18 -0
  155. package/lib/src/embed/liveboard.d.ts.map +1 -1
  156. package/lib/src/embed/liveboard.js +15 -8
  157. package/lib/src/embed/liveboard.js.map +1 -1
  158. package/lib/src/embed/liveboard.spec.js +114 -26
  159. package/lib/src/embed/liveboard.spec.js.map +1 -1
  160. package/lib/src/embed/pinboard.spec.js +1 -1
  161. package/lib/src/embed/pinboard.spec.js.map +1 -1
  162. package/lib/src/embed/sage.spec.js +2 -2
  163. package/lib/src/embed/sage.spec.js.map +1 -1
  164. package/lib/src/embed/search.spec.js +118 -2
  165. package/lib/src/embed/search.spec.js.map +1 -1
  166. package/lib/src/embed/ts-embed-trigger.spec.js +2 -3
  167. package/lib/src/embed/ts-embed-trigger.spec.js.map +1 -1
  168. package/lib/src/embed/ts-embed.d.ts +3 -2
  169. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  170. package/lib/src/embed/ts-embed.js +52 -18
  171. package/lib/src/embed/ts-embed.js.map +1 -1
  172. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  173. package/lib/src/embed/ts-embed.spec.js +336 -72
  174. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  175. package/lib/src/errors.d.ts +8 -0
  176. package/lib/src/errors.d.ts.map +1 -1
  177. package/lib/src/errors.js +8 -0
  178. package/lib/src/errors.js.map +1 -1
  179. package/lib/src/mixpanel-service.spec.js +1 -1
  180. package/lib/src/mixpanel-service.spec.js.map +1 -1
  181. package/lib/src/react/index.spec.js +3 -4
  182. package/lib/src/react/index.spec.js.map +1 -1
  183. package/lib/src/test/test-utils.js +1 -1
  184. package/lib/src/test/test-utils.js.map +1 -1
  185. package/lib/src/types.d.ts +194 -1
  186. package/lib/src/types.d.ts.map +1 -1
  187. package/lib/src/types.js +93 -1
  188. package/lib/src/types.js.map +1 -1
  189. package/lib/src/utils/authService/authService.spec.js +8 -8
  190. package/lib/src/utils/authService/authService.spec.js.map +1 -1
  191. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  192. package/lib/src/utils/graphql/answerService/answerService.spec.js +1 -1
  193. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  194. package/lib/src/utils/graphql/graphql-request.spec.js +1 -1
  195. package/lib/src/utils/graphql/graphql-request.spec.js.map +1 -1
  196. package/lib/src/utils/graphql/sourceService.spec.js +1 -1
  197. package/lib/src/utils/graphql/sourceService.spec.js.map +1 -1
  198. package/lib/src/utils/logger.spec.d.ts +5 -20
  199. package/lib/src/utils/logger.spec.d.ts.map +1 -1
  200. package/lib/src/utils/processData.spec.js +17 -17
  201. package/lib/src/utils/processData.spec.js.map +1 -1
  202. package/lib/src/utils/processTrigger.spec.js +8 -8
  203. package/lib/src/utils/processTrigger.spec.js.map +1 -1
  204. package/lib/src/utils.d.ts +16 -3
  205. package/lib/src/utils.d.ts.map +1 -1
  206. package/lib/src/utils.js +57 -4
  207. package/lib/src/utils.js.map +1 -1
  208. package/lib/src/utils.spec.js +73 -11
  209. package/lib/src/utils.spec.js.map +1 -1
  210. package/package.json +6 -5
  211. package/src/api-intercept.spec.ts +23 -10
  212. package/src/api-intercept.ts +9 -4
  213. package/src/auth.spec.ts +53 -51
  214. package/src/authToken.spec.ts +3 -3
  215. package/src/embed/app.spec.ts +128 -7
  216. package/src/embed/app.ts +30 -4
  217. package/src/embed/base.spec.ts +95 -21
  218. package/src/embed/base.ts +5 -2
  219. package/src/embed/bodyless-conversation.spec.ts +2 -2
  220. package/src/embed/conversation.spec.ts +9 -4
  221. package/src/embed/conversation.ts +7 -2
  222. package/src/embed/embed.spec.ts +122 -2
  223. package/src/embed/events.spec.ts +2 -2
  224. package/src/embed/hostEventClient/host-event-client.spec.ts +2 -2
  225. package/src/embed/liveboard.spec.ts +137 -29
  226. package/src/embed/liveboard.ts +36 -6
  227. package/src/embed/pinboard.spec.ts +1 -1
  228. package/src/embed/sage.spec.ts +2 -2
  229. package/src/embed/search.spec.ts +133 -2
  230. package/src/embed/ts-embed-trigger.spec.ts +2 -3
  231. package/src/embed/ts-embed.spec.ts +424 -91
  232. package/src/embed/ts-embed.ts +56 -19
  233. package/src/errors.ts +8 -0
  234. package/src/mixpanel-service.spec.ts +1 -1
  235. package/src/react/index.spec.tsx +4 -5
  236. package/src/test/test-utils.ts +2 -2
  237. package/src/types.ts +206 -1
  238. package/src/utils/authService/authService.spec.ts +17 -17
  239. package/src/utils/authService/tokenizedAuthService.spec.ts +4 -4
  240. package/src/utils/graphql/answerService/answerService.spec.ts +3 -3
  241. package/src/utils/graphql/graphql-request.spec.ts +2 -2
  242. package/src/utils/graphql/sourceService.spec.ts +1 -1
  243. package/src/utils/processData.spec.ts +26 -26
  244. package/src/utils/processTrigger.spec.ts +8 -8
  245. package/src/utils.spec.ts +100 -11
  246. package/src/utils.ts +59 -7
@@ -43,7 +43,7 @@ beforeAll(() => {
43
43
  thoughtSpotHost,
44
44
  authType: AuthType.None,
45
45
  });
46
- jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
46
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve(undefined));
47
47
  (window as any).ResizeObserver =
48
48
  window.ResizeObserver ||
49
49
  jest.fn().mockImplementation(() => ({
@@ -542,6 +542,100 @@ describe('App embed tests', () => {
542
542
  });
543
543
  });
544
544
 
545
+ test('Should add showMaskedFilterChip true to the iframe src', async () => {
546
+ const appEmbed = new AppEmbed(getRootEl(), {
547
+ ...defaultViewConfig,
548
+ showPrimaryNavbar: false,
549
+ showMaskedFilterChip: true,
550
+ } as AppViewConfig);
551
+
552
+ appEmbed.render();
553
+ await executeAfterWait(() => {
554
+ expectUrlMatchesWithParams(
555
+ getIFrameSrc(),
556
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&showMaskedFilterChip=true${defaultParams}${defaultParamsPost}#/home`,
557
+ );
558
+ });
559
+ });
560
+
561
+ test('Should add showMaskedFilterChip false to the iframe src', async () => {
562
+ const appEmbed = new AppEmbed(getRootEl(), {
563
+ ...defaultViewConfig,
564
+ showPrimaryNavbar: false,
565
+ showMaskedFilterChip: false,
566
+ } as AppViewConfig);
567
+
568
+ appEmbed.render();
569
+ await executeAfterWait(() => {
570
+ expectUrlMatchesWithParams(
571
+ getIFrameSrc(),
572
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&showMaskedFilterChip=false${defaultParams}${defaultParamsPost}#/home`,
573
+ );
574
+ });
575
+ });
576
+
577
+ test('Should add default showMaskedFilterChip false when not specified', async () => {
578
+ const appEmbed = new AppEmbed(getRootEl(), {
579
+ ...defaultViewConfig,
580
+ showPrimaryNavbar: false,
581
+ } as AppViewConfig);
582
+
583
+ appEmbed.render();
584
+ await executeAfterWait(() => {
585
+ expectUrlMatchesWithParams(
586
+ getIFrameSrc(),
587
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&showMaskedFilterChip=false${defaultParams}${defaultParamsPost}#/home`,
588
+ );
589
+ });
590
+ });
591
+
592
+ test('Should add isLiveboardMasterpiecesEnabled true to the iframe src', async () => {
593
+ const appEmbed = new AppEmbed(getRootEl(), {
594
+ ...defaultViewConfig,
595
+ showPrimaryNavbar: false,
596
+ isLiveboardMasterpiecesEnabled: true,
597
+ } as AppViewConfig);
598
+
599
+ appEmbed.render();
600
+ await executeAfterWait(() => {
601
+ expectUrlMatchesWithParams(
602
+ getIFrameSrc(),
603
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&isLiveboardMasterpiecesEnabled=true${defaultParams}${defaultParamsPost}#/home`,
604
+ );
605
+ });
606
+ });
607
+
608
+ test('Should add isLiveboardMasterpiecesEnabled false to the iframe src', async () => {
609
+ const appEmbed = new AppEmbed(getRootEl(), {
610
+ ...defaultViewConfig,
611
+ showPrimaryNavbar: false,
612
+ isLiveboardMasterpiecesEnabled: false,
613
+ } as AppViewConfig);
614
+
615
+ appEmbed.render();
616
+ await executeAfterWait(() => {
617
+ expectUrlMatchesWithParams(
618
+ getIFrameSrc(),
619
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&isLiveboardMasterpiecesEnabled=false${defaultParams}${defaultParamsPost}#/home`,
620
+ );
621
+ });
622
+ });
623
+
624
+ test('Should add default isLiveboardMasterpiecesEnabled false when not specified', async () => {
625
+ const appEmbed = new AppEmbed(getRootEl(), {
626
+ ...defaultViewConfig,
627
+ showPrimaryNavbar: false,
628
+ } as AppViewConfig);
629
+
630
+ appEmbed.render();
631
+ await executeAfterWait(() => {
632
+ expectUrlMatchesWithParams(
633
+ getIFrameSrc(),
634
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&isLiveboardMasterpiecesEnabled=false${defaultParams}${defaultParamsPost}#/home`,
635
+ );
636
+ });
637
+ });
638
+
545
639
  test('Should add enableSearchAssist flagto the iframe src', async () => {
546
640
  const appEmbed = new AppEmbed(getRootEl(), {
547
641
  ...defaultViewConfig,
@@ -1036,13 +1130,13 @@ describe('App embed tests', () => {
1036
1130
  let embedHeightCallback: any = () => { };
1037
1131
  const onSpy = jest.spyOn(AppEmbed.prototype, 'on').mockImplementation((event, callback) => {
1038
1132
  if (event === EmbedEvent.RouteChange) {
1039
- callback({ data: { currentPath: '/answers' } }, jest.fn());
1133
+ callback({ type: EmbedEvent.RouteChange, data: { currentPath: '/answers' } } as any, jest.fn());
1040
1134
  }
1041
1135
  if (event === EmbedEvent.EmbedHeight) {
1042
1136
  embedHeightCallback = callback;
1043
1137
  }
1044
1138
  if (event === EmbedEvent.EmbedIframeCenter) {
1045
- callback({}, jest.fn());
1139
+ callback({ type: EmbedEvent.EmbedIframeCenter, data: {} } as any, jest.fn());
1046
1140
  }
1047
1141
  return null;
1048
1142
  });
@@ -1052,6 +1146,7 @@ describe('App embed tests', () => {
1052
1146
  ...defaultViewConfig,
1053
1147
  fullHeight: true,
1054
1148
  lazyLoadingForFullHeight: true,
1149
+ lazyLoadingMargin: '10px',
1055
1150
  } as AppViewConfig);
1056
1151
 
1057
1152
  // Set the iframe before render
@@ -1133,7 +1228,7 @@ describe('App embed tests', () => {
1133
1228
  },
1134
1229
  });
1135
1230
  await appEmbed.render();
1136
- spyOn(logger, 'warn');
1231
+ jest.spyOn(logger, 'warn').mockImplementation(() => {});
1137
1232
  appEmbed.navigateToPage(-1);
1138
1233
  expect(logger.warn).toHaveBeenCalledWith(
1139
1234
  'Path can only by a string when triggered without noReload',
@@ -1141,7 +1236,7 @@ describe('App embed tests', () => {
1141
1236
  });
1142
1237
 
1143
1238
  test('navigateToPage function use before render', async () => {
1144
- spyOn(logger, 'log');
1239
+ jest.spyOn(logger, 'log').mockImplementation(() => {});
1145
1240
  const appEmbed = new AppEmbed(getRootEl(), {
1146
1241
  frameParams: {
1147
1242
  width: '100%',
@@ -1223,6 +1318,7 @@ describe('App embed tests', () => {
1223
1318
  ...defaultViewConfig,
1224
1319
  fullHeight: true,
1225
1320
  lazyLoadingForFullHeight: true,
1321
+ lazyLoadingMargin: '10px',
1226
1322
  } as AppViewConfig);
1227
1323
 
1228
1324
  // Set the iframe before render
@@ -1299,6 +1395,7 @@ describe('App embed tests', () => {
1299
1395
  ...defaultViewConfig,
1300
1396
  fullHeight: true,
1301
1397
  lazyLoadingForFullHeight: true,
1398
+ lazyLoadingMargin: '10px',
1302
1399
  } as AppViewConfig);
1303
1400
 
1304
1401
  const mockTrigger = jest.spyOn(appEmbed, 'trigger');
@@ -1331,6 +1428,7 @@ describe('App embed tests', () => {
1331
1428
  ...defaultViewConfig,
1332
1429
  fullHeight: true,
1333
1430
  lazyLoadingForFullHeight: true,
1431
+ lazyLoadingMargin: '10px',
1334
1432
  } as AppViewConfig);
1335
1433
 
1336
1434
  const mockTrigger = jest.spyOn(appEmbed, 'trigger');
@@ -1355,6 +1453,7 @@ describe('App embed tests', () => {
1355
1453
  ...defaultViewConfig,
1356
1454
  fullHeight: true,
1357
1455
  lazyLoadingForFullHeight: true,
1456
+ lazyLoadingMargin: '10px',
1358
1457
  } as AppViewConfig);
1359
1458
 
1360
1459
  await appEmbed.render();
@@ -1375,6 +1474,7 @@ describe('App embed tests', () => {
1375
1474
  ...defaultViewConfig,
1376
1475
  fullHeight: true,
1377
1476
  lazyLoadingForFullHeight: true,
1477
+ lazyLoadingMargin: '10px',
1378
1478
  } as AppViewConfig);
1379
1479
 
1380
1480
  await appEmbed.render();
@@ -1402,6 +1502,7 @@ describe('App embed tests', () => {
1402
1502
  ...defaultViewConfig,
1403
1503
  fullHeight: true,
1404
1504
  lazyLoadingForFullHeight: true,
1505
+ lazyLoadingMargin: '10px',
1405
1506
  } as AppViewConfig);
1406
1507
 
1407
1508
  // Set the iframe before render
@@ -1527,13 +1628,33 @@ describe('App embed tests', () => {
1527
1628
 
1528
1629
  await appEmbed.render();
1529
1630
  const mockEvent = {
1530
- data: 0, // This will make it use the scrollHeight
1631
+ data: 0, // This will make it use the default height
1531
1632
  type: EmbedEvent.EmbedHeight,
1532
1633
  };
1533
1634
  appEmbed.updateIFrameHeight(mockEvent);
1534
1635
 
1535
- // Should use the scrollHeight
1636
+ // Should use the default height
1536
1637
  expect(mockIFrame.style.height).toBe('500px');
1537
1638
  });
1538
1639
  });
1539
1640
  });
1641
+
1642
+ describe('App Embed Default Height and Minimum Height Handling', () => {
1643
+ test('should set default height to 500 when neither default height nor minimum height is provided', async () => {
1644
+ const appEmbed = new AppEmbed(getRootEl(), {
1645
+ ...defaultViewConfig,
1646
+ fullHeight: true,
1647
+ } as AppViewConfig);
1648
+ await appEmbed.render();
1649
+ expect(appEmbed['defaultHeight']).toBe(500);
1650
+ });
1651
+ test('should set default height to 700 when default height is provided', async () => {
1652
+ const appEmbed = new AppEmbed(getRootEl(), {
1653
+ ...defaultViewConfig,
1654
+ fullHeight: true,
1655
+ minimumHeight: 700,
1656
+ } as AppViewConfig);
1657
+ await appEmbed.render();
1658
+ expect(appEmbed['defaultHeight']).toBe(700);
1659
+ });
1660
+ });
package/src/embed/app.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { logger } from '../utils/logger';
12
- import { calculateVisibleElementData, getQueryParamString, isUndefined } from '../utils';
12
+ import { calculateVisibleElementData, getQueryParamString, isUndefined, isValidCssMargin } from '../utils';
13
13
  import {
14
14
  Param,
15
15
  DOMSelector,
@@ -626,6 +626,23 @@ export interface AppViewConfig extends AllEmbedViewConfig {
626
626
  * @version SDK: 1.45.0 | ThoughtSpot: 26.2.0.cl
627
627
  */
628
628
  updatedSpotterChatPrompt?: boolean;
629
+ /**
630
+ * This is the minimum height (in pixels) for a full-height App.
631
+ * Setting this height helps resolve issues with empty Apps and
632
+ * other screens navigable from an App.
633
+ *
634
+ * @version SDK: 1.44.2 | ThoughtSpot: 26.0.2.cl
635
+ * @default 500
636
+ * @example
637
+ * ```js
638
+ * const embed = new AppEmbed('#embed', {
639
+ * ... // other app view config
640
+ * fullHeight: true,
641
+ * minimumHeight: 600,
642
+ * });
643
+ * ```
644
+ */
645
+ minimumHeight?: number;
629
646
  }
630
647
 
631
648
  /**
@@ -635,7 +652,7 @@ export interface AppViewConfig extends AllEmbedViewConfig {
635
652
  export class AppEmbed extends V1Embed {
636
653
  protected viewConfig: AppViewConfig;
637
654
 
638
- private defaultHeight = '100%';
655
+ private defaultHeight = 500;
639
656
 
640
657
 
641
658
  constructor(domSelector: DOMSelector, viewConfig: AppViewConfig) {
@@ -672,6 +689,8 @@ export class AppEmbed extends V1Embed {
672
689
  hideLiveboardHeader = false,
673
690
  showLiveboardTitle = true,
674
691
  showLiveboardDescription = true,
692
+ showMaskedFilterChip = false,
693
+ isLiveboardMasterpiecesEnabled = false,
675
694
  hideHomepageLeftNav = false,
676
695
  modularHomeExperience = false,
677
696
  isLiveboardHeaderSticky = true,
@@ -697,6 +716,7 @@ export class AppEmbed extends V1Embed {
697
716
  isCentralizedLiveboardFilterUXEnabled = false,
698
717
  isLinkParametersEnabled,
699
718
  updatedSpotterChatPrompt,
719
+ minimumHeight,
700
720
  } = this.viewConfig;
701
721
 
702
722
  let params: any = {};
@@ -707,6 +727,8 @@ export class AppEmbed extends V1Embed {
707
727
  params[Param.HideLiveboardHeader] = hideLiveboardHeader;
708
728
  params[Param.ShowLiveboardTitle] = showLiveboardTitle;
709
729
  params[Param.ShowLiveboardDescription] = !!showLiveboardDescription;
730
+ params[Param.ShowMaskedFilterChip] = showMaskedFilterChip;
731
+ params[Param.IsLiveboardMasterpiecesEnabled] = isLiveboardMasterpiecesEnabled;
710
732
  params[Param.LiveboardHeaderSticky] = isLiveboardHeaderSticky;
711
733
  params[Param.IsFullAppEmbed] = true;
712
734
  params[Param.LiveboardHeaderV2] = isLiveboardCompactHeaderEnabled;
@@ -739,7 +761,9 @@ export class AppEmbed extends V1Embed {
739
761
  params[Param.fullHeight] = true;
740
762
  if (this.viewConfig.lazyLoadingForFullHeight) {
741
763
  params[Param.IsLazyLoadingForEmbedEnabled] = true;
742
- params[Param.RootMarginForLazyLoad] = this.viewConfig.lazyLoadingMargin;
764
+ if (isValidCssMargin(this.viewConfig.lazyLoadingMargin)) {
765
+ params[Param.RootMarginForLazyLoad] = this.viewConfig.lazyLoadingMargin;
766
+ }
743
767
  }
744
768
  }
745
769
 
@@ -799,6 +823,8 @@ export class AppEmbed extends V1Embed {
799
823
  ] = isCentralizedLiveboardFilterUXEnabled;
800
824
  }
801
825
 
826
+ this.defaultHeight = minimumHeight || this.defaultHeight;
827
+
802
828
  params[Param.DataPanelV2Enabled] = dataPanelV2;
803
829
  params[Param.HideHomepageLeftNav] = hideHomepageLeftNav;
804
830
  params[Param.ModularHomeExperienceEnabled] = modularHomeExperience;
@@ -900,7 +926,7 @@ export class AppEmbed extends V1Embed {
900
926
  * @param data The event payload
901
927
  */
902
928
  protected updateIFrameHeight = (data: MessagePayload) => {
903
- this.setIFrameHeight(Math.max(data.data, this.iFrame?.scrollHeight));
929
+ this.setIFrameHeight(Math.max(data.data, this.defaultHeight));
904
930
  this.sendFullHeightLazyLoadData();
905
931
  };
906
932
 
@@ -11,7 +11,7 @@ import * as base from './base';
11
11
  import * as embedConfigInstance from './embedConfig';
12
12
  import * as resetService from '../utils/resetServices';
13
13
  import * as processTrigger from '../utils/processTrigger';
14
- import { reloadIframe } from './base';
14
+ import { createAndSetInitPromise, getInitPromise, getIsInitCalled, reloadIframe } from './base';
15
15
 
16
16
  import {
17
17
  executeAfterWait,
@@ -22,6 +22,7 @@ import {
22
22
  } from '../test/test-utils';
23
23
  import * as tokenizedFetchInstance from '../tokenizedFetch';
24
24
  import { logger } from '../utils/logger';
25
+ import { ERROR_MESSAGE } from '../errors';
25
26
 
26
27
  const thoughtSpotHost = 'tshost';
27
28
  let authEE: EventEmitter;
@@ -32,14 +33,14 @@ describe('Base TS Embed', () => {
32
33
  thoughtSpotHost,
33
34
  authType: index.AuthType.None,
34
35
  }) as EventEmitter;
35
- jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
36
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve(undefined));
36
37
  });
37
38
 
38
39
  beforeEach(() => {
39
40
  document.body.innerHTML = getDocumentBody();
40
41
  });
41
42
 
42
- test('Should show an alert when third party cookie access is blocked', (done) => {
43
+ test('Should show an alert when third party cookie access is blocked', () => {
43
44
  const tsEmbed = new index.SearchEmbed(getRootEl(), {});
44
45
  const iFrame: any = document.createElement('div');
45
46
  iFrame.contentWindow = null;
@@ -59,18 +60,17 @@ describe('Base TS Embed', () => {
59
60
  jest.spyOn(window, 'alert').mockImplementation(() => undefined);
60
61
  authEE.on(auth.AuthStatus.FAILURE, (reason) => {
61
62
  expect(reason).toEqual(auth.AuthFailureType.NO_COOKIE_ACCESS);
62
- expect(window.alert).toBeCalledWith(
63
+ expect(window.alert).toHaveBeenCalledWith(
63
64
  'Third-party cookie access is blocked on this browser. Please allow third-party cookies for this to work properly. \nYou can use `suppressNoCookieAccessAlert` to suppress this message.',
64
65
  );
65
- done();
66
66
  });
67
67
  });
68
68
 
69
- test('Should ignore cookie blocked alert if ignoreNoCookieAccess is true', async (done) => {
69
+ test('Should ignore cookie blocked alert if ignoreNoCookieAccess is true', async () => {
70
70
  jest.spyOn(window, 'fetch').mockResolvedValue({
71
71
  ok: true,
72
72
  json: jest.fn().mockResolvedValue({}),
73
- });
73
+ } as any);
74
74
  const authEE = index.init({
75
75
  thoughtSpotHost,
76
76
  authType: index.AuthType.None,
@@ -96,7 +96,6 @@ describe('Base TS Embed', () => {
96
96
  authEE.on(auth.AuthStatus.FAILURE, (reason) => {
97
97
  expect(reason).toEqual(auth.AuthFailureType.NO_COOKIE_ACCESS);
98
98
  expect(window.alert).not.toHaveBeenCalled();
99
- done();
100
99
  });
101
100
  });
102
101
 
@@ -104,7 +103,7 @@ describe('Base TS Embed', () => {
104
103
  jest.spyOn(window, 'fetch').mockResolvedValue({
105
104
  ok: true,
106
105
  json: jest.fn().mockResolvedValue({}),
107
- });
106
+ } as any);
108
107
  index.init({
109
108
  thoughtSpotHost,
110
109
  authType: index.AuthType.None,
@@ -161,7 +160,7 @@ describe('Base TS Embed', () => {
161
160
  jest.spyOn(tokenizedFetchInstance, 'tokenizedFetch').mockResolvedValueOnce({
162
161
  ok: true,
163
162
  json: jest.fn().mockResolvedValue({}),
164
- });
163
+ } as any);
165
164
  index.init({
166
165
  thoughtSpotHost,
167
166
  authType: index.AuthType.TrustedAuthTokenCookieless,
@@ -229,7 +228,7 @@ describe('Base TS Embed', () => {
229
228
  jest.spyOn(tokenizedFetchInstance, 'tokenizedFetch').mockResolvedValueOnce({
230
229
  ok: true,
231
230
  json: jest.fn().mockResolvedValue({}),
232
- });
231
+ } as any);
233
232
  index.init({
234
233
  thoughtSpotHost,
235
234
  authType: index.AuthType.None,
@@ -388,7 +387,7 @@ describe('Base TS Embed', () => {
388
387
  });
389
388
  });
390
389
 
391
- test('handleAuth notifies for SDK auth failure', (done) => {
390
+ test('handleAuth notifies for SDK auth failure', () => {
392
391
  jest.spyOn(auth, 'authenticate').mockResolvedValue(false);
393
392
  const authEmitter = index.init({
394
393
  thoughtSpotHost,
@@ -398,11 +397,10 @@ describe('Base TS Embed', () => {
398
397
  });
399
398
  authEmitter.on(auth.AuthStatus.FAILURE, (reason) => {
400
399
  expect(reason).toBe(auth.AuthFailureType.SDK);
401
- done();
402
400
  });
403
401
  });
404
402
 
405
- test('handleAuth notifies for SDK auth success', (done) => {
403
+ test('handleAuth notifies for SDK auth success', () => {
406
404
  jest.spyOn(auth, 'authenticate').mockResolvedValue(true);
407
405
  const failureCallback = jest.fn();
408
406
  const authEmitter = index.init({
@@ -414,16 +412,15 @@ describe('Base TS Embed', () => {
414
412
 
415
413
  authEmitter.on(auth.AuthStatus.FAILURE, failureCallback);
416
414
  authEmitter.on(auth.AuthStatus.SDK_SUCCESS, (...args) => {
417
- expect(failureCallback).not.toBeCalled();
415
+ expect(failureCallback).not.toHaveBeenCalled();
418
416
  expect(args.length).toBe(0);
419
- done();
420
417
  });
421
418
  });
422
419
 
423
420
  test('Logout method should disable autoLogin', () => {
424
421
  jest.spyOn(window, 'fetch').mockResolvedValueOnce({
425
422
  type: 'opaque',
426
- });
423
+ } as any);
427
424
  index.init({
428
425
  thoughtSpotHost,
429
426
  authType: index.AuthType.None,
@@ -461,7 +458,7 @@ describe('Base TS Embed', () => {
461
458
  index.init({
462
459
  authType: index.AuthType.None,
463
460
  } as EmbedConfig);
464
- }).toThrowError();
461
+ }).toThrow();
465
462
  });
466
463
 
467
464
  test('config sanity, no username in trusted auth', () => {
@@ -470,7 +467,7 @@ describe('Base TS Embed', () => {
470
467
  authType: index.AuthType.TrustedAuthToken,
471
468
  thoughtSpotHost,
472
469
  } as EmbedConfig);
473
- }).toThrowError();
470
+ }).toThrow();
474
471
  });
475
472
 
476
473
  test('config sanity, no authEndpoint and getAuthToken', () => {
@@ -480,7 +477,7 @@ describe('Base TS Embed', () => {
480
477
  thoughtSpotHost,
481
478
  username: 'test',
482
479
  });
483
- }).toThrowError();
480
+ }).toThrow();
484
481
  });
485
482
  test('config backward compat, should assign inPopup when noRedirect is set', () => {
486
483
  index.init({
@@ -532,6 +529,83 @@ describe('Init tests', () => {
532
529
  thoughtSpotHost,
533
530
  authType: index.AuthType.None,
534
531
  });
535
- expect(resetService.resetAllCachedServices).toBeCalled();
532
+ expect(resetService.resetAllCachedServices).toHaveBeenCalled();
536
533
  });
537
534
  });
535
+
536
+ describe('Init Promise Functions', () => {
537
+ describe('SSR environment handling', () => {
538
+ let originalWindow: typeof globalThis.window;
539
+
540
+ beforeEach(() => {
541
+ originalWindow = global.window;
542
+ });
543
+
544
+ afterEach(() => {
545
+ global.window = originalWindow;
546
+ });
547
+
548
+ test('createAndSetInitPromise should log error in SSR environment', () => {
549
+ delete global.window;
550
+
551
+ createAndSetInitPromise();
552
+
553
+ expect(logger.error).toHaveBeenCalledWith(
554
+ ERROR_MESSAGE.SSR_ENVIRONMENT_ERROR
555
+ );
556
+ });
557
+
558
+ test('init should log error and return null in SSR environment', () => {
559
+ delete global.window;
560
+
561
+ const result = base.init({
562
+ thoughtSpotHost: 'tshost',
563
+ authType: index.AuthType.None,
564
+ });
565
+
566
+ expect(logger.error).toHaveBeenCalledWith(
567
+ ERROR_MESSAGE.SSR_ENVIRONMENT_ERROR
568
+ );
569
+ expect(result).toBeNull();
570
+ });
571
+ });
572
+ beforeEach(() => {
573
+ base.reset();
574
+ (window as any)._tsEmbedSDK = {};
575
+ createAndSetInitPromise();
576
+ });
577
+
578
+ test('getIsInitCalled should return false before init is called', () => {
579
+ expect(getIsInitCalled()).toBe(false);
580
+ });
581
+
582
+ test('getIsInitCalled should return true after init is called', () => {
583
+ base.init({
584
+ thoughtSpotHost: 'tshost',
585
+ authType: index.AuthType.None,
586
+ });
587
+ expect(getIsInitCalled()).toBe(true);
588
+ });
589
+
590
+ test('getInitPromise should return a promise', () => {
591
+ const promise = getInitPromise();
592
+ expect(promise).toBeInstanceOf(Promise);
593
+ });
594
+
595
+ test('getInitPromise should resolve with authEE after init is called', async () => {
596
+ const initPromise = getInitPromise();
597
+ const authEE = base.init({
598
+ thoughtSpotHost: 'tshost',
599
+ authType: index.AuthType.None,
600
+ });
601
+ const resolvedValue = await initPromise;
602
+ expect(resolvedValue).toBe(authEE);
603
+ });
604
+
605
+ test('createAndSetInitPromise should not override existing promise if ignoreIfAlreadyExists', () => {
606
+ const firstPromise = getInitPromise();
607
+ createAndSetInitPromise();
608
+ const secondPromise = getInitPromise();
609
+ expect(firstPromise).toBe(secondPromise);
610
+ });
611
+ });
package/src/embed/base.ts CHANGED
@@ -33,9 +33,10 @@ import {
33
33
  import '../utils/with-resolvers-polyfill';
34
34
  import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
35
35
  import { getEmbedConfig, setEmbedConfig } from './embedConfig';
36
- import { getQueryParamString, getValueFromWindow, storeValueInWindow } from '../utils';
36
+ import { getQueryParamString, getValueFromWindow, isWindowUndefined, storeValueInWindow } from '../utils';
37
37
  import { resetAllCachedServices } from '../utils/resetServices';
38
38
  import { reload } from '../utils/processTrigger';
39
+ import { ERROR_MESSAGE } from '../errors';
39
40
 
40
41
  const CONFIG_DEFAULTS: Partial<EmbedConfig> = {
41
42
  loginFailedMessage: 'Not logged in',
@@ -192,6 +193,7 @@ type InitFlagStore = {
192
193
  const initFlagKey = 'initFlagKey';
193
194
 
194
195
  export const createAndSetInitPromise = (): void => {
196
+ if (isWindowUndefined()) return;
195
197
  const {
196
198
  promise: initPromise,
197
199
  resolve: initPromiseResolve,
@@ -238,7 +240,8 @@ export const getIsInitCalled = (): boolean => !!getValueFromWindow(initFlagKey)?
238
240
  * @version SDK: 1.0.0 | ThoughtSpot ts7.april.cl, 7.2.1
239
241
  * @group Authentication / Init
240
242
  */
241
- export const init = (embedConfig: EmbedConfig): AuthEventEmitter => {
243
+ export const init = (embedConfig: EmbedConfig): AuthEventEmitter | null => {
244
+ if (isWindowUndefined()) return null;
242
245
  sanity(embedConfig);
243
246
  resetAllCachedServices();
244
247
  embedConfig = setEmbedConfig(
@@ -22,8 +22,8 @@ describe('SpotterAgentEmbed', () => {
22
22
  thoughtSpotHost,
23
23
  authType: AuthType.None,
24
24
  });
25
- jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve({}));
26
- spyOn(window, 'alert');
25
+ jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve(undefined));
26
+ jest.spyOn(window, 'alert').mockImplementation(() => undefined);
27
27
  document.body.innerHTML = getDocumentBody();
28
28
  });
29
29
 
@@ -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,
@@ -19,8 +19,8 @@ beforeAll(() => {
19
19
  thoughtSpotHost,
20
20
  authType: AuthType.None,
21
21
  });
22
- jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve({}));
23
- spyOn(window, 'alert');
22
+ jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve(undefined));
23
+ jest.spyOn(window, 'alert');
24
24
  document.body.innerHTML = getDocumentBody();
25
25
  });
26
26
 
@@ -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;