@thoughtspot/visual-embed-sdk 1.32.0-alpha.0 → 1.32.0-alpha.2

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 (271) hide show
  1. package/README.md +20 -0
  2. package/cjs/package.json +6 -4
  3. package/cjs/src/auth.d.ts +14 -16
  4. package/cjs/src/auth.d.ts.map +1 -1
  5. package/cjs/src/auth.js +57 -66
  6. package/cjs/src/auth.js.map +1 -1
  7. package/cjs/src/auth.spec.d.ts +12 -0
  8. package/cjs/src/auth.spec.d.ts.map +1 -1
  9. package/cjs/src/auth.spec.js +89 -67
  10. package/cjs/src/auth.spec.js.map +1 -1
  11. package/cjs/src/authToken.d.ts +1 -1
  12. package/cjs/src/authToken.d.ts.map +1 -1
  13. package/cjs/src/authToken.js +10 -4
  14. package/cjs/src/authToken.js.map +1 -1
  15. package/cjs/src/embed/app.spec.js +4 -2
  16. package/cjs/src/embed/app.spec.js.map +1 -1
  17. package/cjs/src/embed/base.d.ts.map +1 -1
  18. package/cjs/src/embed/base.js +2 -0
  19. package/cjs/src/embed/base.js.map +1 -1
  20. package/cjs/src/embed/base.spec.js +1 -0
  21. package/cjs/src/embed/base.spec.js.map +1 -1
  22. package/cjs/src/embed/embed.spec.js +3 -0
  23. package/cjs/src/embed/embed.spec.js.map +1 -1
  24. package/cjs/src/embed/events.spec.js +3 -0
  25. package/cjs/src/embed/events.spec.js.map +1 -1
  26. package/cjs/src/embed/liveboard.d.ts +24 -0
  27. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  28. package/cjs/src/embed/liveboard.js +30 -0
  29. package/cjs/src/embed/liveboard.js.map +1 -1
  30. package/cjs/src/embed/liveboard.spec.js +33 -0
  31. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  32. package/cjs/src/embed/pinboard.spec.js +3 -0
  33. package/cjs/src/embed/pinboard.spec.js.map +1 -1
  34. package/cjs/src/embed/sage.spec.js +3 -0
  35. package/cjs/src/embed/sage.spec.js.map +1 -1
  36. package/cjs/src/embed/search.spec.js +1 -0
  37. package/cjs/src/embed/search.spec.js.map +1 -1
  38. package/cjs/src/embed/ts-embed-trigger.spec.js +3 -0
  39. package/cjs/src/embed/ts-embed-trigger.spec.js.map +1 -1
  40. package/cjs/src/embed/ts-embed.d.ts +7 -1
  41. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  42. package/cjs/src/embed/ts-embed.js +13 -3
  43. package/cjs/src/embed/ts-embed.js.map +1 -1
  44. package/cjs/src/embed/ts-embed.spec.js +23 -3
  45. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  46. package/cjs/src/index.d.ts +2 -1
  47. package/cjs/src/index.d.ts.map +1 -1
  48. package/cjs/src/index.js +2 -1
  49. package/cjs/src/index.js.map +1 -1
  50. package/cjs/src/mixpanel-service.d.ts +2 -1
  51. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  52. package/cjs/src/mixpanel-service.js +1 -0
  53. package/cjs/src/mixpanel-service.js.map +1 -1
  54. package/cjs/src/mixpanel-service.spec.js +7 -0
  55. package/cjs/src/mixpanel-service.spec.js.map +1 -1
  56. package/cjs/src/react/index.d.ts +1 -1
  57. package/cjs/src/react/index.d.ts.map +1 -1
  58. package/cjs/src/react/index.js +2 -1
  59. package/cjs/src/react/index.js.map +1 -1
  60. package/cjs/src/react/index.spec.js +6 -0
  61. package/cjs/src/react/index.spec.js.map +1 -1
  62. package/cjs/src/tokenizedFetch.d.ts +8 -0
  63. package/cjs/src/tokenizedFetch.d.ts.map +1 -1
  64. package/cjs/src/tokenizedFetch.js +8 -0
  65. package/cjs/src/tokenizedFetch.js.map +1 -1
  66. package/cjs/src/types.d.ts +49 -25
  67. package/cjs/src/types.d.ts.map +1 -1
  68. package/cjs/src/types.js +36 -25
  69. package/cjs/src/types.js.map +1 -1
  70. package/cjs/src/utils/authService/authService.d.ts +1 -0
  71. package/cjs/src/utils/authService/authService.d.ts.map +1 -1
  72. package/cjs/src/utils/authService/authService.js +1 -0
  73. package/cjs/src/utils/authService/authService.js.map +1 -1
  74. package/cjs/src/utils/authService/authService.spec.js +18 -5
  75. package/cjs/src/utils/authService/authService.spec.js.map +1 -1
  76. package/cjs/src/utils/authService/tokenizedAuthService.d.ts +15 -2
  77. package/cjs/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  78. package/cjs/src/utils/authService/tokenizedAuthService.js +39 -9
  79. package/cjs/src/utils/authService/tokenizedAuthService.js.map +1 -1
  80. package/cjs/src/utils/authService/tokenizedAuthService.spec.d.ts +2 -0
  81. package/cjs/src/utils/authService/tokenizedAuthService.spec.d.ts.map +1 -0
  82. package/cjs/src/utils/authService/tokenizedAuthService.spec.js +32 -0
  83. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -0
  84. package/cjs/src/utils/global-styles.d.ts +2 -0
  85. package/cjs/src/utils/global-styles.d.ts.map +1 -0
  86. package/cjs/src/utils/global-styles.js +44 -0
  87. package/cjs/src/utils/global-styles.js.map +1 -0
  88. package/cjs/src/utils/graphql/preview-service.d.ts +3 -0
  89. package/cjs/src/utils/graphql/preview-service.d.ts.map +1 -0
  90. package/cjs/src/utils/graphql/preview-service.js +30 -0
  91. package/cjs/src/utils/graphql/preview-service.js.map +1 -0
  92. package/cjs/src/utils/processData.js +2 -2
  93. package/cjs/src/utils/processData.js.map +1 -1
  94. package/cjs/src/utils/processData.spec.js +3 -2
  95. package/cjs/src/utils/processData.spec.js.map +1 -1
  96. package/cjs/src/utils/sessionInfoService.d.ts +66 -0
  97. package/cjs/src/utils/sessionInfoService.d.ts.map +1 -0
  98. package/cjs/src/utils/sessionInfoService.js +92 -0
  99. package/cjs/src/utils/sessionInfoService.js.map +1 -0
  100. package/dist/src/auth.d.ts +14 -16
  101. package/dist/src/auth.d.ts.map +1 -1
  102. package/dist/src/auth.spec.d.ts +12 -0
  103. package/dist/src/auth.spec.d.ts.map +1 -1
  104. package/dist/src/authToken.d.ts +1 -1
  105. package/dist/src/authToken.d.ts.map +1 -1
  106. package/dist/src/embed/base.d.ts.map +1 -1
  107. package/dist/src/embed/liveboard.d.ts +24 -0
  108. package/dist/src/embed/liveboard.d.ts.map +1 -1
  109. package/dist/src/embed/ts-embed.d.ts +7 -1
  110. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  111. package/dist/src/index.d.ts +2 -1
  112. package/dist/src/index.d.ts.map +1 -1
  113. package/dist/src/mixpanel-service.d.ts +2 -1
  114. package/dist/src/mixpanel-service.d.ts.map +1 -1
  115. package/dist/src/react/index.d.ts +1 -1
  116. package/dist/src/react/index.d.ts.map +1 -1
  117. package/dist/src/tokenizedFetch.d.ts +8 -0
  118. package/dist/src/tokenizedFetch.d.ts.map +1 -1
  119. package/dist/src/types.d.ts +49 -25
  120. package/dist/src/types.d.ts.map +1 -1
  121. package/dist/src/utils/authService/authService.d.ts +1 -0
  122. package/dist/src/utils/authService/authService.d.ts.map +1 -1
  123. package/dist/src/utils/authService/tokenizedAuthService.d.ts +15 -2
  124. package/dist/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  125. package/dist/src/utils/authService/tokenizedAuthService.spec.d.ts +2 -0
  126. package/dist/src/utils/authService/tokenizedAuthService.spec.d.ts.map +1 -0
  127. package/dist/src/utils/global-styles.d.ts +2 -0
  128. package/dist/src/utils/global-styles.d.ts.map +1 -0
  129. package/dist/src/utils/graphql/preview-service.d.ts +3 -0
  130. package/dist/src/utils/graphql/preview-service.d.ts.map +1 -0
  131. package/dist/src/utils/sessionInfoService.d.ts +66 -0
  132. package/dist/src/utils/sessionInfoService.d.ts.map +1 -0
  133. package/dist/tsembed-react.es.js +298 -93
  134. package/dist/tsembed-react.js +298 -92
  135. package/dist/tsembed.es.js +306 -103
  136. package/dist/tsembed.js +306 -103
  137. package/dist/visual-embed-sdk-react-full.d.ts +169 -44
  138. package/dist/visual-embed-sdk-react.d.ts +169 -44
  139. package/dist/visual-embed-sdk.d.ts +169 -44
  140. package/lib/package.json +6 -4
  141. package/lib/src/auth.d.ts +14 -16
  142. package/lib/src/auth.d.ts.map +1 -1
  143. package/lib/src/auth.js +56 -63
  144. package/lib/src/auth.js.map +1 -1
  145. package/lib/src/auth.spec.d.ts +12 -0
  146. package/lib/src/auth.spec.d.ts.map +1 -1
  147. package/lib/src/auth.spec.js +88 -66
  148. package/lib/src/auth.spec.js.map +1 -1
  149. package/lib/src/authToken.d.ts +1 -1
  150. package/lib/src/authToken.d.ts.map +1 -1
  151. package/lib/src/authToken.js +10 -4
  152. package/lib/src/authToken.js.map +1 -1
  153. package/lib/src/embed/app.spec.js +4 -2
  154. package/lib/src/embed/app.spec.js.map +1 -1
  155. package/lib/src/embed/base.d.ts.map +1 -1
  156. package/lib/src/embed/base.js +3 -1
  157. package/lib/src/embed/base.js.map +1 -1
  158. package/lib/src/embed/base.spec.js +1 -0
  159. package/lib/src/embed/base.spec.js.map +1 -1
  160. package/lib/src/embed/embed.spec.js +2 -0
  161. package/lib/src/embed/embed.spec.js.map +1 -1
  162. package/lib/src/embed/events.spec.js +2 -0
  163. package/lib/src/embed/events.spec.js.map +1 -1
  164. package/lib/src/embed/liveboard.d.ts +24 -0
  165. package/lib/src/embed/liveboard.d.ts.map +1 -1
  166. package/lib/src/embed/liveboard.js +30 -0
  167. package/lib/src/embed/liveboard.js.map +1 -1
  168. package/lib/src/embed/liveboard.spec.js +33 -0
  169. package/lib/src/embed/liveboard.spec.js.map +1 -1
  170. package/lib/src/embed/pinboard.spec.js +2 -0
  171. package/lib/src/embed/pinboard.spec.js.map +1 -1
  172. package/lib/src/embed/sage.spec.js +2 -0
  173. package/lib/src/embed/sage.spec.js.map +1 -1
  174. package/lib/src/embed/search.spec.js +1 -0
  175. package/lib/src/embed/search.spec.js.map +1 -1
  176. package/lib/src/embed/ts-embed-trigger.spec.js +2 -0
  177. package/lib/src/embed/ts-embed-trigger.spec.js.map +1 -1
  178. package/lib/src/embed/ts-embed.d.ts +7 -1
  179. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  180. package/lib/src/embed/ts-embed.js +13 -3
  181. package/lib/src/embed/ts-embed.js.map +1 -1
  182. package/lib/src/embed/ts-embed.spec.js +23 -3
  183. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  184. package/lib/src/index.d.ts +2 -1
  185. package/lib/src/index.d.ts.map +1 -1
  186. package/lib/src/index.js +2 -1
  187. package/lib/src/index.js.map +1 -1
  188. package/lib/src/mixpanel-service.d.ts +2 -1
  189. package/lib/src/mixpanel-service.d.ts.map +1 -1
  190. package/lib/src/mixpanel-service.js +1 -0
  191. package/lib/src/mixpanel-service.js.map +1 -1
  192. package/lib/src/mixpanel-service.spec.js +7 -0
  193. package/lib/src/mixpanel-service.spec.js.map +1 -1
  194. package/lib/src/react/index.d.ts +1 -1
  195. package/lib/src/react/index.d.ts.map +1 -1
  196. package/lib/src/react/index.js +1 -1
  197. package/lib/src/react/index.js.map +1 -1
  198. package/lib/src/react/index.spec.js +6 -0
  199. package/lib/src/react/index.spec.js.map +1 -1
  200. package/lib/src/tokenizedFetch.d.ts +8 -0
  201. package/lib/src/tokenizedFetch.d.ts.map +1 -1
  202. package/lib/src/tokenizedFetch.js +8 -0
  203. package/lib/src/tokenizedFetch.js.map +1 -1
  204. package/lib/src/types.d.ts +49 -25
  205. package/lib/src/types.d.ts.map +1 -1
  206. package/lib/src/types.js +36 -25
  207. package/lib/src/types.js.map +1 -1
  208. package/lib/src/utils/authService/authService.d.ts +1 -0
  209. package/lib/src/utils/authService/authService.d.ts.map +1 -1
  210. package/lib/src/utils/authService/authService.js +1 -0
  211. package/lib/src/utils/authService/authService.js.map +1 -1
  212. package/lib/src/utils/authService/authService.spec.js +18 -5
  213. package/lib/src/utils/authService/authService.spec.js.map +1 -1
  214. package/lib/src/utils/authService/tokenizedAuthService.d.ts +15 -2
  215. package/lib/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  216. package/lib/src/utils/authService/tokenizedAuthService.js +37 -8
  217. package/lib/src/utils/authService/tokenizedAuthService.js.map +1 -1
  218. package/lib/src/utils/authService/tokenizedAuthService.spec.d.ts +2 -0
  219. package/lib/src/utils/authService/tokenizedAuthService.spec.d.ts.map +1 -0
  220. package/lib/src/utils/authService/tokenizedAuthService.spec.js +29 -0
  221. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -0
  222. package/lib/src/utils/global-styles.d.ts +2 -0
  223. package/lib/src/utils/global-styles.d.ts.map +1 -0
  224. package/lib/src/utils/global-styles.js +40 -0
  225. package/lib/src/utils/global-styles.js.map +1 -0
  226. package/lib/src/utils/graphql/preview-service.d.ts +3 -0
  227. package/lib/src/utils/graphql/preview-service.d.ts.map +1 -0
  228. package/lib/src/utils/graphql/preview-service.js +26 -0
  229. package/lib/src/utils/graphql/preview-service.js.map +1 -0
  230. package/lib/src/utils/processData.js +3 -3
  231. package/lib/src/utils/processData.js.map +1 -1
  232. package/lib/src/utils/processData.spec.js +3 -2
  233. package/lib/src/utils/processData.spec.js.map +1 -1
  234. package/lib/src/utils/sessionInfoService.d.ts +66 -0
  235. package/lib/src/utils/sessionInfoService.d.ts.map +1 -0
  236. package/lib/src/utils/sessionInfoService.js +85 -0
  237. package/lib/src/utils/sessionInfoService.js.map +1 -0
  238. package/lib/src/visual-embed-sdk.d.ts +174 -45
  239. package/package.json +6 -4
  240. package/src/auth.spec.ts +92 -72
  241. package/src/auth.ts +57 -75
  242. package/src/authToken.ts +9 -4
  243. package/src/embed/app.spec.ts +4 -2
  244. package/src/embed/base.spec.ts +1 -0
  245. package/src/embed/base.ts +3 -0
  246. package/src/embed/embed.spec.ts +2 -0
  247. package/src/embed/events.spec.ts +2 -0
  248. package/src/embed/liveboard.spec.ts +36 -0
  249. package/src/embed/liveboard.ts +61 -1
  250. package/src/embed/pinboard.spec.ts +2 -0
  251. package/src/embed/sage.spec.ts +3 -0
  252. package/src/embed/search.spec.ts +1 -0
  253. package/src/embed/ts-embed-trigger.spec.ts +3 -0
  254. package/src/embed/ts-embed.spec.ts +26 -3
  255. package/src/embed/ts-embed.ts +15 -4
  256. package/src/index.ts +2 -1
  257. package/src/mixpanel-service.spec.ts +12 -3
  258. package/src/mixpanel-service.ts +3 -1
  259. package/src/react/index.spec.tsx +7 -0
  260. package/src/react/index.tsx +1 -0
  261. package/src/tokenizedFetch.ts +8 -0
  262. package/src/types.ts +55 -29
  263. package/src/utils/authService/authService.spec.ts +18 -5
  264. package/src/utils/authService/authService.ts +1 -0
  265. package/src/utils/authService/tokenizedAuthService.spec.ts +36 -0
  266. package/src/utils/authService/tokenizedAuthService.ts +38 -8
  267. package/src/utils/global-styles.ts +40 -0
  268. package/src/utils/graphql/preview-service.ts +31 -0
  269. package/src/utils/processData.spec.ts +3 -2
  270. package/src/utils/processData.ts +3 -3
  271. package/src/utils/sessionInfoService.ts +101 -0
@@ -9,6 +9,7 @@ import {
9
9
  getIFrameEl,
10
10
  getRootEl,
11
11
  } from '../test/test-utils';
12
+ import * as authInstance from '../auth';
12
13
 
13
14
  const thoughtSpotHost = 'tshost';
14
15
  const defaultViewConfig = {
@@ -24,6 +25,7 @@ beforeAll(() => {
24
25
  authType: AuthType.None,
25
26
  });
26
27
  spyOn(window, 'alert');
28
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
27
29
  });
28
30
 
29
31
  describe('test view config', () => {
@@ -20,6 +20,7 @@ import {
20
20
  postMessageToParent,
21
21
  } from '../test/test-utils';
22
22
  import { LiveboardViewConfig } from './liveboard';
23
+ import * as authInstance from '../auth';
23
24
 
24
25
  const thoughtSpotHost = 'tshost';
25
26
  const defaultViewConfig = {
@@ -36,6 +37,7 @@ beforeAll(() => {
36
37
  authType: AuthType.None,
37
38
  });
38
39
  spyOn(window, 'alert');
40
+ jest.spyOn(authInstance, 'postLoginService').mockReturnValue(true);
39
41
  });
40
42
 
41
43
  describe('test communication between host app and ThoughtSpot', () => {
@@ -23,6 +23,8 @@ import {
23
23
  } from '../test/test-utils';
24
24
  import * as tsEmbed from './ts-embed';
25
25
  import * as processTriggerInstance from '../utils/processTrigger';
26
+ import * as auth from '../auth';
27
+ import * as previewService from '../utils/graphql/preview-service';
26
28
 
27
29
  const defaultViewConfig = {
28
30
  frameParams: {
@@ -43,6 +45,7 @@ beforeAll(() => {
43
45
  thoughtSpotHost,
44
46
  authType: AuthType.None,
45
47
  });
48
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
46
49
  });
47
50
 
48
51
  describe('Liveboard/viz embed tests', () => {
@@ -551,6 +554,39 @@ describe('Liveboard/viz embed tests', () => {
551
554
  });
552
555
  });
553
556
 
557
+ test('Show preview loader should not show the loader if not viz embed or showPreviewLoader is false', async () => {
558
+ const libEmbed = new LiveboardEmbed(getRootEl(), {
559
+ liveboardId: '1234',
560
+ });
561
+ await libEmbed.render();
562
+ await executeAfterWait(() => {
563
+ expect(getRootEl().innerHTML).not.toContain('ts-viz-preview-loader');
564
+ });
565
+ });
566
+
567
+ test('Show preview loader should show the loader if viz embed and showPreviewLoader is true', async () => {
568
+ jest.spyOn(previewService, 'getPreview').mockResolvedValue({
569
+ vizContent: '<div id=test>test</div>',
570
+ });
571
+ const libEmbed = new LiveboardEmbed(getRootEl(), {
572
+ liveboardId: '1234',
573
+ vizId: '5678',
574
+ showPreviewLoader: true,
575
+ });
576
+ await libEmbed.render();
577
+ expect(previewService.getPreview).toHaveBeenCalledWith('http://tshost', '5678', '1234');
578
+ await executeAfterWait(() => {
579
+ expect(getRootEl().style.position).toEqual('relative');
580
+ expect(getRootEl().innerHTML).toContain('<div class="ts-viz-preview-loader">');
581
+ expect(getRootEl().innerHTML).toContain('<div id="test">test</div>');
582
+ });
583
+
584
+ libEmbed.test__executeCallbacks(EmbedEvent.Data, {});
585
+ await executeAfterWait(() => {
586
+ expect(getRootEl().innerHTML).not.toContain('ts-viz-preview-loader');
587
+ });
588
+ });
589
+
554
590
  test('it should navigateToLiveboard with liveboard id is not passed', async (done) => {
555
591
  mockMessageChannel();
556
592
  const consoleSpy = jest.spyOn(console, 'error');
@@ -8,6 +8,7 @@
8
8
  * @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
9
9
  */
10
10
 
11
+ import { getPreview } from '../utils/graphql/preview-service';
11
12
  import { ERROR_MESSAGE } from '../errors';
12
13
  import {
13
14
  EmbedEvent,
@@ -21,6 +22,7 @@ import {
21
22
  import { getQueryParamString, isUndefined } from '../utils';
22
23
  import { getAuthPromise } from './base';
23
24
  import { V1Embed } from './ts-embed';
25
+ import { addPreviewStylesIfNotPresent } from '../utils/global-styles';
24
26
 
25
27
  /**
26
28
  * The configuration for the embedded Liveboard or visualization page view.
@@ -259,6 +261,29 @@ export interface LiveboardViewConfig
259
261
  * ```
260
262
  */
261
263
  enable2ColumnLayout?: boolean;
264
+ /**
265
+ * Show a preview image of the visualization before the visualization loads.
266
+ * Only works for visualizations embeds with a viz id.
267
+ *
268
+ * Also, viz snashot should be enabled in the ThoughtSpot instance.
269
+ * Contact ThoughtSpot support to enable this feature.
270
+ *
271
+ * Since, this will show preview images, be careful that it may show
272
+ * undesired data to the user when using row level security.
273
+ *
274
+ * @example
275
+ * ```js
276
+ * const embed = new LiveboardEmbed('#embed-container', {
277
+ * liveboardId: 'liveboard-id',
278
+ * vizId: 'viz-id',
279
+ * showPreviewLoader: true,
280
+ * });
281
+ * embed.render();
282
+ * ```
283
+ *
284
+ * @version SDK: 1.32.0 | ThoughtSpot: 10.0.0.cl
285
+ */
286
+ showPreviewLoader?: boolean;
262
287
  }
263
288
 
264
289
  /**
@@ -431,6 +456,40 @@ export class LiveboardEmbed extends V1Embed {
431
456
  }
432
457
  }
433
458
 
459
+ private async showPreviewLoader() {
460
+ if (!this.viewConfig.showPreviewLoader || !this.viewConfig.vizId) {
461
+ return;
462
+ }
463
+
464
+ try {
465
+ const preview = await getPreview(
466
+ this.thoughtSpotHost,
467
+ this.viewConfig.vizId,
468
+ this.viewConfig.liveboardId,
469
+ );
470
+
471
+ if (!preview.vizContent) {
472
+ return;
473
+ }
474
+ addPreviewStylesIfNotPresent();
475
+
476
+ const div = document.createElement('div');
477
+ div.innerHTML = `
478
+ <div class=ts-viz-preview-loader>
479
+ ${preview.vizContent}
480
+ </div>
481
+ `;
482
+ const previewDiv = div.firstElementChild as HTMLElement;
483
+ this.el.appendChild(previewDiv);
484
+ this.el.style.position = 'relative';
485
+ this.on(EmbedEvent.Data, () => {
486
+ previewDiv.remove();
487
+ });
488
+ } catch (error) {
489
+ console.error('Error fetching preview', error);
490
+ }
491
+ }
492
+
434
493
  protected beforePrerenderVisible(): void {
435
494
  const embedObj = this.insertedDomEl?.[this.embedNodeKey] as LiveboardEmbed;
436
495
 
@@ -480,6 +539,7 @@ export class LiveboardEmbed extends V1Embed {
480
539
 
481
540
  const src = this.getIFrameSrc();
482
541
  await this.renderV1Embed(src);
542
+ this.showPreviewLoader();
483
543
 
484
544
  return this;
485
545
  }
@@ -502,4 +562,4 @@ export class LiveboardEmbed extends V1Embed {
502
562
  /**
503
563
  * @hidden
504
564
  */
505
- export class PinboardEmbed extends LiveboardEmbed {}
565
+ export class PinboardEmbed extends LiveboardEmbed { }
@@ -13,6 +13,7 @@ import {
13
13
  expectUrlMatchesWithParams,
14
14
  } from '../test/test-utils';
15
15
  import { version } from '../../package.json';
16
+ import * as auth from '../auth';
16
17
 
17
18
  const defaultViewConfig = {
18
19
  frameParams: {
@@ -30,6 +31,7 @@ beforeAll(() => {
30
31
  thoughtSpotHost,
31
32
  authType: AuthType.None,
32
33
  });
34
+ jest.spyOn(auth, 'postLoginService').mockReturnValue(true);
33
35
  });
34
36
 
35
37
  describe('Pinboard/viz embed tests', () => {
@@ -9,6 +9,8 @@ import {
9
9
  getRootEl,
10
10
  } from '../test/test-utils';
11
11
 
12
+ import * as authInstance from '../auth';
13
+
12
14
  const defaultConfig: SageViewConfig = {
13
15
  disableWorksheetChange: false,
14
16
  hideWorksheetSelector: false,
@@ -26,6 +28,7 @@ beforeAll(() => {
26
28
  authType: AuthType.None,
27
29
  });
28
30
  spyOn(window, 'alert');
31
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
29
32
  });
30
33
 
31
34
  describe('Sage embed tests', () => {
@@ -36,6 +36,7 @@ beforeAll(() => {
36
36
  thoughtSpotHost,
37
37
  authType: AuthType.None,
38
38
  });
39
+ jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve({}));
39
40
  spyOn(window, 'alert');
40
41
  });
41
42
 
@@ -8,9 +8,12 @@ import {
8
8
  getRootEl,
9
9
  } from '../test/test-utils';
10
10
 
11
+ import * as authInstance from '../auth';
12
+
11
13
  describe('Trigger', () => {
12
14
  beforeEach(() => {
13
15
  document.body.innerHTML = getDocumentBody();
16
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
14
17
  });
15
18
  test('should trigger the event', async (done) => {
16
19
  init({
@@ -84,6 +84,10 @@ describe('Unit test case for ts embed', () => {
84
84
  resetCachedAuthToken();
85
85
  });
86
86
 
87
+ beforeAll(() => {
88
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
89
+ });
90
+
87
91
  describe('AuthExpire embedEvent in cookieless authentication authType', () => {
88
92
  beforeAll(() => {
89
93
  jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
@@ -730,6 +734,7 @@ describe('Unit test case for ts embed', () => {
730
734
  const mockPort: any = {
731
735
  postMessage: jest.fn(),
732
736
  };
737
+ const loggerSpy = jest.spyOn(logger, 'error').mockResolvedValueOnce(true);
733
738
  await executeAfterWait(() => {
734
739
  const iframe = getIFrameEl();
735
740
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
@@ -739,6 +744,7 @@ describe('Unit test case for ts embed', () => {
739
744
  expect(baseInstance.notifyAuthFailure).toBeCalledWith(
740
745
  authInstance.AuthFailureType.EXPIRY,
741
746
  );
747
+ expect(loggerSpy).toHaveBeenCalledTimes(1);
742
748
  });
743
749
 
744
750
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -757,6 +763,7 @@ describe('Unit test case for ts embed', () => {
757
763
  const searchEmbed = new SearchEmbed(getRootEl(), { ...defaultViewConfig, preRenderId: 'test' });
758
764
  jest.spyOn(baseInstance, 'notifyAuthFailure');
759
765
  searchEmbed.preRender();
766
+ const loggerSpy = jest.spyOn(logger, 'error').mockResolvedValueOnce(true);
760
767
  const mockPort: any = {
761
768
  postMessage: jest.fn(),
762
769
  };
@@ -770,6 +777,7 @@ describe('Unit test case for ts embed', () => {
770
777
  expect(baseInstance.notifyAuthFailure).toBeCalledWith(
771
778
  authInstance.AuthFailureType.EXPIRY,
772
779
  );
780
+ expect(loggerSpy).toHaveBeenCalledTimes(1);
773
781
  });
774
782
 
775
783
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -1100,17 +1108,32 @@ describe('Unit test case for ts embed', () => {
1100
1108
  });
1101
1109
 
1102
1110
  describe('V1Embed ', () => {
1111
+ beforeEach(() => {
1112
+ jest.spyOn(config, 'getThoughtSpotHost').mockImplementation(() => 'http://tshost');
1113
+ });
1114
+
1103
1115
  test('when isRendered is true than isError will be true', () => {
1104
- spyOn(logger, 'error');
1116
+ spyOn(logger, 'warn');
1105
1117
  const viEmbedIns = new tsEmbedInstance.V1Embed(getRootEl(), defaultViewConfig);
1106
1118
  expect(viEmbedIns['isError']).toBe(false);
1107
1119
  viEmbedIns.render();
1108
1120
  viEmbedIns.on(EmbedEvent.CustomAction, jest.fn()).render();
1109
- expect(viEmbedIns['isError']).toBe(true);
1110
- expect(logger.error).toHaveBeenCalledWith(
1121
+ expect(logger.warn).toHaveBeenCalledWith(
1111
1122
  'Please register event handlers before calling render',
1112
1123
  );
1113
1124
  });
1125
+
1126
+ test('Generates the correct url for V1Embed when V2 shell is enabled', async () => {
1127
+ const v1Embed = new LiveboardEmbed(getRootEl(), {
1128
+ ...defaultViewConfig,
1129
+ liveboardId: '123',
1130
+ enableV2Shell_experimental: true,
1131
+ });
1132
+ await v1Embed.render();
1133
+ await executeAfterWait(() => {
1134
+ expect(getIFrameSrc()).toContain('/v2/?');
1135
+ });
1136
+ });
1114
1137
  });
1115
1138
 
1116
1139
  describe('Navigate to Page API', () => {
@@ -93,7 +93,7 @@ export class TsEmbed {
93
93
  /**
94
94
  * The DOM node where the ThoughtSpot app is to be embedded.
95
95
  */
96
- protected el: Element;
96
+ protected el: HTMLElement;
97
97
 
98
98
  /**
99
99
  * The key to store the embed instance in the DOM node
@@ -347,6 +347,7 @@ export class TsEmbed {
347
347
  data: { authToken },
348
348
  });
349
349
  } catch (e) {
350
+ logger.error(`Received invalid token. Error : ${e?.message}`);
350
351
  processAuthFailure(e, this.isPreRendered ? this.preRenderWrapper : this.el);
351
352
  }
352
353
  } else if (autoLogin) {
@@ -368,7 +369,7 @@ export class TsEmbed {
368
369
  * @param query
369
370
  */
370
371
  protected getEmbedBasePath(query: string): string {
371
- let queryString = query;
372
+ let queryString = (query.startsWith('?')) ? query : `?${query}`;
372
373
  if (this.shouldEncodeUrlQueryParams) {
373
374
  queryString = `?base64UrlEncodedFlags=${getEncodedQueryParamsString(
374
375
  queryString.substr(1),
@@ -901,7 +902,7 @@ export class TsEmbed {
901
902
  isRegisteredBySDK,
902
903
  });
903
904
  if (this.isRendered) {
904
- this.handleError('Please register event handlers before calling render');
905
+ logger.warn('Please register event handlers before calling render');
905
906
  }
906
907
  const callbacks = this.eventHandlerMap.get(messageType) || [];
907
908
  callbacks.push({ options, callback });
@@ -1257,7 +1258,9 @@ export class V1Embed extends TsEmbed {
1257
1258
  const filterQuery = getFilterQuery(runtimeFilters || []);
1258
1259
  queryString = [filterQuery, queryString].filter(Boolean).join('&');
1259
1260
  }
1260
- return this.getV1EmbedBasePath(queryString);
1261
+ return (this.viewConfig.enableV2Shell_experimental)
1262
+ ? this.getEmbedBasePath(queryString)
1263
+ : this.getV1EmbedBasePath(queryString);
1261
1264
  }
1262
1265
 
1263
1266
  /**
@@ -1285,4 +1288,12 @@ export class V1Embed extends TsEmbed {
1285
1288
  const eventType = this.getCompatibleEventType(messageType);
1286
1289
  return super.on(eventType, callback, options);
1287
1290
  }
1291
+
1292
+ /**
1293
+ * Only for testing purposes.
1294
+ *
1295
+ * @hidden
1296
+ */
1297
+ // eslint-disable-next-line camelcase
1298
+ public test__executeCallbacks = this.executeCallbacks;
1288
1299
  }
package/src/index.ts CHANGED
@@ -20,8 +20,9 @@ import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/live
20
20
  import { SearchEmbed, SearchViewConfig } from './embed/search';
21
21
  import { SearchBarEmbed, SearchBarViewConfig } from './embed/search-bar';
22
22
  import {
23
- AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter, getSessionInfo,
23
+ AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter,
24
24
  } from './auth';
25
+ import { getSessionInfo } from './utils/sessionInfoService';
25
26
  import {
26
27
  AuthType,
27
28
  RuntimeFilter,
@@ -6,6 +6,8 @@ import {
6
6
  testResetMixpanel,
7
7
  } from './mixpanel-service';
8
8
  import { AuthType } from './types';
9
+ import { SessionInfo } from './utils/sessionInfoService';
10
+ import { logger } from './utils/logger';
9
11
 
10
12
  const config = {
11
13
  thoughtSpotHost: 'https://10.87.89.232',
@@ -29,7 +31,7 @@ describe('Unit test for mixpanel', () => {
29
31
  mixpanelToken: 'abc123',
30
32
  userGUID: '12345',
31
33
  isPublicUser: false,
32
- };
34
+ } as SessionInfo;
33
35
  initMixpanel(sessionInfo);
34
36
  expect(mixpanel.init).toHaveBeenCalledWith(sessionInfo.mixpanelToken, undefined, 'tsEmbed');
35
37
  expect(mixpanel.identify).toHaveBeenCalledWith(sessionInfo.userGUID);
@@ -49,7 +51,7 @@ describe('Unit test for mixpanel', () => {
49
51
  clusterId: 'newClusterId',
50
52
  clusterName: 'newClusterName',
51
53
  releaseVersion: 'newReleaseVersion',
52
- };
54
+ } as SessionInfo;
53
55
  initMixpanel(sessionInfo);
54
56
 
55
57
  expect(mixpanel.init).toHaveBeenCalledWith(sessionInfo.mixpanelToken, undefined, 'tsEmbed');
@@ -74,8 +76,15 @@ describe('Unit test for mixpanel', () => {
74
76
  mixpanelToken: 'abc123',
75
77
  userGUID: '12345',
76
78
  isPublicUser: false,
77
- };
79
+ } as SessionInfo;
78
80
  initMixpanel(sessionInfo);
79
81
  expect(mixpanel.track).toHaveBeenCalledTimes(2);
80
82
  });
83
+
84
+ test('init mixpanel with no mixpanel token', () => {
85
+ jest.spyOn(logger, 'error').mockReturnValueOnce(true);
86
+ initMixpanel({ test: 'dummy' } as any);
87
+ expect(logger.error).toHaveBeenCalled();
88
+ expect(mixpanel.register_once).not.toHaveBeenCalled();
89
+ });
81
90
  });
@@ -1,5 +1,6 @@
1
1
  import * as mixpanel from 'mixpanel-browser';
2
2
  import { logger } from './utils/logger';
3
+ import { SessionInfo } from './utils/sessionInfoService';
3
4
 
4
5
  export const EndPoints = {
5
6
  CONFIG: '/callosum/v1/system/config',
@@ -54,8 +55,9 @@ function emptyQueue() {
54
55
  *
55
56
  * @param sessionInfo
56
57
  */
57
- export function initMixpanel(sessionInfo: any): void {
58
+ export function initMixpanel(sessionInfo: SessionInfo): void {
58
59
  if (!sessionInfo || !sessionInfo.mixpanelToken) {
60
+ logger.error('Mixpanel token not found in session info');
59
61
  return;
60
62
  }
61
63
  // On a public cluster the user is anonymous, so don't set the identify to
@@ -24,6 +24,9 @@ import {
24
24
 
25
25
  import { version } from '../../package.json';
26
26
 
27
+ import * as auth from '../auth';
28
+ import * as sessionService from '../utils/sessionInfoService';
29
+
27
30
  const thoughtSpotHost = 'localhost';
28
31
 
29
32
  beforeAll(() => {
@@ -31,6 +34,10 @@ beforeAll(() => {
31
34
  thoughtSpotHost,
32
35
  authType: AuthType.None,
33
36
  });
37
+ jest.spyOn(auth, 'postLoginService').mockReturnValue(true);
38
+ jest.spyOn(sessionService, 'getSessionInfo').mockReturnValue({
39
+ userGUID: 'abcd',
40
+ });
34
41
  spyOn(window, 'alert');
35
42
  });
36
43
 
@@ -370,4 +370,5 @@ export {
370
370
  HomeLeftNavItem,
371
371
  HomepageModule,
372
372
  LogLevel,
373
+ getSessionInfo,
373
374
  } from '../index';
@@ -6,8 +6,16 @@ import { AuthType } from './types';
6
6
  /**
7
7
  * Fetch wrapper that adds the authentication token to the request.
8
8
  * Use this to call the ThoughtSpot APIs when using the visual embed sdk.
9
+ * The interface for this method is the same as Web `Fetch`.
10
+ *
9
11
  * @param input
10
12
  * @param init
13
+ * @example
14
+ * ```js
15
+ * tokenizedFetch("<TS_ORIGIN>/api/rest/2.0/auth/session/user", {
16
+ * // .. fetch options ..
17
+ * });
18
+ *```
11
19
  * @version SDK: 1.28.0
12
20
  * @group Global methods
13
21
  */
package/src/types.ts CHANGED
@@ -998,6 +998,20 @@ export interface ViewConfig {
998
998
  * @version SDK: 1.29.0 | ThoughtSpot: 10.1.0.cl
999
999
  */
1000
1000
  excludeRuntimeParametersfromURL?: boolean;
1001
+ /**
1002
+ * Enable the V2 shell. This can provide performance benefits
1003
+ * due to a lighterweight shell.
1004
+ * @example
1005
+ * ```js
1006
+ * const embed = new LiveboardEmbed('#embed', {
1007
+ * liveboardId: '123',
1008
+ * enableV2Shell_experimental: true
1009
+ * });
1010
+ * ```
1011
+ * @version SDK: 1.31.2 | ThoughtSpot: 10.0.0.cl
1012
+ */
1013
+ // eslint-disable-next-line camelcase
1014
+ enableV2Shell_experimental?: boolean;
1001
1015
  }
1002
1016
 
1003
1017
  /**
@@ -2086,26 +2100,33 @@ export enum EmbedEvent {
2086
2100
  /**
2087
2101
  * Emitted when user wants to intercept the search execution
2088
2102
  *
2089
- * Make isOnBeforeGetVizDataEnabled : true to use this embed
2090
- * event
2103
+ * Set IsOnBeforeGetVizDataInterceptEnabled : true to use
2104
+ * this embed event
2091
2105
  *
2092
2106
  *```js
2093
- * searchEmbed.on(EmbedEvent.OnBeforeGetVizData, (payload, responder) => {
2094
- * responder({
2095
- * data: {
2096
- * execute: true,
2097
- * error: {errorText: "My own customised error"}
2098
- * }})
2099
- * })
2107
+ * searchEmbed.on(EmbedEvent.OnBeforeGetVizDataIntercept,
2108
+ * (payload, responder) => {
2109
+ * responder({
2110
+ * data: {
2111
+ * execute: true,
2112
+ * }})
2113
+ * })
2100
2114
  *```
2101
- * @version SDK : 1.29.0 | Thoughtspot : 10.1.0.cl
2102
- */
2103
- OnBeforeGetVizDataIntercept = 'onBeforeGetVizDataIntercept',
2104
- /**
2105
- * Emitted when runtime parameters changes
2106
- * @version SDK : 1.29.0 | Thoughtspot : 10.1.0.cl
2107
- */
2108
- ParameterChanged = 'ParameterChanged'
2115
+ * @version SDK : 1.29.0 | Thoughtspot : 10.2.0.cl
2116
+ */
2117
+ OnBeforeGetVizDataIntercept = 'onBeforeGetVizDataIntercept',
2118
+ /**
2119
+ * Emitted when parameter changes in an answer
2120
+ * or liveboard
2121
+ *
2122
+ * ```js
2123
+ * liveboardEmbed.on(EmbedEvent.ParameterChanged, (payload) => {
2124
+ * console.log('payload', payload);
2125
+ * })
2126
+ *```
2127
+ * @version SDK : 1.29.0 | Thoughtspot : 10.2.0.cl
2128
+ */
2129
+ ParameterChanged = 'parameterChanged',
2109
2130
  }
2110
2131
 
2111
2132
  /**
@@ -2325,7 +2346,7 @@ export enum HostEvent {
2325
2346
  * sorting, toggling of legends, and data drill down.
2326
2347
  * @example
2327
2348
  * ```js
2328
- * liveboardEmbed.trigger(HostEvent.getexportrequestforcurrentpinboard).then(
2349
+ * liveboardEmbed.trigger(HostEvent.getExportRequestForCurrentPinboard).then(
2329
2350
  * data=>console.log(data))
2330
2351
  * ```
2331
2352
  * @version SDK: 1.13.0 | ThoughtSpot: 8.5.0.cl, 8.8.1.sw
@@ -2935,15 +2956,6 @@ export enum HostEvent {
2935
2956
  * @version SDK: 1.29.0 | Thoughtspot: 10.1.0.cl
2936
2957
  */
2937
2958
  ResetLiveboardPersonalisedView = 'ResetLiveboardPersonalisedView',
2938
- /**
2939
- * Trigger CreateLiveboard for liveboard list page & Pin Modal
2940
- * @example
2941
- * ```js
2942
- * liveboardEmbed.trigger(HostEvent.CreateLiveboard);
2943
- *
2944
- * @version SDK: 1.29.0 | Thoughtspot: 10.1.0.cl
2945
- */
2946
- CreateLiveboard = 'CreateLiveboard',
2947
2959
  /**
2948
2960
  * Triggers Update RuntimeParameters for answers and liveboard
2949
2961
  * @example
@@ -2959,8 +2971,10 @@ export enum HostEvent {
2959
2971
  /**
2960
2972
  * Triggers GetParameters to fetch the runtime parameters
2961
2973
  * ```js
2962
- * liveboardEmbed.trigger(HostEvent.GetParameters);
2963
- *
2974
+ * liveboardEmbed.trigger(HostEvent.GetParameters).then((parameter) => {
2975
+ * console.log('parameters', parameter);
2976
+ * });
2977
+ *```
2964
2978
  * @version SDK: 1.29.0 | Thoughtspot: 10.1.0.cl
2965
2979
  */
2966
2980
  GetParameters = 'GetParameters',
@@ -3937,6 +3951,18 @@ export enum Action {
3937
3951
  */
3938
3952
  TML = 'tml',
3939
3953
 
3954
+ /**
3955
+ * Action Id for CreateLiveboard for liveboard list page & Pin Modal
3956
+ * @example
3957
+ * ```js
3958
+ * hiddenAction: [Action.CreateLiveboard]
3959
+ * disabledActions: [Action.CreateLiveboard]
3960
+ * ```
3961
+ *
3962
+ * @version SDK: 1.32.0 | Thoughtspot: 10.1.0.cl
3963
+ */
3964
+ CreateLiveboard = 'CreateLiveboard',
3965
+
3940
3966
  /**
3941
3967
  * Action ID for to hide Verified Liveboard Banner
3942
3968
  * @example
@@ -26,9 +26,10 @@ describe('Unit test for authService', () => {
26
26
  status: 200,
27
27
  ok: true,
28
28
  }));
29
- const response = await fetchSessionInfoService(authVerificationUrl);
30
- expect(response.status).toBe(200);
29
+ const response = await fetchSessionInfoService(thoughtSpotHost);
30
+ expect(response.success).toBe(true);
31
31
  expect(fetch).toHaveBeenCalledTimes(1);
32
+ expect(fetch).toBeCalledWith(`${thoughtSpotHost}${EndPoints.SESSION_INFO}`, {});
32
33
  });
33
34
 
34
35
  test('fetchAuthTokenService', async () => {
@@ -108,11 +109,15 @@ describe('Unit test for authService', () => {
108
109
  status: 500,
109
110
  ok: false,
110
111
  }));
111
- await fetchSessionInfoService(authVerificationUrl);
112
- expect(logger.error).toHaveBeenCalledWith('Failure', 'error');
112
+ try {
113
+ await fetchSessionInfoService(authVerificationUrl);
114
+ } catch (e) {
115
+ expect(e.message).toContain('Failed to fetch session info');
116
+ }
117
+ expect(logger.error).toHaveBeenCalledWith('Failed to fetch http://localhost:3000/callosum/v1/session/info', 'error');
113
118
  });
114
119
 
115
- test('verifyTokenService', async () => {
120
+ test('verifyTokenService if token api works', async () => {
116
121
  global.fetch = jest.fn(() => Promise.resolve({ success: true, ok: true }));
117
122
  await verifyTokenService(thoughtSpotHost, authToken);
118
123
  expect(fetch).toBeCalledWith(`${thoughtSpotHost}${EndPoints.IS_ACTIVE}`, {
@@ -123,4 +128,12 @@ describe('Unit test for authService', () => {
123
128
  },
124
129
  });
125
130
  });
131
+
132
+ test('verifyTokenService if token api fails', async () => {
133
+ global.fetch = jest.fn(() => Promise.reject(new Error('error')));
134
+ jest.spyOn(logger, 'warn');
135
+ const status = await verifyTokenService(thoughtSpotHost, authToken);
136
+ expect(status).toBe(false);
137
+ expect(logger.warn).toHaveBeenCalledWith('Token Verification Service failed : error');
138
+ });
126
139
  });