@thoughtspot/visual-embed-sdk 1.37.0 → 1.37.1-spotter-embed

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 (173) hide show
  1. package/cjs/package.json +3 -3
  2. package/cjs/src/auth.d.ts +9 -4
  3. package/cjs/src/auth.d.ts.map +1 -1
  4. package/cjs/src/auth.js +21 -0
  5. package/cjs/src/auth.js.map +1 -1
  6. package/cjs/src/auth.spec.js +48 -0
  7. package/cjs/src/auth.spec.js.map +1 -1
  8. package/cjs/src/embed/app.d.ts +59 -0
  9. package/cjs/src/embed/app.d.ts.map +1 -1
  10. package/cjs/src/embed/app.js +13 -1
  11. package/cjs/src/embed/app.js.map +1 -1
  12. package/cjs/src/embed/app.spec.js +44 -0
  13. package/cjs/src/embed/app.spec.js.map +1 -1
  14. package/cjs/src/embed/bodyless-conversation.d.ts +39 -9
  15. package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
  16. package/cjs/src/embed/bodyless-conversation.js +32 -5
  17. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  18. package/cjs/src/embed/bodyless-conversation.spec.js +4 -4
  19. package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
  20. package/cjs/src/embed/conversation.d.ts +38 -11
  21. package/cjs/src/embed/conversation.d.ts.map +1 -1
  22. package/cjs/src/embed/conversation.js +28 -4
  23. package/cjs/src/embed/conversation.js.map +1 -1
  24. package/cjs/src/embed/conversation.spec.js +7 -7
  25. package/cjs/src/embed/conversation.spec.js.map +1 -1
  26. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  27. package/cjs/src/embed/ts-embed.js +4 -1
  28. package/cjs/src/embed/ts-embed.js.map +1 -1
  29. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  30. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  31. package/cjs/src/index.d.ts +3 -3
  32. package/cjs/src/index.d.ts.map +1 -1
  33. package/cjs/src/index.js +5 -3
  34. package/cjs/src/index.js.map +1 -1
  35. package/cjs/src/pages/embed-test.page.d.ts +8 -0
  36. package/cjs/src/pages/embed-test.page.d.ts.map +1 -0
  37. package/cjs/src/pages/embed-test.page.js +20 -0
  38. package/cjs/src/pages/embed-test.page.js.map +1 -0
  39. package/cjs/src/pages/home.page.d.ts +6 -0
  40. package/cjs/src/pages/home.page.d.ts.map +1 -0
  41. package/cjs/src/pages/home.page.js +12 -0
  42. package/cjs/src/pages/home.page.js.map +1 -0
  43. package/cjs/src/pages/login.page.d.ts +15 -0
  44. package/cjs/src/pages/login.page.d.ts.map +1 -0
  45. package/cjs/src/pages/login.page.js +22 -0
  46. package/cjs/src/pages/login.page.js.map +1 -0
  47. package/cjs/src/react/all-types-export.d.ts +1 -1
  48. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  49. package/cjs/src/react/all-types-export.js +2 -1
  50. package/cjs/src/react/all-types-export.js.map +1 -1
  51. package/cjs/src/react/index.d.ts +24 -5
  52. package/cjs/src/react/index.d.ts.map +1 -1
  53. package/cjs/src/react/index.js +21 -4
  54. package/cjs/src/react/index.js.map +1 -1
  55. package/cjs/src/tests/auth.test.d.ts +1 -0
  56. package/cjs/src/tests/auth.test.d.ts.map +1 -0
  57. package/cjs/src/tests/auth.test.js +1 -0
  58. package/cjs/src/tests/auth.test.js.map +1 -0
  59. package/cjs/src/tests/e2e/auth.spec.d.ts +2 -0
  60. package/cjs/src/tests/e2e/auth.spec.d.ts.map +1 -0
  61. package/cjs/src/tests/e2e/auth.spec.js +54 -0
  62. package/cjs/src/tests/e2e/auth.spec.js.map +1 -0
  63. package/cjs/src/types.d.ts +95 -3
  64. package/cjs/src/types.d.ts.map +1 -1
  65. package/cjs/src/types.js +79 -0
  66. package/cjs/src/types.js.map +1 -1
  67. package/cjs/src/utils/graphql/answerService/answerService.d.ts +35 -15
  68. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  69. package/cjs/src/utils/graphql/answerService/answerService.js +35 -15
  70. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  71. package/cjs/src/utils/processData.js +6 -4
  72. package/cjs/src/utils/processData.js.map +1 -1
  73. package/dist/index-Cj4BVGHL.js +7371 -0
  74. package/dist/index-DUaG1OG2.js +7447 -0
  75. package/dist/index-Fhk1V_Gw.js +7371 -0
  76. package/dist/index-OuiZF3zE.js +7371 -0
  77. package/dist/src/auth.d.ts +9 -4
  78. package/dist/src/auth.d.ts.map +1 -1
  79. package/dist/src/embed/app.d.ts +59 -0
  80. package/dist/src/embed/app.d.ts.map +1 -1
  81. package/dist/src/embed/bodyless-conversation.d.ts +39 -9
  82. package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
  83. package/dist/src/embed/conversation.d.ts +38 -11
  84. package/dist/src/embed/conversation.d.ts.map +1 -1
  85. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  86. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  87. package/dist/src/index.d.ts +3 -3
  88. package/dist/src/index.d.ts.map +1 -1
  89. package/dist/src/react/all-types-export.d.ts +1 -1
  90. package/dist/src/react/all-types-export.d.ts.map +1 -1
  91. package/dist/src/react/index.d.ts +24 -5
  92. package/dist/src/react/index.d.ts.map +1 -1
  93. package/dist/src/types.d.ts +95 -3
  94. package/dist/src/types.d.ts.map +1 -1
  95. package/dist/src/utils/graphql/answerService/answerService.d.ts +35 -15
  96. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  97. package/dist/tsembed-react.es.js +208 -31
  98. package/dist/tsembed-react.js +428 -174
  99. package/dist/tsembed.es.js +170 -32
  100. package/dist/tsembed.js +392 -176
  101. package/dist/visual-embed-sdk-react-full.d.ts +299 -47
  102. package/dist/visual-embed-sdk-react.d.ts +299 -47
  103. package/dist/visual-embed-sdk.d.ts +276 -43
  104. package/lib/package.json +3 -3
  105. package/lib/src/auth.d.ts +9 -4
  106. package/lib/src/auth.d.ts.map +1 -1
  107. package/lib/src/auth.js +21 -0
  108. package/lib/src/auth.js.map +1 -1
  109. package/lib/src/auth.spec.js +48 -0
  110. package/lib/src/auth.spec.js.map +1 -1
  111. package/lib/src/embed/app.d.ts +59 -0
  112. package/lib/src/embed/app.d.ts.map +1 -1
  113. package/lib/src/embed/app.js +13 -1
  114. package/lib/src/embed/app.js.map +1 -1
  115. package/lib/src/embed/app.spec.js +44 -0
  116. package/lib/src/embed/app.spec.js.map +1 -1
  117. package/lib/src/embed/bodyless-conversation.d.ts +39 -9
  118. package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
  119. package/lib/src/embed/bodyless-conversation.js +30 -4
  120. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  121. package/lib/src/embed/bodyless-conversation.spec.js +5 -5
  122. package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
  123. package/lib/src/embed/conversation.d.ts +38 -11
  124. package/lib/src/embed/conversation.d.ts.map +1 -1
  125. package/lib/src/embed/conversation.js +26 -3
  126. package/lib/src/embed/conversation.js.map +1 -1
  127. package/lib/src/embed/conversation.spec.js +8 -8
  128. package/lib/src/embed/conversation.spec.js.map +1 -1
  129. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  130. package/lib/src/embed/ts-embed.js +4 -1
  131. package/lib/src/embed/ts-embed.js.map +1 -1
  132. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  133. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  134. package/lib/src/index.d.ts +3 -3
  135. package/lib/src/index.d.ts.map +1 -1
  136. package/lib/src/index.js +3 -3
  137. package/lib/src/index.js.map +1 -1
  138. package/lib/src/react/all-types-export.d.ts +1 -1
  139. package/lib/src/react/all-types-export.d.ts.map +1 -1
  140. package/lib/src/react/all-types-export.js +1 -1
  141. package/lib/src/react/all-types-export.js.map +1 -1
  142. package/lib/src/react/index.d.ts +24 -5
  143. package/lib/src/react/index.d.ts.map +1 -1
  144. package/lib/src/react/index.js +21 -4
  145. package/lib/src/react/index.js.map +1 -1
  146. package/lib/src/types.d.ts +95 -3
  147. package/lib/src/types.d.ts.map +1 -1
  148. package/lib/src/types.js +79 -0
  149. package/lib/src/types.js.map +1 -1
  150. package/lib/src/utils/graphql/answerService/answerService.d.ts +35 -15
  151. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  152. package/lib/src/utils/graphql/answerService/answerService.js +35 -15
  153. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  154. package/lib/src/utils/processData.js +6 -4
  155. package/lib/src/utils/processData.js.map +1 -1
  156. package/lib/src/visual-embed-sdk.d.ts +278 -45
  157. package/package.json +3 -3
  158. package/src/auth.spec.ts +52 -0
  159. package/src/auth.ts +25 -3
  160. package/src/embed/app.spec.ts +64 -0
  161. package/src/embed/app.ts +80 -0
  162. package/src/embed/bodyless-conversation.spec.ts +6 -6
  163. package/src/embed/bodyless-conversation.ts +43 -8
  164. package/src/embed/conversation.spec.ts +16 -16
  165. package/src/embed/conversation.ts +42 -11
  166. package/src/embed/ts-embed.spec.ts +0 -2
  167. package/src/embed/ts-embed.ts +4 -0
  168. package/src/index.ts +8 -4
  169. package/src/react/all-types-export.ts +1 -0
  170. package/src/react/index.tsx +36 -10
  171. package/src/types.ts +99 -1
  172. package/src/utils/graphql/answerService/answerService.ts +35 -15
  173. package/src/utils/processData.ts +6 -6
package/src/auth.spec.ts CHANGED
@@ -385,6 +385,45 @@ describe('Unit test for auth', () => {
385
385
  expect(global.window.location.href).toBe(samalLoginUrl);
386
386
  });
387
387
 
388
+ it('should emit SAML_POPUP_CLOSED_NO_AUTH when popup window is closed', async () => {
389
+ jest.useFakeTimers();
390
+ const mockPopupWindow = {
391
+ closed: false,
392
+ focus: jest.fn(),
393
+ close: jest.fn()
394
+ };
395
+ global.window.open = jest.fn().mockReturnValue(mockPopupWindow);
396
+ Object.defineProperty(window, 'location', {
397
+ value: {
398
+ href: '',
399
+ hash: '',
400
+ },
401
+ });
402
+ spyOn(authInstance, 'samlCompletionPromise').and.returnValue(Promise.resolve(false));
403
+ const emitSpy = jest.fn();
404
+ const mockEventEmitter = {
405
+ emit: emitSpy,
406
+ once: jest.fn(),
407
+ on: jest.fn()
408
+ };
409
+ authInstance.setAuthEE(mockEventEmitter as any);
410
+ jest.spyOn(tokenAuthService, 'isActiveService')
411
+ .mockReturnValueOnce(false)
412
+ .mockReturnValueOnce(true);
413
+ expect(
414
+ await authInstance.doSamlAuth({
415
+ ...embedConfig.doSamlAuthNoRedirect,
416
+ }),
417
+ ).toBe(true);
418
+ document.getElementById('ts-auth-btn').click();
419
+ mockPopupWindow.closed = true;
420
+ jest.advanceTimersByTime(1000);
421
+ window.postMessage({ type: EmbedEvent.SAMLComplete }, '*');
422
+ await authInstance.samlCompletionPromise;
423
+ expect(emitSpy).toHaveBeenCalledWith(authInstance.AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
424
+ jest.useRealTimers();
425
+ authInstance.setAuthEE(null);
426
+ });
388
427
  it('when user is not loggedIn, in config noRedirect is true and isAtSSORedirectUrl is false', async () => {
389
428
  Object.defineProperty(window, 'location', {
390
429
  value: {
@@ -408,6 +447,19 @@ describe('Unit test for auth', () => {
408
447
  await authInstance.samlCompletionPromise;
409
448
  expect(authInstance.loggedInStatus).toBe(true);
410
449
  });
450
+
451
+ it('should support emitting SAML_POPUP_CLOSED_NO_AUTH event', () => {
452
+ const emitSpy = jest.fn();
453
+ const mockEventEmitter = {
454
+ emit: emitSpy,
455
+ once: jest.fn()
456
+ };
457
+ authInstance.setAuthEE(mockEventEmitter as any);
458
+ authInstance.getAuthEE().emit(authInstance.AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
459
+ expect(emitSpy).toHaveBeenCalledWith(authInstance.AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
460
+ authInstance.setAuthEE(null);
461
+ });
462
+
411
463
  });
412
464
 
413
465
  describe('doOIDCAuth', () => {
package/src/auth.ts CHANGED
@@ -40,7 +40,8 @@ export enum AuthFailureType {
40
40
  NO_COOKIE_ACCESS = 'NO_COOKIE_ACCESS',
41
41
  EXPIRY = 'EXPIRY',
42
42
  OTHER = 'OTHER',
43
- IDLE_SESSION_TIMEOUT = 'IDLE_SESSION_TIMEOUT'
43
+ IDLE_SESSION_TIMEOUT = 'IDLE_SESSION_TIMEOUT',
44
+ UNAUTHENTICATED_FAILURE = 'UNAUTHENTICATED_FAILURE',
44
45
  }
45
46
 
46
47
  /**
@@ -76,6 +77,11 @@ export enum AuthStatus {
76
77
  * @version SDK: 1.19.0
77
78
  */
78
79
  WAITING_FOR_POPUP = 'WAITING_FOR_POPUP',
80
+
81
+ /**
82
+ * Emitted when the SAML popup is closed without authentication
83
+ */
84
+ SAML_POPUP_CLOSED_NO_AUTH = 'SAML_POPUP_CLOSED_NO_AUTH',
79
85
  }
80
86
 
81
87
  /**
@@ -95,13 +101,13 @@ export interface AuthEventEmitter {
95
101
  * @param listener
96
102
  */
97
103
  on(
98
- event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP,
104
+ event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP | AuthStatus.SAML_POPUP_CLOSED_NO_AUTH,
99
105
  listener: () => void,
100
106
  ): this;
101
107
  on(event: AuthStatus.SUCCESS, listener: (sessionInfo: any) => void): this;
102
108
  once(event: AuthStatus.FAILURE, listener: (failureType: AuthFailureType) => void): this;
103
109
  once(
104
- event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP,
110
+ event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP | AuthStatus.SAML_POPUP_CLOSED_NO_AUTH,
105
111
  listener: () => void,
106
112
  ): this;
107
113
  once(event: AuthStatus.SUCCESS, listener: (sessionInfo: any) => void): this;
@@ -363,6 +369,7 @@ export const doBasicAuth = async (embedConfig: EmbedConfig): Promise<boolean> =>
363
369
  * @param triggerText
364
370
  */
365
371
  async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, triggerText: string) {
372
+ let popupClosedCheck: NodeJS.Timeout;
366
373
  const openPopup = () => {
367
374
  if (samlAuthWindow === null || samlAuthWindow.closed) {
368
375
  samlAuthWindow = window.open(
@@ -370,10 +377,21 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
370
377
  '_blank',
371
378
  'location=no,height=570,width=520,scrollbars=yes,status=yes',
372
379
  );
380
+ if (samlAuthWindow) {
381
+ popupClosedCheck = setInterval(() => {
382
+ if (samlAuthWindow.closed) {
383
+ clearInterval(popupClosedCheck);
384
+ if (samlCompletionPromise && !samlCompletionResolved) {
385
+ authEE?.emit(AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
386
+ }
387
+ }
388
+ }, 500);
389
+ }
373
390
  } else {
374
391
  samlAuthWindow.focus();
375
392
  }
376
393
  };
394
+ let samlCompletionResolved = false;
377
395
  authEE?.emit(AuthStatus.WAITING_FOR_POPUP);
378
396
  const containerEl = getDOMNode(triggerContainer);
379
397
  if (containerEl) {
@@ -385,6 +403,10 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
385
403
  samlCompletionPromise = samlCompletionPromise || new Promise<void>((resolve, reject) => {
386
404
  window.addEventListener('message', (e) => {
387
405
  if (e.data.type === EmbedEvent.SAMLComplete) {
406
+ samlCompletionResolved = true;
407
+ if (popupClosedCheck) {
408
+ clearInterval(popupClosedCheck);
409
+ }
388
410
  (e.source as Window).close();
389
411
  resolve();
390
412
  }
@@ -494,6 +494,70 @@ describe('App embed tests', () => {
494
494
  });
495
495
  });
496
496
 
497
+ test('Should add hideHamburger, hideObjectSearch, hideNotification flags to the iframe src', async () => {
498
+ const appEmbed = new AppEmbed(getRootEl(), {
499
+ ...defaultViewConfig,
500
+ hideHamburger: true,
501
+ hideObjectSearch: true,
502
+ hideNotification: true,
503
+ } as AppViewConfig);
504
+
505
+ appEmbed.render();
506
+ await executeAfterWait(() => {
507
+ expectUrlMatchesWithParams(
508
+ getIFrameSrc(),
509
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&hideHamburger=true&hideObjectSearch=true&hideNotification=true${defaultParams}${defaultParamsPost}#/home`,
510
+ );
511
+ });
512
+ });
513
+
514
+ test('Should not add when hideHamburger, hideObjectSearch, hideNotification values are not true to the iframe src', async () => {
515
+ const appEmbed = new AppEmbed(getRootEl(), {
516
+ ...defaultViewConfig,
517
+ hideHamburger: false,
518
+ hideObjectSearch: undefined,
519
+ hideNotification: null,
520
+ } as AppViewConfig);
521
+
522
+ appEmbed.render();
523
+ await executeAfterWait(() => {
524
+ expectUrlMatchesWithParams(
525
+ getIFrameSrc(),
526
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false${defaultParams}${defaultParamsPost}#/home`,
527
+ );
528
+ });
529
+ });
530
+
531
+ test('Should add navigationVersion=v3 when modularHomeExperienceV3 is true to the iframe src', async () => {
532
+ const appEmbed = new AppEmbed(getRootEl(), {
533
+ ...defaultViewConfig,
534
+ modularHomeExperienceV3: true,
535
+ } as AppViewConfig);
536
+
537
+ appEmbed.render();
538
+ await executeAfterWait(() => {
539
+ expectUrlMatchesWithParams(
540
+ getIFrameSrc(),
541
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&navigationVersion=v3${defaultParams}${defaultParamsPost}#/home`,
542
+ );
543
+ });
544
+ });
545
+
546
+ test('Should not add navigationVersion when modularHomeExperienceV3 is false to the iframe src', async () => {
547
+ const appEmbed = new AppEmbed(getRootEl(), {
548
+ ...defaultViewConfig,
549
+ modularHomeExperienceV3: false,
550
+ } as AppViewConfig);
551
+
552
+ appEmbed.render();
553
+ await executeAfterWait(() => {
554
+ expectUrlMatchesWithParams(
555
+ getIFrameSrc(),
556
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false${defaultParams}${defaultParamsPost}#/home`,
557
+ );
558
+ });
559
+ });
560
+
497
561
  test('Should add enableAskSage flag to the iframe src', async () => {
498
562
  const appEmbed = new AppEmbed(getRootEl(), {
499
563
  ...defaultViewConfig,
package/src/embed/app.ts CHANGED
@@ -151,6 +151,51 @@ export interface AppViewConfig extends Omit<ViewConfig, 'visibleTabs'> {
151
151
  * ```
152
152
  */
153
153
  enablePendoHelp?: boolean
154
+ /**
155
+ * Control the visibility of the hamburger icon on the top nav bar
156
+ * available when new navigation V3 is enabled.
157
+ *
158
+ * @default false
159
+ * @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
160
+ * @example
161
+ * ```js
162
+ * const embed = new AppEmbed('#tsEmbed', {
163
+ * ... // other options
164
+ * hideHamburger : true,
165
+ * })
166
+ * ```
167
+ */
168
+ hideHamburger?: boolean;
169
+ /**
170
+ * Control the visibility of the Eureka search on the top nav bar
171
+ * this will control for both new V2 and new navigation V3.
172
+ *
173
+ * @default true
174
+ * @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
175
+ * @example
176
+ * ```js
177
+ * const embed = new AppEmbed('#tsEmbed', {
178
+ * ... // other options
179
+ * hideObjectSearch: false,
180
+ * })
181
+ * ```
182
+ */
183
+ hideObjectSearch?: boolean;
184
+ /**
185
+ * Control the visibility of the notification on the top nav bar V3,
186
+ * available when new navigation V3 is enabled.
187
+ *
188
+ * @default true
189
+ * @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
190
+ * @example
191
+ * ```js
192
+ * const embed = new AppEmbed('#tsEmbed', {
193
+ * ... // other options
194
+ * hideNotification: false,
195
+ * })
196
+ * ```
197
+ */
198
+ hideNotification?: boolean;
154
199
  /**
155
200
  * Control the visibility of the application switcher button on the nav-bar.
156
201
  * By default, the application switcher is shown.
@@ -344,6 +389,20 @@ export interface AppViewConfig extends Omit<ViewConfig, 'visibleTabs'> {
344
389
  * ```
345
390
  */
346
391
  modularHomeExperience?: boolean;
392
+ /**
393
+ * Flag to control new navigation v3 home experience.
394
+ *
395
+ * @default false
396
+ * @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
397
+ * @example
398
+ * ```js
399
+ * const embed = new AppEmbed('#tsEmbed', {
400
+ * ... // other options
401
+ * modularHomeExperienceV3 : true,
402
+ * })
403
+ * ```
404
+ */
405
+ modularHomeExperienceV3?: boolean;
347
406
  /**
348
407
  * Boolean to control if Liveboard header is sticky or not.
349
408
  * @example
@@ -515,6 +574,9 @@ export class AppEmbed extends V1Embed {
515
574
  liveboardV2,
516
575
  showPrimaryNavbar,
517
576
  disableProfileAndHelp,
577
+ hideHamburger,
578
+ hideObjectSearch,
579
+ hideNotification,
518
580
  hideApplicationSwitcher,
519
581
  hideOrgSwitcher,
520
582
  enableSearchAssist,
@@ -525,6 +587,7 @@ export class AppEmbed extends V1Embed {
525
587
  showLiveboardDescription = true,
526
588
  hideHomepageLeftNav = false,
527
589
  modularHomeExperience = false,
590
+ modularHomeExperienceV3 = false,
528
591
  isLiveboardHeaderSticky = true,
529
592
  enableAskSage,
530
593
  collapseSearchBarInitially = false,
@@ -561,6 +624,22 @@ export class AppEmbed extends V1Embed {
561
624
 
562
625
  params = this.getBaseQueryParams(params);
563
626
 
627
+ if (modularHomeExperienceV3) {
628
+ params[Param.NavigationVersion] = 'v3';
629
+ }
630
+
631
+ if (hideObjectSearch) {
632
+ params[Param.HideObjectSearch] = !!hideObjectSearch;
633
+ }
634
+
635
+ if (hideHamburger) {
636
+ params[Param.HideHamburger] = !!hideHamburger;
637
+ }
638
+
639
+ if (hideNotification) {
640
+ params[Param.HideNotification] = !!hideNotification;
641
+ }
642
+
564
643
  if (fullHeight === true) {
565
644
  params[Param.fullHeight] = true;
566
645
  }
@@ -620,6 +699,7 @@ export class AppEmbed extends V1Embed {
620
699
  /* eslint-disable-next-line max-len */
621
700
  params[Param.DataPanelCustomGroupsAccordionInitialState] = DataPanelCustomColumnGroupsAccordionState.EXPAND_ALL;
622
701
  }
702
+
623
703
  const queryParams = getQueryParamString(params, true);
624
704
 
625
705
  return queryParams;
@@ -1,5 +1,5 @@
1
1
  import 'jest-fetch-mock';
2
- import { BodylessConversation, BodylessConversationViewConfig } from './bodyless-conversation';
2
+ import { SpotterAgentEmbed, SpotterAgentEmbedViewConfig } from './bodyless-conversation';
3
3
  import * as authInstance from '../auth';
4
4
  import { init } from '../index';
5
5
  import { Action, AuthType, RuntimeFilterOp } from '../types';
@@ -14,7 +14,7 @@ import {
14
14
  expectUrlToHaveParamsWithValues,
15
15
  } from '../test/test-utils';
16
16
 
17
- describe('BodylessConversation', () => {
17
+ describe('SpotterAgentEmbed', () => {
18
18
  const thoughtSpotHost = 'tshost';
19
19
 
20
20
  beforeAll(() => {
@@ -117,12 +117,12 @@ describe('BodylessConversation', () => {
117
117
  },
118
118
  }),
119
119
  );
120
- const viewConfig: BodylessConversationViewConfig = {
120
+ const viewConfig: SpotterAgentEmbedViewConfig = {
121
121
  worksheetId: 'worksheetId',
122
122
  };
123
123
 
124
- const conversationEmbed = new BodylessConversation(viewConfig);
125
- const result = await conversationEmbed.sendMessage('userMessage');
124
+ const spotterEmbed = new SpotterAgentEmbed(viewConfig);
125
+ const result = await spotterEmbed.sendMessage('userMessage');
126
126
  const iframeSrc = getIFrameSrc(result.container);
127
127
  expectUrlToHaveParamsWithValues(iframeSrc, {
128
128
  sessionId: 'sessionId',
@@ -134,7 +134,7 @@ describe('BodylessConversation', () => {
134
134
  fetchMock.mockRejectOnce(
135
135
  new Error('error'),
136
136
  );
137
- const errorResult = await conversationEmbed.sendMessage('userMessage');
137
+ const errorResult = await spotterEmbed.sendMessage('userMessage');
138
138
  expect(errorResult.error instanceof Error).toBeTruthy();
139
139
  });
140
140
  });
@@ -8,14 +8,22 @@ import { getQueryParamString } from '../utils';
8
8
  * Configuration for bodyless conversation options.
9
9
  * @group Embed components
10
10
  */
11
- export interface BodylessConversationViewConfig extends ViewConfig {
11
+ export interface SpotterAgentEmbedViewConfig extends ViewConfig {
12
12
  /**
13
13
  * The ID of the worksheet to use for the conversation.
14
14
  */
15
15
  worksheetId: string;
16
16
  }
17
17
 
18
- interface ConversationMessageViewConfig extends BodylessConversationViewConfig {
18
+ /**
19
+ * Configuration for conversation options.
20
+ * @deprecated Renamed to SpotterAgentEmbedViewConfig
21
+ * @group Embed components
22
+ */
23
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
24
+ export interface BodylessConversationViewConfig extends SpotterAgentEmbedViewConfig {}
25
+
26
+ interface SpotterAgentMessageViewConfig extends SpotterAgentEmbedViewConfig {
19
27
  sessionId: string;
20
28
  genNo: number;
21
29
  acSessionId: string;
@@ -23,7 +31,7 @@ interface ConversationMessageViewConfig extends BodylessConversationViewConfig {
23
31
  }
24
32
 
25
33
  class ConversationMessage extends TsEmbed {
26
- constructor(container: HTMLElement, protected viewConfig: ConversationMessageViewConfig) {
34
+ constructor(container: HTMLElement, protected viewConfig: SpotterAgentMessageViewConfig) {
27
35
  viewConfig.embedComponentType = 'bodyless-conversation';
28
36
  super(container, viewConfig);
29
37
  }
@@ -39,6 +47,7 @@ class ConversationMessage extends TsEmbed {
39
47
  const queryParams = this.getBaseQueryParams();
40
48
 
41
49
  queryParams[Param.HideActions] = [...(queryParams[Param.HideActions] ?? [])];
50
+ queryParams[Param.isSpotterAgentEmbed] = true;
42
51
  let query = '';
43
52
  const queryParamsString = getQueryParamString(queryParams, true);
44
53
  if (queryParamsString) {
@@ -68,9 +77,9 @@ class ConversationMessage extends TsEmbed {
68
77
  * chatbots or other conversational interfaces.
69
78
  * @example
70
79
  * ```js
71
- * import { BodylessConversation } from '@thoughtspot/visual-embed-sdk';
80
+ * import { SpotterAgentEmbed } from '@thoughtspot/visual-embed-sdk';
72
81
  *
73
- * const conversation = new BodylessConversation({
82
+ * const conversation = new SpotterAgentEmbed({
74
83
  * worksheetId: 'worksheetId',
75
84
  * });
76
85
  *
@@ -80,12 +89,12 @@ class ConversationMessage extends TsEmbed {
80
89
  * document.body.appendChild(container); // or to any other element
81
90
  * ```
82
91
  * @group Embed components
83
- * @version SDK: 1.33.1 | ThoughtSpot: 10.5.0.cl
92
+ * @version SDK: 1.37.0 | ThoughtSpot: 10.9.0.cl
84
93
  */
85
- export class BodylessConversation {
94
+ export class SpotterAgentEmbed {
86
95
  private conversationService: ConversationService;
87
96
 
88
- constructor(private viewConfig: BodylessConversationViewConfig) {
97
+ constructor(private viewConfig: SpotterAgentEmbedViewConfig) {
89
98
  const embedConfig = getEmbedConfig();
90
99
 
91
100
  this.conversationService = new ConversationService(
@@ -112,3 +121,29 @@ export class BodylessConversation {
112
121
  return { container, viz: embed };
113
122
  }
114
123
  }
124
+
125
+ /**
126
+ * Create a conversation embed, which can be integrated inside
127
+ * chatbots or other conversational interfaces.
128
+ * @deprecated Renamed to SpotterAgentEmbed
129
+ * @example
130
+ * ```js
131
+ * import { SpotterAgentEmbed } from '@thoughtspot/visual-embed-sdk';
132
+ *
133
+ * const conversation = new SpotterAgentEmbed({
134
+ * worksheetId: 'worksheetId',
135
+ * });
136
+ *
137
+ * const { container, error } = await conversation.sendMessage('show me sales by region');
138
+ *
139
+ * // append the container to the DOM
140
+ * document.body.appendChild(container); // or to any other element
141
+ * ```
142
+ * @group Embed components
143
+ * @version SDK: 1.37.0 | ThoughtSpot: 10.9.0.cl
144
+ */
145
+ export class BodylessConversation extends SpotterAgentEmbed {
146
+ constructor(viewConfig: BodylessConversationViewConfig) {
147
+ super(viewConfig);
148
+ }
149
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
- ConversationEmbed,
3
- ConversationViewConfig,
2
+ SpotterEmbed,
3
+ SpotterEmbedViewConfig,
4
4
  } from './conversation';
5
5
  import * as authInstance from '../auth';
6
6
  import { init } from '../index';
@@ -28,14 +28,14 @@ beforeAll(() => {
28
28
 
29
29
  describe('ConversationEmbed', () => {
30
30
  it('should render the conversation embed', async () => {
31
- const viewConfig: ConversationViewConfig = {
31
+ const viewConfig: SpotterEmbedViewConfig = {
32
32
  worksheetId: 'worksheetId',
33
33
  searchOptions: {
34
34
  searchQuery: 'searchQuery',
35
35
  },
36
36
  };
37
37
 
38
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
38
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
39
39
  await conversationEmbed.render();
40
40
  expectUrlMatchesWithParams(
41
41
  getIFrameSrc(),
@@ -44,7 +44,7 @@ describe('ConversationEmbed', () => {
44
44
  });
45
45
 
46
46
  it('should render the conversation embed with worksheets disabled', async () => {
47
- const viewConfig: ConversationViewConfig = {
47
+ const viewConfig: SpotterEmbedViewConfig = {
48
48
  worksheetId: 'worksheetId',
49
49
  searchOptions: {
50
50
  searchQuery: 'searchQuery',
@@ -52,7 +52,7 @@ describe('ConversationEmbed', () => {
52
52
  disableSourceSelection: true,
53
53
  };
54
54
 
55
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
55
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
56
56
  await conversationEmbed.render();
57
57
  expectUrlMatchesWithParams(
58
58
  getIFrameSrc(),
@@ -61,7 +61,7 @@ describe('ConversationEmbed', () => {
61
61
  });
62
62
 
63
63
  it('should render the conversation embed with spotter limitations text if flag is set', async () => {
64
- const viewConfig: ConversationViewConfig = {
64
+ const viewConfig: SpotterEmbedViewConfig = {
65
65
  worksheetId: 'worksheetId',
66
66
  searchOptions: {
67
67
  searchQuery: 'searchQuery',
@@ -69,7 +69,7 @@ describe('ConversationEmbed', () => {
69
69
  showSpotterLimitations: true,
70
70
  };
71
71
 
72
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
72
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
73
73
  await conversationEmbed.render();
74
74
  expectUrlMatchesWithParams(
75
75
  getIFrameSrc(),
@@ -78,7 +78,7 @@ describe('ConversationEmbed', () => {
78
78
  });
79
79
 
80
80
  it('should render the conversation embed with sample questions hidden', async () => {
81
- const viewConfig: ConversationViewConfig = {
81
+ const viewConfig: SpotterEmbedViewConfig = {
82
82
  worksheetId: 'worksheetId',
83
83
  searchOptions: {
84
84
  searchQuery: 'searchQuery',
@@ -86,7 +86,7 @@ describe('ConversationEmbed', () => {
86
86
  hideSampleQuestions: true,
87
87
  };
88
88
 
89
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
89
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
90
90
  await conversationEmbed.render();
91
91
  expectUrlMatchesWithParams(
92
92
  getIFrameSrc(),
@@ -95,7 +95,7 @@ describe('ConversationEmbed', () => {
95
95
  });
96
96
 
97
97
  it('should render the conversation embed with worksheets hidden', async () => {
98
- const viewConfig: ConversationViewConfig = {
98
+ const viewConfig: SpotterEmbedViewConfig = {
99
99
  worksheetId: 'worksheetId',
100
100
  searchOptions: {
101
101
  searchQuery: 'searchQuery',
@@ -103,7 +103,7 @@ describe('ConversationEmbed', () => {
103
103
  hideSourceSelection: true,
104
104
  };
105
105
 
106
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
106
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
107
107
  await conversationEmbed.render();
108
108
  expectUrlMatchesWithParams(
109
109
  getIFrameSrc(),
@@ -112,13 +112,13 @@ describe('ConversationEmbed', () => {
112
112
  });
113
113
 
114
114
  it('should handle error when worksheetId is not provided', async () => {
115
- const viewConfig: ConversationViewConfig = {
115
+ const viewConfig: SpotterEmbedViewConfig = {
116
116
  worksheetId: '',
117
117
  searchOptions: {
118
118
  searchQuery: 'searchQuery',
119
119
  },
120
120
  };
121
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
121
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
122
122
  (conversationEmbed as any).handleError = jest.fn();
123
123
  await conversationEmbed.render();
124
124
  expect((conversationEmbed as any).handleError).toHaveBeenCalledWith(
@@ -127,7 +127,7 @@ describe('ConversationEmbed', () => {
127
127
  });
128
128
 
129
129
  it('should render the conversation embed if data panel v2 flag is true', async () => {
130
- const viewConfig: ConversationViewConfig = {
130
+ const viewConfig: SpotterEmbedViewConfig = {
131
131
  worksheetId: 'worksheetId',
132
132
  searchOptions: {
133
133
  searchQuery: 'searchQuery',
@@ -135,7 +135,7 @@ describe('ConversationEmbed', () => {
135
135
  dataPanelV2: true,
136
136
  };
137
137
 
138
- const conversationEmbed = new ConversationEmbed(getRootEl(), viewConfig);
138
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
139
139
  await conversationEmbed.render();
140
140
  expectUrlMatchesWithParams(
141
141
  getIFrameSrc(),