@thoughtspot/visual-embed-sdk 1.52.2-beta.2 → 1.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/css-variables.d.ts +373 -5
  3. package/cjs/src/css-variables.d.ts.map +1 -1
  4. package/cjs/src/embed/app.d.ts +14 -0
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +6 -3
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +28 -0
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/auto-frame-renderer.d.ts.map +1 -1
  11. package/cjs/src/embed/auto-frame-renderer.js +244 -4
  12. package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
  13. package/cjs/src/embed/auto-frame-renderer.spec.js +389 -0
  14. package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
  15. package/cjs/src/embed/bodyless-conversation.js +1 -1
  16. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  17. package/cjs/src/embed/conversation.d.ts +15 -0
  18. package/cjs/src/embed/conversation.d.ts.map +1 -1
  19. package/cjs/src/embed/conversation.js +7 -3
  20. package/cjs/src/embed/conversation.js.map +1 -1
  21. package/cjs/src/embed/conversation.spec.js +66 -0
  22. package/cjs/src/embed/conversation.spec.js.map +1 -1
  23. package/cjs/src/embed/liveboard-override-utils.d.ts +59 -0
  24. package/cjs/src/embed/liveboard-override-utils.d.ts.map +1 -0
  25. package/cjs/src/embed/liveboard-override-utils.js +19 -0
  26. package/cjs/src/embed/liveboard-override-utils.js.map +1 -0
  27. package/cjs/src/embed/liveboard-override-utils.spec.d.ts +2 -0
  28. package/cjs/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
  29. package/cjs/src/embed/liveboard-override-utils.spec.js +34 -0
  30. package/cjs/src/embed/liveboard-override-utils.spec.js.map +1 -0
  31. package/cjs/src/embed/liveboard.d.ts +58 -13
  32. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  33. package/cjs/src/embed/liveboard.js +11 -34
  34. package/cjs/src/embed/liveboard.js.map +1 -1
  35. package/cjs/src/embed/liveboard.spec.js +104 -79
  36. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  37. package/cjs/src/embed/search-bar.js +1 -1
  38. package/cjs/src/embed/search-bar.js.map +1 -1
  39. package/cjs/src/embed/search.js +1 -1
  40. package/cjs/src/embed/search.js.map +1 -1
  41. package/cjs/src/embed/search.spec.js +20 -0
  42. package/cjs/src/embed/search.spec.js.map +1 -1
  43. package/cjs/src/embed/spotter-utils.d.ts +11 -0
  44. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  45. package/cjs/src/embed/spotter-utils.js +13 -1
  46. package/cjs/src/embed/spotter-utils.js.map +1 -1
  47. package/cjs/src/embed/spotter-viz-utils.d.ts +15 -0
  48. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
  49. package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
  50. package/cjs/src/embed/spotter-viz-utils.spec.js +11 -0
  51. package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -1
  52. package/cjs/src/embed/ts-embed.d.ts +27 -34
  53. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  54. package/cjs/src/embed/ts-embed.js +224 -102
  55. package/cjs/src/embed/ts-embed.js.map +1 -1
  56. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  57. package/cjs/src/embed/ts-embed.spec.js +543 -166
  58. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  59. package/cjs/src/index.d.ts +4 -2
  60. package/cjs/src/index.d.ts.map +1 -1
  61. package/cjs/src/index.js +4 -2
  62. package/cjs/src/index.js.map +1 -1
  63. package/cjs/src/mixpanel-service.d.ts +1 -0
  64. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  65. package/cjs/src/mixpanel-service.js +1 -0
  66. package/cjs/src/mixpanel-service.js.map +1 -1
  67. package/cjs/src/react/all-types-export.d.ts +1 -1
  68. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  69. package/cjs/src/react/all-types-export.js +2 -1
  70. package/cjs/src/react/all-types-export.js.map +1 -1
  71. package/cjs/src/types.d.ts +182 -2
  72. package/cjs/src/types.d.ts.map +1 -1
  73. package/cjs/src/types.js +109 -0
  74. package/cjs/src/types.js.map +1 -1
  75. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  76. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  77. package/cjs/src/utils/graphql/answerService/answer-queries.js +8 -1
  78. package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  79. package/cjs/src/utils/graphql/answerService/answerService.d.ts +28 -4
  80. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  81. package/cjs/src/utils/graphql/answerService/answerService.js +39 -4
  82. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  83. package/cjs/src/utils/graphql/answerService/answerService.spec.js +124 -0
  84. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  85. package/dist/{index-CnHREfvN.js → index-CyDR8j_0.js} +1 -1
  86. package/dist/src/css-variables.d.ts +373 -5
  87. package/dist/src/css-variables.d.ts.map +1 -1
  88. package/dist/src/embed/app.d.ts +14 -0
  89. package/dist/src/embed/app.d.ts.map +1 -1
  90. package/dist/src/embed/auto-frame-renderer.d.ts.map +1 -1
  91. package/dist/src/embed/conversation.d.ts +15 -0
  92. package/dist/src/embed/conversation.d.ts.map +1 -1
  93. package/dist/src/embed/liveboard-override-utils.d.ts +59 -0
  94. package/dist/src/embed/liveboard-override-utils.d.ts.map +1 -0
  95. package/dist/src/embed/liveboard-override-utils.spec.d.ts +2 -0
  96. package/dist/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
  97. package/dist/src/embed/liveboard.d.ts +58 -13
  98. package/dist/src/embed/liveboard.d.ts.map +1 -1
  99. package/dist/src/embed/spotter-utils.d.ts +11 -0
  100. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  101. package/dist/src/embed/spotter-viz-utils.d.ts +15 -0
  102. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
  103. package/dist/src/embed/ts-embed.d.ts +27 -34
  104. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  105. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  106. package/dist/src/index.d.ts +4 -2
  107. package/dist/src/index.d.ts.map +1 -1
  108. package/dist/src/mixpanel-service.d.ts +1 -0
  109. package/dist/src/mixpanel-service.d.ts.map +1 -1
  110. package/dist/src/react/all-types-export.d.ts +1 -1
  111. package/dist/src/react/all-types-export.d.ts.map +1 -1
  112. package/dist/src/types.d.ts +182 -2
  113. package/dist/src/types.d.ts.map +1 -1
  114. package/dist/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  115. package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  116. package/dist/src/utils/graphql/answerService/answerService.d.ts +28 -4
  117. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  118. package/dist/tsembed-react.es.js +437 -191
  119. package/dist/tsembed-react.js +436 -190
  120. package/dist/tsembed.es.js +680 -196
  121. package/dist/tsembed.js +678 -194
  122. package/dist/visual-embed-sdk-react-full.d.ts +702 -56
  123. package/dist/visual-embed-sdk-react.d.ts +697 -56
  124. package/dist/visual-embed-sdk.d.ts +744 -57
  125. package/lib/package.json +1 -1
  126. package/lib/src/css-variables.d.ts +373 -5
  127. package/lib/src/css-variables.d.ts.map +1 -1
  128. package/lib/src/embed/app.d.ts +14 -0
  129. package/lib/src/embed/app.d.ts.map +1 -1
  130. package/lib/src/embed/app.js +7 -4
  131. package/lib/src/embed/app.js.map +1 -1
  132. package/lib/src/embed/app.spec.js +28 -0
  133. package/lib/src/embed/app.spec.js.map +1 -1
  134. package/lib/src/embed/auto-frame-renderer.d.ts.map +1 -1
  135. package/lib/src/embed/auto-frame-renderer.js +244 -4
  136. package/lib/src/embed/auto-frame-renderer.js.map +1 -1
  137. package/lib/src/embed/auto-frame-renderer.spec.js +389 -0
  138. package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
  139. package/lib/src/embed/bodyless-conversation.js +1 -1
  140. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  141. package/lib/src/embed/conversation.d.ts +15 -0
  142. package/lib/src/embed/conversation.d.ts.map +1 -1
  143. package/lib/src/embed/conversation.js +8 -4
  144. package/lib/src/embed/conversation.js.map +1 -1
  145. package/lib/src/embed/conversation.spec.js +67 -1
  146. package/lib/src/embed/conversation.spec.js.map +1 -1
  147. package/lib/src/embed/liveboard-override-utils.d.ts +59 -0
  148. package/lib/src/embed/liveboard-override-utils.d.ts.map +1 -0
  149. package/lib/src/embed/liveboard-override-utils.js +15 -0
  150. package/lib/src/embed/liveboard-override-utils.js.map +1 -0
  151. package/lib/src/embed/liveboard-override-utils.spec.d.ts +2 -0
  152. package/lib/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
  153. package/lib/src/embed/liveboard-override-utils.spec.js +32 -0
  154. package/lib/src/embed/liveboard-override-utils.spec.js.map +1 -0
  155. package/lib/src/embed/liveboard.d.ts +58 -13
  156. package/lib/src/embed/liveboard.d.ts.map +1 -1
  157. package/lib/src/embed/liveboard.js +11 -33
  158. package/lib/src/embed/liveboard.js.map +1 -1
  159. package/lib/src/embed/liveboard.spec.js +104 -79
  160. package/lib/src/embed/liveboard.spec.js.map +1 -1
  161. package/lib/src/embed/search-bar.js +1 -1
  162. package/lib/src/embed/search-bar.js.map +1 -1
  163. package/lib/src/embed/search.js +1 -1
  164. package/lib/src/embed/search.js.map +1 -1
  165. package/lib/src/embed/search.spec.js +20 -0
  166. package/lib/src/embed/search.spec.js.map +1 -1
  167. package/lib/src/embed/spotter-utils.d.ts +11 -0
  168. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  169. package/lib/src/embed/spotter-utils.js +12 -0
  170. package/lib/src/embed/spotter-utils.js.map +1 -1
  171. package/lib/src/embed/spotter-viz-utils.d.ts +15 -0
  172. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
  173. package/lib/src/embed/spotter-viz-utils.js.map +1 -1
  174. package/lib/src/embed/spotter-viz-utils.spec.js +11 -0
  175. package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -1
  176. package/lib/src/embed/ts-embed.d.ts +27 -34
  177. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  178. package/lib/src/embed/ts-embed.js +224 -102
  179. package/lib/src/embed/ts-embed.js.map +1 -1
  180. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  181. package/lib/src/embed/ts-embed.spec.js +544 -167
  182. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  183. package/lib/src/index.d.ts +4 -2
  184. package/lib/src/index.d.ts.map +1 -1
  185. package/lib/src/index.js +3 -2
  186. package/lib/src/index.js.map +1 -1
  187. package/lib/src/mixpanel-service.d.ts +1 -0
  188. package/lib/src/mixpanel-service.d.ts.map +1 -1
  189. package/lib/src/mixpanel-service.js +1 -0
  190. package/lib/src/mixpanel-service.js.map +1 -1
  191. package/lib/src/react/all-types-export.d.ts +1 -1
  192. package/lib/src/react/all-types-export.d.ts.map +1 -1
  193. package/lib/src/react/all-types-export.js +1 -1
  194. package/lib/src/react/all-types-export.js.map +1 -1
  195. package/lib/src/types.d.ts +182 -2
  196. package/lib/src/types.d.ts.map +1 -1
  197. package/lib/src/types.js +109 -0
  198. package/lib/src/types.js.map +1 -1
  199. package/lib/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  200. package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  201. package/lib/src/utils/graphql/answerService/answer-queries.js +7 -0
  202. package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  203. package/lib/src/utils/graphql/answerService/answerService.d.ts +28 -4
  204. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  205. package/lib/src/utils/graphql/answerService/answerService.js +39 -4
  206. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  207. package/lib/src/utils/graphql/answerService/answerService.spec.js +125 -1
  208. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  209. package/lib/src/visual-embed-sdk.d.ts +744 -57
  210. package/package.json +1 -1
  211. package/src/css-variables.ts +475 -26
  212. package/src/embed/app.spec.ts +32 -0
  213. package/src/embed/app.ts +28 -4
  214. package/src/embed/auto-frame-renderer.spec.ts +464 -0
  215. package/src/embed/auto-frame-renderer.ts +305 -6
  216. package/src/embed/bodyless-conversation.ts +1 -1
  217. package/src/embed/conversation.spec.ts +94 -1
  218. package/src/embed/conversation.ts +28 -3
  219. package/src/embed/liveboard-override-utils.spec.ts +38 -0
  220. package/src/embed/liveboard-override-utils.ts +71 -0
  221. package/src/embed/liveboard.spec.ts +119 -92
  222. package/src/embed/liveboard.ts +56 -40
  223. package/src/embed/search-bar.tsx +1 -1
  224. package/src/embed/search.spec.ts +23 -0
  225. package/src/embed/search.ts +1 -1
  226. package/src/embed/spotter-utils.ts +12 -0
  227. package/src/embed/spotter-viz-utils.spec.ts +11 -0
  228. package/src/embed/spotter-viz-utils.ts +15 -0
  229. package/src/embed/ts-embed.spec.ts +685 -207
  230. package/src/embed/ts-embed.ts +227 -97
  231. package/src/index.ts +16 -1
  232. package/src/mixpanel-service.ts +1 -0
  233. package/src/react/all-types-export.ts +6 -0
  234. package/src/types.ts +186 -5
  235. package/src/utils/graphql/answerService/answer-queries.ts +8 -0
  236. package/src/utils/graphql/answerService/answerService.spec.ts +145 -1
  237. package/src/utils/graphql/answerService/answerService.ts +65 -3
@@ -1,4 +1,5 @@
1
1
  import { LiveboardViewConfig, LiveboardEmbed } from './liveboard';
2
+ import { SpotterExperienceVersion } from './spotter-utils';
2
3
  import { init, UIPassthroughEvent } from '../index';
3
4
  import {
4
5
  Action,
@@ -174,6 +175,37 @@ describe('Liveboard/viz embed tests', () => {
174
175
  });
175
176
  });
176
177
 
178
+ test('should set EditLiveboard and EditVisualization independently of each other and of Edit', async () => {
179
+ expect(Action.Edit).toBe('edit');
180
+ expect(Action.EditLiveboard).toBe('editLiveboard');
181
+ expect(Action.EditVisualization).toBe('editVisualization');
182
+
183
+ const liveboardEmbed1 = new LiveboardEmbed(getRootEl(), {
184
+ hiddenActions: [Action.EditVisualization],
185
+ ...defaultViewConfig,
186
+ liveboardId,
187
+ } as LiveboardViewConfig);
188
+ liveboardEmbed1.render();
189
+ await executeAfterWait(() => {
190
+ expectUrlToHaveParamsWithValues(getIFrameSrc(), {
191
+ hideAction: JSON.stringify([Action.ReportError, Action.EditVisualization]),
192
+ });
193
+ });
194
+
195
+ document.body.innerHTML = getDocumentBody();
196
+ const liveboardEmbed2 = new LiveboardEmbed(getRootEl(), {
197
+ hiddenActions: [Action.EditLiveboard],
198
+ ...defaultViewConfig,
199
+ liveboardId,
200
+ } as LiveboardViewConfig);
201
+ liveboardEmbed2.render();
202
+ await executeAfterWait(() => {
203
+ expectUrlToHaveParamsWithValues(getIFrameSrc(), {
204
+ hideAction: JSON.stringify([Action.ReportError, Action.EditLiveboard]),
205
+ });
206
+ });
207
+ });
208
+
177
209
  test('should set visible actions', async () => {
178
210
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
179
211
  visibleActions: [Action.DownloadAsCsv, Action.DownloadAsPdf, Action.DownloadAsXlsx],
@@ -1621,6 +1653,58 @@ describe('Liveboard/viz embed tests', () => {
1621
1653
  });
1622
1654
  });
1623
1655
 
1656
+ describe('liveboardOverride in APP_INIT embedParams', () => {
1657
+ const liveboardOverride = {
1658
+ dataSourceOverride: [{
1659
+ dataSourceIdentifier: 'model-guid',
1660
+ filterQuery: [{ tabName: 'Sales', groupName: 'Region', filterQueryToken: 'color = red' }],
1661
+ }],
1662
+ };
1663
+
1664
+ const getAppInitResponse = async (viewConfig: Partial<LiveboardViewConfig>) => {
1665
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1666
+ ...defaultViewConfig,
1667
+ liveboardId,
1668
+ ...viewConfig,
1669
+ } as LiveboardViewConfig);
1670
+
1671
+ mockMessageChannel();
1672
+ await liveboardEmbed.render();
1673
+
1674
+ const mockPort: any = { postMessage: jest.fn() };
1675
+ await executeAfterWait(() => {
1676
+ postMessageToParent(getIFrameEl().contentWindow, { type: EmbedEvent.APP_INIT, data: {} }, mockPort);
1677
+ });
1678
+ let data: any;
1679
+ await executeAfterWait(() => {
1680
+ data = mockPort.postMessage.mock.calls[0][0].data;
1681
+ });
1682
+ return data;
1683
+ };
1684
+
1685
+ test('should include liveboardOverride when provided', async () => {
1686
+ const data = await getAppInitResponse({ liveboardOverride });
1687
+ expect(data.embedParams.liveboardOverride).toEqual(liveboardOverride);
1688
+ });
1689
+
1690
+ test('should not include liveboardOverride when not provided', async () => {
1691
+ const data = await getAppInitResponse({});
1692
+ expect(data.embedParams?.liveboardOverride).toBeUndefined();
1693
+ });
1694
+
1695
+ test('should not include liveboardOverride when dataSourceOverride is empty', async () => {
1696
+ const data = await getAppInitResponse({ liveboardOverride: { dataSourceOverride: [] } });
1697
+ expect(data.embedParams?.liveboardOverride).toBeUndefined();
1698
+ });
1699
+
1700
+ test('should send liveboardOverride alongside spotterVizConfig', async () => {
1701
+ const spotterViz = { brandName: 'MyBrand' };
1702
+ const data = await getAppInitResponse({ liveboardOverride, spotterViz });
1703
+ expect(data.embedParams.liveboardOverride).toEqual(liveboardOverride);
1704
+ expect(data.embedParams.spotterVizConfig).toEqual(spotterViz);
1705
+ });
1706
+ });
1707
+
1624
1708
  test('should include starterPrompts in APP_INIT embedParams', async () => {
1625
1709
  const starterPrompts = {
1626
1710
  enable: true,
@@ -2748,98 +2832,6 @@ describe('Liveboard/viz embed tests', () => {
2748
2832
  expect(navigateToLiveboardSpy).toHaveBeenCalled();
2749
2833
  });
2750
2834
 
2751
- test('should not route via home when a new instance shows an equal config', async () => {
2752
- const viewConfig = {
2753
- liveboardId,
2754
- vizId,
2755
- activeTabId,
2756
- ...defaultViewConfig,
2757
- };
2758
- const previous = new LiveboardEmbed(getRootEl(), { ...viewConfig, beforeRender: () => {} } as any);
2759
- const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...viewConfig, beforeRender: () => {} } as any);
2760
-
2761
- // React constructs a new embed on every mount.
2762
- jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(previous);
2763
- const triggerSpy = jest
2764
- .spyOn(liveboardEmbed, 'trigger')
2765
- .mockImplementation(() => Promise.resolve(undefined as any));
2766
- const navigateToLiveboardSpy = jest
2767
- .spyOn(liveboardEmbed, 'navigateToLiveboard')
2768
- .mockImplementation(() => Promise.resolve(undefined));
2769
-
2770
- liveboardEmbed.isEmbedContainerLoaded = false;
2771
- liveboardEmbed['beforePrerenderVisible']();
2772
- liveboardEmbed.isEmbedContainerLoaded = true;
2773
- liveboardEmbed['executeEmbedContainerReadyCallbacks']();
2774
- await waitForPreRenderNavigate();
2775
-
2776
- expect(triggerSpy).not.toHaveBeenCalledWith(HostEvent.Navigate, 'home');
2777
- expect(navigateToLiveboardSpy).toHaveBeenCalled();
2778
- });
2779
-
2780
- test('should not route via home when the previous instance has been shown once', async () => {
2781
- // navigateToLiveboard assigns vizId/activeTabId/personalizedViewId
2782
- // unconditionally, so a shown instance carries them as undefined
2783
- // while a fresh one lacks the keys entirely. Comparing raw objects
2784
- // counts own keys, so it never matches again.
2785
- const viewConfig = { liveboardId, ...defaultViewConfig };
2786
- const previous = new LiveboardEmbed(getRootEl(), { ...viewConfig } as any);
2787
- (previous as any).viewConfig.vizId = undefined;
2788
- (previous as any).viewConfig.activeTabId = undefined;
2789
- (previous as any).viewConfig.personalizedViewId = undefined;
2790
-
2791
- const liveboardEmbed = new LiveboardEmbed(getRootEl(), { ...viewConfig } as any);
2792
-
2793
- jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(previous);
2794
- const triggerSpy = jest
2795
- .spyOn(liveboardEmbed, 'trigger')
2796
- .mockImplementation(() => Promise.resolve(undefined as any));
2797
- jest
2798
- .spyOn(liveboardEmbed, 'navigateToLiveboard')
2799
- .mockImplementation(() => Promise.resolve(undefined));
2800
-
2801
- liveboardEmbed.isEmbedContainerLoaded = false;
2802
- liveboardEmbed['beforePrerenderVisible']();
2803
- liveboardEmbed.isEmbedContainerLoaded = true;
2804
- liveboardEmbed['executeEmbedContainerReadyCallbacks']();
2805
- await waitForPreRenderNavigate();
2806
-
2807
- expect(triggerSpy).not.toHaveBeenCalledWith(HostEvent.Navigate, 'home');
2808
- });
2809
-
2810
- test('should route via home when a new instance shows the same route with other filters', async () => {
2811
- const viewConfig = {
2812
- liveboardId,
2813
- vizId,
2814
- activeTabId,
2815
- ...defaultViewConfig,
2816
- };
2817
- const previous = new LiveboardEmbed(getRootEl(), {
2818
- ...viewConfig,
2819
- runtimeFilters: [{ columnName: 'region', operator: RuntimeFilterOp.EQ, values: ['east'] }],
2820
- });
2821
- const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2822
- ...viewConfig,
2823
- runtimeFilters: [{ columnName: 'region', operator: RuntimeFilterOp.EQ, values: ['west'] }],
2824
- });
2825
-
2826
- jest.spyOn(liveboardEmbed as any, 'getPreRenderObj').mockReturnValue(previous);
2827
- const triggerSpy = jest
2828
- .spyOn(liveboardEmbed, 'trigger')
2829
- .mockImplementation(() => Promise.resolve(undefined as any));
2830
- jest
2831
- .spyOn(liveboardEmbed, 'navigateToLiveboard')
2832
- .mockImplementation(() => Promise.resolve(undefined));
2833
-
2834
- liveboardEmbed.isEmbedContainerLoaded = false;
2835
- liveboardEmbed['beforePrerenderVisible']();
2836
- liveboardEmbed.isEmbedContainerLoaded = true;
2837
- liveboardEmbed['executeEmbedContainerReadyCallbacks']();
2838
- await waitForHomeHopNavigate();
2839
-
2840
- expect(triggerSpy).toHaveBeenCalledWith(HostEvent.Navigate, 'home');
2841
- });
2842
-
2843
2835
  test('should not route via home when the pre-render is on another liveboard', async () => {
2844
2836
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2845
2837
  liveboardId,
@@ -3179,3 +3171,38 @@ describe('LiveboardEmbed updatedSpotterExperience tests', () => {
3179
3171
  });
3180
3172
  });
3181
3173
  });
3174
+
3175
+ describe('LiveboardEmbed spotterExperienceVersion tests', () => {
3176
+ beforeEach(() => {
3177
+ document.body.innerHTML = getDocumentBody();
3178
+ });
3179
+
3180
+ const renderWithConfig = async (config: Partial<LiveboardViewConfig>) => {
3181
+ document.body.innerHTML = getDocumentBody();
3182
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
3183
+ ...defaultViewConfig,
3184
+ liveboardId,
3185
+ ...config,
3186
+ } as LiveboardViewConfig);
3187
+ await liveboardEmbed.render();
3188
+ let src = '';
3189
+ await executeAfterWait(() => {
3190
+ src = getIFrameSrc();
3191
+ });
3192
+ return src;
3193
+ };
3194
+
3195
+ test('should add the spotterExperienceVersion param when spotterExperienceVersion is set', async () => {
3196
+ const src = await renderWithConfig({
3197
+ spotterExperienceVersion: SpotterExperienceVersion.SPOTTER_2026_11,
3198
+ });
3199
+ expect(src).toContain(
3200
+ `spotterExperienceVersion=${SpotterExperienceVersion.SPOTTER_2026_11}`,
3201
+ );
3202
+ });
3203
+
3204
+ test('should not add the spotterExperienceVersion param when spotterExperienceVersion is not set', async () => {
3205
+ const src = await renderWithConfig({});
3206
+ expect(src).not.toContain('spotterExperienceVersion=');
3207
+ });
3208
+ });
@@ -8,7 +8,6 @@
8
8
  * @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
9
9
  */
10
10
 
11
- import isEqualWith from 'lodash/isEqualWith';
12
11
  import { getPreview } from '../utils/graphql/preview-service';
13
12
  import { ERROR_MESSAGE } from '../errors';
14
13
  import {
@@ -35,8 +34,9 @@ import { addPreviewStylesIfNotPresent } from '../utils/global-styles';
35
34
  import { HostEventRequest, TriggerData, TriggerResponse } from '../contracts/host-event-contracts';
36
35
  import { logger } from '../utils/logger';
37
36
  import { SpotterChatViewConfig, StarterPromptsConfig } from './conversation';
38
- import { buildStarterPromptsAppInitData } from './spotter-utils';
37
+ import { buildStarterPromptsAppInitData, SpotterExperienceVersion } from './spotter-utils';
39
38
  import { SpotterVizConfig, buildSpotterVizAppInitData } from './spotter-viz-utils';
39
+ import { LiveboardOverride, buildLiveboardOverrideAppInitData } from './liveboard-override-utils';
40
40
 
41
41
  // Home unmounts the liveboard container, which is how its state gets cleared.
42
42
  // The settle window gives the container time to do it before we ask for the
@@ -52,6 +52,7 @@ export interface LiveboardEmbedAppInitData extends DefaultAppInitData {
52
52
  embedParams?: {
53
53
  spotterVizConfig?: SpotterVizConfig;
54
54
  starterPrompts?: StarterPromptsConfig;
55
+ liveboardOverride?: LiveboardOverride;
55
56
  };
56
57
  }
57
58
 
@@ -61,7 +62,8 @@ export interface LiveboardEmbedAppInitData extends DefaultAppInitData {
61
62
  * @group Embed components
62
63
  */
63
64
  export interface LiveboardViewConfig
64
- extends BaseViewConfig,
65
+ extends
66
+ BaseViewConfig,
65
67
  FullHeightViewConfig,
66
68
  LiveboardOtherViewConfig,
67
69
  LiveboardAppEmbedViewConfig {
@@ -546,6 +548,46 @@ export interface LiveboardViewConfig
546
548
  * ```
547
549
  */
548
550
  updatedSpotterExperience?: boolean;
551
+ /**
552
+ * Filters and Parameters to apply to the Liveboard when it loads.
553
+ *
554
+ * In an embedded Liveboard, this is the only way to set these overrides.
555
+ * The `filter` and `parameter` URL query params are ignored.
556
+ * Clauses without a query token are dropped.
557
+ *
558
+ * Supported embed types: `LiveboardEmbed`
559
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
560
+ * @example
561
+ * ```js
562
+ * const embed = new LiveboardEmbed('#tsEmbed', {
563
+ * ... // other embed view config
564
+ * liveboardOverride: {
565
+ * dataSourceOverride: [{
566
+ * dataSourceIdentifier: '<model-guid>',
567
+ * filterQuery: [{
568
+ * tabName: 'Sales',
569
+ * groupName: 'Region',
570
+ * filterQueryToken: 'color = red',
571
+ * }],
572
+ * }],
573
+ * },
574
+ * })
575
+ * ```
576
+ */
577
+ liveboardOverride?: LiveboardOverride;
578
+ /**
579
+ * The Spotter experience version to load for the Spotter surface shown within
580
+ * this embed.
581
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.11.0.cl
582
+ * @example
583
+ * ```js
584
+ * const embed = new LiveboardEmbed('#tsEmbed', {
585
+ * ... // other options
586
+ * spotterExperienceVersion: SpotterExperienceVersion.SPOTTER_2026_11,
587
+ * });
588
+ * ```
589
+ */
590
+ spotterExperienceVersion?: SpotterExperienceVersion;
549
591
  }
550
592
 
551
593
  /**
@@ -563,14 +605,6 @@ export interface LiveboardViewConfig
563
605
  * })
564
606
  * ```
565
607
  */
566
- /**
567
- * A shallow copy without the keys whose value is `undefined`, so a key that was
568
- * assigned `undefined` compares equal to one that was never set.
569
- */
570
- const definedEntries = (config: Record<string, any> = {}): Record<string, any> => Object.fromEntries(
571
- Object.entries(config).filter(([, value]) => value !== undefined),
572
- );
573
-
574
608
  export class LiveboardEmbed extends V1Embed {
575
609
  protected viewConfig: LiveboardViewConfig;
576
610
 
@@ -600,7 +634,8 @@ export class LiveboardEmbed extends V1Embed {
600
634
  protected async getAppInitData(): Promise<LiveboardEmbedAppInitData> {
601
635
  const defaultAppInitData = await super.getAppInitData();
602
636
  const vizInitData = buildSpotterVizAppInitData(defaultAppInitData, this.viewConfig);
603
- return buildStarterPromptsAppInitData(vizInitData, this.viewConfig);
637
+ const starterPromptsInitData = buildStarterPromptsAppInitData(vizInitData, this.viewConfig);
638
+ return buildLiveboardOverrideAppInitData(starterPromptsInitData, this.viewConfig);
604
639
  }
605
640
 
606
641
  /**
@@ -608,7 +643,7 @@ export class LiveboardEmbed extends V1Embed {
608
643
  * embedded Liveboard or visualization.
609
644
  */
610
645
  protected getEmbedParams() {
611
- const params = this.getEmbedParamsObject();
646
+ const params = this.getUrlQueryParamsObject();
612
647
  const queryParams = getQueryParamString(params, true);
613
648
  return queryParams;
614
649
  }
@@ -661,6 +696,7 @@ export class LiveboardEmbed extends V1Embed {
661
696
  isThisPeriodInDateFiltersEnabled,
662
697
  isContinuousLiveboardPDFEnabled,
663
698
  enableLiveboardDataCache,
699
+ spotterExperienceVersion,
664
700
  } = this.viewConfig;
665
701
 
666
702
  const preventLiveboardFilterRemoval = this.viewConfig.preventLiveboardFilterRemoval
@@ -730,6 +766,10 @@ export class LiveboardEmbed extends V1Embed {
730
766
  params[Param.IsLiveboardStylingAndGroupingEnabled] = isLiveboardStylingAndGroupingEnabled;
731
767
  }
732
768
 
769
+ if (spotterExperienceVersion !== undefined) {
770
+ params[Param.SpotterExperienceVersion] = spotterExperienceVersion;
771
+ }
772
+
733
773
  if (liveboardGutter !== undefined) {
734
774
  params[Param.LiveboardGutter] = liveboardGutter;
735
775
  }
@@ -964,12 +1004,10 @@ export class LiveboardEmbed extends V1Embed {
964
1004
  super.beforePrerenderVisible();
965
1005
 
966
1006
  // Captured before showPreRender() hands the wrapper over to this
967
- // instance. React builds a new instance per mount, so an equal config
968
- // is a hide/show, not a hand-over: there is nothing stale to clear.
1007
+ // instance. Itself means a hide/show, not a hand-over, so there is
1008
+ // nothing stale to clear.
969
1009
  const previous = this.getPreRenderObj<LiveboardEmbed>();
970
- const showing = this.isSameEmbedConfig(previous)
971
- ? undefined
972
- : previous?.currentLiveboardState;
1010
+ const showing = previous === this ? undefined : previous?.currentLiveboardState;
973
1011
 
974
1012
  this.executeAfterEmbedContainerLoaded(async () => {
975
1013
  // Without this the params callback suspends on its await and
@@ -1003,28 +1041,6 @@ export class LiveboardEmbed extends V1Embed {
1003
1041
  });
1004
1042
  }
1005
1043
 
1006
- /**
1007
- * Whether `previous` was showing what this instance is about to show.
1008
- *
1009
- * Undefined-valued keys are dropped before comparing. `navigateToLiveboard`
1010
- * assigns `vizId`, `activeTabId` and `personalizedViewId` unconditionally,
1011
- * so an instance that has been shown once carries those keys as `undefined`
1012
- * while a freshly constructed one does not have them at all. `isEqual`
1013
- * counts own keys, so without this the comparison can never be true after
1014
- * the first show — which is the whole case this exists for.
1015
- *
1016
- * Callbacks compare as equal: React passes a fresh closure per render.
1017
- */
1018
- private isSameEmbedConfig(previous?: LiveboardEmbed): boolean {
1019
- if (!previous) return false;
1020
- if (previous === this) return true;
1021
- return isEqualWith(
1022
- definedEntries(previous.viewConfig),
1023
- definedEntries(this.viewConfig),
1024
- (a, b) => (typeof a === 'function' && typeof b === 'function' ? true : undefined),
1025
- );
1026
- }
1027
-
1028
1044
  // The whole route, not just the liveboard id: the path is built from the
1029
1045
  // viz, tab and view too, so a same-liveboard show onto another tab is a
1030
1046
  // real navigation.
@@ -163,7 +163,7 @@ export class SearchBarEmbed extends TsEmbed {
163
163
  * @param dataSources A list of data source GUIDs
164
164
  */
165
165
  private getIFrameSrc() {
166
- const queryParams = this.getEmbedParamsObject();
166
+ const queryParams = this.getUrlQueryParamsObject();
167
167
  const path = 'search-bar-embed';
168
168
 
169
169
  let query = '';
@@ -854,6 +854,29 @@ test('should pass forceTable parameter when forceTable is true', async () => {
854
854
  });
855
855
 
856
856
  describe('SearchBarEmbed tests', () => {
857
+ test('should keep view config off the URL when excludeConfigFromURL is set', async () => {
858
+ const searchBarEmbed = new SearchBarEmbed(getRootEl() as any, {
859
+ ...defaultViewConfig,
860
+ dataSources: ['source-1', 'source-2'],
861
+ additionalFlags: { excludeConfigFromURL: true },
862
+ } as any);
863
+ searchBarEmbed.render();
864
+ await executeAfterWait(() => {
865
+ const iframeSrc = getIFrameSrc();
866
+
867
+ // Bootstrap params stay: the handshake, the embed marker that
868
+ // picks the app shell, and the data sources it boots against.
869
+ expect(iframeSrc).toContain('hostAppUrl=');
870
+ expect(iframeSrc).toContain('isSearchEmbed=true');
871
+ expect(iframeSrc).toContain('dataSources');
872
+
873
+ // The rest of the view config goes over
874
+ // HostEvent.UpdateEmbedParams.
875
+ expect(iframeSrc).not.toContain('hideAction');
876
+ expect(iframeSrc).not.toContain('useLastSelectedDataSource');
877
+ });
878
+ });
879
+
857
880
  test('should pass dataSources parameter when dataSources array is provided', async () => {
858
881
  const searchBarEmbed = new SearchBarEmbed(getRootEl() as any, {
859
882
  ...defaultViewConfig,
@@ -546,7 +546,7 @@ export class SearchEmbed extends TsEmbed {
546
546
  excludeRuntimeParametersfromURL,
547
547
  excludeRuntimeFiltersfromURL,
548
548
  } = this.viewConfig;
549
- const queryParams = this.getEmbedParamsObject();
549
+ const queryParams = this.getUrlQueryParamsObject();
550
550
  let query = '';
551
551
  const queryParamsString = getQueryParamString(queryParams, true);
552
552
  if (queryParamsString) {
@@ -130,3 +130,15 @@ export function buildSpotterAnalystAppInitData<T extends DefaultAppInitData>(
130
130
  },
131
131
  };
132
132
  }
133
+
134
+ /**
135
+ * The Spotter experience version to load in the embedded view.
136
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.11.0.cl
137
+ * @group Embed components
138
+ */
139
+ export enum SpotterExperienceVersion {
140
+ /**
141
+ * The Spotter experience version introduced in ThoughtSpot 26.11.
142
+ */
143
+ SPOTTER_2026_11 = 'spotter_2026_11',
144
+ }
@@ -37,6 +37,17 @@ describe('buildSpotterVizAppInitData', () => {
37
37
  expect(result.embedParams?.spotterVizConfig?.insightTileLoaderText).toBe('Generating insight');
38
38
  });
39
39
 
40
+ it('passes fileUploadEnabled and fileUploadFileTypes through spotterVizConfig', () => {
41
+ const spotterViz = {
42
+ brandName: 'MyBrand',
43
+ fileUploadEnabled: false,
44
+ fileUploadFileTypes: ['csv', '.pdf'],
45
+ };
46
+ const result = buildSpotterVizAppInitData(base, { spotterViz });
47
+ expect(result.embedParams?.spotterVizConfig?.fileUploadEnabled).toBe(false);
48
+ expect(result.embedParams?.spotterVizConfig?.fileUploadFileTypes).toEqual(['csv', '.pdf']);
49
+ });
50
+
40
51
  it('preserves existing embedParams when adding spotterVizConfig', () => {
41
52
  const existing = { ...base, embedParams: { spotterSidebarConfig: { enablePastConversationsSidebar: true } } };
42
53
  const spotterViz = { brandName: 'MyBrand' };
@@ -127,6 +127,21 @@ export interface SpotterVizConfig {
127
127
  * @version SDK: 1.51.0 | ThoughtSpot Cloud: 26.7.0.cl
128
128
  */
129
129
  insightTileLoaderText?: string;
130
+ /**
131
+ * Set to `false` to hide the file upload feature in the SpotterViz chat
132
+ * input on a cluster where the feature is available.
133
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
134
+ * @default true
135
+ */
136
+ fileUploadEnabled?: boolean;
137
+ /**
138
+ * Restricts the allowed file types for SpotterViz file upload to a
139
+ * subset of the types SpotterViz supports, e.g. `['csv', 'pdf']`.
140
+ * Entries are file extensions (with or without the leading dot); types
141
+ * SpotterViz does not support are ignored, as are empty lists.
142
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
143
+ */
144
+ fileUploadFileTypes?: string[];
130
145
  }
131
146
 
132
147
  /**