@thoughtspot/visual-embed-sdk 1.45.1 → 1.45.3

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 (213) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/authToken.d.ts +1 -1
  3. package/cjs/src/authToken.d.ts.map +1 -1
  4. package/cjs/src/authToken.js +2 -2
  5. package/cjs/src/authToken.js.map +1 -1
  6. package/cjs/src/authToken.spec.js +71 -0
  7. package/cjs/src/authToken.spec.js.map +1 -1
  8. package/cjs/src/css-variables.d.ts +48 -0
  9. package/cjs/src/css-variables.d.ts.map +1 -1
  10. package/cjs/src/embed/app.d.ts +37 -0
  11. package/cjs/src/embed/app.d.ts.map +1 -1
  12. package/cjs/src/embed/app.js +37 -1
  13. package/cjs/src/embed/app.js.map +1 -1
  14. package/cjs/src/embed/app.spec.js +24 -0
  15. package/cjs/src/embed/app.spec.js.map +1 -1
  16. package/cjs/src/embed/conversation.d.ts +127 -9
  17. package/cjs/src/embed/conversation.d.ts.map +1 -1
  18. package/cjs/src/embed/conversation.js +41 -18
  19. package/cjs/src/embed/conversation.js.map +1 -1
  20. package/cjs/src/embed/conversation.spec.js +96 -3
  21. package/cjs/src/embed/conversation.spec.js.map +1 -1
  22. package/cjs/src/embed/hostEventClient/contracts.d.ts +3 -3
  23. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  24. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  25. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +8 -8
  26. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  27. package/cjs/src/embed/hostEventClient/host-event-client.js +18 -18
  28. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  29. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +7 -7
  30. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  31. package/cjs/src/embed/liveboard.d.ts +40 -3
  32. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  33. package/cjs/src/embed/liveboard.js +40 -12
  34. package/cjs/src/embed/liveboard.js.map +1 -1
  35. package/cjs/src/embed/liveboard.spec.js +180 -8
  36. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  37. package/cjs/src/embed/ts-embed.d.ts +23 -2
  38. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  39. package/cjs/src/embed/ts-embed.js +64 -22
  40. package/cjs/src/embed/ts-embed.js.map +1 -1
  41. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  42. package/cjs/src/embed/ts-embed.spec.js +138 -19
  43. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  44. package/cjs/src/errors.d.ts +1 -0
  45. package/cjs/src/errors.d.ts.map +1 -1
  46. package/cjs/src/errors.js +1 -0
  47. package/cjs/src/errors.js.map +1 -1
  48. package/cjs/src/index.d.ts +3 -3
  49. package/cjs/src/index.d.ts.map +1 -1
  50. package/cjs/src/index.js +3 -2
  51. package/cjs/src/index.js.map +1 -1
  52. package/cjs/src/types.d.ts +356 -42
  53. package/cjs/src/types.d.ts.map +1 -1
  54. package/cjs/src/types.js +227 -20
  55. package/cjs/src/types.js.map +1 -1
  56. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  57. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  58. package/cjs/src/utils/graphql/answerService/answer-queries.js +23 -1
  59. package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  60. package/cjs/src/utils/graphql/answerService/answerService.d.ts +2 -1
  61. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  62. package/cjs/src/utils/graphql/answerService/answerService.js +9 -1
  63. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  64. package/cjs/src/utils/graphql/answerService/answerService.spec.js +73 -0
  65. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  66. package/cjs/src/utils/processTrigger.d.ts +3 -2
  67. package/cjs/src/utils/processTrigger.d.ts.map +1 -1
  68. package/cjs/src/utils/processTrigger.js +4 -2
  69. package/cjs/src/utils/processTrigger.js.map +1 -1
  70. package/cjs/src/utils.d.ts +20 -1
  71. package/cjs/src/utils.d.ts.map +1 -1
  72. package/cjs/src/utils.js +40 -1
  73. package/cjs/src/utils.js.map +1 -1
  74. package/cjs/src/utils.spec.js +49 -0
  75. package/cjs/src/utils.spec.js.map +1 -1
  76. package/dist/{index-Dgzjq7qH.js → index-BuwECGdm.js} +1 -1
  77. package/dist/src/authToken.d.ts +1 -1
  78. package/dist/src/authToken.d.ts.map +1 -1
  79. package/dist/src/css-variables.d.ts +48 -0
  80. package/dist/src/css-variables.d.ts.map +1 -1
  81. package/dist/src/embed/app.d.ts +37 -0
  82. package/dist/src/embed/app.d.ts.map +1 -1
  83. package/dist/src/embed/conversation.d.ts +127 -9
  84. package/dist/src/embed/conversation.d.ts.map +1 -1
  85. package/dist/src/embed/hostEventClient/contracts.d.ts +3 -3
  86. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  87. package/dist/src/embed/hostEventClient/host-event-client.d.ts +8 -8
  88. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  89. package/dist/src/embed/liveboard.d.ts +40 -3
  90. package/dist/src/embed/liveboard.d.ts.map +1 -1
  91. package/dist/src/embed/ts-embed.d.ts +23 -2
  92. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  93. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  94. package/dist/src/errors.d.ts +1 -0
  95. package/dist/src/errors.d.ts.map +1 -1
  96. package/dist/src/index.d.ts +3 -3
  97. package/dist/src/index.d.ts.map +1 -1
  98. package/dist/src/types.d.ts +356 -42
  99. package/dist/src/types.d.ts.map +1 -1
  100. package/dist/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  101. package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  102. package/dist/src/utils/graphql/answerService/answerService.d.ts +2 -1
  103. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  104. package/dist/src/utils/processTrigger.d.ts +3 -2
  105. package/dist/src/utils/processTrigger.d.ts.map +1 -1
  106. package/dist/src/utils.d.ts +20 -1
  107. package/dist/src/utils.d.ts.map +1 -1
  108. package/dist/tsembed-react.es.js +501 -98
  109. package/dist/tsembed-react.js +500 -97
  110. package/dist/tsembed.es.js +516 -113
  111. package/dist/tsembed.js +29956 -29553
  112. package/dist/visual-embed-sdk-react-full.d.ts +819 -282
  113. package/dist/visual-embed-sdk-react.d.ts +818 -281
  114. package/dist/visual-embed-sdk.d.ts +882 -321
  115. package/lib/package.json +1 -1
  116. package/lib/src/authToken.d.ts +1 -1
  117. package/lib/src/authToken.d.ts.map +1 -1
  118. package/lib/src/authToken.js +2 -2
  119. package/lib/src/authToken.js.map +1 -1
  120. package/lib/src/authToken.spec.js +72 -1
  121. package/lib/src/authToken.spec.js.map +1 -1
  122. package/lib/src/css-variables.d.ts +48 -0
  123. package/lib/src/css-variables.d.ts.map +1 -1
  124. package/lib/src/embed/app.d.ts +37 -0
  125. package/lib/src/embed/app.d.ts.map +1 -1
  126. package/lib/src/embed/app.js +39 -3
  127. package/lib/src/embed/app.js.map +1 -1
  128. package/lib/src/embed/app.spec.js +24 -0
  129. package/lib/src/embed/app.spec.js.map +1 -1
  130. package/lib/src/embed/conversation.d.ts +127 -9
  131. package/lib/src/embed/conversation.d.ts.map +1 -1
  132. package/lib/src/embed/conversation.js +42 -19
  133. package/lib/src/embed/conversation.js.map +1 -1
  134. package/lib/src/embed/conversation.spec.js +96 -3
  135. package/lib/src/embed/conversation.spec.js.map +1 -1
  136. package/lib/src/embed/hostEventClient/contracts.d.ts +3 -3
  137. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  138. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  139. package/lib/src/embed/hostEventClient/host-event-client.d.ts +8 -8
  140. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  141. package/lib/src/embed/hostEventClient/host-event-client.js +18 -18
  142. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  143. package/lib/src/embed/hostEventClient/host-event-client.spec.js +7 -7
  144. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  145. package/lib/src/embed/liveboard.d.ts +40 -3
  146. package/lib/src/embed/liveboard.d.ts.map +1 -1
  147. package/lib/src/embed/liveboard.js +41 -13
  148. package/lib/src/embed/liveboard.js.map +1 -1
  149. package/lib/src/embed/liveboard.spec.js +180 -8
  150. package/lib/src/embed/liveboard.spec.js.map +1 -1
  151. package/lib/src/embed/ts-embed.d.ts +23 -2
  152. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  153. package/lib/src/embed/ts-embed.js +64 -22
  154. package/lib/src/embed/ts-embed.js.map +1 -1
  155. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  156. package/lib/src/embed/ts-embed.spec.js +139 -20
  157. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  158. package/lib/src/errors.d.ts +1 -0
  159. package/lib/src/errors.d.ts.map +1 -1
  160. package/lib/src/errors.js +1 -0
  161. package/lib/src/errors.js.map +1 -1
  162. package/lib/src/index.d.ts +3 -3
  163. package/lib/src/index.d.ts.map +1 -1
  164. package/lib/src/index.js +2 -2
  165. package/lib/src/index.js.map +1 -1
  166. package/lib/src/types.d.ts +356 -42
  167. package/lib/src/types.d.ts.map +1 -1
  168. package/lib/src/types.js +226 -19
  169. package/lib/src/types.js.map +1 -1
  170. package/lib/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  171. package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  172. package/lib/src/utils/graphql/answerService/answer-queries.js +22 -0
  173. package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  174. package/lib/src/utils/graphql/answerService/answerService.d.ts +2 -1
  175. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  176. package/lib/src/utils/graphql/answerService/answerService.js +9 -1
  177. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  178. package/lib/src/utils/graphql/answerService/answerService.spec.js +73 -0
  179. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  180. package/lib/src/utils/processTrigger.d.ts +3 -2
  181. package/lib/src/utils/processTrigger.d.ts.map +1 -1
  182. package/lib/src/utils/processTrigger.js +4 -2
  183. package/lib/src/utils/processTrigger.js.map +1 -1
  184. package/lib/src/utils.d.ts +20 -1
  185. package/lib/src/utils.d.ts.map +1 -1
  186. package/lib/src/utils.js +36 -0
  187. package/lib/src/utils.js.map +1 -1
  188. package/lib/src/utils.spec.js +50 -1
  189. package/lib/src/utils.spec.js.map +1 -1
  190. package/package.json +1 -1
  191. package/src/authToken.spec.ts +91 -2
  192. package/src/authToken.ts +2 -2
  193. package/src/css-variables.ts +60 -0
  194. package/src/embed/app.spec.ts +32 -0
  195. package/src/embed/app.ts +97 -1
  196. package/src/embed/conversation.spec.ts +117 -3
  197. package/src/embed/conversation.ts +188 -29
  198. package/src/embed/hostEventClient/contracts.ts +4 -4
  199. package/src/embed/hostEventClient/host-event-client.spec.ts +7 -1
  200. package/src/embed/hostEventClient/host-event-client.ts +22 -11
  201. package/src/embed/liveboard.spec.ts +264 -10
  202. package/src/embed/liveboard.ts +105 -14
  203. package/src/embed/ts-embed.spec.ts +184 -8
  204. package/src/embed/ts-embed.ts +81 -24
  205. package/src/errors.ts +1 -0
  206. package/src/index.ts +7 -1
  207. package/src/types.ts +364 -40
  208. package/src/utils/graphql/answerService/answer-queries.ts +23 -0
  209. package/src/utils/graphql/answerService/answerService.spec.ts +87 -0
  210. package/src/utils/graphql/answerService/answerService.ts +13 -1
  211. package/src/utils/processTrigger.ts +6 -3
  212. package/src/utils.spec.ts +56 -0
  213. package/src/utils.ts +44 -0
@@ -1,7 +1,8 @@
1
1
  import { getAuthenticationToken, resetCachedAuthToken, validateAuthToken } from './authToken';
2
+ import * as authTokenModule from './authToken';
2
3
  import * as authServiceInstance from './utils/authService/authService';
3
- import { EmbedConfig } from './types';
4
- import { formatTemplate } from './utils';
4
+ import { EmbedConfig, AuthType } from './types';
5
+ import { formatTemplate, storeValueInWindow } from './utils';
5
6
  import { logger } from './utils/logger';
6
7
  import { ERROR_MESSAGE } from './errors';
7
8
 
@@ -75,4 +76,92 @@ describe('AuthToken Unit tests', () => {
75
76
 
76
77
  loggerSpy.mockRestore();
77
78
  });
79
+
80
+ describe('getAuthenticationToken: cached token skip validation condition', () => {
81
+ beforeEach(() => {
82
+ resetCachedAuthToken();
83
+ jest.clearAllMocks();
84
+ });
85
+
86
+ test('should validate cached token when validation is not skipped', async () => {
87
+ const cachedToken = 'cached-token-123';
88
+ storeValueInWindow('cachedAuthToken', cachedToken);
89
+
90
+ const validateAuthTokenSpy = jest.spyOn(authTokenModule, 'validateAuthToken')
91
+ .mockImplementation(() => Promise.resolve(true));
92
+
93
+ const getAuthTokenMock = jest.fn().mockResolvedValue('new-token-456');
94
+ const config: EmbedConfig = {
95
+ thoughtSpotHost: 'test',
96
+ authType: AuthType.TrustedAuthToken,
97
+ getAuthToken: getAuthTokenMock,
98
+ disableTokenVerification: false,
99
+ };
100
+
101
+ const token = await getAuthenticationToken(config, false);
102
+
103
+ expect(token).toBe(cachedToken);
104
+ // Should validate cached token (condition at line 23 is true)
105
+ expect(validateAuthTokenSpy).toHaveBeenCalledWith(config, cachedToken, true);
106
+ expect(getAuthTokenMock).not.toHaveBeenCalled();
107
+
108
+ validateAuthTokenSpy.mockReset();
109
+ });
110
+
111
+ test('should skip cached token validation when disableTokenVerification is true', async () => {
112
+ const cachedToken = 'cached-token-123';
113
+ storeValueInWindow('cachedAuthToken', cachedToken);
114
+
115
+ const validateAuthTokenSpy = jest.spyOn(authTokenModule, 'validateAuthToken')
116
+ .mockImplementation(() => Promise.resolve(true));
117
+
118
+ const newToken = 'new-token-456';
119
+ const getAuthTokenMock = jest.fn().mockResolvedValue(newToken);
120
+ const config: EmbedConfig = {
121
+ thoughtSpotHost: 'test',
122
+ authType: AuthType.TrustedAuthToken,
123
+ getAuthToken: getAuthTokenMock,
124
+ disableTokenVerification: true,
125
+ };
126
+
127
+ const token = await getAuthenticationToken(config, false);
128
+
129
+ expect(token).toBe(newToken);
130
+ // Should not validate cached token (condition at line 23 is false)
131
+ expect(validateAuthTokenSpy).not.toHaveBeenCalledWith(config, cachedToken, true);
132
+ // But should validate new token (though it returns early when disableTokenVerification is true)
133
+ expect(validateAuthTokenSpy).toHaveBeenCalledWith(config, newToken);
134
+ expect(getAuthTokenMock).toHaveBeenCalled();
135
+
136
+ validateAuthTokenSpy.mockReset();
137
+ });
138
+
139
+ test('should skip cached token validation when skipvalidation is true', async () => {
140
+ const cachedToken = 'cached-token-123';
141
+ storeValueInWindow('cachedAuthToken', cachedToken);
142
+
143
+ const validateAuthTokenSpy = jest.spyOn(authTokenModule, 'validateAuthToken')
144
+ .mockImplementation(() => Promise.resolve(true));
145
+
146
+ const newToken = 'new-token-456';
147
+ const getAuthTokenMock = jest.fn().mockResolvedValue(newToken);
148
+ const config: EmbedConfig = {
149
+ thoughtSpotHost: 'test',
150
+ authType: AuthType.TrustedAuthToken,
151
+ getAuthToken: getAuthTokenMock,
152
+ disableTokenVerification: false,
153
+ };
154
+
155
+ const token = await getAuthenticationToken(config, true);
156
+
157
+ expect(token).toBe(newToken);
158
+ // Should not validate cached token (condition at line 23 is false)
159
+ expect(validateAuthTokenSpy).not.toHaveBeenCalledWith(config, cachedToken, true);
160
+ // But should validate new token
161
+ expect(validateAuthTokenSpy).toHaveBeenCalledWith(config, newToken);
162
+ expect(getAuthTokenMock).toHaveBeenCalled();
163
+
164
+ validateAuthTokenSpy.mockReset();
165
+ });
166
+ });
78
167
  });
package/src/authToken.ts CHANGED
@@ -16,11 +16,11 @@ const storeAuthTokenInCache = (token: string): void => {
16
16
  *
17
17
  * @param embedConfig
18
18
  */
19
- export async function getAuthenticationToken(embedConfig: EmbedConfig): Promise<string> {
19
+ export async function getAuthenticationToken(embedConfig: EmbedConfig, skipvalidation: boolean = false): Promise<string> {
20
20
  const cachedAuthToken = getCacheAuthToken();
21
21
  // Since we don't have token validation enabled , we cannot tell if the
22
22
  // cached token is valid or not. So we will always fetch a new token.
23
- if (cachedAuthToken && !embedConfig.disableTokenVerification) {
23
+ if (cachedAuthToken && !embedConfig.disableTokenVerification && !skipvalidation) {
24
24
  let isCachedTokenStillValid;
25
25
  try {
26
26
  isCachedTokenStillValid = await validateAuthToken(embedConfig, cachedAuthToken, true);
@@ -852,4 +852,64 @@ export interface CustomCssVariables {
852
852
  * Width of the Spotter chat window.
853
853
  */
854
854
  '--ts-var-spotter-chat-width'?: string;
855
+
856
+ /**
857
+ * Border color for the saved chats sidebar container.
858
+ */
859
+ '--ts-var-saved-chats-border-color'?: string;
860
+
861
+ /**
862
+ * Background color for the saved chats sidebar container.
863
+ */
864
+ '--ts-var-saved-chats-bg'?: string;
865
+
866
+ /**
867
+ * Text color for the saved chats sidebar container.
868
+ */
869
+ '--ts-var-saved-chats-text-color'?: string;
870
+
871
+ /**
872
+ * Border color for the saved chats sidebar header.
873
+ */
874
+ '--ts-var-saved-chats-header-border'?: string;
875
+
876
+ /**
877
+ * Color for the saved chats sidebar title text.
878
+ */
879
+ '--ts-var-saved-chats-title-color'?: string;
880
+
881
+ /**
882
+ * Background color for buttons (new chat, toggle, footer) in the saved chats sidebar.
883
+ */
884
+ '--ts-var-saved-chats-btn-bg'?: string;
885
+
886
+ /**
887
+ * Hover background color for buttons in the saved chats sidebar.
888
+ */
889
+ '--ts-var-saved-chats-btn-hover-bg'?: string;
890
+
891
+ /**
892
+ * Text color for conversation items in the saved chats sidebar.
893
+ */
894
+ '--ts-var-saved-chats-conv-text-color'?: string;
895
+
896
+ /**
897
+ * Background color for conversation items on hover in the saved chats sidebar.
898
+ */
899
+ '--ts-var-saved-chats-conv-hover-bg'?: string;
900
+
901
+ /**
902
+ * Background color for the active/selected conversation in the saved chats sidebar.
903
+ */
904
+ '--ts-var-saved-chats-conv-active-bg'?: string;
905
+
906
+ /**
907
+ * Border color for the saved chats sidebar footer.
908
+ */
909
+ '--ts-var-saved-chats-footer-border'?: string;
910
+
911
+ /**
912
+ * Color for section title text (e.g., "Recent", "Older") in the saved chats sidebar.
913
+ */
914
+ '--ts-var-saved-chats-section-title-color'?: string;
855
915
  }
@@ -443,6 +443,38 @@ describe('App embed tests', () => {
443
443
  });
444
444
  });
445
445
 
446
+ test('should set hideToolResponseCardBranding to true in url via spotterChatConfig', async () => {
447
+ const appEmbed = new AppEmbed(getRootEl(), {
448
+ ...defaultViewConfig,
449
+ spotterChatConfig: {
450
+ hideToolResponseCardBranding: true,
451
+ },
452
+ } as AppViewConfig);
453
+ appEmbed.render();
454
+ await executeAfterWait(() => {
455
+ expectUrlMatchesWithParams(
456
+ getIFrameSrc(),
457
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&hideToolResponseCardBranding=true${defaultParamsPost}#/home`,
458
+ );
459
+ });
460
+ });
461
+
462
+ test('should set toolResponseCardBrandingLabel in url via spotterChatConfig', async () => {
463
+ const appEmbed = new AppEmbed(getRootEl(), {
464
+ ...defaultViewConfig,
465
+ spotterChatConfig: {
466
+ toolResponseCardBrandingLabel: 'MyBrand',
467
+ },
468
+ } as AppViewConfig);
469
+ appEmbed.render();
470
+ await executeAfterWait(() => {
471
+ expectUrlMatchesWithParams(
472
+ getIFrameSrc(),
473
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&toolResponseCardBrandingLabel=MyBrand${defaultParamsPost}#/home`,
474
+ );
475
+ });
476
+ });
477
+
446
478
  test('should set isLiveboardXLSXCSVDownloadEnabled to false in url', async () => {
447
479
  const appEmbed = new AppEmbed(getRootEl(), {
448
480
  ...defaultViewConfig,
package/src/embed/app.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { logger } from '../utils/logger';
12
- import { calculateVisibleElementData, getQueryParamString, isUndefined, isValidCssMargin } from '../utils';
12
+ import { calculateVisibleElementData, getQueryParamString, isUndefined, isValidCssMargin, setParamIfDefined, validateHttpUrl } from '../utils';
13
13
  import {
14
14
  Param,
15
15
  DOMSelector,
@@ -17,8 +17,12 @@ import {
17
17
  EmbedEvent,
18
18
  MessagePayload,
19
19
  AllEmbedViewConfig,
20
+ ErrorDetailsTypes,
21
+ EmbedErrorCodes,
20
22
  } from '../types';
21
23
  import { V1Embed } from './ts-embed';
24
+ import { SpotterChatViewConfig, SpotterSidebarViewConfig } from './conversation';
25
+ import { ERROR_MESSAGE } from '../errors';
22
26
 
23
27
  /**
24
28
  * Pages within the ThoughtSpot app that can be embedded.
@@ -672,6 +676,42 @@ export interface AppViewConfig extends AllEmbedViewConfig {
672
676
  * @version SDK: 1.45.0 | ThoughtSpot: 26.2.0.cl
673
677
  */
674
678
  updatedSpotterChatPrompt?: boolean;
679
+ /**
680
+ * Configuration for the Spotter sidebar UI customization.
681
+ * Only applicable when navigating to Spotter within the app.
682
+ *
683
+ * Supported embed types: `AppEmbed`
684
+ * @example
685
+ * ```js
686
+ * const embed = new AppEmbed('#tsEmbed', {
687
+ * ... //other embed view config
688
+ * spotterSidebarConfig: {
689
+ * enablePastConversationsSidebar: true,
690
+ * spotterSidebarTitle: 'My Conversations',
691
+ * },
692
+ * })
693
+ * ```
694
+ * @version SDK: 1.46.0 | ThoughtSpot: 26.3.0.cl
695
+ */
696
+ spotterSidebarConfig?: SpotterSidebarViewConfig;
697
+ /**
698
+ * Configuration for customizing Spotter chat UI
699
+ * branding in tool response cards.
700
+ *
701
+ * Supported embed types: `AppEmbed`
702
+ * @example
703
+ * ```js
704
+ * const embed = new AppEmbed('#tsEmbed', {
705
+ * ... //other embed view config
706
+ * spotterChatConfig: {
707
+ * hideToolResponseCardBranding: true,
708
+ * toolResponseCardBrandingLabel: 'MyBrand',
709
+ * },
710
+ * })
711
+ * ```
712
+ * @version SDK: 1.46.0 | ThoughtSpot: 26.4.0.cl
713
+ */
714
+ spotterChatConfig?: SpotterChatViewConfig;
675
715
  /**
676
716
  * This is the minimum height (in pixels) for a full-height App.
677
717
  * Setting this height helps resolve issues with empty Apps and
@@ -763,6 +803,8 @@ export class AppEmbed extends V1Embed {
763
803
  isCentralizedLiveboardFilterUXEnabled = false,
764
804
  isLinkParametersEnabled,
765
805
  updatedSpotterChatPrompt,
806
+ spotterSidebarConfig,
807
+ spotterChatConfig,
766
808
  minimumHeight,
767
809
  isThisPeriodInDateFiltersEnabled,
768
810
  } = this.viewConfig;
@@ -793,6 +835,60 @@ export class AppEmbed extends V1Embed {
793
835
  params[Param.UpdatedSpotterChatPrompt] = !!updatedSpotterChatPrompt;
794
836
  }
795
837
 
838
+ // Handle spotterSidebarConfig params
839
+ if (spotterSidebarConfig) {
840
+ const {
841
+ enablePastConversationsSidebar,
842
+ spotterSidebarTitle,
843
+ spotterSidebarDefaultExpanded,
844
+ spotterChatRenameLabel,
845
+ spotterChatDeleteLabel,
846
+ spotterDeleteConversationModalTitle,
847
+ spotterPastConversationAlertMessage,
848
+ spotterDocumentationUrl,
849
+ spotterBestPracticesLabel,
850
+ spotterConversationsBatchSize,
851
+ spotterNewChatButtonTitle,
852
+ } = spotterSidebarConfig;
853
+
854
+ setParamIfDefined(params, Param.EnablePastConversationsSidebar, enablePastConversationsSidebar, true);
855
+ setParamIfDefined(params, Param.SpotterSidebarDefaultExpanded, spotterSidebarDefaultExpanded, true);
856
+ setParamIfDefined(params, Param.SpotterSidebarTitle, spotterSidebarTitle);
857
+ setParamIfDefined(params, Param.SpotterChatRenameLabel, spotterChatRenameLabel);
858
+ setParamIfDefined(params, Param.SpotterChatDeleteLabel, spotterChatDeleteLabel);
859
+ setParamIfDefined(params, Param.SpotterDeleteConversationModalTitle, spotterDeleteConversationModalTitle);
860
+ setParamIfDefined(params, Param.SpotterPastConversationAlertMessage, spotterPastConversationAlertMessage);
861
+ setParamIfDefined(params, Param.SpotterBestPracticesLabel, spotterBestPracticesLabel);
862
+ setParamIfDefined(params, Param.SpotterConversationsBatchSize, spotterConversationsBatchSize);
863
+ setParamIfDefined(params, Param.SpotterNewChatButtonTitle, spotterNewChatButtonTitle);
864
+
865
+ // URL param with validation
866
+ if (spotterDocumentationUrl !== undefined) {
867
+ const [isValid, validationError] = validateHttpUrl(spotterDocumentationUrl);
868
+ if (isValid) {
869
+ params[Param.SpotterDocumentationUrl] = spotterDocumentationUrl;
870
+ } else {
871
+ this.handleError({
872
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
873
+ message: ERROR_MESSAGE.INVALID_SPOTTER_DOCUMENTATION_URL,
874
+ code: EmbedErrorCodes.INVALID_URL,
875
+ error: validationError?.message || ERROR_MESSAGE.INVALID_SPOTTER_DOCUMENTATION_URL,
876
+ });
877
+ }
878
+ }
879
+ }
880
+
881
+ // Handle spotterChatConfig params
882
+ if (spotterChatConfig) {
883
+ const {
884
+ hideToolResponseCardBranding,
885
+ toolResponseCardBrandingLabel,
886
+ } = spotterChatConfig;
887
+
888
+ setParamIfDefined(params, Param.HideToolResponseCardBranding, hideToolResponseCardBranding, true);
889
+ setParamIfDefined(params, Param.ToolResponseCardBrandingLabel, toolResponseCardBrandingLabel);
890
+ }
891
+
796
892
  if (hideObjectSearch) {
797
893
  params[Param.HideObjectSearch] = !!hideObjectSearch;
798
894
  }
@@ -295,7 +295,9 @@ describe('ConversationEmbed', () => {
295
295
  searchOptions: {
296
296
  searchQuery: 'searchQuery',
297
297
  },
298
- enablePastConversationsSidebar: true,
298
+ spotterSidebarConfig: {
299
+ enablePastConversationsSidebar: true,
300
+ },
299
301
  };
300
302
 
301
303
  const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
@@ -312,7 +314,9 @@ describe('ConversationEmbed', () => {
312
314
  searchOptions: {
313
315
  searchQuery: 'searchQuery',
314
316
  },
315
- enablePastConversationsSidebar: false,
317
+ spotterSidebarConfig: {
318
+ enablePastConversationsSidebar: false,
319
+ },
316
320
  };
317
321
 
318
322
  const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
@@ -334,7 +338,9 @@ describe('ConversationEmbed', () => {
334
338
  dataPanelV2: true,
335
339
  showSpotterLimitations: true,
336
340
  hideSampleQuestions: true,
337
- enablePastConversationsSidebar: true,
341
+ spotterSidebarConfig: {
342
+ enablePastConversationsSidebar: true,
343
+ },
338
344
  };
339
345
 
340
346
  const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
@@ -345,6 +351,44 @@ describe('ConversationEmbed', () => {
345
351
  );
346
352
  });
347
353
 
354
+ it('should render the conversation embed with tool response card branding hidden', async () => {
355
+ const viewConfig: SpotterEmbedViewConfig = {
356
+ worksheetId: 'worksheetId',
357
+ searchOptions: {
358
+ searchQuery: 'searchQuery',
359
+ },
360
+ spotterChatConfig: {
361
+ hideToolResponseCardBranding: true,
362
+ },
363
+ };
364
+
365
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
366
+ await conversationEmbed.render();
367
+ expectUrlMatchesWithParams(
368
+ getIFrameSrc(),
369
+ `http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&hideToolResponseCardBranding=true#/embed/insights/conv-assist?worksheet=worksheetId&query=searchQuery`,
370
+ );
371
+ });
372
+
373
+ it('should render the conversation embed with custom tool response card branding label', async () => {
374
+ const viewConfig: SpotterEmbedViewConfig = {
375
+ worksheetId: 'worksheetId',
376
+ searchOptions: {
377
+ searchQuery: 'searchQuery',
378
+ },
379
+ spotterChatConfig: {
380
+ toolResponseCardBrandingLabel: 'MyBrand',
381
+ },
382
+ };
383
+
384
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
385
+ await conversationEmbed.render();
386
+ expectUrlMatchesWithParams(
387
+ getIFrameSrc(),
388
+ `http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&toolResponseCardBrandingLabel=MyBrand#/embed/insights/conv-assist?worksheet=worksheetId&query=searchQuery`,
389
+ );
390
+ });
391
+
348
392
  it('should ensure deprecated ConversationEmbed class maintains same functionality as SpotterEmbed', async () => {
349
393
  const viewConfig: SpotterEmbedViewConfig = {
350
394
  worksheetId: 'worksheetId',
@@ -402,4 +446,74 @@ describe('ConversationEmbed', () => {
402
446
  `http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&updatedSpotterChatPrompt=false#/embed/insights/conv-assist?worksheet=worksheetId&query=searchQuery`,
403
447
  );
404
448
  });
449
+
450
+ describe('spotter sidebar config params', () => {
451
+ it.each([
452
+ ['enablePastConversationsSidebar', true, 'enablePastConversationsSidebar=true'],
453
+ ['spotterSidebarTitle', 'My Conversations', 'spotterSidebarTitle=My%20Conversations'],
454
+ ['spotterSidebarDefaultExpanded', true, 'spotterSidebarDefaultExpanded=true'],
455
+ ['spotterChatRenameLabel', 'Edit Name', 'spotterChatRenameLabel=Edit%20Name'],
456
+ ['spotterChatDeleteLabel', 'Remove', 'spotterChatDeleteLabel=Remove'],
457
+ ['spotterDeleteConversationModalTitle', 'Remove Conversation', 'spotterDeleteConversationModalTitle=Remove%20Conversation'],
458
+ ['spotterPastConversationAlertMessage', 'Viewing past conversation', 'spotterPastConversationAlertMessage=Viewing%20past%20conversation'],
459
+ ['spotterBestPracticesLabel', 'Help Tips', 'spotterBestPracticesLabel=Help%20Tips'],
460
+ ['spotterConversationsBatchSize', 50, 'spotterConversationsBatchSize=50'],
461
+ ['spotterNewChatButtonTitle', 'Start New Conversation', 'spotterNewChatButtonTitle=Start%20New%20Conversation'],
462
+ ['spotterDocumentationUrl', 'https://docs.example.com/spotter', 'spotterDocumentationUrl=https%3A%2F%2Fdocs.example.com%2Fspotter'],
463
+ ])('should render with spotterSidebarConfig.%s', async (configKey, configValue, expectedParam) => {
464
+ const viewConfig: SpotterEmbedViewConfig = {
465
+ worksheetId: 'worksheetId',
466
+ spotterSidebarConfig: {
467
+ [configKey]: configValue,
468
+ },
469
+ };
470
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
471
+ await conversationEmbed.render();
472
+ expectUrlMatchesWithParams(
473
+ getIFrameSrc(),
474
+ `http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&${expectedParam}#/embed/insights/conv-assist?worksheet=worksheetId&query=`,
475
+ );
476
+ });
477
+
478
+ it.each([
479
+ ['invalid URL format', 'invalid-url'],
480
+ ['invalid protocol (ftp)', 'ftp://docs.example.com/spotter'],
481
+ ])('should handle error for spotterSidebarConfig.spotterDocumentationUrl with %s', async (_, invalidUrl) => {
482
+ const viewConfig: SpotterEmbedViewConfig = {
483
+ worksheetId: 'worksheetId',
484
+ spotterSidebarConfig: {
485
+ spotterDocumentationUrl: invalidUrl,
486
+ },
487
+ };
488
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
489
+ (conversationEmbed as any).handleError = jest.fn();
490
+ await conversationEmbed.render();
491
+ expect((conversationEmbed as any).handleError).toHaveBeenCalledWith(
492
+ expect.objectContaining({
493
+ errorType: ErrorDetailsTypes.VALIDATION_ERROR,
494
+ message: ERROR_MESSAGE.INVALID_SPOTTER_DOCUMENTATION_URL,
495
+ code: EmbedErrorCodes.INVALID_URL,
496
+ }),
497
+ );
498
+ });
499
+
500
+ it('should render with multiple spotterSidebarConfig options', async () => {
501
+ const viewConfig: SpotterEmbedViewConfig = {
502
+ worksheetId: 'worksheetId',
503
+ spotterSidebarConfig: {
504
+ enablePastConversationsSidebar: true,
505
+ spotterSidebarTitle: 'Chats',
506
+ spotterSidebarDefaultExpanded: true,
507
+ spotterNewChatButtonTitle: 'New',
508
+ spotterConversationsBatchSize: 25,
509
+ },
510
+ };
511
+ const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
512
+ await conversationEmbed.render();
513
+ expectUrlMatchesWithParams(
514
+ getIFrameSrc(),
515
+ `http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&enablePastConversationsSidebar=true&spotterSidebarDefaultExpanded=true&spotterSidebarTitle=Chats&spotterConversationsBatchSize=25&spotterNewChatButtonTitle=New#/embed/insights/conv-assist?worksheet=worksheetId&query=`,
516
+ );
517
+ });
518
+ });
405
519
  });