@thoughtspot/visual-embed-sdk 1.47.3 → 1.49.0

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 (244) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/auth.d.ts.map +1 -1
  3. package/cjs/src/auth.js +11 -1
  4. package/cjs/src/auth.js.map +1 -1
  5. package/cjs/src/auth.spec.js +38 -0
  6. package/cjs/src/auth.spec.js.map +1 -1
  7. package/cjs/src/authToken.d.ts +2 -0
  8. package/cjs/src/authToken.d.ts.map +1 -1
  9. package/cjs/src/authToken.js +7 -5
  10. package/cjs/src/authToken.js.map +1 -1
  11. package/cjs/src/css-variables.d.ts +140 -0
  12. package/cjs/src/css-variables.d.ts.map +1 -1
  13. package/cjs/src/embed/app.d.ts +63 -2
  14. package/cjs/src/embed/app.d.ts.map +1 -1
  15. package/cjs/src/embed/app.js +57 -6
  16. package/cjs/src/embed/app.js.map +1 -1
  17. package/cjs/src/embed/app.spec.js +200 -1
  18. package/cjs/src/embed/app.spec.js.map +1 -1
  19. package/cjs/src/embed/auto-frame-renderer.js +7 -2
  20. package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
  21. package/cjs/src/embed/auto-frame-renderer.spec.js +385 -6
  22. package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
  23. package/cjs/src/embed/base.d.ts +1 -0
  24. package/cjs/src/embed/base.d.ts.map +1 -1
  25. package/cjs/src/embed/base.js +13 -1
  26. package/cjs/src/embed/base.js.map +1 -1
  27. package/cjs/src/embed/base.spec.js +21 -0
  28. package/cjs/src/embed/base.spec.js.map +1 -1
  29. package/cjs/src/embed/bodyless-conversation.spec.js +86 -0
  30. package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
  31. package/cjs/src/embed/conversation.d.ts +16 -1
  32. package/cjs/src/embed/conversation.d.ts.map +1 -1
  33. package/cjs/src/embed/conversation.js +5 -1
  34. package/cjs/src/embed/conversation.js.map +1 -1
  35. package/cjs/src/embed/conversation.spec.js +26 -0
  36. package/cjs/src/embed/conversation.spec.js.map +1 -1
  37. package/cjs/src/embed/liveboard.d.ts +48 -2
  38. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  39. package/cjs/src/embed/liveboard.js +48 -7
  40. package/cjs/src/embed/liveboard.js.map +1 -1
  41. package/cjs/src/embed/liveboard.spec.js +139 -1
  42. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  43. package/cjs/src/embed/spotter-viz-utils.d.ts +85 -0
  44. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -0
  45. package/cjs/src/embed/spotter-viz-utils.js +17 -0
  46. package/cjs/src/embed/spotter-viz-utils.js.map +1 -0
  47. package/cjs/src/embed/spotter-viz-utils.spec.d.ts +2 -0
  48. package/cjs/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
  49. package/cjs/src/embed/spotter-viz-utils.spec.js +31 -0
  50. package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -0
  51. package/cjs/src/embed/ts-embed.d.ts +58 -38
  52. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  53. package/cjs/src/embed/ts-embed.js +247 -151
  54. package/cjs/src/embed/ts-embed.js.map +1 -1
  55. package/cjs/src/embed/ts-embed.spec.js +397 -122
  56. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  57. package/cjs/src/index.d.ts +2 -1
  58. package/cjs/src/index.d.ts.map +1 -1
  59. package/cjs/src/index.js.map +1 -1
  60. package/cjs/src/react/index.d.ts.map +1 -1
  61. package/cjs/src/react/index.js +3 -0
  62. package/cjs/src/react/index.js.map +1 -1
  63. package/cjs/src/tokenizedFetch.d.ts.map +1 -1
  64. package/cjs/src/tokenizedFetch.js +12 -9
  65. package/cjs/src/tokenizedFetch.js.map +1 -1
  66. package/cjs/src/tokenizedFetch.spec.d.ts +2 -0
  67. package/cjs/src/tokenizedFetch.spec.d.ts.map +1 -0
  68. package/cjs/src/tokenizedFetch.spec.js +68 -0
  69. package/cjs/src/tokenizedFetch.spec.js.map +1 -0
  70. package/cjs/src/types.d.ts +309 -40
  71. package/cjs/src/types.d.ts.map +1 -1
  72. package/cjs/src/types.js +251 -23
  73. package/cjs/src/types.js.map +1 -1
  74. package/cjs/src/utils/authService/tokenizedAuthService.spec.js +6 -7
  75. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  76. package/cjs/src/utils/logger.js +2 -1
  77. package/cjs/src/utils/logger.js.map +1 -1
  78. package/cjs/src/utils/logger.spec.d.ts +1 -0
  79. package/cjs/src/utils/logger.spec.d.ts.map +1 -1
  80. package/cjs/src/utils/logger.spec.js +10 -9
  81. package/cjs/src/utils/logger.spec.js.map +1 -1
  82. package/cjs/src/utils.d.ts +4 -1
  83. package/cjs/src/utils.d.ts.map +1 -1
  84. package/cjs/src/utils.js +107 -10
  85. package/cjs/src/utils.js.map +1 -1
  86. package/cjs/src/utils.spec.js +163 -4
  87. package/cjs/src/utils.spec.js.map +1 -1
  88. package/dist/{index-DZq20cR6.js → index-_UGCSSDR.js} +1 -1
  89. package/dist/src/auth.d.ts.map +1 -1
  90. package/dist/src/authToken.d.ts +2 -0
  91. package/dist/src/authToken.d.ts.map +1 -1
  92. package/dist/src/css-variables.d.ts +140 -0
  93. package/dist/src/css-variables.d.ts.map +1 -1
  94. package/dist/src/embed/app.d.ts +63 -2
  95. package/dist/src/embed/app.d.ts.map +1 -1
  96. package/dist/src/embed/base.d.ts +1 -0
  97. package/dist/src/embed/base.d.ts.map +1 -1
  98. package/dist/src/embed/conversation.d.ts +16 -1
  99. package/dist/src/embed/conversation.d.ts.map +1 -1
  100. package/dist/src/embed/liveboard.d.ts +48 -2
  101. package/dist/src/embed/liveboard.d.ts.map +1 -1
  102. package/dist/src/embed/spotter-viz-utils.d.ts +85 -0
  103. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -0
  104. package/dist/src/embed/spotter-viz-utils.spec.d.ts +2 -0
  105. package/dist/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
  106. package/dist/src/embed/ts-embed.d.ts +58 -38
  107. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  108. package/dist/src/index.d.ts +2 -1
  109. package/dist/src/index.d.ts.map +1 -1
  110. package/dist/src/react/index.d.ts.map +1 -1
  111. package/dist/src/tokenizedFetch.d.ts.map +1 -1
  112. package/dist/src/tokenizedFetch.spec.d.ts +2 -0
  113. package/dist/src/tokenizedFetch.spec.d.ts.map +1 -0
  114. package/dist/src/types.d.ts +309 -40
  115. package/dist/src/types.d.ts.map +1 -1
  116. package/dist/src/utils/logger.spec.d.ts +1 -0
  117. package/dist/src/utils/logger.spec.d.ts.map +1 -1
  118. package/dist/src/utils.d.ts +4 -1
  119. package/dist/src/utils.d.ts.map +1 -1
  120. package/dist/tsembed-react.es.js +3418 -2899
  121. package/dist/tsembed-react.js +3420 -2901
  122. package/dist/tsembed.es.js +3426 -2905
  123. package/dist/tsembed.js +3419 -2898
  124. package/dist/visual-embed-sdk-react-full.d.ts +687 -78
  125. package/dist/visual-embed-sdk-react.d.ts +687 -78
  126. package/dist/visual-embed-sdk.d.ts +702 -80
  127. package/lib/package.json +1 -1
  128. package/lib/src/auth.d.ts.map +1 -1
  129. package/lib/src/auth.js +12 -2
  130. package/lib/src/auth.js.map +1 -1
  131. package/lib/src/auth.spec.js +38 -0
  132. package/lib/src/auth.spec.js.map +1 -1
  133. package/lib/src/authToken.d.ts +2 -0
  134. package/lib/src/authToken.d.ts.map +1 -1
  135. package/lib/src/authToken.js +2 -2
  136. package/lib/src/authToken.js.map +1 -1
  137. package/lib/src/css-variables.d.ts +140 -0
  138. package/lib/src/css-variables.d.ts.map +1 -1
  139. package/lib/src/embed/app.d.ts +63 -2
  140. package/lib/src/embed/app.d.ts.map +1 -1
  141. package/lib/src/embed/app.js +58 -7
  142. package/lib/src/embed/app.js.map +1 -1
  143. package/lib/src/embed/app.spec.js +201 -2
  144. package/lib/src/embed/app.spec.js.map +1 -1
  145. package/lib/src/embed/auto-frame-renderer.js +7 -2
  146. package/lib/src/embed/auto-frame-renderer.js.map +1 -1
  147. package/lib/src/embed/auto-frame-renderer.spec.js +387 -8
  148. package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
  149. package/lib/src/embed/base.d.ts +1 -0
  150. package/lib/src/embed/base.d.ts.map +1 -1
  151. package/lib/src/embed/base.js +11 -0
  152. package/lib/src/embed/base.js.map +1 -1
  153. package/lib/src/embed/base.spec.js +22 -1
  154. package/lib/src/embed/base.spec.js.map +1 -1
  155. package/lib/src/embed/bodyless-conversation.spec.js +86 -0
  156. package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
  157. package/lib/src/embed/conversation.d.ts +16 -1
  158. package/lib/src/embed/conversation.d.ts.map +1 -1
  159. package/lib/src/embed/conversation.js +5 -1
  160. package/lib/src/embed/conversation.js.map +1 -1
  161. package/lib/src/embed/conversation.spec.js +27 -1
  162. package/lib/src/embed/conversation.spec.js.map +1 -1
  163. package/lib/src/embed/liveboard.d.ts +48 -2
  164. package/lib/src/embed/liveboard.d.ts.map +1 -1
  165. package/lib/src/embed/liveboard.js +49 -8
  166. package/lib/src/embed/liveboard.js.map +1 -1
  167. package/lib/src/embed/liveboard.spec.js +139 -1
  168. package/lib/src/embed/liveboard.spec.js.map +1 -1
  169. package/lib/src/embed/spotter-viz-utils.d.ts +85 -0
  170. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -0
  171. package/lib/src/embed/spotter-viz-utils.js +13 -0
  172. package/lib/src/embed/spotter-viz-utils.js.map +1 -0
  173. package/lib/src/embed/spotter-viz-utils.spec.d.ts +2 -0
  174. package/lib/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
  175. package/lib/src/embed/spotter-viz-utils.spec.js +29 -0
  176. package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -0
  177. package/lib/src/embed/ts-embed.d.ts +58 -38
  178. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  179. package/lib/src/embed/ts-embed.js +250 -154
  180. package/lib/src/embed/ts-embed.js.map +1 -1
  181. package/lib/src/embed/ts-embed.spec.js +397 -122
  182. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  183. package/lib/src/index.d.ts +2 -1
  184. package/lib/src/index.d.ts.map +1 -1
  185. package/lib/src/index.js.map +1 -1
  186. package/lib/src/react/index.d.ts.map +1 -1
  187. package/lib/src/react/index.js +3 -0
  188. package/lib/src/react/index.js.map +1 -1
  189. package/lib/src/tokenizedFetch.d.ts.map +1 -1
  190. package/lib/src/tokenizedFetch.js +13 -10
  191. package/lib/src/tokenizedFetch.js.map +1 -1
  192. package/lib/src/tokenizedFetch.spec.d.ts +2 -0
  193. package/lib/src/tokenizedFetch.spec.d.ts.map +1 -0
  194. package/lib/src/tokenizedFetch.spec.js +65 -0
  195. package/lib/src/tokenizedFetch.spec.js.map +1 -0
  196. package/lib/src/types.d.ts +309 -40
  197. package/lib/src/types.d.ts.map +1 -1
  198. package/lib/src/types.js +251 -23
  199. package/lib/src/types.js.map +1 -1
  200. package/lib/src/utils/authService/tokenizedAuthService.spec.js +6 -7
  201. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  202. package/lib/src/utils/logger.js +2 -1
  203. package/lib/src/utils/logger.js.map +1 -1
  204. package/lib/src/utils/logger.spec.d.ts +1 -0
  205. package/lib/src/utils/logger.spec.d.ts.map +1 -1
  206. package/lib/src/utils/logger.spec.js +10 -9
  207. package/lib/src/utils/logger.spec.js.map +1 -1
  208. package/lib/src/utils.d.ts +4 -1
  209. package/lib/src/utils.d.ts.map +1 -1
  210. package/lib/src/utils.js +103 -9
  211. package/lib/src/utils.js.map +1 -1
  212. package/lib/src/utils.spec.js +164 -5
  213. package/lib/src/utils.spec.js.map +1 -1
  214. package/lib/src/visual-embed-sdk.d.ts +702 -80
  215. package/package.json +1 -1
  216. package/src/auth.spec.ts +55 -1
  217. package/src/auth.ts +11 -2
  218. package/src/authToken.ts +2 -2
  219. package/src/css-variables.ts +175 -1
  220. package/src/embed/app.spec.ts +260 -3
  221. package/src/embed/app.ts +127 -7
  222. package/src/embed/auto-frame-renderer.spec.ts +457 -58
  223. package/src/embed/auto-frame-renderer.ts +7 -2
  224. package/src/embed/base.spec.ts +25 -1
  225. package/src/embed/base.ts +19 -5
  226. package/src/embed/bodyless-conversation.spec.ts +93 -0
  227. package/src/embed/conversation.spec.ts +34 -0
  228. package/src/embed/conversation.ts +22 -1
  229. package/src/embed/liveboard.spec.ts +163 -1
  230. package/src/embed/liveboard.ts +106 -10
  231. package/src/embed/spotter-viz-utils.spec.ts +30 -0
  232. package/src/embed/spotter-viz-utils.ts +94 -0
  233. package/src/embed/ts-embed.spec.ts +564 -231
  234. package/src/embed/ts-embed.ts +384 -258
  235. package/src/index.ts +3 -0
  236. package/src/react/index.tsx +3 -0
  237. package/src/tokenizedFetch.spec.ts +81 -0
  238. package/src/tokenizedFetch.ts +14 -11
  239. package/src/types.ts +326 -36
  240. package/src/utils/authService/tokenizedAuthService.spec.ts +6 -6
  241. package/src/utils/logger.spec.ts +11 -9
  242. package/src/utils/logger.ts +2 -2
  243. package/src/utils.spec.ts +200 -4
  244. package/src/utils.ts +128 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thoughtspot/visual-embed-sdk",
3
- "version": "1.47.3",
3
+ "version": "1.49.0",
4
4
  "description": "ThoughtSpot Embed SDK",
5
5
  "module": "lib/src/index.js",
6
6
  "main": "dist/tsembed.js",
package/src/auth.spec.ts CHANGED
@@ -450,7 +450,7 @@ describe('Unit test for auth', () => {
450
450
 
451
451
  it('should support emitting SAML_POPUP_CLOSED_NO_AUTH event', () => {
452
452
  const emitSpy = jest.fn();
453
- const mockEventEmitter = {
453
+ const mockEventEmitter = {
454
454
  emit: emitSpy,
455
455
  once: jest.fn()
456
456
  };
@@ -460,6 +460,60 @@ describe('Unit test for auth', () => {
460
460
  authInstance.setAuthEE(null);
461
461
  });
462
462
 
463
+ it('should set loggedInStatus from cachedAuthToken without calling isLoggedIn again after popup flow', async () => {
464
+ Object.defineProperty(window, 'location', { value: { href: '', hash: '' } });
465
+ checkReleaseVersionInBetaInstance.storeValueInWindow('cachedAuthToken', 'test-cached-token');
466
+ (authInstance as any).samlCompletionPromise = Promise.resolve();
467
+ global.window.open = jest.fn();
468
+
469
+ jest.spyOn(tokenAuthService, 'isActiveService')
470
+ .mockReturnValueOnce(Promise.resolve(false));
471
+
472
+ await authInstance.doSamlAuth({ ...embedConfig.doSamlAuthNoRedirect });
473
+
474
+ expect(authInstance.loggedInStatus).toBe(true);
475
+ expect(tokenAuthService.isActiveService).toHaveBeenCalledTimes(1);
476
+ });
477
+
478
+ it('should store decoded accessToken in window when SAMLComplete event includes accessToken', async () => {
479
+ Object.defineProperty(window, 'location', { value: { href: '', hash: '' } });
480
+ global.window.open = jest.fn().mockReturnValue({ closed: false, focus: jest.fn(), close: jest.fn() });
481
+
482
+ (authInstance as any).samlCompletionPromise = null;
483
+
484
+ let capturedMessageHandler: ((e: any) => void) | null = null;
485
+ jest.spyOn(window, 'addEventListener').mockImplementation((type: any, handler: any) => {
486
+ if (type === 'message') {
487
+ capturedMessageHandler = handler;
488
+ }
489
+ });
490
+
491
+ jest.spyOn(tokenAuthService, 'isActiveService')
492
+ .mockReturnValueOnce(Promise.resolve(false));
493
+
494
+ const authPromise = authInstance.doSamlAuth({ ...embedConfig.doSamlAuthNoRedirect });
495
+
496
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
497
+
498
+ expect(capturedMessageHandler).not.toBeNull();
499
+
500
+ const accessToken = 'my-access-token';
501
+ capturedMessageHandler!({
502
+ data: {
503
+ type: EmbedEvent.SAMLComplete,
504
+ accessToken: encodeURIComponent(accessToken),
505
+ },
506
+ source: { close: jest.fn() },
507
+ });
508
+
509
+ await authPromise;
510
+
511
+ expect(
512
+ checkReleaseVersionInBetaInstance.getValueFromWindow('cachedAuthToken'),
513
+ ).toBe(accessToken);
514
+ expect(authInstance.loggedInStatus).toBe(true);
515
+ });
516
+
463
517
  });
464
518
 
465
519
  describe('doOIDCAuth', () => {
package/src/auth.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import EventEmitter from 'eventemitter3';
2
- import { getAuthenticationToken } from './authToken';
2
+ import { getAuthenticationToken, storeAuthTokenInCache, getCacheAuthToken } from './authToken';
3
3
  import { getEmbedConfig } from './embed/embedConfig';
4
4
  import { initMixpanel } from './mixpanel-service';
5
5
  import {
@@ -462,6 +462,10 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
462
462
  samlCompletionPromise = samlCompletionPromise || new Promise<void>((resolve, reject) => {
463
463
  window.addEventListener('message', (e) => {
464
464
  if (e.data.type === EmbedEvent.SAMLComplete) {
465
+ if (e.data.accessToken) {
466
+ const decodedToken = decodeURIComponent(e.data.accessToken);
467
+ storeAuthTokenInCache(decodedToken);
468
+ }
465
469
  samlCompletionResolved = true;
466
470
  if (popupClosedCheck) {
467
471
  clearInterval(popupClosedCheck);
@@ -503,7 +507,12 @@ const doSSOAuth = async (embedConfig: EmbedConfig, ssoEndPoint: string): Promise
503
507
  const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
504
508
  if (embedConfig.inPopup) {
505
509
  await samlPopupFlow(ssoURL, embedConfig.authTriggerContainer, embedConfig.authTriggerText);
506
- loggedInStatus = await isLoggedIn(thoughtSpotHost);
510
+ const cachedToken = getCacheAuthToken();
511
+ if (cachedToken) {
512
+ loggedInStatus = true;
513
+ } else {
514
+ loggedInStatus = await isLoggedIn(thoughtSpotHost);
515
+ }
507
516
  return;
508
517
  }
509
518
 
package/src/authToken.ts CHANGED
@@ -6,8 +6,8 @@ import { logger } from './utils/logger';
6
6
 
7
7
  const cacheAuthTokenKey = 'cachedAuthToken';
8
8
 
9
- const getCacheAuthToken = (): string | null => getValueFromWindow(cacheAuthTokenKey);
10
- const storeAuthTokenInCache = (token: string): void => {
9
+ export const getCacheAuthToken = (): string | null => getValueFromWindow(cacheAuthTokenKey);
10
+ export const storeAuthTokenInCache = (token: string): void => {
11
11
  storeValueInWindow(cacheAuthTokenKey, token);
12
12
  };
13
13
 
@@ -991,4 +991,178 @@ export interface CustomCssVariables {
991
991
  * Background color of the color palette in the Liveboard styling panel.
992
992
  */
993
993
  '--ts-var-liveboard-styling-color-palette-background'?: string;
994
- }
994
+
995
+ /**
996
+ * Main panel background of the SpotterViz.
997
+ */
998
+ '--ts-var-spotterviz-panel-background'?: string;
999
+
1000
+ /**
1001
+ * Background color of the chat input field in SpotterViz.
1002
+ */
1003
+ '--ts-var-spotterviz-input-background'?: string;
1004
+
1005
+ /**
1006
+ * Placeholder text color of the chat input field in SpotterViz.
1007
+ */
1008
+ '--ts-var-spotterviz-input-placeholder-color'?: string;
1009
+
1010
+ /**
1011
+ * CTA color of the chat input field in SpotterViz.
1012
+ */
1013
+ '--ts-var-spotterviz-input-cta-color'?: string;
1014
+
1015
+ /**
1016
+ * CTA hover color of the chat input field in SpotterViz.
1017
+ */
1018
+ '--ts-var-spotterviz-input-cta-hover-color'?: string;
1019
+
1020
+ /**
1021
+ * Text color for the SpotterViz label in the empty state, displayed below
1022
+ * the SpotterViz icon.
1023
+ */
1024
+ '--ts-var-spotterviz-emptystate-spotterviz-color'?: string;
1025
+
1026
+ /**
1027
+ * Background color of the starter prompt cards in SpotterViz.
1028
+ */
1029
+ '--ts-var-spotterviz-prompt-card-background'?: string;
1030
+
1031
+ /**
1032
+ * Background hover color of the starter prompt cards in SpotterViz.
1033
+ */
1034
+ '--ts-var-spotterviz-prompt-card-hover-background'?: string;
1035
+
1036
+ /**
1037
+ * Primary text color in SpotterViz, also used for tool response text,
1038
+ * upvote/downvote buttons, and other primary content.
1039
+ */
1040
+ '--ts-var-spotterviz-text-primary'?: string;
1041
+
1042
+ /**
1043
+ * Secondary text color in SpotterViz.
1044
+ */
1045
+ '--ts-var-spotterviz-text-secondary'?: string;
1046
+
1047
+ /**
1048
+ * Background color of the user chat message bubble in SpotterViz.
1049
+ */
1050
+ '--ts-var-spotterviz-message-background'?: string;
1051
+
1052
+ /**
1053
+ * Hover color for the user chat message expand button in SpotterViz.
1054
+ */
1055
+ '--ts-var-spotterviz-usermessage-icon-hover'?: string;
1056
+
1057
+ /**
1058
+ * Background color of the user chat message expand button in SpotterViz.
1059
+ */
1060
+ '--ts-var-spotterviz-usermessage-icon-background'?: string;
1061
+
1062
+ /**
1063
+ * Color of the thinking step header when in progress in SpotterViz.
1064
+ */
1065
+ '--ts-var-spotterviz-thinking-inprogress-header-color'?: string;
1066
+
1067
+ /**
1068
+ * Color of the thinking step header when completed in SpotterViz.
1069
+ */
1070
+ '--ts-var-spotterviz-thinking-completed-header-color'?: string;
1071
+
1072
+ /**
1073
+ * Color of the final completion indicator icon shown when all work is done.
1074
+ * The last green dot which is shown when work is done.
1075
+ */
1076
+ '--ts-var-spotterviz-thinking-work-done-icon-color'?: string;
1077
+
1078
+ /**
1079
+ * Hover background color for the working/work done CTA in SpotterViz.
1080
+ */
1081
+ '--ts-var-spotterviz-thinking-cta-hover-background'?: string;
1082
+
1083
+ /**
1084
+ * Background color of tool call panels in SpotterViz.
1085
+ */
1086
+ '--ts-var-spotterviz-tool-call-background'?: string;
1087
+
1088
+ /**
1089
+ * Color of tool titles and icons in SpotterViz.
1090
+ */
1091
+ '--ts-var-spotterviz-tool-title-color'?: string;
1092
+
1093
+ /**
1094
+ * Border color of tool call panels in SpotterViz.
1095
+ */
1096
+ '--ts-var-spotterviz-tool-border-color'?: string;
1097
+
1098
+ /**
1099
+ * Background color of the JSON input panel inside a tool call in SpotterViz.
1100
+ */
1101
+ '--ts-var-spotterviz-tool-json-input-background'?: string;
1102
+
1103
+ /**
1104
+ * Background color of the upvote/downvote feedback buttons in SpotterViz.
1105
+ */
1106
+ '--ts-var-spotterviz-tool-feedback-button-background'?: string;
1107
+
1108
+ /**
1109
+ * Hover background color of the upvote/downvote feedback buttons in SpotterViz.
1110
+ */
1111
+ '--ts-var-spotterviz-tool-feedback-button-hover'?: string;
1112
+
1113
+ /**
1114
+ * Text color of the JSON input panel inside a tool call in SpotterViz.
1115
+ */
1116
+ '--ts-var-spotterviz-tool-json-input-color'?: string;
1117
+
1118
+ /**
1119
+ * Background color of the last checkpoint section in SpotterViz.
1120
+ */
1121
+ '--ts-var-spotterviz-last-checkpoint-background'?: string;
1122
+
1123
+ /**
1124
+ * Border color of the last checkpoint section in SpotterViz.
1125
+ */
1126
+ '--ts-var-spotterviz-last-checkpoint-border'?: string;
1127
+
1128
+ /**
1129
+ * Border color of the Liveboard edit header toolbar.
1130
+ */
1131
+ '--ts-var-liveboard-edit-toolbar-border'?: string;
1132
+
1133
+ /**
1134
+ * Background color of the selected section in the Liveboard edit header toolbar.
1135
+ */
1136
+ '--ts-var-liveboard-edit-toolbar-selected-background'?: string;
1137
+
1138
+ /**
1139
+ * Text color of the selected section in the Liveboard edit header toolbar.
1140
+ */
1141
+ '--ts-var-liveboard-edit-toolbar-selected-text-color'?: string;
1142
+
1143
+ /**
1144
+ * Text color of unselected items in the Liveboard edit header toolbar.
1145
+ */
1146
+ '--ts-var-liveboard-edit-toolbar-text'?: string;
1147
+
1148
+ /**
1149
+ * Hover background color of unselected items in the Liveboard edit header toolbar.
1150
+ */
1151
+ '--ts-var-liveboard-edit-toolbar-hover-background'?: string;
1152
+
1153
+ /**
1154
+ * Hover text color of unselected items in the Liveboard edit header toolbar.
1155
+ */
1156
+ '--ts-var-liveboard-edit-toolbar-hover-text-color'?: string;
1157
+
1158
+ /**
1159
+ * Text color of the SpotterViz footer.
1160
+ */
1161
+ '--ts-var-spotterviz-footer-text-color'?: string;
1162
+
1163
+ /**
1164
+ * Shared border color used throughout SpotterViz: input box, user message,
1165
+ * header underline, left panel border, thinking step connector and dots.
1166
+ */
1167
+ '--ts-var-spotterviz-border-color'?: string;
1168
+ }
@@ -23,6 +23,7 @@ import {
23
23
  expectUrlMatchesWithParams,
24
24
  postMessageToParent,
25
25
  testVisualOverridesInEmbed,
26
+ expectUrlToHaveParamsWithValues,
26
27
  } from '../test/test-utils';
27
28
  import { version } from '../../package.json';
28
29
  import * as config from '../config';
@@ -480,6 +481,19 @@ describe('App embed tests', () => {
480
481
  });
481
482
  });
482
483
 
484
+ test('should disable isWYSIWYGLiveboardPDFEnabled by default in url', async () => {
485
+ const appEmbed = new AppEmbed(getRootEl(), {
486
+ ...defaultViewConfig,
487
+ } as AppViewConfig);
488
+ appEmbed.render();
489
+ await executeAfterWait(() => {
490
+ expectUrlMatchesWithParams(
491
+ getIFrameSrc(),
492
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&isWYSIWYGLiveboardPDFEnabled=false${defaultParamsPost}#/home`,
493
+ );
494
+ });
495
+ });
496
+
483
497
  test('should set isLinkParametersEnabled to true in url', async () => {
484
498
  const appEmbed = new AppEmbed(getRootEl(), {
485
499
  ...defaultViewConfig,
@@ -508,6 +522,18 @@ describe('App embed tests', () => {
508
522
  });
509
523
  });
510
524
 
525
+ test('Should add homepageVersion=v4 when homePage is Focused to the iframe src', async () => {
526
+ await testUrlParams(
527
+ {
528
+ ...defaultViewConfig,
529
+ discoveryExperience: {
530
+ homePage: HomePage.Focused,
531
+ },
532
+ } as AppViewConfig,
533
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&navigationVersion=v2&homepageVersion=v4${defaultParams}${defaultParamsPost}#/home`,
534
+ );
535
+ });
536
+
511
537
  test('should set isLiveboardXLSXCSVDownloadEnabled to true in url', async () => {
512
538
  const appEmbed = new AppEmbed(getRootEl(), {
513
539
  ...defaultViewConfig,
@@ -566,6 +592,141 @@ describe('App embed tests', () => {
566
592
  });
567
593
  });
568
594
 
595
+ test('should include spotterVizConfig in APP_INIT embedParams when spotterViz is provided', async () => {
596
+ const spotterViz = {
597
+ brandName: 'MyBrand',
598
+ brandHeadline: "Hi, there! I'm",
599
+ description: 'Ask questions about your data',
600
+ inputChatPlaceholder: 'Ask a question...',
601
+ hideStarterPrompts: false,
602
+ customStarterPrompts: [
603
+ {
604
+ id: '001',
605
+ displayText: 'Show revenue by region',
606
+ fullPrompt: 'Show revenue by region',
607
+ },
608
+ { id: '002', displayText: 'Top customers', fullPrompt: 'Top customers by sales' },
609
+ ],
610
+ };
611
+ const appEmbed = new AppEmbed(getRootEl(), {
612
+ ...defaultViewConfig,
613
+ spotterViz,
614
+ } as AppViewConfig);
615
+
616
+ mockMessageChannel();
617
+ appEmbed.render();
618
+
619
+ const mockPort: any = { postMessage: jest.fn() };
620
+ await executeAfterWait(() => {
621
+ postMessageToParent(
622
+ getIFrameEl().contentWindow,
623
+ { type: EmbedEvent.APP_INIT, data: {} },
624
+ mockPort,
625
+ );
626
+ });
627
+ await executeAfterWait(() => {
628
+ expect(mockPort.postMessage).toHaveBeenCalledWith({
629
+ type: EmbedEvent.APP_INIT,
630
+ data: expect.objectContaining({
631
+ embedParams: expect.objectContaining({
632
+ spotterVizConfig: spotterViz,
633
+ }),
634
+ }),
635
+ });
636
+ });
637
+ });
638
+
639
+ test('should pass brandHeadline through spotterVizConfig in APP_INIT', async () => {
640
+ const spotterViz = { brandName: 'MyBrand', brandHeadline: "Hi, there! I'm" };
641
+ const appEmbed = new AppEmbed(getRootEl(), {
642
+ ...defaultViewConfig,
643
+ spotterViz,
644
+ } as AppViewConfig);
645
+
646
+ mockMessageChannel();
647
+ appEmbed.render();
648
+
649
+ const mockPort: any = { postMessage: jest.fn() };
650
+ await executeAfterWait(() => {
651
+ postMessageToParent(
652
+ getIFrameEl().contentWindow,
653
+ { type: EmbedEvent.APP_INIT, data: {} },
654
+ mockPort,
655
+ );
656
+ });
657
+ await executeAfterWait(() => {
658
+ expect(mockPort.postMessage).toHaveBeenCalledWith({
659
+ type: EmbedEvent.APP_INIT,
660
+ data: expect.objectContaining({
661
+ embedParams: expect.objectContaining({
662
+ spotterVizConfig: expect.objectContaining({
663
+ brandHeadline: "Hi, there! I'm",
664
+ }),
665
+ }),
666
+ }),
667
+ });
668
+ });
669
+ });
670
+
671
+ test('should not include spotterVizConfig in APP_INIT when spotterViz is not provided', async () => {
672
+ const appEmbed = new AppEmbed(getRootEl(), {
673
+ ...defaultViewConfig,
674
+ } as AppViewConfig);
675
+
676
+ mockMessageChannel();
677
+ appEmbed.render();
678
+
679
+ const mockPort: any = { postMessage: jest.fn() };
680
+ await executeAfterWait(() => {
681
+ postMessageToParent(
682
+ getIFrameEl().contentWindow,
683
+ { type: EmbedEvent.APP_INIT, data: {} },
684
+ mockPort,
685
+ );
686
+ });
687
+ await executeAfterWait(() => {
688
+ const callArgs = mockPort.postMessage.mock.calls[0][0];
689
+ expect(callArgs.type).toBe(EmbedEvent.APP_INIT);
690
+ if (callArgs.data.embedParams) {
691
+ expect(callArgs.data.embedParams.spotterVizConfig).toBeUndefined();
692
+ }
693
+ });
694
+ });
695
+
696
+ test('should include spotterVizConfig alongside spotterSidebarConfig in APP_INIT', async () => {
697
+ const spotterViz = { brandName: 'MyBrand' };
698
+ const appEmbed = new AppEmbed(getRootEl(), {
699
+ ...defaultViewConfig,
700
+ spotterViz,
701
+ spotterSidebarConfig: { enablePastConversationsSidebar: true },
702
+ } as AppViewConfig);
703
+
704
+ mockMessageChannel();
705
+ appEmbed.render();
706
+
707
+ const mockPort: any = { postMessage: jest.fn() };
708
+ await executeAfterWait(() => {
709
+ postMessageToParent(
710
+ getIFrameEl().contentWindow,
711
+ { type: EmbedEvent.APP_INIT, data: {} },
712
+ mockPort,
713
+ );
714
+ });
715
+ await executeAfterWait(() => {
716
+ expect(mockPort.postMessage).toHaveBeenCalledWith({
717
+ type: EmbedEvent.APP_INIT,
718
+ data: expect.objectContaining({
719
+ embedParams: expect.objectContaining({
720
+ spotterVizConfig: spotterViz,
721
+ spotterSidebarConfig: expect.objectContaining({
722
+ enablePastConversationsSidebar: true,
723
+ }),
724
+ }),
725
+ }),
726
+ });
727
+ });
728
+ });
729
+
569
730
  test('should set toolResponseCardBrandingLabel in url via spotterChatConfig', async () => {
570
731
  const appEmbed = new AppEmbed(getRootEl(), {
571
732
  ...defaultViewConfig,
@@ -582,6 +743,33 @@ describe('App embed tests', () => {
582
743
  });
583
744
  });
584
745
 
746
+ test('should set spotterFileUploadEnabled to true in url', async () => {
747
+ const appEmbed = new AppEmbed(getRootEl(), {
748
+ ...defaultViewConfig,
749
+ spotterChatConfig: { spotterFileUploadEnabled: true },
750
+ } as AppViewConfig);
751
+ appEmbed.render();
752
+ await executeAfterWait(() => {
753
+ expectUrlMatchesWithParams(
754
+ getIFrameSrc(),
755
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&spotterFileUploadEnabled=true${defaultParamsPost}#/home`,
756
+ );
757
+ });
758
+ });
759
+
760
+ test('should set spotterFileUploadFileTypes in url', async () => {
761
+ const appEmbed = new AppEmbed(getRootEl(), {
762
+ ...defaultViewConfig,
763
+ spotterChatConfig: { spotterFileUploadFileTypes: { types: ['image/png', 'application/pdf'] } },
764
+ } as AppViewConfig);
765
+ appEmbed.render();
766
+ await executeAfterWait(() => {
767
+ expectUrlToHaveParamsWithValues(getIFrameSrc(), {
768
+ spotterFileUploadFileTypes: JSON.stringify({ types: ['image/png', 'application/pdf'] }),
769
+ });
770
+ });
771
+ });
772
+
585
773
  test('should set isLiveboardXLSXCSVDownloadEnabled to false in url', async () => {
586
774
  const appEmbed = new AppEmbed(getRootEl(), {
587
775
  ...defaultViewConfig,
@@ -974,6 +1162,47 @@ describe('App embed tests', () => {
974
1162
  });
975
1163
  });
976
1164
 
1165
+ test('should set newConnectionsExperience to true in url', async () => {
1166
+ const appEmbed = new AppEmbed(getRootEl(), {
1167
+ ...defaultViewConfig,
1168
+ newConnectionsExperience: true,
1169
+ } as AppViewConfig);
1170
+ appEmbed.render();
1171
+ await executeAfterWait(() => {
1172
+ expectUrlMatchesWithParams(
1173
+ getIFrameSrc(),
1174
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&newConnectionsExperience=true${defaultParams}${defaultParamsPost}#/home`,
1175
+ );
1176
+ });
1177
+ });
1178
+
1179
+ test('should set newConnectionsExperience to false in url', async () => {
1180
+ const appEmbed = new AppEmbed(getRootEl(), {
1181
+ ...defaultViewConfig,
1182
+ newConnectionsExperience: false,
1183
+ } as AppViewConfig);
1184
+ appEmbed.render();
1185
+ await executeAfterWait(() => {
1186
+ expectUrlMatchesWithParams(
1187
+ getIFrameSrc(),
1188
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&newConnectionsExperience=false${defaultParams}${defaultParamsPost}#/home`,
1189
+ );
1190
+ });
1191
+ });
1192
+
1193
+ test('should disable connection new experience by default in url', async () => {
1194
+ const appEmbed = new AppEmbed(getRootEl(), {
1195
+ ...defaultViewConfig,
1196
+ } as AppViewConfig);
1197
+ appEmbed.render();
1198
+ await executeAfterWait(() => {
1199
+ expectUrlMatchesWithParams(
1200
+ getIFrameSrc(),
1201
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
1202
+ );
1203
+ });
1204
+ });
1205
+
977
1206
  test('Should add hideIrrelevantFiltersAtTabLevel flag to the iframe src', async () => {
978
1207
  const appEmbed = new AppEmbed(getRootEl(), {
979
1208
  ...defaultViewConfig,
@@ -1707,6 +1936,36 @@ describe('App embed tests', () => {
1707
1936
  addEventListenerSpy.mockRestore();
1708
1937
  });
1709
1938
 
1939
+ test('should listen to scroll and resize changes from scrollable iframe ancestors', async () => {
1940
+ const scrollContainer = getRootEl();
1941
+ scrollContainer.style.overflow = 'auto';
1942
+
1943
+ const scrollContainerAddEventListenerSpy = jest.spyOn(scrollContainer, 'addEventListener');
1944
+ const resizeObserveSpy = jest.fn();
1945
+ const resizeDisconnectSpy = jest.fn();
1946
+ (window as any).ResizeObserver = jest.fn().mockImplementation(() => ({
1947
+ observe: resizeObserveSpy,
1948
+ disconnect: resizeDisconnectSpy,
1949
+ }));
1950
+
1951
+ const appEmbed = new AppEmbed(getRootEl(), {
1952
+ ...defaultViewConfig,
1953
+ fullHeight: true,
1954
+ lazyLoadingForFullHeight: true,
1955
+ enableScrollableContainerLazyLoading: true,
1956
+ } as AppViewConfig);
1957
+
1958
+ await appEmbed.render();
1959
+
1960
+ await executeAfterWait(() => {
1961
+ expect(scrollContainerAddEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function));
1962
+ expect(resizeObserveSpy).toHaveBeenCalledWith(scrollContainer);
1963
+ }, 100);
1964
+
1965
+ appEmbed.destroy();
1966
+ expect(resizeDisconnectSpy).toHaveBeenCalled();
1967
+ });
1968
+
1710
1969
  test('should remove window event listeners on destroy when fullHeight and lazyLoadingForFullHeight are enabled', async () => {
1711
1970
  const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
1712
1971
 
@@ -1721,7 +1980,7 @@ describe('App embed tests', () => {
1721
1980
  appEmbed.destroy();
1722
1981
 
1723
1982
  expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function));
1724
- expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function));
1983
+ expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function), true);
1725
1984
 
1726
1985
  removeEventListenerSpy.mockRestore();
1727
1986
  });
@@ -1952,5 +2211,3 @@ describe('AppEmbed visualOverrides tests', () => {
1952
2211
  await testVisualOverridesInEmbed(appEmbed, visualOverrides);
1953
2212
  });
1954
2213
  });
1955
-
1956
-