@thoughtspot/visual-embed-sdk 1.51.0 → 1.51.2

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 (228) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/config.d.ts +1 -0
  3. package/cjs/src/config.d.ts.map +1 -1
  4. package/cjs/src/config.js +2 -1
  5. package/cjs/src/config.js.map +1 -1
  6. package/cjs/src/css-variables.d.ts +27 -0
  7. package/cjs/src/css-variables.d.ts.map +1 -1
  8. package/cjs/src/embed/app.d.ts +43 -12
  9. package/cjs/src/embed/app.d.ts.map +1 -1
  10. package/cjs/src/embed/app.js +29 -3
  11. package/cjs/src/embed/app.js.map +1 -1
  12. package/cjs/src/embed/app.spec.js +253 -1
  13. package/cjs/src/embed/app.spec.js.map +1 -1
  14. package/cjs/src/embed/base.d.ts +1 -1
  15. package/cjs/src/embed/base.js +1 -1
  16. package/cjs/src/embed/conversation.d.ts +171 -1
  17. package/cjs/src/embed/conversation.d.ts.map +1 -1
  18. package/cjs/src/embed/conversation.js +4 -2
  19. package/cjs/src/embed/conversation.js.map +1 -1
  20. package/cjs/src/embed/conversation.spec.js +125 -0
  21. package/cjs/src/embed/conversation.spec.js.map +1 -1
  22. package/cjs/src/embed/events.spec.js +3 -0
  23. package/cjs/src/embed/events.spec.js.map +1 -1
  24. package/cjs/src/embed/host-events.spec.js +36 -0
  25. package/cjs/src/embed/host-events.spec.js.map +1 -1
  26. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +1 -1
  27. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  28. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +18 -0
  29. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  30. package/cjs/src/embed/liveboard.d.ts +40 -13
  31. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  32. package/cjs/src/embed/liveboard.js +25 -4
  33. package/cjs/src/embed/liveboard.js.map +1 -1
  34. package/cjs/src/embed/liveboard.spec.js +349 -2
  35. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  36. package/cjs/src/embed/search.spec.js +28 -0
  37. package/cjs/src/embed/search.spec.js.map +1 -1
  38. package/cjs/src/embed/spotter-utils.d.ts +8 -1
  39. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  40. package/cjs/src/embed/spotter-utils.js +15 -1
  41. package/cjs/src/embed/spotter-utils.js.map +1 -1
  42. package/cjs/src/embed/spotter-utils.spec.js +68 -0
  43. package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
  44. package/cjs/src/embed/spotter-viz-utils.d.ts +9 -10
  45. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
  46. package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
  47. package/cjs/src/embed/ts-embed.d.ts +97 -9
  48. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  49. package/cjs/src/embed/ts-embed.js +76 -35
  50. package/cjs/src/embed/ts-embed.js.map +1 -1
  51. package/cjs/src/embed/ts-embed.spec.js +537 -3
  52. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  53. package/cjs/src/index.d.ts +3 -3
  54. package/cjs/src/index.d.ts.map +1 -1
  55. package/cjs/src/index.js +3 -2
  56. package/cjs/src/index.js.map +1 -1
  57. package/cjs/src/react/all-types-export.d.ts +1 -1
  58. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  59. package/cjs/src/react/all-types-export.js +2 -1
  60. package/cjs/src/react/all-types-export.js.map +1 -1
  61. package/cjs/src/react/all-types-export.parity.spec.d.ts +2 -0
  62. package/cjs/src/react/all-types-export.parity.spec.d.ts.map +1 -0
  63. package/cjs/src/react/all-types-export.parity.spec.js +194 -0
  64. package/cjs/src/react/all-types-export.parity.spec.js.map +1 -0
  65. package/cjs/src/react/index.d.ts +66 -32
  66. package/cjs/src/react/index.d.ts.map +1 -1
  67. package/cjs/src/react/index.js +5 -3
  68. package/cjs/src/react/index.js.map +1 -1
  69. package/cjs/src/react/index.spec.js +101 -0
  70. package/cjs/src/react/index.spec.js.map +1 -1
  71. package/cjs/src/types.d.ts +330 -18
  72. package/cjs/src/types.d.ts.map +1 -1
  73. package/cjs/src/types.js +182 -12
  74. package/cjs/src/types.js.map +1 -1
  75. package/cjs/src/utils.d.ts +5 -0
  76. package/cjs/src/utils.d.ts.map +1 -1
  77. package/cjs/src/utils.js +19 -1
  78. package/cjs/src/utils.js.map +1 -1
  79. package/cjs/src/utils.spec.js +37 -0
  80. package/cjs/src/utils.spec.js.map +1 -1
  81. package/dist/{index-aBzH5ZwF.js → index-D8_Zs-Nr.js} +1 -1
  82. package/dist/src/config.d.ts +1 -0
  83. package/dist/src/config.d.ts.map +1 -1
  84. package/dist/src/css-variables.d.ts +27 -0
  85. package/dist/src/css-variables.d.ts.map +1 -1
  86. package/dist/src/embed/app.d.ts +43 -12
  87. package/dist/src/embed/app.d.ts.map +1 -1
  88. package/dist/src/embed/base.d.ts +1 -1
  89. package/dist/src/embed/conversation.d.ts +171 -1
  90. package/dist/src/embed/conversation.d.ts.map +1 -1
  91. package/dist/src/embed/hostEventClient/host-event-client.d.ts +1 -1
  92. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  93. package/dist/src/embed/liveboard.d.ts +40 -13
  94. package/dist/src/embed/liveboard.d.ts.map +1 -1
  95. package/dist/src/embed/spotter-utils.d.ts +8 -1
  96. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  97. package/dist/src/embed/spotter-viz-utils.d.ts +9 -10
  98. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
  99. package/dist/src/embed/ts-embed.d.ts +97 -9
  100. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  101. package/dist/src/index.d.ts +3 -3
  102. package/dist/src/index.d.ts.map +1 -1
  103. package/dist/src/react/all-types-export.d.ts +1 -1
  104. package/dist/src/react/all-types-export.d.ts.map +1 -1
  105. package/dist/src/react/all-types-export.parity.spec.d.ts +2 -0
  106. package/dist/src/react/all-types-export.parity.spec.d.ts.map +1 -0
  107. package/dist/src/react/index.d.ts +66 -32
  108. package/dist/src/react/index.d.ts.map +1 -1
  109. package/dist/src/types.d.ts +330 -18
  110. package/dist/src/types.d.ts.map +1 -1
  111. package/dist/src/utils.d.ts +5 -0
  112. package/dist/src/utils.d.ts.map +1 -1
  113. package/dist/tsembed-react.es.js +354 -64
  114. package/dist/tsembed-react.js +353 -63
  115. package/dist/tsembed.es.js +414 -126
  116. package/dist/tsembed.js +416 -128
  117. package/dist/visual-embed-sdk-react-full.d.ts +777 -90
  118. package/dist/visual-embed-sdk-react.d.ts +773 -89
  119. package/dist/visual-embed-sdk.d.ts +713 -60
  120. package/lib/package.json +1 -1
  121. package/lib/src/config.d.ts +1 -0
  122. package/lib/src/config.d.ts.map +1 -1
  123. package/lib/src/config.js +1 -0
  124. package/lib/src/config.js.map +1 -1
  125. package/lib/src/css-variables.d.ts +27 -0
  126. package/lib/src/css-variables.d.ts.map +1 -1
  127. package/lib/src/embed/app.d.ts +43 -12
  128. package/lib/src/embed/app.d.ts.map +1 -1
  129. package/lib/src/embed/app.js +30 -4
  130. package/lib/src/embed/app.js.map +1 -1
  131. package/lib/src/embed/app.spec.js +253 -1
  132. package/lib/src/embed/app.spec.js.map +1 -1
  133. package/lib/src/embed/base.d.ts +1 -1
  134. package/lib/src/embed/base.js +1 -1
  135. package/lib/src/embed/conversation.d.ts +171 -1
  136. package/lib/src/embed/conversation.d.ts.map +1 -1
  137. package/lib/src/embed/conversation.js +5 -3
  138. package/lib/src/embed/conversation.js.map +1 -1
  139. package/lib/src/embed/conversation.spec.js +125 -0
  140. package/lib/src/embed/conversation.spec.js.map +1 -1
  141. package/lib/src/embed/events.spec.js +3 -0
  142. package/lib/src/embed/events.spec.js.map +1 -1
  143. package/lib/src/embed/host-events.spec.js +36 -0
  144. package/lib/src/embed/host-events.spec.js.map +1 -1
  145. package/lib/src/embed/hostEventClient/host-event-client.d.ts +1 -1
  146. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  147. package/lib/src/embed/hostEventClient/host-event-client.spec.js +18 -0
  148. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  149. package/lib/src/embed/liveboard.d.ts +40 -13
  150. package/lib/src/embed/liveboard.d.ts.map +1 -1
  151. package/lib/src/embed/liveboard.js +25 -4
  152. package/lib/src/embed/liveboard.js.map +1 -1
  153. package/lib/src/embed/liveboard.spec.js +349 -2
  154. package/lib/src/embed/liveboard.spec.js.map +1 -1
  155. package/lib/src/embed/search.spec.js +28 -0
  156. package/lib/src/embed/search.spec.js.map +1 -1
  157. package/lib/src/embed/spotter-utils.d.ts +8 -1
  158. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  159. package/lib/src/embed/spotter-utils.js +13 -0
  160. package/lib/src/embed/spotter-utils.js.map +1 -1
  161. package/lib/src/embed/spotter-utils.spec.js +69 -1
  162. package/lib/src/embed/spotter-utils.spec.js.map +1 -1
  163. package/lib/src/embed/spotter-viz-utils.d.ts +9 -10
  164. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
  165. package/lib/src/embed/spotter-viz-utils.js.map +1 -1
  166. package/lib/src/embed/ts-embed.d.ts +97 -9
  167. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  168. package/lib/src/embed/ts-embed.js +77 -36
  169. package/lib/src/embed/ts-embed.js.map +1 -1
  170. package/lib/src/embed/ts-embed.spec.js +537 -3
  171. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  172. package/lib/src/index.d.ts +3 -3
  173. package/lib/src/index.d.ts.map +1 -1
  174. package/lib/src/index.js +2 -2
  175. package/lib/src/index.js.map +1 -1
  176. package/lib/src/react/all-types-export.d.ts +1 -1
  177. package/lib/src/react/all-types-export.d.ts.map +1 -1
  178. package/lib/src/react/all-types-export.js +1 -1
  179. package/lib/src/react/all-types-export.js.map +1 -1
  180. package/lib/src/react/all-types-export.parity.spec.d.ts +2 -0
  181. package/lib/src/react/all-types-export.parity.spec.d.ts.map +1 -0
  182. package/lib/src/react/all-types-export.parity.spec.js +191 -0
  183. package/lib/src/react/all-types-export.parity.spec.js.map +1 -0
  184. package/lib/src/react/index.d.ts +66 -32
  185. package/lib/src/react/index.d.ts.map +1 -1
  186. package/lib/src/react/index.js +5 -3
  187. package/lib/src/react/index.js.map +1 -1
  188. package/lib/src/react/index.spec.js +102 -1
  189. package/lib/src/react/index.spec.js.map +1 -1
  190. package/lib/src/types.d.ts +330 -18
  191. package/lib/src/types.d.ts.map +1 -1
  192. package/lib/src/types.js +182 -12
  193. package/lib/src/types.js.map +1 -1
  194. package/lib/src/utils.d.ts +5 -0
  195. package/lib/src/utils.d.ts.map +1 -1
  196. package/lib/src/utils.js +17 -0
  197. package/lib/src/utils.js.map +1 -1
  198. package/lib/src/utils.spec.js +38 -1
  199. package/lib/src/utils.spec.js.map +1 -1
  200. package/lib/src/visual-embed-sdk.d.ts +713 -60
  201. package/package.json +1 -1
  202. package/src/config.ts +1 -0
  203. package/src/css-variables.ts +32 -0
  204. package/src/embed/app.spec.ts +335 -1
  205. package/src/embed/app.ts +71 -13
  206. package/src/embed/base.ts +1 -1
  207. package/src/embed/conversation.spec.ts +136 -0
  208. package/src/embed/conversation.ts +181 -3
  209. package/src/embed/events.spec.ts +4 -0
  210. package/src/embed/host-events.spec.ts +48 -0
  211. package/src/embed/hostEventClient/host-event-client.spec.ts +34 -0
  212. package/src/embed/hostEventClient/host-event-client.ts +2 -2
  213. package/src/embed/liveboard.spec.ts +457 -2
  214. package/src/embed/liveboard.ts +74 -15
  215. package/src/embed/search.spec.ts +31 -0
  216. package/src/embed/spotter-utils.spec.ts +72 -0
  217. package/src/embed/spotter-utils.ts +21 -1
  218. package/src/embed/spotter-viz-utils.ts +9 -10
  219. package/src/embed/ts-embed.spec.ts +699 -3
  220. package/src/embed/ts-embed.ts +91 -41
  221. package/src/index.ts +43 -2
  222. package/src/react/all-types-export.parity.spec.ts +208 -0
  223. package/src/react/all-types-export.ts +22 -0
  224. package/src/react/index.spec.tsx +158 -0
  225. package/src/react/index.tsx +70 -33
  226. package/src/types.ts +329 -16
  227. package/src/utils.spec.ts +49 -0
  228. package/src/utils.ts +16 -0
package/src/embed/base.ts CHANGED
@@ -233,7 +233,7 @@ export const getIsInitCalled = (): boolean => !!getValueFromWindow(initFlagKey)?
233
233
  /**
234
234
  * Initializes the Visual Embed SDK globally and perform
235
235
  * authentication if applicable. This function needs to be called before any ThoughtSpot
236
- * component like Liveboard etc can be embedded. But need not wait for AuthEvent.SUCCESS
236
+ * component like Liveboard etc can be embedded. But need not wait for AuthStatus.SUCCESS
237
237
  * to actually embed. That is handled internally.
238
238
  * @param embedConfig The configuration object containing ThoughtSpot host,
239
239
  * authentication mechanism and so on.
@@ -537,6 +537,49 @@ describe('ConversationEmbed', () => {
537
537
  );
538
538
  });
539
539
 
540
+ it('should render the conversation embed with spotterAnalystConfig.analystId in the url', async () => {
541
+ const viewConfig: SpotterEmbedViewConfig = {
542
+ worksheetId: 'worksheetId',
543
+ searchOptions: {
544
+ searchQuery: 'searchQuery',
545
+ },
546
+ spotterAnalystConfig: {
547
+ analystId: 'analyst-id-1234',
548
+ },
549
+ };
550
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
551
+ await conversationEmbed.render();
552
+ expectUrlMatchesWithParams(
553
+ getIFrameSrc(),
554
+ `http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&analystId=analyst-id-1234#/embed/insights/conv-assist?worksheet=worksheetId&query=searchQuery`,
555
+ );
556
+ });
557
+
558
+ it('should not add analystId to the url when spotterAnalystConfig is not provided', async () => {
559
+ const viewConfig: SpotterEmbedViewConfig = {
560
+ worksheetId: 'worksheetId',
561
+ searchOptions: {
562
+ searchQuery: 'searchQuery',
563
+ },
564
+ };
565
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
566
+ await conversationEmbed.render();
567
+ expect(getIFrameSrc()).not.toContain('analystId');
568
+ });
569
+
570
+ it('should not add analystId to the url when spotterAnalystConfig is empty', async () => {
571
+ const viewConfig: SpotterEmbedViewConfig = {
572
+ worksheetId: 'worksheetId',
573
+ searchOptions: {
574
+ searchQuery: 'searchQuery',
575
+ },
576
+ spotterAnalystConfig: {},
577
+ };
578
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
579
+ await conversationEmbed.render();
580
+ expect(getIFrameSrc()).not.toContain('analystId');
581
+ });
582
+
540
583
  describe('spotter chat hiddenActions', () => {
541
584
  it.each([
542
585
  ['SpotterChatConnectorResources', Action.SpotterChatConnectorResources],
@@ -548,6 +591,8 @@ describe('ConversationEmbed', () => {
548
591
  ['SpotterAnalystDelete', Action.SpotterAnalystDelete],
549
592
  ['SpotterAnalystMakeACopy', Action.SpotterAnalystMakeACopy],
550
593
  ['SpotterAnalystSidebar', Action.SpotterAnalystSidebar],
594
+ ['SpotterAnalystList', Action.SpotterAnalystList],
595
+ ['SpotterDefaultAnalyst', Action.SpotterDefaultAnalyst],
551
596
  ])('should render with hiddenActions for %s', async (_, action) => {
552
597
  const viewConfig: SpotterEmbedViewConfig = {
553
598
  worksheetId: 'worksheetId',
@@ -592,6 +637,8 @@ describe('ConversationEmbed', () => {
592
637
  ['SpotterAnalystDelete', Action.SpotterAnalystDelete],
593
638
  ['SpotterAnalystMakeACopy', Action.SpotterAnalystMakeACopy],
594
639
  ['SpotterAnalystSidebar', Action.SpotterAnalystSidebar],
640
+ ['SpotterAnalystList', Action.SpotterAnalystList],
641
+ ['SpotterDefaultAnalyst', Action.SpotterDefaultAnalyst],
595
642
  ])('should render with disabledActions for %s', async (_, action) => {
596
643
  const disabledReason = 'testing disabled reason';
597
644
  const viewConfig: SpotterEmbedViewConfig = {
@@ -922,3 +969,92 @@ describe('SpotterEmbed updatedSpotterExperience', () => {
922
969
  );
923
970
  });
924
971
  });
972
+
973
+ describe('SpotterEmbed APP_INIT starterPrompts', () => {
974
+ const mockEmbedEventPayload = { type: EmbedEvent.APP_INIT, data: {} };
975
+
976
+ async function getAppInitResponse(viewConfig: SpotterEmbedViewConfig) {
977
+ const embed = new SpotterEmbed(getRootEl(), viewConfig);
978
+ embed.render();
979
+ const mockPort: any = { postMessage: jest.fn() };
980
+ await executeAfterWait(() => {
981
+ postMessageToParent(getIFrameEl().contentWindow, mockEmbedEventPayload, mockPort);
982
+ });
983
+ await executeAfterWait(() => {});
984
+ return mockPort.postMessage.mock.calls[0]?.[0];
985
+ }
986
+
987
+ it('should include starterPrompts in embedParams when configured', async () => {
988
+ const response = await getAppInitResponse({
989
+ worksheetId: 'ws1',
990
+ spotterChatConfig: {
991
+ starterPrompts: {
992
+ enable: true,
993
+ quick: {
994
+ label: 'Quick',
995
+ questions: [{ label: 'Q1', prompt: 'P1' }],
996
+ },
997
+ research: { label: 'Research' },
998
+ previewData: { label: 'Explore' },
999
+ },
1000
+ },
1001
+ });
1002
+ expect(response.data.embedParams.starterPrompts).toEqual({
1003
+ enable: true,
1004
+ quick: {
1005
+ label: 'Quick',
1006
+ questions: [{ label: 'Q1', prompt: 'P1' }],
1007
+ },
1008
+ research: { label: 'Research' },
1009
+ previewData: { label: 'Explore' },
1010
+ });
1011
+ });
1012
+
1013
+ it('should forward the config as is, the app enforces the limits', async () => {
1014
+ const starterPrompts = {
1015
+ quick: {
1016
+ label: 'L'.repeat(50),
1017
+ questions: [
1018
+ { label: 'Q'.repeat(100), prompt: 'P'.repeat(400) },
1019
+ { label: 'Q2', prompt: 'P2' },
1020
+ { label: 'Q3', prompt: 'P3' },
1021
+ { label: 'Q4', prompt: 'P4' },
1022
+ { label: 'Q5', prompt: 'P5' },
1023
+ ],
1024
+ },
1025
+ previewData: { label: 'L'.repeat(50) },
1026
+ };
1027
+ const response = await getAppInitResponse({
1028
+ worksheetId: 'ws1',
1029
+ spotterChatConfig: { starterPrompts },
1030
+ });
1031
+ expect(response.data.embedParams.starterPrompts).toEqual(starterPrompts);
1032
+ });
1033
+
1034
+ it('should not include starterPrompts in embedParams when not configured', async () => {
1035
+ const response = await getAppInitResponse({ worksheetId: 'ws1' });
1036
+ expect(response.data.embedParams?.starterPrompts).toBeUndefined();
1037
+ });
1038
+
1039
+ it('exposes per-pill starter-prompt actions with the strings the app gates on', () => {
1040
+ expect(Action.QuickSearchPill).toBe('quickSearchPill');
1041
+ expect(Action.DeepAnalysisPill).toBe('deepAnalysisPill');
1042
+ expect(Action.DataLiteracyPill).toBe('dataLiteracyPill');
1043
+ });
1044
+
1045
+ it('forwards the enable feature flag when disabled', async () => {
1046
+ const response = await getAppInitResponse({
1047
+ worksheetId: 'ws1',
1048
+ spotterChatConfig: {
1049
+ starterPrompts: {
1050
+ enable: false,
1051
+ quick: { questions: [{ label: 'Q1', prompt: 'P1' }] },
1052
+ },
1053
+ },
1054
+ });
1055
+ expect(response.data.embedParams.starterPrompts).toEqual({
1056
+ enable: false,
1057
+ quick: { questions: [{ label: 'Q1', prompt: 'P1' }] },
1058
+ });
1059
+ });
1060
+ });
@@ -1,6 +1,6 @@
1
1
  import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter, ErrorDetailsTypes, EmbedErrorCodes, DefaultAppInitData, VisualizationOverrides, SpotterFileUploadFileTypes } from '../types';
2
2
  import { TsEmbed } from './ts-embed';
3
- import { buildSpotterSidebarAppInitData, buildSpotterShareConversationAppInitData } from './spotter-utils';
3
+ import { buildSpotterSidebarAppInitData, buildSpotterShareConversationAppInitData, buildStarterPromptsAppInitData } from './spotter-utils';
4
4
  import { getQueryParamString, getFilterQuery, getRuntimeParameters, setParamIfDefined } from '../utils';
5
5
 
6
6
  /**
@@ -227,6 +227,91 @@ export interface SpotterShareConversationConfig {
227
227
  spotterSharedConversationExitLabel?: string;
228
228
  }
229
229
 
230
+ /**
231
+ * A single starter prompt question shown under a category pill.
232
+ * @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
233
+ * @group Embed components
234
+ */
235
+ export interface StarterPromptQuestion {
236
+ /**
237
+ * Short label shown as a clickable suggestion. Falls back to `prompt` when
238
+ * omitted. ThoughtSpot truncates it beyond 80 characters.
239
+ */
240
+ label?: string;
241
+ /**
242
+ * Prompt text sent to Spotter on click. ThoughtSpot truncates it beyond
243
+ * 300 characters.
244
+ */
245
+ prompt: string;
246
+ }
247
+
248
+ /**
249
+ * Configuration for a starter prompt category with questions
250
+ * (`quick` and `research`).
251
+ * @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
252
+ * @group Embed components
253
+ */
254
+ export interface StarterPromptCategory {
255
+ /**
256
+ * Overrides the default category pill label. ThoughtSpot truncates it
257
+ * beyond 30 characters.
258
+ */
259
+ label?: string;
260
+ /**
261
+ * Replaces the backend-generated prompts. ThoughtSpot renders the first 4
262
+ * and drops any entry without a `prompt`.
263
+ */
264
+ questions?: StarterPromptQuestion[];
265
+ }
266
+
267
+ /**
268
+ * Configuration for the Data Literacy starter prompt category.
269
+ * Only the label is customizable; the prompt text comes from the backend.
270
+ * @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
271
+ * @group Embed components
272
+ */
273
+ export interface StarterPreviewDataCategory {
274
+ /**
275
+ * Overrides the default category pill label. ThoughtSpot truncates it
276
+ * beyond 30 characters.
277
+ */
278
+ label?: string;
279
+ }
280
+
281
+ /**
282
+ * Content configuration for the Spotter starter prompts.
283
+ * Keys are fixed: `quick` (Basic Search), `research` (Deep Analysis),
284
+ * `previewData` (Data Literacy) and `liveboard` (Liveboard chat panel).
285
+ *
286
+ * Note: this controls the Spotter chat interface only. The starter prompts on
287
+ * the Liveboard SpotterViz surface are configured separately through
288
+ * {@link SpotterVizConfig.customStarterPrompts}.
289
+ * @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
290
+ * @group Embed components
291
+ */
292
+ export interface StarterPromptsConfig {
293
+ /**
294
+ * Turns the starter prompts surface on. Must be set explicitly, an
295
+ * unset flag leaves the surface off.
296
+ *
297
+ * Either this or `enableStarterPrompts` turns the surface on, so `false`
298
+ * here does not switch it off while `enableStarterPrompts` is `true`.
299
+ * @default false
300
+ */
301
+ enable?: boolean;
302
+ /** Basic Search category configuration. */
303
+ quick?: StarterPromptCategory;
304
+ /** Deep Analysis category configuration. */
305
+ research?: StarterPromptCategory;
306
+ /** Data Literacy category configuration. */
307
+ previewData?: StarterPreviewDataCategory;
308
+ /**
309
+ * Starter prompts for the Spotter chat panel on a Liveboard.
310
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
311
+ */
312
+ liveboard?: StarterPromptQuestion[];
313
+ }
314
+
230
315
  /**
231
316
  * Configuration for customizing Spotter chat UI branding.
232
317
  * @version SDK: 1.46.0 | ThoughtSpot: 26.4.0.cl
@@ -267,11 +352,84 @@ export interface SpotterChatViewConfig {
267
352
  /**
268
353
  * Enables starter prompts in the Spotter chat interface.
269
354
  *
270
- * Supported embed types: SpotterEmbed, LiveboardEmbed, AppEmbed
355
+ * Either this or `starterPrompts.enable` turns the surface on, so it stays
356
+ * on while this is `true` even if `starterPrompts.enable` is `false`.
357
+ *
358
+ * Supported embed types: `SpotterEmbed`, `LiveboardEmbed`, `AppEmbed`
271
359
  * @version SDK: 1.51.0 | ThoughtSpot: 26.8.0.cl
272
360
  * @default false
273
361
  */
274
362
  enableStarterPrompts?: boolean;
363
+ /**
364
+ * Customizes the labels and questions of the Spotter starter prompts.
365
+ * Individual pills are hidden or shown with `hiddenActions` /
366
+ * `visibleActions` using `Action.QuickSearchPill`,
367
+ * `Action.DeepAnalysisPill` and `Action.DataLiteracyPill`.
368
+ *
369
+ * Supported embed types: `SpotterEmbed`, `LiveboardEmbed`, `AppEmbed`
370
+ * @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
371
+ * @example
372
+ * ```js
373
+ * const embed = new SpotterEmbed('#tsEmbed', {
374
+ * worksheetId: 'worksheet-id',
375
+ * hiddenActions: [Action.DeepAnalysisPill],
376
+ * spotterChatConfig: {
377
+ * starterPrompts: {
378
+ * enable: true,
379
+ * quick: {
380
+ * label: 'Quick questions',
381
+ * questions: [
382
+ * { label: 'Top products', prompt: 'What are the top products by revenue?' },
383
+ * ],
384
+ * },
385
+ * previewData: { label: 'Explore your data' },
386
+ * },
387
+ * },
388
+ * })
389
+ * ```
390
+ */
391
+ starterPrompts?: StarterPromptsConfig;
392
+ /**
393
+ * Opens the Spotter chat panel when the Liveboard loads.
394
+ *
395
+ * Supported embed types: `LiveboardEmbed`, `AppEmbed`
396
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
397
+ * @default true
398
+ * @example
399
+ * ```js
400
+ * const embed = new LiveboardEmbed('#tsEmbed', {
401
+ * liveboardId: 'liveboard-id',
402
+ * spotterChatConfig: {
403
+ * openSpotterOnLiveboardByDefault: false,
404
+ * },
405
+ * })
406
+ * ```
407
+ */
408
+ openSpotterOnLiveboardByDefault?: boolean;
409
+ }
410
+
411
+ /**
412
+ * Configuration for the Spotter Analyst experience.
413
+ * Can be used in SpotterEmbed.
414
+ * @group Embed components
415
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
416
+ * @example
417
+ * ```js
418
+ * const embed = new SpotterEmbed('#tsEmbed', {
419
+ * ... //other embed view config
420
+ * spotterAnalystConfig: {
421
+ * analystId: 'analyst-id-1234',
422
+ * },
423
+ * })
424
+ * ```
425
+ */
426
+ export interface SpotterAnalystConfig {
427
+ /**
428
+ * Pins the embed to a single spotter analyst. Implies no default Spotter
429
+ * and no "Show all".
430
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
431
+ */
432
+ analystId?: string;
275
433
  }
276
434
 
277
435
  /**
@@ -303,6 +461,22 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
303
461
  * @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
304
462
  */
305
463
  dataSources?: string[];
464
+ /**
465
+ * Configuration for the Spotter Analyst experience.
466
+ *
467
+ * Supported embed types: `SpotterEmbed`
468
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.10.0.cl
469
+ * @example
470
+ * ```js
471
+ * const embed = new SpotterEmbed('#tsEmbed', {
472
+ * ... //other embed view config
473
+ * spotterAnalystConfig: {
474
+ * analystId: 'analyst-id-1234',
475
+ * },
476
+ * })
477
+ * ```
478
+ */
479
+ spotterAnalystConfig?: SpotterAnalystConfig;
306
480
  /**
307
481
  * Ability to pass a starting search query to the conversation.
308
482
  */
@@ -626,6 +800,7 @@ export interface SpotterAppInitData extends DefaultAppInitData {
626
800
  spotterSidebarConfig?: SpotterSidebarViewConfig;
627
801
  spotterShareConversationConfig?: SpotterShareConversationConfig;
628
802
  visualOverridesParams?: VisualizationOverrides | null;
803
+ starterPrompts?: StarterPromptsConfig;
629
804
  };
630
805
  }
631
806
 
@@ -674,7 +849,8 @@ export class SpotterEmbed extends TsEmbed {
674
849
  this.viewConfig,
675
850
  this.handleError.bind(this),
676
851
  );
677
- return buildSpotterShareConversationAppInitData(sidebarInitData, this.viewConfig);
852
+ const shareInitData = buildSpotterShareConversationAppInitData(sidebarInitData, this.viewConfig);
853
+ return buildStarterPromptsAppInitData(shareInitData, this.viewConfig);
678
854
  }
679
855
 
680
856
  protected getEmbedParamsObject() {
@@ -695,6 +871,7 @@ export class SpotterEmbed extends TsEmbed {
695
871
  defaultQueryMode,
696
872
  enableStopAnswerGenerationEmbed,
697
873
  spotterChatConfig,
874
+ spotterAnalystConfig,
698
875
  } = this.viewConfig;
699
876
 
700
877
  const queryParams = this.getBaseQueryParams();
@@ -710,6 +887,7 @@ export class SpotterEmbed extends TsEmbed {
710
887
  setParamIfDefined(queryParams, Param.ShowSpotterRadiance, showSpotterRadiance, true);
711
888
  setParamIfDefined(queryParams, Param.DefaultQueryMode, defaultQueryMode);
712
889
  setParamIfDefined(queryParams, Param.EnableStopAnswerGenerationEmbed, enableStopAnswerGenerationEmbed, true);
890
+ setParamIfDefined(queryParams, Param.AnalystId, spotterAnalystConfig?.analystId);
713
891
 
714
892
  // Handle spotterChatConfig params
715
893
  if (spotterChatConfig) {
@@ -474,6 +474,10 @@ describe('Action enum values', () => {
474
474
  test('RemoveFromFavorites should resolve to its string value', () => {
475
475
  expect(Action.RemoveFromFavorites).toBe('removeFromFavorites');
476
476
  });
477
+
478
+ test('EditInputTable should resolve to its string value', () => {
479
+ expect(Action.EditInputTable).toBe('editInputTable');
480
+ });
477
481
  });
478
482
 
479
483
  describe('EmbedEvent basic routing', () => {
@@ -180,6 +180,54 @@ describe('HostEvent.OpenParameter', () => {
180
180
  });
181
181
  });
182
182
 
183
+ // ---------------------------------------------------------------------------
184
+ // 10c – OpenAddFilterModal
185
+ // ---------------------------------------------------------------------------
186
+ describe('HostEvent.OpenAddFilterModal', () => {
187
+ test('postMessage type is openAddFilterModal (camelCase, no payload)', async () => {
188
+ mockMessageChannel();
189
+ const { lb, iframe } = await renderLiveboard();
190
+ await executeAfterWait(() => {
191
+ lb.trigger(HostEvent.OpenAddFilterModal);
192
+ expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(
193
+ expect.objectContaining({ type: 'openAddFilterModal' }),
194
+ thoughtSpotHost,
195
+ expect.anything(),
196
+ );
197
+ });
198
+ });
199
+
200
+ test('returns null when !isRendered', async () => {
201
+ const lb = unrenderedLiveboard();
202
+ const result = await lb.trigger(HostEvent.OpenAddFilterModal);
203
+ expect(result).toBeNull();
204
+ });
205
+ });
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // 10d – OpenAddParameterModal
209
+ // ---------------------------------------------------------------------------
210
+ describe('HostEvent.OpenAddParameterModal', () => {
211
+ test('postMessage type is openAddParameterModal (camelCase, no payload)', async () => {
212
+ mockMessageChannel();
213
+ const { lb, iframe } = await renderLiveboard();
214
+ await executeAfterWait(() => {
215
+ lb.trigger(HostEvent.OpenAddParameterModal);
216
+ expect(iframe.contentWindow.postMessage).toHaveBeenCalledWith(
217
+ expect.objectContaining({ type: 'openAddParameterModal' }),
218
+ thoughtSpotHost,
219
+ expect.anything(),
220
+ );
221
+ });
222
+ });
223
+
224
+ test('returns null when !isRendered', async () => {
225
+ const lb = unrenderedLiveboard();
226
+ const result = await lb.trigger(HostEvent.OpenAddParameterModal);
227
+ expect(result).toBeNull();
228
+ });
229
+ });
230
+
183
231
  // ---------------------------------------------------------------------------
184
232
  // 11 – AddColumns
185
233
  // ---------------------------------------------------------------------------
@@ -1154,4 +1154,38 @@ describe('HostEventClient', () => {
1154
1154
  expect(result.answerId).toBeUndefined();
1155
1155
  });
1156
1156
  });
1157
+
1158
+ describe('trigger typing contracts (compile-time)', () => {
1159
+ // These assertions are enforced by ts-jest at compile time; the runtime
1160
+ // expect() is trivial. They lock the PayloadT default on
1161
+ // triggerHostEvent: no-payload calls must infer the contract response
1162
+ // instead of collapsing to `any`.
1163
+ type IsAny<T> = 0 extends 1 & T ? true : false;
1164
+ type Extends<A, B> = A extends B ? true : false;
1165
+
1166
+ it('infers typed response for no-payload contracted events and keeps any for uncontracted', () => {
1167
+ const { client } = createHostEventClient();
1168
+
1169
+ // Contracted event, called with no payload — the fixed case.
1170
+ const getTabs = () => client.triggerHostEvent(HostEvent.GetTabs);
1171
+ type TabsResponse = Awaited<ReturnType<typeof getTabs>>;
1172
+ const tabsIsTyped: IsAny<TabsResponse> = false;
1173
+ const tabsHasContractFields: Extends<
1174
+ TabsResponse,
1175
+ { numberOfTabs: number; orderedTabIds: string[] }
1176
+ > = true;
1177
+ const probeUnknownField = (r: TabsResponse) =>
1178
+ // @ts-expect-error — field not on the GetTabs contract (was silent when `any`)
1179
+ r.tabCount;
1180
+ void probeUnknownField;
1181
+
1182
+ // Uncontracted event — must remain `any` with or without payload.
1183
+ const reload = () => client.triggerHostEvent(HostEvent.Reload);
1184
+ type ReloadResponse = Awaited<ReturnType<typeof reload>>;
1185
+ const reloadStaysAny: IsAny<ReloadResponse> = true;
1186
+
1187
+ expect([tabsIsTyped, tabsHasContractFields, reloadStaysAny])
1188
+ .toEqual([false, true, true]);
1189
+ });
1190
+ });
1157
1191
  });
@@ -281,8 +281,8 @@ export class HostEventClient {
281
281
  */
282
282
  public async triggerHostEvent<
283
283
  HostEventT extends HostEvent,
284
- PayloadT,
285
- ContextT extends ContextType,
284
+ PayloadT = HostEventRequest<HostEventT>,
285
+ ContextT extends ContextType = ContextType,
286
286
  >(
287
287
  hostEvent: HostEventT,
288
288
  payload?: TriggerPayload<PayloadT, HostEventT>,