@thoughtspot/visual-embed-sdk 1.35.14 → 1.36.1

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 (127) hide show
  1. package/cjs/package.json +2 -3
  2. package/cjs/src/auth.d.ts +5 -0
  3. package/cjs/src/auth.d.ts.map +1 -1
  4. package/cjs/src/auth.js +7 -0
  5. package/cjs/src/auth.js.map +1 -1
  6. package/cjs/src/css-variables.d.ts +8 -0
  7. package/cjs/src/css-variables.d.ts.map +1 -1
  8. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  9. package/cjs/src/embed/hostEventClient/host-event-client.js +8 -3
  10. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  11. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +54 -0
  12. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  13. package/cjs/src/embed/ts-embed.d.ts +6 -0
  14. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  15. package/cjs/src/embed/ts-embed.js +27 -0
  16. package/cjs/src/embed/ts-embed.js.map +1 -1
  17. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  18. package/cjs/src/embed/ts-embed.spec.js +73 -1
  19. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  20. package/cjs/src/react/index.spec.js +2 -2
  21. package/cjs/src/react/index.spec.js.map +1 -1
  22. package/cjs/src/types.d.ts +82 -7
  23. package/cjs/src/types.d.ts.map +1 -1
  24. package/cjs/src/types.js +81 -7
  25. package/cjs/src/types.js.map +1 -1
  26. package/cjs/src/utils/authService/authService.d.ts +1 -0
  27. package/cjs/src/utils/authService/authService.d.ts.map +1 -1
  28. package/cjs/src/utils/authService/authService.js +1 -0
  29. package/cjs/src/utils/authService/authService.js.map +1 -1
  30. package/cjs/src/utils/authService/index.d.ts +1 -1
  31. package/cjs/src/utils/authService/index.d.ts.map +1 -1
  32. package/cjs/src/utils/authService/index.js +2 -1
  33. package/cjs/src/utils/authService/index.js.map +1 -1
  34. package/cjs/src/utils/authService/tokenizedAuthService.d.ts +10 -0
  35. package/cjs/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  36. package/cjs/src/utils/authService/tokenizedAuthService.js +27 -1
  37. package/cjs/src/utils/authService/tokenizedAuthService.js.map +1 -1
  38. package/cjs/src/utils/authService/tokenizedAuthService.spec.js +58 -1
  39. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  40. package/cjs/src/utils/sessionInfoService.d.ts +30 -0
  41. package/cjs/src/utils/sessionInfoService.d.ts.map +1 -1
  42. package/cjs/src/utils/sessionInfoService.js +59 -1
  43. package/cjs/src/utils/sessionInfoService.js.map +1 -1
  44. package/dist/index-CR5u7BMC.js +7370 -0
  45. package/dist/src/auth.d.ts +5 -0
  46. package/dist/src/auth.d.ts.map +1 -1
  47. package/dist/src/css-variables.d.ts +8 -0
  48. package/dist/src/css-variables.d.ts.map +1 -1
  49. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  50. package/dist/src/embed/ts-embed.d.ts +6 -0
  51. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  52. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  53. package/dist/src/types.d.ts +82 -7
  54. package/dist/src/types.d.ts.map +1 -1
  55. package/dist/src/utils/authService/authService.d.ts +1 -0
  56. package/dist/src/utils/authService/authService.d.ts.map +1 -1
  57. package/dist/src/utils/authService/index.d.ts +1 -1
  58. package/dist/src/utils/authService/index.d.ts.map +1 -1
  59. package/dist/src/utils/authService/tokenizedAuthService.d.ts +10 -0
  60. package/dist/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  61. package/dist/src/utils/sessionInfoService.d.ts +30 -0
  62. package/dist/src/utils/sessionInfoService.d.ts.map +1 -1
  63. package/dist/tsembed-react.es.js +206 -13
  64. package/dist/tsembed-react.js +205 -12
  65. package/dist/tsembed.es.js +207 -13
  66. package/dist/tsembed.js +206 -12
  67. package/dist/visual-embed-sdk-react-full.d.ts +125 -7
  68. package/dist/visual-embed-sdk-react.d.ts +125 -7
  69. package/dist/visual-embed-sdk.d.ts +125 -7
  70. package/lib/package.json +2 -3
  71. package/lib/src/auth.d.ts +5 -0
  72. package/lib/src/auth.d.ts.map +1 -1
  73. package/lib/src/auth.js +8 -1
  74. package/lib/src/auth.js.map +1 -1
  75. package/lib/src/css-variables.d.ts +8 -0
  76. package/lib/src/css-variables.d.ts.map +1 -1
  77. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  78. package/lib/src/embed/hostEventClient/host-event-client.js +8 -3
  79. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  80. package/lib/src/embed/hostEventClient/host-event-client.spec.js +54 -0
  81. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  82. package/lib/src/embed/ts-embed.d.ts +6 -0
  83. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  84. package/lib/src/embed/ts-embed.js +27 -0
  85. package/lib/src/embed/ts-embed.js.map +1 -1
  86. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  87. package/lib/src/embed/ts-embed.spec.js +73 -1
  88. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  89. package/lib/src/react/index.spec.js +2 -2
  90. package/lib/src/react/index.spec.js.map +1 -1
  91. package/lib/src/types.d.ts +82 -7
  92. package/lib/src/types.d.ts.map +1 -1
  93. package/lib/src/types.js +81 -7
  94. package/lib/src/types.js.map +1 -1
  95. package/lib/src/utils/authService/authService.d.ts +1 -0
  96. package/lib/src/utils/authService/authService.d.ts.map +1 -1
  97. package/lib/src/utils/authService/authService.js +1 -0
  98. package/lib/src/utils/authService/authService.js.map +1 -1
  99. package/lib/src/utils/authService/index.d.ts +1 -1
  100. package/lib/src/utils/authService/index.d.ts.map +1 -1
  101. package/lib/src/utils/authService/index.js +1 -1
  102. package/lib/src/utils/authService/index.js.map +1 -1
  103. package/lib/src/utils/authService/tokenizedAuthService.d.ts +10 -0
  104. package/lib/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  105. package/lib/src/utils/authService/tokenizedAuthService.js +25 -0
  106. package/lib/src/utils/authService/tokenizedAuthService.js.map +1 -1
  107. package/lib/src/utils/authService/tokenizedAuthService.spec.js +59 -2
  108. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
  109. package/lib/src/utils/sessionInfoService.d.ts +30 -0
  110. package/lib/src/utils/sessionInfoService.d.ts.map +1 -1
  111. package/lib/src/utils/sessionInfoService.js +57 -1
  112. package/lib/src/utils/sessionInfoService.js.map +1 -1
  113. package/lib/src/visual-embed-sdk.d.ts +125 -7
  114. package/package.json +2 -3
  115. package/src/auth.ts +8 -1
  116. package/src/css-variables.ts +10 -0
  117. package/src/embed/hostEventClient/host-event-client.spec.ts +61 -0
  118. package/src/embed/hostEventClient/host-event-client.ts +8 -3
  119. package/src/embed/ts-embed.spec.ts +95 -1
  120. package/src/embed/ts-embed.ts +31 -0
  121. package/src/react/index.spec.tsx +2 -2
  122. package/src/types.ts +83 -7
  123. package/src/utils/authService/authService.ts +1 -0
  124. package/src/utils/authService/index.ts +5 -1
  125. package/src/utils/authService/tokenizedAuthService.spec.ts +66 -2
  126. package/src/utils/authService/tokenizedAuthService.ts +26 -0
  127. package/src/utils/sessionInfoService.ts +64 -1
@@ -1698,6 +1698,11 @@ declare module '@thoughtspot/visual-embed-sdk/auth' {
1698
1698
  * Emits when the SDK authenticates successfully
1699
1699
  */
1700
1700
  SDK_SUCCESS = "SDK_SUCCESS",
1701
+ /**
1702
+ * @hidden
1703
+ * Emits when iframe is loaded and session info is available
1704
+ */
1705
+ SESSION_INFO_SUCCESS = "SESSION_INFO_SUCCESS",
1701
1706
  /**
1702
1707
  * Emits when the app sends an authentication success message
1703
1708
  */
@@ -1852,6 +1857,36 @@ declare module '@thoughtspot/visual-embed-sdk/utils/sessionInfoService' {
1852
1857
  clusterName: string;
1853
1858
  [key: string]: any;
1854
1859
  };
1860
+ export type PreauthInfo = {
1861
+ info?: SessionInfo;
1862
+ headers: Record<string, string>;
1863
+ status: number;
1864
+ [key: string]: any;
1865
+ };
1866
+ /**
1867
+ * Processes the session info response and returns the session info object.
1868
+ * @param preauthInfoResp {any} Response from the session info API.
1869
+ * @returns {PreauthInfo} The session info object.
1870
+ * @example ```js
1871
+ * const preauthInfoResp = await fetch(sessionInfoPath);
1872
+ * const sessionInfo = await formatPreauthInfo(preauthInfoResp);
1873
+ * console.log(sessionInfo);
1874
+ * ```
1875
+ * @version SDK: 1.28.3 | ThoughtSpot: *
1876
+ */
1877
+ export const formatPreauthInfo: (preauthInfoResp: any) => Promise<PreauthInfo>;
1878
+ /**
1879
+ * Returns the session info object and caches it for future use.
1880
+ * Once fetched the session info object is cached and returned from the cache on
1881
+ * subsequent calls.
1882
+ * @example ```js
1883
+ * const preauthInfo = await getPreauthInfo();
1884
+ * console.log(preauthInfo);
1885
+ * ```
1886
+ * @version SDK: 1.28.3 | ThoughtSpot: *
1887
+ * @returns {Promise<SessionInfo>} The session info object.
1888
+ */
1889
+ export function getPreauthInfo(allowCache?: boolean): Promise<PreauthInfo>;
1855
1890
  /**
1856
1891
  * Returns the session info object and caches it for future use.
1857
1892
  * Once fetched the session info object is cached and returned from the cache on
@@ -2510,6 +2545,7 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
2510
2545
  * @version SDK 1.37.0 | ThoughtSpot: 10.7.0.cl
2511
2546
  */
2512
2547
  customVariablesForThirdPartyTools?: Record<string, any>;
2548
+ disablePreauthCache?: boolean;
2513
2549
  }
2514
2550
  export interface LayoutConfig {
2515
2551
  }
@@ -4469,16 +4505,63 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
4469
4505
  */
4470
4506
  getExportRequestForCurrentPinboard = "getExportRequestForCurrentPinboard",
4471
4507
  /**
4472
- * Trigger the **Pin** action on an embedded object
4473
- * @param - Liveboard embed takes the `vizId` as a
4474
- * key. Can be left undefined when embedding Search, full app, or
4475
- * a visualization.
4508
+ * Trigger **Pin** action on an embedded object.
4509
+ * If no parameters are defined, the pin action is triggered
4510
+ * for the Answer that the user is currently on
4511
+ * and a modal opens for Liveboard selection.
4512
+ * To add an Answer or visualization to a Liveboard programmatically without
4513
+ * showing requiring additional user input via *Pin to Liveboard* modal, define
4514
+ * the following parameters:
4515
+ *
4516
+ * @param
4517
+ * `vizId`- GUID of the saved Answer or visualization to pin to a Liveboard.
4518
+ * Optional when pinning a new chart or table generated from a Search query.
4519
+ * @param
4520
+ * `liveboardID` - GUID of the Liveboard to pin an Answer. If there is no Liveboard,
4521
+ * specify the `newLiveboardName` parameter to create a new Liveboard.
4522
+ * @param
4523
+ * `tabId` - GUID of the Liveboard tab. Adds the Answer to the Liveboard tab
4524
+ * specified in the code.
4525
+ * @param
4526
+ * `newVizName` - Name string for the Answer or visualization. If defined,
4527
+ * this parameter adds a new visualization object or creates a copy of the
4528
+ * Answer or visualization specified in `vizId`.
4529
+ * Required attribute.
4530
+ * @param
4531
+ * `newLiveboardName` - Name string for the Liveboard.
4532
+ * Creates a new Liveboard object with the specified name.
4533
+ * @param
4534
+ * `newTabName` - Name of the tab. Adds a new tab Liveboard specified
4535
+ * in the code.
4536
+ *
4476
4537
  * @example
4477
4538
  * ```js
4478
- * appEmbed.trigger(HostEvent.Pin)
4539
+ * const pinResponse = await appEmbed.trigger(HostEvent.Pin, {
4540
+ * vizId: "123",
4541
+ * newVizName: "Sales by region",
4542
+ * liveboardId: "123",
4543
+ * tabId: "123"
4544
+ * });
4479
4545
  * ```
4546
+ * @example
4547
+ * ```js
4548
+ * const pinResponse = await appEmbed.trigger(HostEvent.Pin, {
4549
+ * newVizName: "Total sales of Jackets",
4550
+ * liveboardId: "123"
4551
+ * });
4552
+ * ```
4553
+ *
4554
+ * @example
4480
4555
  * ```js
4481
- * searchEmbed.trigger(HostEvent.Pin)
4556
+ * const pinResponse = await searchEmbed.trigger(HostEvent.Pin, {
4557
+ * newVizName: "Sales by state",
4558
+ * newLiveboardName: "Sales",
4559
+ * newTabName: "Products"
4560
+ * });
4561
+ * ```
4562
+ * @example
4563
+ * ```js
4564
+ * appEmbed.trigger(HostEvent.Pin)
4482
4565
  * ```
4483
4566
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1.sw
4484
4567
  */
@@ -5125,7 +5208,33 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
5125
5208
  */
5126
5209
  UpdatePersonalisedView = "UpdatePersonalisedView",
5127
5210
  /**
5128
- * Triggers the action to get the current view of the Liveboard.
5211
+ * @hidden
5212
+ * Notify when info call is completed successfully
5213
+ * ```js
5214
+ * liveboardEmbed.trigger(HostEvent.InfoSuccess, data);
5215
+ *```
5216
+ * @version SDK: 1.36.0 | Thoughtspot: 10.6.0.cl
5217
+ */
5218
+ InfoSuccess = "InfoSuccess",
5219
+ /**
5220
+ * Trigger the save action for an Answer.
5221
+ * To programmatically save an answer without opening the
5222
+ * *Describe your Answer* modal, define the `name` and `description`
5223
+ * properties.
5224
+ * If no parameters are specified, the save action is
5225
+ * triggered with a modal to prompt users to
5226
+ * add a name and description for the Answer.
5227
+ * @param - optional attributes to set Answer properties.
5228
+ * `name` - Name string for the Answer.
5229
+ * `description` - Description text for the Answer.
5230
+ *
5231
+ * @example
5232
+ * ```js
5233
+ * const saveAnswerResponse = await searchEmbed.trigger(HostEvent.SaveAnswer, {
5234
+ * name: "Sales by states",
5235
+ * description: "Total sales by states in MidWest"
5236
+ * });
5237
+ * ```
5129
5238
  * @version SDK: 1.36.0 | ThoughtSpot: 10.6.0.cl
5130
5239
  */
5131
5240
  SaveAnswer = "saveAnswer",
@@ -5273,6 +5382,7 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
5273
5382
  OauthPollingInterval = "oAuthPollingInterval",
5274
5383
  IsForceRedirect = "isForceRedirect",
5275
5384
  DataSourceId = "dataSourceId",
5385
+ preAuthCache = "preAuthCache",
5276
5386
  ShowSpotterLimitations = "showSpotterLimitations"
5277
5387
  }
5278
5388
  /**
@@ -6710,6 +6820,14 @@ declare module '@thoughtspot/visual-embed-sdk/css-variables' {
6710
6820
  * panel.
6711
6821
  */
6712
6822
  '--ts-var-search-auto-complete-subtext-font-color'?: string;
6823
+ /**
6824
+ * Background color of the input box in the Spotter page.
6825
+ */
6826
+ '--ts-var-spotter-input-background'?: string;
6827
+ /**
6828
+ * Background color of the previously asked prompt message in the Spotter page.
6829
+ */
6830
+ '--ts-var-spotter-prompt-background': string;
6713
6831
  /**
6714
6832
  * Background color of the data panel.
6715
6833
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thoughtspot/visual-embed-sdk",
3
- "version": "1.35.14",
3
+ "version": "1.36.1",
4
4
  "description": "ThoughtSpot Embed SDK",
5
5
  "module": "lib/src/index.js",
6
6
  "main": "dist/tsembed.js",
@@ -72,7 +72,6 @@
72
72
  "classnames": "^2.3.1",
73
73
  "eventemitter3": "^4.0.7",
74
74
  "gatsby-plugin-vercel": "^1.0.3",
75
- "html-react-parser": "^1.4.12",
76
75
  "lodash": "^4.17.21",
77
76
  "mixpanel-browser": "2.47.0",
78
77
  "ts-deepmerge": "^6.0.2",
@@ -117,7 +116,7 @@
117
116
  "eslint-plugin-comment-length": "1.7.3",
118
117
  "eslint-plugin-jsdoc": "^46.9.0",
119
118
  "fs-extra": "^10.0.0",
120
- "gh-pages": "^3.1.0",
119
+ "gh-pages": "6.3.0",
121
120
  "highlight.js": "^10.6.0",
122
121
  "html-to-text": "^8.0.0",
123
122
  "identity-obj-proxy": "^3.0.0",
package/src/auth.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  } from './utils/authService';
16
16
  import { isActiveService } from './utils/authService/tokenizedAuthService';
17
17
  import { logger } from './utils/logger';
18
- import { getSessionInfo } from './utils/sessionInfoService';
18
+ import { getSessionInfo, getPreauthInfo } from './utils/sessionInfoService';
19
19
  import { ERROR_MESSAGE } from './errors';
20
20
 
21
21
  // eslint-disable-next-line import/no-mutable-exports
@@ -55,6 +55,11 @@ export enum AuthStatus {
55
55
  * Emits when the SDK authenticates successfully
56
56
  */
57
57
  SDK_SUCCESS = 'SDK_SUCCESS',
58
+ /**
59
+ * @hidden
60
+ * Emits when iframe is loaded and session info is available
61
+ */
62
+ SESSION_INFO_SUCCESS = 'SESSION_INFO_SUCCESS',
58
63
  /**
59
64
  * Emits when the app sends an authentication success message
60
65
  */
@@ -168,6 +173,7 @@ export async function notifyAuthSuccess(): Promise<void> {
168
173
  return;
169
174
  }
170
175
  try {
176
+ getPreauthInfo();
171
177
  const sessionInfo = await getSessionInfo();
172
178
  authEE.emit(AuthStatus.SUCCESS, sessionInfo);
173
179
  } catch (e) {
@@ -224,6 +230,7 @@ async function isLoggedIn(thoughtSpotHost: string): Promise<boolean> {
224
230
  */
225
231
  export async function postLoginService(): Promise<void> {
226
232
  try {
233
+ getPreauthInfo();
227
234
  const sessionInfo = await getSessionInfo();
228
235
  releaseVersion = sessionInfo.releaseVersion;
229
236
  const embedConfig = getEmbedConfig();
@@ -111,6 +111,16 @@ export interface CustomCssVariables {
111
111
  */
112
112
  '--ts-var-search-auto-complete-subtext-font-color'?: string;
113
113
 
114
+ /**
115
+ * Background color of the input box in the Spotter page.
116
+ */
117
+ '--ts-var-spotter-input-background'?: string;
118
+
119
+ /**
120
+ * Background color of the previously asked prompt message in the Spotter page.
121
+ */
122
+ '--ts-var-spotter-prompt-background': string;
123
+
114
124
  /**
115
125
  * Background color of the data panel.
116
126
  */
@@ -133,6 +133,7 @@ describe('HostEventClient', () => {
133
133
  const mockResponse = {
134
134
  value: {
135
135
  pinboardId: 'testPinboard',
136
+ liveboardId: 'testPinboard',
136
137
  tabId: 'testTab',
137
138
  vizId: 'testVizId',
138
139
  },
@@ -250,5 +251,65 @@ describe('HostEventClient', () => {
250
251
  );
251
252
  expect(result).toEqual([mockResponse]);
252
253
  });
254
+
255
+ it('Pin response support pinboardId as well', async () => {
256
+ const { client, mockIframe } = createHostEventClient();
257
+ const hostEvent = HostEvent.Pin;
258
+ const payload: HostEventRequest<typeof hostEvent> = {
259
+ newVizDescription: 'Test Description',
260
+ vizId: 'testVizId',
261
+ newVizName: 'Test Answer',
262
+ newLiveboardName: 'testLiveboard',
263
+ } as any;
264
+ const mockResponse = [{
265
+ value: {
266
+ pinboardId: 'testLiveboard',
267
+ liveboardId: 'testPinboard',
268
+ tabId: 'testTab',
269
+ vizId: 'testVizId',
270
+ },
271
+ refId: 'testVizId',
272
+ }];
273
+ mockProcessTrigger.mockResolvedValue(mockResponse);
274
+ const result = await client.triggerHostEvent(hostEvent, payload);
275
+ expect(result.liveboardId).toBe('testLiveboard');
276
+ });
277
+
278
+ it('should request liveboardId as well', async () => {
279
+ const { client, mockIframe } = createHostEventClient();
280
+ const hostEvent = HostEvent.Pin;
281
+ const payload: HostEventRequest<typeof hostEvent> = {
282
+ liveboardId: 'test',
283
+ newVizName: 'Test Answer',
284
+ newPinboardName: 'testLiveboard1',
285
+ newLiveboardName: 'testLiveboard',
286
+ } as any;
287
+ const mockResponse = [{
288
+ value: {
289
+ pinboardId: 'testLiveboard',
290
+ tabId: 'testTab',
291
+ vizId: 'testVizId',
292
+ },
293
+ refId: 'testVizId',
294
+ }];
295
+ mockProcessTrigger.mockResolvedValue(mockResponse);
296
+ const result = await client.triggerHostEvent(hostEvent, payload);
297
+ expect(result.liveboardId).toBe('testLiveboard');
298
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
299
+ mockIframe,
300
+ HostEvent.UIPassthrough,
301
+ mockThoughtSpotHost,
302
+ {
303
+ parameters: { ...payload, pinboardId: 'test', newPinboardName: 'testLiveboard' },
304
+ type: 'addVizToPinboard',
305
+ },
306
+ );
307
+ expect(result).toEqual({
308
+ pinboardId: 'testLiveboard',
309
+ tabId: 'testTab',
310
+ vizId: 'testVizId',
311
+ liveboardId: 'testLiveboard',
312
+ });
313
+ });
253
314
  });
254
315
  });
@@ -98,13 +98,18 @@ export class HostEventClient {
98
98
 
99
99
  const formattedPayload = {
100
100
  ...payload,
101
- pinboardId: payload.liveboardId,
102
- newPinboardName: payload.newLiveboardName,
101
+ pinboardId: payload.liveboardId ?? (payload as any).pinboardId,
102
+ newPinboardName: payload.newLiveboardName ?? (payload as any).newPinboardName,
103
103
  };
104
104
 
105
- return this.handleHostEventWithParam(
105
+ const data = await this.handleHostEventWithParam(
106
106
  UIPassthroughEvent.PinAnswerToLiveboard, formattedPayload,
107
107
  );
108
+
109
+ return {
110
+ ...data,
111
+ liveboardId: (data as any).pinboardId,
112
+ };
108
113
  }
109
114
 
110
115
  protected async handleSaveAnswerEvent(
@@ -51,12 +51,13 @@ import * as mixpanelInstance from '../mixpanel-service';
51
51
  import * as authInstance from '../auth';
52
52
  import * as baseInstance from './base';
53
53
  import { MIXPANEL_EVENT } from '../mixpanel-service';
54
- import * as authService from '../utils/authService/authService';
54
+ import * as authService from '../utils/authService';
55
55
  import { logger } from '../utils/logger';
56
56
  import { version } from '../../package.json';
57
57
  import { HiddenActionItemByDefaultForSearchEmbed } from './search';
58
58
  import { processTrigger } from '../utils/processTrigger';
59
59
  import { UIPassthroughEvent } from './hostEventClient/contracts';
60
+ import * as sessionInfoService from '../utils/sessionInfoService';
60
61
 
61
62
  jest.mock('../utils/processTrigger');
62
63
 
@@ -1147,6 +1148,99 @@ describe('Unit test case for ts embed', () => {
1147
1148
  });
1148
1149
  });
1149
1150
 
1151
+ describe('Trigger infoSuccess event on iframe load', () => {
1152
+ beforeAll(() => {
1153
+ jest.clearAllMocks();
1154
+ init({
1155
+ thoughtSpotHost,
1156
+ authType: AuthType.None,
1157
+ loginFailedMessage: 'Failed to Login',
1158
+ });
1159
+ });
1160
+
1161
+ const setup = async (isLoggedIn = false, overrideOrgId: number | undefined = undefined) => {
1162
+ jest.spyOn(window, 'addEventListener').mockImplementationOnce(
1163
+ (event, handler, options) => {
1164
+ handler({
1165
+ data: {
1166
+ type: 'xyz',
1167
+ },
1168
+ ports: [3000],
1169
+ source: null,
1170
+ });
1171
+ },
1172
+ );
1173
+ mockProcessTrigger.mockResolvedValueOnce({ session: 'test' });
1174
+ // resetCachedPreauthInfo();
1175
+ let mockGetPreauthInfo = null;
1176
+
1177
+ if (overrideOrgId) {
1178
+ mockGetPreauthInfo = jest.spyOn(sessionInfoService, 'getPreauthInfo').mockImplementation(jest.fn());
1179
+ }
1180
+
1181
+ const mockPreauthInfoFetch = jest.spyOn(authService, 'fetchPreauthInfoService').mockResolvedValueOnce({
1182
+ ok: true,
1183
+ headers: new Headers({ 'content-type': 'application/json' }), // Mock headers correctly
1184
+ json: async () => ({
1185
+ info: {
1186
+ configInfo: {
1187
+ mixpanelConfig: {
1188
+ devSdkKey: 'devSdkKey',
1189
+ },
1190
+ },
1191
+ userGUID: 'userGUID',
1192
+ },
1193
+ }), // Mock JSON response
1194
+ });
1195
+ const iFrame: any = document.createElement('div');
1196
+ jest.spyOn(baseInstance, 'getAuthPromise').mockResolvedValueOnce(isLoggedIn);
1197
+ const tsEmbed = new SearchEmbed(getRootEl(), {
1198
+ overrideOrgId,
1199
+ });
1200
+ iFrame.contentWindow = {
1201
+ postMessage: jest.fn(),
1202
+ };
1203
+ tsEmbed.on(EmbedEvent.CustomAction, jest.fn());
1204
+ jest.spyOn(iFrame, 'addEventListener').mockImplementationOnce(
1205
+ (event, handler, options) => {
1206
+ handler({});
1207
+ },
1208
+ );
1209
+ jest.spyOn(document, 'createElement').mockReturnValueOnce(iFrame);
1210
+ await tsEmbed.render();
1211
+
1212
+ return {
1213
+ mockPreauthInfoFetch,
1214
+ mockGetPreauthInfo,
1215
+ iFrame,
1216
+ };
1217
+ };
1218
+
1219
+ test('should call InfoSuccess Event on preauth call success', async () => {
1220
+ const {
1221
+ mockPreauthInfoFetch,
1222
+ iFrame,
1223
+ } = await setup(true);
1224
+ expect(mockPreauthInfoFetch).toHaveBeenCalledTimes(1);
1225
+
1226
+ await executeAfterWait(() => {
1227
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
1228
+ iFrame,
1229
+ HostEvent.InfoSuccess,
1230
+ 'http://tshost',
1231
+ expect.objectContaining({ info: expect.any(Object) }),
1232
+ );
1233
+ });
1234
+ });
1235
+
1236
+ test('should not call InfoSuccess Event if overrideOrgId is true', async () => {
1237
+ const {
1238
+ mockGetPreauthInfo,
1239
+ } = await setup(true, 123);
1240
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
1241
+ });
1242
+ });
1243
+
1150
1244
  describe('when thoughtSpotHost have value and authPromise return error', () => {
1151
1245
  beforeAll(() => {
1152
1246
  init({
@@ -70,6 +70,7 @@ import {
70
70
  import { AuthFailureType } from '../auth';
71
71
  import { getEmbedConfig } from './embedConfig';
72
72
  import { ERROR_MESSAGE } from '../errors';
73
+ import { getPreauthInfo } from '../utils/sessionInfoService';
73
74
  import { HostEventClient } from './hostEventClient/host-event-client';
74
75
 
75
76
  const { version } = pkgInfo;
@@ -244,6 +245,24 @@ export class TsEmbed {
244
245
  return null;
245
246
  }
246
247
 
248
+ /**
249
+ * Checks if preauth cache is enabled
250
+ * from the view config and embed config
251
+ * @returns boolean
252
+ */
253
+ private isPreAuthCacheEnabled() {
254
+ // Disable preauth cache when:
255
+ // 1. overrideOrgId is present since:
256
+ // - cached auth info would be for wrong org
257
+ // - info call response changes for each different overrideOrgId
258
+ // 2. disablePreauthCache is explicitly set to true
259
+ const isDisabled = (
260
+ this.viewConfig.overrideOrgId !== undefined
261
+ || this.embedConfig.disablePreauthCache === true
262
+ );
263
+ return !isDisabled;
264
+ }
265
+
247
266
  /**
248
267
  * fix for ts7.sep.cl
249
268
  * will be removed for ts7.oct.cl
@@ -586,6 +605,10 @@ export class TsEmbed {
586
605
  queryParams[Param.OverrideOrgId] = overrideOrgId;
587
606
  }
588
607
 
608
+ if (this.isPreAuthCacheEnabled()) {
609
+ queryParams[Param.preAuthCache] = true;
610
+ }
611
+
589
612
  queryParams[Param.OverrideNativeConsole] = true;
590
613
  queryParams[Param.ClientLogLevel] = this.embedConfig.logLevel;
591
614
 
@@ -722,6 +745,14 @@ export class TsEmbed {
722
745
  elHeight: this.iFrame.clientHeight,
723
746
  timeTookToLoad: loadTimestamp - initTimestamp,
724
747
  });
748
+ // Send info event if preauth cache is enabled
749
+ if (this.isPreAuthCacheEnabled()) {
750
+ getPreauthInfo().then((data) => {
751
+ if (data?.info) {
752
+ this.trigger(HostEvent.InfoSuccess, data);
753
+ }
754
+ });
755
+ }
725
756
  });
726
757
  this.iFrame.addEventListener('error', () => {
727
758
  nextInQueue();
@@ -56,7 +56,7 @@ describe('React Components', () => {
56
56
  ),
57
57
  ).toBe(true);
58
58
  expect(getIFrameSrc(container)).toBe(
59
- `http://${thoughtSpotHost}/?embedApp=true&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}&authType=None&blockNonEmbedFullAppAccess=true&hideAction=[%22${Action.ReportError}%22,%22editACopy%22,%22saveAsView%22,%22updateTSL%22,%22editTSL%22,%22onDeleteAnswer%22]&overrideConsoleLogs=true&clientLogLevel=ERROR&enableDataPanelV2=false&dataSourceMode=hide&useLastSelectedSources=false&isSearchEmbed=true&collapseSearchBarInitially=true&enableCustomColumnGroups=false&dataPanelCustomGroupsAccordionInitialState=EXPAND_ALL#/embed/answer`,
59
+ `http://${thoughtSpotHost}/?embedApp=true&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}&authType=None&blockNonEmbedFullAppAccess=true&hideAction=[%22${Action.ReportError}%22,%22editACopy%22,%22saveAsView%22,%22updateTSL%22,%22editTSL%22,%22onDeleteAnswer%22]&preAuthCache=true&overrideConsoleLogs=true&clientLogLevel=ERROR&enableDataPanelV2=false&dataSourceMode=hide&useLastSelectedSources=false&isSearchEmbed=true&collapseSearchBarInitially=true&enableCustomColumnGroups=false&dataPanelCustomGroupsAccordionInitialState=EXPAND_ALL#/embed/answer`,
60
60
  );
61
61
  });
62
62
 
@@ -230,7 +230,7 @@ describe('React Components', () => {
230
230
  ),
231
231
  ).toBe(true);
232
232
  expect(getIFrameSrc(container)).toBe(
233
- `http://${thoughtSpotHost}/?embedApp=true&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}&authType=None&blockNonEmbedFullAppAccess=true&hideAction=[%22${Action.ReportError}%22]&overrideConsoleLogs=true&clientLogLevel=ERROR&dataSources=[%22test%22]&searchTokenString=%5Brevenue%5D&executeSearch=true&useLastSelectedSources=false&isSearchEmbed=true#/embed/search-bar-embed`,
233
+ `http://${thoughtSpotHost}/?embedApp=true&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}&authType=None&blockNonEmbedFullAppAccess=true&hideAction=[%22${Action.ReportError}%22]&preAuthCache=true&overrideConsoleLogs=true&clientLogLevel=ERROR&dataSources=[%22test%22]&searchTokenString=%5Brevenue%5D&executeSearch=true&useLastSelectedSources=false&isSearchEmbed=true#/embed/search-bar-embed`,
234
234
  );
235
235
  });
236
236
  });
package/src/types.ts CHANGED
@@ -629,6 +629,8 @@ export interface EmbedConfig {
629
629
  * @version SDK 1.37.0 | ThoughtSpot: 10.7.0.cl
630
630
  */
631
631
  customVariablesForThirdPartyTools?: Record< string, any >;
632
+
633
+ disablePreauthCache?: boolean;
632
634
  }
633
635
 
634
636
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
@@ -2613,16 +2615,63 @@ export enum HostEvent {
2613
2615
  */
2614
2616
  getExportRequestForCurrentPinboard = 'getExportRequestForCurrentPinboard',
2615
2617
  /**
2616
- * Trigger the **Pin** action on an embedded object
2617
- * @param - Liveboard embed takes the `vizId` as a
2618
- * key. Can be left undefined when embedding Search, full app, or
2619
- * a visualization.
2618
+ * Trigger **Pin** action on an embedded object.
2619
+ * If no parameters are defined, the pin action is triggered
2620
+ * for the Answer that the user is currently on
2621
+ * and a modal opens for Liveboard selection.
2622
+ * To add an Answer or visualization to a Liveboard programmatically without
2623
+ * showing requiring additional user input via *Pin to Liveboard* modal, define
2624
+ * the following parameters:
2625
+ *
2626
+ * @param
2627
+ * `vizId`- GUID of the saved Answer or visualization to pin to a Liveboard.
2628
+ * Optional when pinning a new chart or table generated from a Search query.
2629
+ * @param
2630
+ * `liveboardID` - GUID of the Liveboard to pin an Answer. If there is no Liveboard,
2631
+ * specify the `newLiveboardName` parameter to create a new Liveboard.
2632
+ * @param
2633
+ * `tabId` - GUID of the Liveboard tab. Adds the Answer to the Liveboard tab
2634
+ * specified in the code.
2635
+ * @param
2636
+ * `newVizName` - Name string for the Answer or visualization. If defined,
2637
+ * this parameter adds a new visualization object or creates a copy of the
2638
+ * Answer or visualization specified in `vizId`.
2639
+ * Required attribute.
2640
+ * @param
2641
+ * `newLiveboardName` - Name string for the Liveboard.
2642
+ * Creates a new Liveboard object with the specified name.
2643
+ * @param
2644
+ * `newTabName` - Name of the tab. Adds a new tab Liveboard specified
2645
+ * in the code.
2646
+ *
2620
2647
  * @example
2621
2648
  * ```js
2622
- * appEmbed.trigger(HostEvent.Pin)
2649
+ * const pinResponse = await appEmbed.trigger(HostEvent.Pin, {
2650
+ * vizId: "123",
2651
+ * newVizName: "Sales by region",
2652
+ * liveboardId: "123",
2653
+ * tabId: "123"
2654
+ * });
2655
+ * ```
2656
+ * @example
2657
+ * ```js
2658
+ * const pinResponse = await appEmbed.trigger(HostEvent.Pin, {
2659
+ * newVizName: "Total sales of Jackets",
2660
+ * liveboardId: "123"
2661
+ * });
2623
2662
  * ```
2663
+ *
2664
+ * @example
2624
2665
  * ```js
2625
- * searchEmbed.trigger(HostEvent.Pin)
2666
+ * const pinResponse = await searchEmbed.trigger(HostEvent.Pin, {
2667
+ * newVizName: "Sales by state",
2668
+ * newLiveboardName: "Sales",
2669
+ * newTabName: "Products"
2670
+ * });
2671
+ * ```
2672
+ * @example
2673
+ * ```js
2674
+ * appEmbed.trigger(HostEvent.Pin)
2626
2675
  * ```
2627
2676
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1.sw
2628
2677
  */
@@ -3269,7 +3318,33 @@ export enum HostEvent {
3269
3318
  */
3270
3319
  UpdatePersonalisedView = 'UpdatePersonalisedView',
3271
3320
  /**
3272
- * Triggers the action to get the current view of the Liveboard.
3321
+ * @hidden
3322
+ * Notify when info call is completed successfully
3323
+ * ```js
3324
+ * liveboardEmbed.trigger(HostEvent.InfoSuccess, data);
3325
+ *```
3326
+ * @version SDK: 1.36.0 | Thoughtspot: 10.6.0.cl
3327
+ */
3328
+ InfoSuccess = 'InfoSuccess',
3329
+ /**
3330
+ * Trigger the save action for an Answer.
3331
+ * To programmatically save an answer without opening the
3332
+ * *Describe your Answer* modal, define the `name` and `description`
3333
+ * properties.
3334
+ * If no parameters are specified, the save action is
3335
+ * triggered with a modal to prompt users to
3336
+ * add a name and description for the Answer.
3337
+ * @param - optional attributes to set Answer properties.
3338
+ * `name` - Name string for the Answer.
3339
+ * `description` - Description text for the Answer.
3340
+ *
3341
+ * @example
3342
+ * ```js
3343
+ * const saveAnswerResponse = await searchEmbed.trigger(HostEvent.SaveAnswer, {
3344
+ * name: "Sales by states",
3345
+ * description: "Total sales by states in MidWest"
3346
+ * });
3347
+ * ```
3273
3348
  * @version SDK: 1.36.0 | ThoughtSpot: 10.6.0.cl
3274
3349
  */
3275
3350
  SaveAnswer = 'saveAnswer',
@@ -3427,6 +3502,7 @@ export enum Param {
3427
3502
  OauthPollingInterval = 'oAuthPollingInterval',
3428
3503
  IsForceRedirect = 'isForceRedirect',
3429
3504
  DataSourceId = 'dataSourceId',
3505
+ preAuthCache = 'preAuthCache',
3430
3506
  ShowSpotterLimitations = 'showSpotterLimitations',
3431
3507
  }
3432
3508