@thoughtspot/visual-embed-sdk 1.32.3 → 1.32.6

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 (158) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/embed/app.d.ts +42 -0
  3. package/cjs/src/embed/app.d.ts.map +1 -1
  4. package/cjs/src/embed/app.js +4 -1
  5. package/cjs/src/embed/app.js.map +1 -1
  6. package/cjs/src/embed/app.spec.js +30 -0
  7. package/cjs/src/embed/app.spec.js.map +1 -1
  8. package/cjs/src/embed/base.d.ts +1 -1
  9. package/cjs/src/embed/base.d.ts.map +1 -1
  10. package/cjs/src/embed/base.js +6 -7
  11. package/cjs/src/embed/base.js.map +1 -1
  12. package/cjs/src/embed/embed.spec.js +0 -19
  13. package/cjs/src/embed/embed.spec.js.map +1 -1
  14. package/cjs/src/embed/liveboard.d.ts +42 -0
  15. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  16. package/cjs/src/embed/liveboard.js +4 -1
  17. package/cjs/src/embed/liveboard.js.map +1 -1
  18. package/cjs/src/embed/liveboard.spec.js +33 -0
  19. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  20. package/cjs/src/embed/ts-embed.d.ts +0 -1
  21. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  22. package/cjs/src/embed/ts-embed.js +3 -9
  23. package/cjs/src/embed/ts-embed.js.map +1 -1
  24. package/cjs/src/embed/ts-embed.spec.js +0 -9
  25. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  26. package/cjs/src/types.d.ts +62 -16
  27. package/cjs/src/types.d.ts.map +1 -1
  28. package/cjs/src/types.js +55 -7
  29. package/cjs/src/types.js.map +1 -1
  30. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  31. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  32. package/cjs/src/utils/graphql/answerService/answer-queries.js +9 -2
  33. package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  34. package/cjs/src/utils/graphql/answerService/answerService.d.ts +15 -0
  35. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  36. package/cjs/src/utils/graphql/answerService/answerService.js +25 -0
  37. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  38. package/cjs/src/utils/graphql/answerService/answerService.spec.js +35 -0
  39. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  40. package/cjs/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  41. package/cjs/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  42. package/cjs/src/utils/graphql/graphql-request.spec.js +36 -0
  43. package/cjs/src/utils/graphql/graphql-request.spec.js.map +1 -0
  44. package/cjs/src/utils/processData.js +2 -2
  45. package/cjs/src/utils/processData.js.map +1 -1
  46. package/cjs/src/utils/processData.spec.js +14 -0
  47. package/cjs/src/utils/processData.spec.js.map +1 -1
  48. package/cjs/src/utils/processTrigger.d.ts +1 -0
  49. package/cjs/src/utils/processTrigger.d.ts.map +1 -1
  50. package/cjs/src/utils/processTrigger.js +3 -3
  51. package/cjs/src/utils/processTrigger.js.map +1 -1
  52. package/cjs/src/utils/processTrigger.spec.js +10 -0
  53. package/cjs/src/utils/processTrigger.spec.js.map +1 -1
  54. package/cjs/src/utils.d.ts.map +1 -1
  55. package/cjs/src/utils.js +1 -5
  56. package/cjs/src/utils.js.map +1 -1
  57. package/dist/src/embed/app.d.ts +42 -0
  58. package/dist/src/embed/app.d.ts.map +1 -1
  59. package/dist/src/embed/base.d.ts +1 -1
  60. package/dist/src/embed/base.d.ts.map +1 -1
  61. package/dist/src/embed/liveboard.d.ts +42 -0
  62. package/dist/src/embed/liveboard.d.ts.map +1 -1
  63. package/dist/src/embed/ts-embed.d.ts +0 -1
  64. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  65. package/dist/src/types.d.ts +62 -16
  66. package/dist/src/types.d.ts.map +1 -1
  67. package/dist/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  68. package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  69. package/dist/src/utils/graphql/answerService/answerService.d.ts +15 -0
  70. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  71. package/dist/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  72. package/dist/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  73. package/dist/src/utils/processTrigger.d.ts +1 -0
  74. package/dist/src/utils/processTrigger.d.ts.map +1 -1
  75. package/dist/src/utils.d.ts.map +1 -1
  76. package/dist/tsembed-react.es.js +103 -27
  77. package/dist/tsembed-react.js +103 -27
  78. package/dist/tsembed.es.js +109 -34
  79. package/dist/tsembed.js +109 -34
  80. package/dist/visual-embed-sdk-react-full.d.ts +162 -18
  81. package/dist/visual-embed-sdk-react.d.ts +162 -18
  82. package/dist/visual-embed-sdk.d.ts +162 -18
  83. package/lib/package.json +1 -1
  84. package/lib/src/embed/app.d.ts +42 -0
  85. package/lib/src/embed/app.d.ts.map +1 -1
  86. package/lib/src/embed/app.js +4 -1
  87. package/lib/src/embed/app.js.map +1 -1
  88. package/lib/src/embed/app.spec.js +30 -0
  89. package/lib/src/embed/app.spec.js.map +1 -1
  90. package/lib/src/embed/base.d.ts +1 -1
  91. package/lib/src/embed/base.d.ts.map +1 -1
  92. package/lib/src/embed/base.js +6 -7
  93. package/lib/src/embed/base.js.map +1 -1
  94. package/lib/src/embed/embed.spec.js +0 -19
  95. package/lib/src/embed/embed.spec.js.map +1 -1
  96. package/lib/src/embed/liveboard.d.ts +42 -0
  97. package/lib/src/embed/liveboard.d.ts.map +1 -1
  98. package/lib/src/embed/liveboard.js +4 -1
  99. package/lib/src/embed/liveboard.js.map +1 -1
  100. package/lib/src/embed/liveboard.spec.js +33 -0
  101. package/lib/src/embed/liveboard.spec.js.map +1 -1
  102. package/lib/src/embed/ts-embed.d.ts +0 -1
  103. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  104. package/lib/src/embed/ts-embed.js +3 -9
  105. package/lib/src/embed/ts-embed.js.map +1 -1
  106. package/lib/src/embed/ts-embed.spec.js +0 -9
  107. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  108. package/lib/src/types.d.ts +62 -16
  109. package/lib/src/types.d.ts.map +1 -1
  110. package/lib/src/types.js +55 -7
  111. package/lib/src/types.js.map +1 -1
  112. package/lib/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  113. package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  114. package/lib/src/utils/graphql/answerService/answer-queries.js +8 -1
  115. package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  116. package/lib/src/utils/graphql/answerService/answerService.d.ts +15 -0
  117. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  118. package/lib/src/utils/graphql/answerService/answerService.js +25 -0
  119. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  120. package/lib/src/utils/graphql/answerService/answerService.spec.js +36 -1
  121. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  122. package/lib/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  123. package/lib/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  124. package/lib/src/utils/graphql/graphql-request.spec.js +33 -0
  125. package/lib/src/utils/graphql/graphql-request.spec.js.map +1 -0
  126. package/lib/src/utils/processData.js +2 -2
  127. package/lib/src/utils/processData.js.map +1 -1
  128. package/lib/src/utils/processData.spec.js +14 -0
  129. package/lib/src/utils/processData.spec.js.map +1 -1
  130. package/lib/src/utils/processTrigger.d.ts +1 -0
  131. package/lib/src/utils/processTrigger.d.ts.map +1 -1
  132. package/lib/src/utils/processTrigger.js +1 -1
  133. package/lib/src/utils/processTrigger.js.map +1 -1
  134. package/lib/src/utils/processTrigger.spec.js +10 -0
  135. package/lib/src/utils/processTrigger.spec.js.map +1 -1
  136. package/lib/src/utils.d.ts.map +1 -1
  137. package/lib/src/utils.js +1 -5
  138. package/lib/src/utils.js.map +1 -1
  139. package/lib/src/visual-embed-sdk.d.ts +162 -18
  140. package/package.json +1 -1
  141. package/src/embed/app.spec.ts +45 -0
  142. package/src/embed/app.ts +48 -0
  143. package/src/embed/base.ts +1 -2
  144. package/src/embed/embed.spec.ts +0 -22
  145. package/src/embed/liveboard.spec.ts +48 -0
  146. package/src/embed/liveboard.ts +48 -0
  147. package/src/embed/ts-embed.spec.ts +0 -11
  148. package/src/embed/ts-embed.ts +1 -9
  149. package/src/types.ts +62 -15
  150. package/src/utils/graphql/answerService/answer-queries.ts +9 -1
  151. package/src/utils/graphql/answerService/answerService.spec.ts +45 -0
  152. package/src/utils/graphql/answerService/answerService.ts +35 -0
  153. package/src/utils/graphql/graphql-request.spec.ts +38 -0
  154. package/src/utils/processData.spec.ts +16 -0
  155. package/src/utils/processData.ts +2 -2
  156. package/src/utils/processTrigger.spec.ts +19 -0
  157. package/src/utils/processTrigger.ts +1 -1
  158. package/src/utils.ts +0 -5
@@ -241,6 +241,54 @@ describe('Liveboard/viz embed tests', () => {
241
241
  });
242
242
  });
243
243
 
244
+ test('Should add isLiveboardCompactHeaderEnabled flag to the iframe src', async () => {
245
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
246
+ ...defaultViewConfig,
247
+ liveboardId,
248
+ isLiveboardCompactHeaderEnabled: false,
249
+ } as LiveboardViewConfig);
250
+
251
+ liveboardEmbed.render();
252
+ await executeAfterWait(() => {
253
+ expectUrlMatchesWithParams(
254
+ getIFrameSrc(),
255
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardHeaderV2Enabled=false${prefixParams}#/embed/viz/${liveboardId}`,
256
+ );
257
+ });
258
+ });
259
+
260
+ test('Should add showLiveboardReverifyBanner flag to the iframe src', async () => {
261
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
262
+ ...defaultViewConfig,
263
+ liveboardId,
264
+ showLiveboardReverifyBanner: false,
265
+ } as LiveboardViewConfig);
266
+
267
+ liveboardEmbed.render();
268
+ await executeAfterWait(() => {
269
+ expectUrlMatchesWithParams(
270
+ getIFrameSrc(),
271
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showLiveboardReverifyBanner=false${prefixParams}#/embed/viz/${liveboardId}`,
272
+ );
273
+ });
274
+ });
275
+
276
+ test('Should add showLiveboardVerifiedBadge flag to the iframe src', async () => {
277
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
278
+ ...defaultViewConfig,
279
+ liveboardId,
280
+ showLiveboardVerifiedBadge: false,
281
+ } as LiveboardViewConfig);
282
+
283
+ liveboardEmbed.render();
284
+ await executeAfterWait(() => {
285
+ expectUrlMatchesWithParams(
286
+ getIFrameSrc(),
287
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&showLiveboardVerifiedBadge=false${prefixParams}#/embed/viz/${liveboardId}`,
288
+ );
289
+ });
290
+ });
291
+
244
292
  test('should not append runtime filters in URL if excludeRuntimeFiltersfromURL is true', async () => {
245
293
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
246
294
  ...defaultViewConfig,
@@ -284,6 +284,48 @@ export interface LiveboardViewConfig
284
284
  * @version SDK: 1.32.0 | ThoughtSpot: 10.0.0.cl
285
285
  */
286
286
  showPreviewLoader?: boolean;
287
+ /**
288
+ * This flag is used to enable the compact header in liveboard
289
+ * @type {boolean}
290
+ * @default false
291
+ * @version SDK: 1.35.0 | ThoughtSpot:10.3.0.cl
292
+ * @example
293
+ * ```js
294
+ * const embed = new LiveboardEmbed('#embed-container', {
295
+ * ... // other options
296
+ * isLiveboardCompactHeaderEnabled: true,
297
+ * })
298
+ * ```
299
+ */
300
+ isLiveboardCompactHeaderEnabled?: boolean;
301
+ /**
302
+ * This flag is used to show/hide verified Icon in liveboard compact header
303
+ * @type {boolean}
304
+ * @default true
305
+ * @version SDK: 1.35.0 | ThoughtSpot:10.4.0.cl
306
+ * @example
307
+ * ```js
308
+ * const embed = new LiveboardEmbed('#embed-container', {
309
+ * ... // other options
310
+ * showLiveboardVerifiedBadge: true,
311
+ * })
312
+ * ```
313
+ */
314
+ showLiveboardVerifiedBadge?: boolean;
315
+ /**
316
+ * This flag is used to show/hide re-verify banner in liveboard compact header
317
+ * @type {boolean}
318
+ * @default true
319
+ * @version SDK: 1.35.0 | ThoughtSpot:10.4.0.cl
320
+ * @example
321
+ * ```js
322
+ * const embed = new LiveboardEmbed('#embed-container', {
323
+ * ... // other options
324
+ * showLiveboardReverifyBanner: true,
325
+ * })
326
+ * ```
327
+ */
328
+ showLiveboardReverifyBanner?: boolean;
287
329
  }
288
330
 
289
331
  /**
@@ -338,6 +380,9 @@ export class LiveboardEmbed extends V1Embed {
338
380
  showLiveboardDescription,
339
381
  showLiveboardTitle,
340
382
  isLiveboardHeaderSticky = true,
383
+ isLiveboardCompactHeaderEnabled = false,
384
+ showLiveboardVerifiedBadge = true,
385
+ showLiveboardReverifyBanner = true,
341
386
  enableAskSage,
342
387
  enable2ColumnLayout,
343
388
  dataPanelV2 = true,
@@ -388,6 +433,9 @@ export class LiveboardEmbed extends V1Embed {
388
433
  }
389
434
 
390
435
  params[Param.LiveboardHeaderSticky] = isLiveboardHeaderSticky;
436
+ params[Param.LiveboardHeaderV2] = isLiveboardCompactHeaderEnabled;
437
+ params[Param.ShowLiveboardVerifiedBadge] = showLiveboardVerifiedBadge;
438
+ params[Param.ShowLiveboardReverifyBanner] = showLiveboardReverifyBanner;
391
439
 
392
440
  params[Param.DataPanelV2Enabled] = dataPanelV2;
393
441
  const queryParams = getQueryParamString(params, true);
@@ -56,7 +56,6 @@ beforeAll(() => {
56
56
  const customisations = {
57
57
  style: {
58
58
  customCSS: {},
59
- customCSSUrl: 'http://localhost:3000',
60
59
  },
61
60
  content: {},
62
61
  };
@@ -64,7 +63,6 @@ const customisations = {
64
63
  const customisationsView = {
65
64
  style: {
66
65
  customCSS: {},
67
- customCSSUrl: 'http://localhost:8000',
68
66
  },
69
67
  content: {
70
68
  strings: {
@@ -95,7 +93,6 @@ describe('Unit test case for ts embed', () => {
95
93
  init({
96
94
  thoughtSpotHost: 'tshost',
97
95
  customizations: customisations,
98
- customCssUrl: 'http://localhost:5000',
99
96
  authType: AuthType.TrustedAuthTokenCookieless,
100
97
  getAuthToken: () => Promise.resolve('test_auth_token2'),
101
98
  });
@@ -136,7 +133,6 @@ describe('Unit test case for ts embed', () => {
136
133
  thoughtSpotHost: 'tshost',
137
134
  authType: AuthType.None,
138
135
  customizations: customisations,
139
- customCssUrl: 'http://localhost:5000',
140
136
  });
141
137
  });
142
138
 
@@ -199,9 +195,6 @@ describe('Unit test case for ts embed', () => {
199
195
  reorderedHomepageModules: [],
200
196
  },
201
197
  });
202
- expect(getIFrameSrc()).toContain(
203
- `customCssUrl=${customisationsView.style.customCSSUrl}`,
204
- );
205
198
  });
206
199
 
207
200
  test('hide home page modules from view Config should be part of app_init payload', async () => {
@@ -601,7 +594,6 @@ describe('Unit test case for ts embed', () => {
601
594
  init({
602
595
  thoughtSpotHost: 'tshost',
603
596
  customizations: customisations,
604
- customCssUrl: 'http://localhost:5000',
605
597
  authType: AuthType.TrustedAuthTokenCookieless,
606
598
  getAuthToken: () => Promise.resolve('test_auth_token1'),
607
599
  });
@@ -655,7 +647,6 @@ describe('Unit test case for ts embed', () => {
655
647
  init({
656
648
  thoughtSpotHost: 'tshost',
657
649
  customizations: customisations,
658
- customCssUrl: 'http://localhost:5000',
659
650
  authType: AuthType.TrustedAuthTokenCookieless,
660
651
  getAuthToken: () => Promise.reject(),
661
652
  });
@@ -790,7 +781,6 @@ describe('Unit test case for ts embed', () => {
790
781
  init({
791
782
  thoughtSpotHost: 'tshost',
792
783
  customizations: customisations,
793
- customCssUrl: 'http://localhost:5000',
794
784
  authType: AuthType.TrustedAuthToken,
795
785
  username: 'tsadmin',
796
786
  getAuthToken: () => Promise.resolve('test_auth_token3'),
@@ -819,7 +809,6 @@ describe('Unit test case for ts embed', () => {
819
809
  init({
820
810
  thoughtSpotHost: 'tshost',
821
811
  customizations: customisations,
822
- customCssUrl: 'http://localhost:5000',
823
812
  authType: AuthType.TrustedAuthToken,
824
813
  username: 'tsadmin',
825
814
  getAuthToken: () => Promise.resolve('test_auth_token4'),
@@ -454,13 +454,6 @@ export class TsEmbed {
454
454
  return queryParams;
455
455
  }
456
456
 
457
- // TODO remove embedConfig.customCssUrl
458
- const cssUrlParam = customizations?.style?.customCSSUrl || this.embedConfig.customCssUrl;
459
-
460
- if (cssUrlParam) {
461
- queryParams[Param.CustomCSSUrl] = cssUrlParam;
462
- }
463
-
464
457
  if (disabledActions?.length) {
465
458
  queryParams[Param.DisableActions] = disabledActions;
466
459
  }
@@ -1221,7 +1214,7 @@ export class TsEmbed {
1221
1214
  * @version SDK: 1.25.0 / ThoughtSpot 9.10.0
1222
1215
  */
1223
1216
  public async getAnswerService(vizId?: string): Promise<AnswerService> {
1224
- const { session } = await this.trigger(HostEvent.GetAnswerSession, vizId);
1217
+ const { session } = await this.trigger(HostEvent.GetAnswerSession, vizId ? { vizId } : {});
1225
1218
 
1226
1219
  return new AnswerService(session, null, this.embedConfig.thoughtSpotHost);
1227
1220
  }
@@ -1298,7 +1291,6 @@ export class V1Embed extends TsEmbed {
1298
1291
 
1299
1292
  /**
1300
1293
  * Only for testing purposes.
1301
- *
1302
1294
  * @hidden
1303
1295
  */
1304
1296
  // eslint-disable-next-line camelcase
package/src/types.ts CHANGED
@@ -255,7 +255,6 @@ export interface customCssInterface {
255
255
  * Styles within the {@link CustomisationsInterface}.
256
256
  */
257
257
  export interface CustomStyles {
258
- customCSSUrl?: string;
259
258
  customCSS?: customCssInterface;
260
259
  }
261
260
 
@@ -449,13 +448,6 @@ export interface EmbedConfig {
449
448
  */
450
449
  queueMultiRenders?: boolean;
451
450
 
452
- /**
453
- * Dynamic CSS URL to be injected in the loaded application.
454
- * You would also need to set `style-src` in the CSP settings.
455
- * @version SDK: 1.6.0 | ThoughtSpot: ts8.nov.cl, 8.4.1.sw
456
- * @default ''
457
- */
458
- customCssUrl?: string;
459
451
  /**
460
452
  * [AuthServer|Basic] Detect if third-party party cookies are enabled by doing an
461
453
  * additional call. This is slower and should be avoided. Listen to the
@@ -589,6 +581,13 @@ export interface EmbedConfig {
589
581
  * @version SDK: 1.28.5 | Thoughtspot: *
590
582
  */
591
583
  disableTokenVerification?: boolean;
584
+
585
+ /**
586
+ * This flag is used to disable showing the login failure page in the embedded app.
587
+ *
588
+ * @version SDK 1.32.3 | Thoughtspot: *
589
+ */
590
+ disableLoginFailurePage?: boolean;
592
591
  }
593
592
 
594
593
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
@@ -2134,20 +2133,57 @@ export enum EmbedEvent {
2134
2133
  */
2135
2134
  Rename = 'rename',
2136
2135
  /**
2137
- * Emitted when user wants to intercept the search execution
2136
+ * Emitted if the user wants to intercept the search execution
2137
+ * and implement logic to decide whether to run the search or not
2138
2138
  *
2139
- * Set IsOnBeforeGetVizDataInterceptEnabled : true to use
2140
- * this embed event
2139
+ * Prerequisite: Set isOnBeforeGetVizDataInterceptEnabled : true
2140
+ * for this embed event to get emitted.
2141
+ *
2142
+ * Parameter: payload
2143
+ * Parameter: responder
2144
+ * Contains elements that lets developers define whether ThoughtSpot
2145
+ * will run the search or not, and if not, which error message to provide.
2146
+ * execute: When execute returns true, the search will be run.
2147
+ * When execute returns false, the search will not be executed.
2148
+ * error: Developers can customize the user facing message when execute is
2149
+ * set to false using the error parameter in responder
2141
2150
  *
2142
2151
  *```js
2143
- * searchEmbed.on(EmbedEvent.OnBeforeGetVizDataIntercept,
2152
+ * .on(EmbedEvent.OnBeforeGetVizDataIntercept,
2144
2153
  * (payload, responder) => {
2145
2154
  * responder({
2146
2155
  * data: {
2147
- * execute: true,
2148
- * }})
2156
+ * execute:false,
2157
+ * error: {
2158
+ * //Provide a custom error message to explain to your end user
2159
+ * //why their search did not run
2160
+ * errorText: "This search query cannot be run.
2161
+ * Please contact your administrator for more details."
2162
+ * }
2163
+ * }})
2164
+ * })
2165
+ * ```
2166
+ *
2167
+ *```js
2168
+ * .on(EmbedEvent.OnBeforeGetVizDataIntercept,
2169
+ * (payload, responder) => {
2170
+ * const query = payload.data.data.answer.search_query
2171
+ * responder({
2172
+ * data: {
2173
+ * // returns true as long as the query does not include
2174
+ * // both the 'sales' AND the 'county' column
2175
+ * execute: !(query.includes("sales")&&query.includes("county")),
2176
+ * error: {
2177
+ * //Provide a custom error message to explain to your end user
2178
+ * // why their search did not run, and which searches are accepted by your custom logic.
2179
+ * errorText: "You can't use this query :" + query + ".
2180
+ * The 'sales' measures can never be used at the 'county' level.
2181
+ * Please try another measure, or remove 'county' from your search."
2182
+ * }
2183
+ * }})
2149
2184
  * })
2150
2185
  *```
2186
+ *
2151
2187
  * @version SDK : 1.29.0 | Thoughtspot : 10.2.0.cl
2152
2188
  */
2153
2189
  OnBeforeGetVizDataIntercept = 'onBeforeGetVizDataIntercept',
@@ -2268,6 +2304,15 @@ export enum HostEvent {
2268
2304
  * @hidden
2269
2305
  */
2270
2306
  Reload = 'reload',
2307
+ /**
2308
+ * Get current iframe src
2309
+ * @example
2310
+ * ```js
2311
+ * const frameUrl = AppEmbed.trigger(HostEvent.GetIframeUrl)
2312
+ * ```
2313
+ * @version SDK: 1.35.0 | Thoughtspot: 10.4.0.cl
2314
+ */
2315
+ GetIframeUrl = 'GetIframeUrl',
2271
2316
  /**
2272
2317
  * Display specific visualizations on a Liveboard.
2273
2318
  * @param - An array of GUIDs of the visualization to show. The visualization IDs not passed
@@ -3080,7 +3125,6 @@ export enum Param {
3080
3125
  ViewPortHeight = 'viewPortHeight',
3081
3126
  ViewPortWidth = 'viewPortWidth',
3082
3127
  VisibleActions = 'visibleAction',
3083
- CustomCSSUrl = 'customCssUrl',
3084
3128
  DisableLoginRedirect = 'disableLoginRedirect',
3085
3129
  visibleVizs = 'pinboardVisibleVizs',
3086
3130
  LiveboardV2Enabled = 'isPinboardV2Enabled',
@@ -3139,6 +3183,9 @@ export enum Param {
3139
3183
  FocusSearchBarOnRender = 'focusSearchBarOnRender',
3140
3184
  DisableRedirectionLinksInNewTab = 'disableRedirectionLinksInNewTab',
3141
3185
  HomePageSearchBarMode = 'homePageSearchBarMode',
3186
+ ShowLiveboardVerifiedBadge = 'showLiveboardVerifiedBadge',
3187
+ ShowLiveboardReverifyBanner = 'showLiveboardReverifyBanner',
3188
+ LiveboardHeaderV2 = 'isLiveboardHeaderV2Enabled',
3142
3189
  }
3143
3190
 
3144
3191
  /**
@@ -101,7 +101,6 @@ export const getAnswer = `
101
101
  isDiscoverable
102
102
  isHidden
103
103
  modifiedAt
104
- tags
105
104
  }
106
105
  visualizations {
107
106
  ... on TableViz {
@@ -164,3 +163,12 @@ export const addVizToLiveboard = `
164
163
  }
165
164
  }
166
165
  `;
166
+
167
+ export const getSQLQuery = `
168
+ mutation GetSQLQuery($session: BachSessionIdInput!) {
169
+ Answer__getQuery(session: $session) {
170
+ ${bachSessionId}
171
+ sql
172
+ }
173
+ }
174
+ `;
@@ -3,7 +3,9 @@ import { AuthType, RuntimeFilterOp, VizPoint } from '../../../types';
3
3
  import { AnswerService } from './answerService';
4
4
  import {
5
5
  getAnswerData, removeColumns, addFilter, addColumns,
6
+ getSQLQuery,
6
7
  } from './answer-queries';
8
+ import * as queries from './answer-queries';
7
9
  import * as authTokenInstance from '../../../authToken';
8
10
  import * as tokenizedFetch from '../../../tokenizedFetch';
9
11
  import * as embedConfigInstance from '../../../embed/embedConfig';
@@ -34,6 +36,23 @@ describe('Answer service tests', () => {
34
36
  beforeEach(() => {
35
37
  fetchMock.resetMocks();
36
38
  });
39
+
40
+ test('should call executeQuery with correct parameters to add columns', async () => {
41
+ const service = createAnswerService();
42
+ const executeQuerySpy = jest.spyOn(service, 'executeQuery').mockResolvedValue({
43
+ id: { genNo: 2 },
44
+
45
+ });
46
+
47
+ const columnIds = ['col1', 'col2'];
48
+ const result = await service.addColumns(columnIds);
49
+
50
+ expect(executeQuerySpy).toHaveBeenCalledWith(queries.addColumns, {
51
+ columns: columnIds.map((colId) => ({ logicalColumnId: colId })),
52
+ });
53
+ expect(result.id.genNo).toBe(2);
54
+ });
55
+
37
56
  test('Execute query should execute the supplied graphql on the session', async () => {
38
57
  fetchMock.mockResponseOnce(JSON.stringify({
39
58
  data: {
@@ -404,4 +423,30 @@ describe('Answer service tests', () => {
404
423
  }),
405
424
  );
406
425
  });
426
+
427
+ test('Get SQL query should call the right API', async () => {
428
+ fetchMock.mockResponseOnce(JSON.stringify({
429
+ data: {
430
+ Answer__getQuery: {
431
+ id: {},
432
+ sql: 'SELECT * FROM table',
433
+ },
434
+ },
435
+ }));
436
+ const answerService = createAnswerService();
437
+ const sql = await answerService.getSQLQuery();
438
+ expect(fetchMock).toHaveBeenCalledWith(
439
+ 'https://tshost/prism/?op=GetSQLQuery',
440
+ expect.objectContaining({
441
+ body: JSON.stringify({
442
+ operationName: 'GetSQLQuery',
443
+ query: getSQLQuery,
444
+ variables: {
445
+ session: defaultSession,
446
+ },
447
+ }),
448
+ }),
449
+ );
450
+ expect(sql).toBe('SELECT * FROM table');
451
+ });
407
452
  });
@@ -173,6 +173,14 @@ export class AnswerService {
173
173
  );
174
174
  }
175
175
 
176
+ public async getSQLQuery(): Promise<string> {
177
+ const { sql } = await this.executeQuery(
178
+ queries.getSQLQuery,
179
+ {},
180
+ );
181
+ return sql;
182
+ }
183
+
176
184
  /**
177
185
  * Fetch data from the answer.
178
186
  * @param offset
@@ -214,6 +222,25 @@ export class AnswerService {
214
222
  });
215
223
  }
216
224
 
225
+ /**
226
+ * Fetch the data for the answer as a PNG blob. This might be
227
+ * quicker for larger data.
228
+ * @param userLocale
229
+ * @param omitBackground Omit the background in the PNG
230
+ * @param deviceScaleFactor The scale factor for the PNG
231
+ * @return Response
232
+ */
233
+ public async fetchPNGBlob(userLocale = 'en-us', includeInfo = false, omitBackground = false, deviceScaleFactor = 2): Promise<Response> {
234
+ const fetchUrl = this.getFetchPNGBlobUrl(
235
+ userLocale,
236
+ omitBackground,
237
+ deviceScaleFactor,
238
+ );
239
+ return tokenizedFetch(fetchUrl, {
240
+ credentials: 'include',
241
+ });
242
+ }
243
+
217
244
  /**
218
245
  * Just get the internal URL for this answer's data
219
246
  * as a CSV blob.
@@ -225,6 +252,14 @@ export class AnswerService {
225
252
  return `${this.thoughtSpotHost}/prism/download/answer/csv?sessionId=${this.session.sessionId}&genNo=${this.session.genNo}&userLocale=${userLocale}&exportFileName=data&hideCsvHeader=${!includeInfo}`;
226
253
  }
227
254
 
255
+ /**
256
+ * Just get the internal URL for this answer's data
257
+ * as a PNG blob.
258
+ */
259
+ public getFetchPNGBlobUrl(userLocale = 'en-us', omitBackground = false, deviceScaleFactor = 2): string {
260
+ return `${this.thoughtSpotHost}/prism/download/answer/png?sessionId=${this.session.sessionId}&deviceScaleFactor=${deviceScaleFactor}&omitBackground=${omitBackground}&genNo=${this.session.genNo}&userLocale=${userLocale}&exportFileName=data`;
261
+ }
262
+
228
263
  /**
229
264
  * Get underlying data given a point and the output column names.
230
265
  * In case of a context menu action, the selectedPoints are
@@ -0,0 +1,38 @@
1
+ import 'jest-fetch-mock';
2
+ import { getSourceDetail } from './sourceService';
3
+ import * as tokenizedFetchUtil from '../../tokenizedFetch';
4
+ import { graphqlQuery } from './graphql-request';
5
+
6
+ const getSourceDetailQuery = `
7
+ query GetSourceDetail($ids: [GUID!]!) {
8
+ getSourceDetailById(ids: $ids, type: LOGICAL_TABLE) {
9
+ id
10
+ name
11
+ }
12
+ }
13
+ `;
14
+
15
+ const thoughtSpotHost = 'TSHOST';
16
+
17
+ describe('graphQl tests', () => {
18
+ test('should call tokenizedFetch with correct parameters when graphqlQuery is called', async () => {
19
+ jest.spyOn(tokenizedFetchUtil, 'tokenizedFetch');
20
+
21
+ const details = await graphqlQuery({
22
+ query: getSourceDetailQuery,
23
+ variables: {
24
+ ids: [2],
25
+ },
26
+ thoughtSpotHost,
27
+ });
28
+
29
+ expect(tokenizedFetchUtil.tokenizedFetch).toBeCalledWith('TSHOST/prism/?op=GetSourceDetail', {
30
+ body: '{"operationName":"GetSourceDetail","query":"\\n query GetSourceDetail($ids: [GUID!]!) {\\n getSourceDetailById(ids: $ids, type: LOGICAL_TABLE) {\\n id\\n name\\n }\\n } \\n","variables":{"ids":[2]}}',
31
+ credentials: 'include',
32
+ headers: {
33
+ accept: '*/*', 'accept-language': 'en-us', 'content-type': 'application/json;charset=UTF-8', 'x-requested-by': 'ThoughtSpot',
34
+ },
35
+ method: 'POST',
36
+ });
37
+ });
38
+ });
@@ -1,3 +1,4 @@
1
+ import { disable } from 'mixpanel-browser';
1
2
  import * as processDataInstance from './processData';
2
3
  import * as answerServiceInstance from './graphql/answerService/answerService';
3
4
  import * as auth from '../auth';
@@ -171,4 +172,19 @@ describe('Unit test for process data', () => {
171
172
  expect(el.innerHTML).toBe('Hello');
172
173
  expect(embedConfigInstance.getEmbedConfig().autoLogin).toBe(false);
173
174
  });
175
+
176
+ test('process authFailure AuthType=None', () => {
177
+ const e = { type: EmbedEvent.AuthFailure };
178
+ jest.spyOn(embedConfigInstance, 'getEmbedConfig').mockReturnValue({
179
+ loginFailedMessage: 'Hello',
180
+ authType: AuthType.EmbeddedSSO,
181
+ disableLoginFailurePage: true,
182
+ });
183
+ const el: any = {};
184
+ expect(processDataInstance.processEventData(e.type, e, '', el)).toEqual({
185
+ type: e.type,
186
+ });
187
+ expect(base.notifyAuthFailure).not.toBeCalled();
188
+ expect(el.innerHTML).not.toBe('Hello');
189
+ });
174
190
  });
@@ -78,8 +78,8 @@ function processNoCookieAccess(e: any, containerEl: Element) {
78
78
  * @param containerEl
79
79
  */
80
80
  export function processAuthFailure(e: any, containerEl: Element) {
81
- const { loginFailedMessage, authType } = getEmbedConfig();
82
- if (authType !== AuthType.None) {
81
+ const { loginFailedMessage, authType, disableLoginFailurePage } = getEmbedConfig();
82
+ if (authType !== AuthType.None && !disableLoginFailurePage) {
83
83
  // eslint-disable-next-line no-param-reassign
84
84
  containerEl.innerHTML = loginFailedMessage;
85
85
  notifyAuthFailure(AuthFailureType.OTHER);
@@ -67,4 +67,23 @@ describe('Unit test for processTrigger', () => {
67
67
  expect(messageChannelMock.port1.close).toBeCalled();
68
68
  expect(triggerPromise).rejects.toEqual(res.data.error);
69
69
  });
70
+
71
+ test('should close channel.port1 when timeout exceeds TRIGGER_TIMEOUT', async () => {
72
+ const messageType = HostEvent.Search;
73
+ const thoughtSpotHost = 'http://localhost:3000';
74
+ const data = {};
75
+ mockMessageChannel();
76
+
77
+ const triggerPromise = _processTriggerInstance.processTrigger(
78
+ iFrame,
79
+ messageType,
80
+ thoughtSpotHost,
81
+ data,
82
+ );
83
+
84
+ jest.advanceTimersByTime(_processTriggerInstance.TRIGGER_TIMEOUT);
85
+
86
+ expect(messageChannelMock.port1.close).toBeCalled();
87
+ await expect(triggerPromise).resolves.toBeInstanceOf(Error);
88
+ });
70
89
  });
@@ -31,7 +31,7 @@ function postIframeMessage(
31
31
  return iFrame.contentWindow.postMessage(message, thoughtSpotHost, [channel?.port2]);
32
32
  }
33
33
 
34
- const TRIGGER_TIMEOUT = 30000;
34
+ export const TRIGGER_TIMEOUT = 30000;
35
35
 
36
36
  /**
37
37
  *
package/src/utils.ts CHANGED
@@ -206,7 +206,6 @@ export const getCustomisations = (
206
206
  embedConfig: EmbedConfig,
207
207
  viewConfig: ViewConfig,
208
208
  ): CustomisationsInterface => {
209
- const customCssUrlFromEmbedConfig = embedConfig.customCssUrl;
210
209
  const customizationsFromViewConfig = viewConfig.customizations;
211
210
  const customizationsFromEmbedConfig = embedConfig.customizations
212
211
  || ((embedConfig as any).customisations as CustomisationsInterface);
@@ -219,10 +218,6 @@ export const getCustomisations = (
219
218
  ...customizationsFromEmbedConfig?.style?.customCSS,
220
219
  ...customizationsFromViewConfig?.style?.customCSS,
221
220
  },
222
- customCSSUrl:
223
- customizationsFromViewConfig?.style?.customCSSUrl
224
- || customizationsFromEmbedConfig?.style?.customCSSUrl
225
- || customCssUrlFromEmbedConfig,
226
221
  },
227
222
  content: {
228
223
  ...customizationsFromEmbedConfig?.content,