@thoughtspot/visual-embed-sdk 1.20.0-alpha.2 → 1.20.0-prerender.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 (184) hide show
  1. package/dist/src/auth.d.ts +75 -5
  2. package/dist/src/auth.d.ts.map +1 -1
  3. package/dist/src/config.d.ts +1 -0
  4. package/dist/src/config.d.ts.map +1 -1
  5. package/dist/src/embed/app.d.ts +19 -7
  6. package/dist/src/embed/app.d.ts.map +1 -1
  7. package/dist/src/embed/base.d.ts +39 -19
  8. package/dist/src/embed/base.d.ts.map +1 -1
  9. package/dist/src/embed/liveboard.d.ts +19 -7
  10. package/dist/src/embed/liveboard.d.ts.map +1 -1
  11. package/dist/src/embed/search-bar.d.ts +7 -1
  12. package/dist/src/embed/search-bar.d.ts.map +1 -1
  13. package/dist/src/embed/search.d.ts +11 -3
  14. package/dist/src/embed/search.d.ts.map +1 -1
  15. package/dist/src/embed/ts-embed.d.ts +76 -5
  16. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  17. package/dist/src/errors.d.ts.map +1 -1
  18. package/dist/src/index.d.ts +3 -3
  19. package/dist/src/index.d.ts.map +1 -1
  20. package/dist/src/mixpanel-service.d.ts +8 -0
  21. package/dist/src/mixpanel-service.d.ts.map +1 -1
  22. package/dist/src/react/index.d.ts.map +1 -1
  23. package/dist/src/react/util.d.ts +4 -0
  24. package/dist/src/react/util.d.ts.map +1 -1
  25. package/dist/src/test/test-utils.d.ts +11 -2
  26. package/dist/src/test/test-utils.d.ts.map +1 -1
  27. package/dist/src/types.d.ts +429 -97
  28. package/dist/src/types.d.ts.map +1 -1
  29. package/dist/src/utils/answerService.d.ts +7 -0
  30. package/dist/src/utils/answerService.d.ts.map +1 -1
  31. package/dist/src/utils/authService.d.ts +30 -0
  32. package/dist/src/utils/authService.d.ts.map +1 -1
  33. package/dist/src/utils/processData.d.ts +12 -0
  34. package/dist/src/utils/processData.d.ts.map +1 -1
  35. package/dist/src/utils/processTrigger.d.ts +7 -0
  36. package/dist/src/utils/processTrigger.d.ts.map +1 -1
  37. package/dist/src/utils.d.ts +12 -0
  38. package/dist/src/utils.d.ts.map +1 -1
  39. package/dist/tsembed.es.js +818 -285
  40. package/dist/tsembed.js +791 -284
  41. package/lib/package.json +4 -3
  42. package/lib/src/auth.d.ts +75 -5
  43. package/lib/src/auth.d.ts.map +1 -1
  44. package/lib/src/auth.js +86 -26
  45. package/lib/src/auth.js.map +1 -1
  46. package/lib/src/auth.spec.js +14 -5
  47. package/lib/src/auth.spec.js.map +1 -1
  48. package/lib/src/config.d.ts +1 -0
  49. package/lib/src/config.d.ts.map +1 -1
  50. package/lib/src/config.js +5 -3
  51. package/lib/src/config.js.map +1 -1
  52. package/lib/src/config.spec.js.map +1 -1
  53. package/lib/src/embed/app.d.ts +19 -7
  54. package/lib/src/embed/app.d.ts.map +1 -1
  55. package/lib/src/embed/app.js +26 -16
  56. package/lib/src/embed/app.js.map +1 -1
  57. package/lib/src/embed/app.spec.js +12 -12
  58. package/lib/src/embed/app.spec.js.map +1 -1
  59. package/lib/src/embed/base.d.ts +39 -19
  60. package/lib/src/embed/base.d.ts.map +1 -1
  61. package/lib/src/embed/base.js +49 -15
  62. package/lib/src/embed/base.js.map +1 -1
  63. package/lib/src/embed/base.spec.js +2 -2
  64. package/lib/src/embed/base.spec.js.map +1 -1
  65. package/lib/src/embed/embed.spec.js +1 -1
  66. package/lib/src/embed/embed.spec.js.map +1 -1
  67. package/lib/src/embed/liveboard.d.ts +19 -7
  68. package/lib/src/embed/liveboard.d.ts.map +1 -1
  69. package/lib/src/embed/liveboard.js +50 -38
  70. package/lib/src/embed/liveboard.js.map +1 -1
  71. package/lib/src/embed/liveboard.spec.js +37 -30
  72. package/lib/src/embed/liveboard.spec.js.map +1 -1
  73. package/lib/src/embed/pinboard.spec.js +14 -26
  74. package/lib/src/embed/pinboard.spec.js.map +1 -1
  75. package/lib/src/embed/search-bar.d.ts +7 -1
  76. package/lib/src/embed/search-bar.d.ts.map +1 -1
  77. package/lib/src/embed/search-bar.js +6 -7
  78. package/lib/src/embed/search-bar.js.map +1 -1
  79. package/lib/src/embed/search.d.ts +11 -3
  80. package/lib/src/embed/search.d.ts.map +1 -1
  81. package/lib/src/embed/search.js +19 -15
  82. package/lib/src/embed/search.js.map +1 -1
  83. package/lib/src/embed/search.spec.js +16 -19
  84. package/lib/src/embed/search.spec.js.map +1 -1
  85. package/lib/src/embed/searchEmbed-basic-auth.spec.js +4 -0
  86. package/lib/src/embed/searchEmbed-basic-auth.spec.js.map +1 -1
  87. package/lib/src/embed/ts-embed.d.ts +76 -5
  88. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  89. package/lib/src/embed/ts-embed.js +150 -72
  90. package/lib/src/embed/ts-embed.js.map +1 -1
  91. package/lib/src/embed/ts-embed.spec.js +23 -24
  92. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  93. package/lib/src/errors.d.ts.map +1 -1
  94. package/lib/src/errors.js.map +1 -1
  95. package/lib/src/index.d.ts +3 -3
  96. package/lib/src/index.d.ts.map +1 -1
  97. package/lib/src/index.js +3 -3
  98. package/lib/src/index.js.map +1 -1
  99. package/lib/src/mixpanel-service.d.ts +8 -0
  100. package/lib/src/mixpanel-service.d.ts.map +1 -1
  101. package/lib/src/mixpanel-service.js +13 -1
  102. package/lib/src/mixpanel-service.js.map +1 -1
  103. package/lib/src/mixpanel-service.spec.js.map +1 -1
  104. package/lib/src/react/index.d.ts.map +1 -1
  105. package/lib/src/react/index.js +4 -6
  106. package/lib/src/react/index.js.map +1 -1
  107. package/lib/src/react/index.spec.js +3 -6
  108. package/lib/src/react/index.spec.js.map +1 -1
  109. package/lib/src/react/util.d.ts +4 -0
  110. package/lib/src/react/util.d.ts.map +1 -1
  111. package/lib/src/react/util.js +4 -0
  112. package/lib/src/react/util.js.map +1 -1
  113. package/lib/src/test/test-utils.d.ts +11 -2
  114. package/lib/src/test/test-utils.d.ts.map +1 -1
  115. package/lib/src/test/test-utils.js +36 -25
  116. package/lib/src/test/test-utils.js.map +1 -1
  117. package/lib/src/types.d.ts +429 -97
  118. package/lib/src/types.d.ts.map +1 -1
  119. package/lib/src/types.js +310 -72
  120. package/lib/src/types.js.map +1 -1
  121. package/lib/src/utils/answerService.d.ts +7 -0
  122. package/lib/src/utils/answerService.d.ts.map +1 -1
  123. package/lib/src/utils/answerService.js +7 -0
  124. package/lib/src/utils/answerService.js.map +1 -1
  125. package/lib/src/utils/answerService.spec.js.map +1 -1
  126. package/lib/src/utils/authService.d.ts +30 -0
  127. package/lib/src/utils/authService.d.ts.map +1 -1
  128. package/lib/src/utils/authService.js +39 -2
  129. package/lib/src/utils/authService.js.map +1 -1
  130. package/lib/src/utils/authService.spec.js.map +1 -1
  131. package/lib/src/utils/processData.d.ts +12 -0
  132. package/lib/src/utils/processData.d.ts.map +1 -1
  133. package/lib/src/utils/processData.js +33 -5
  134. package/lib/src/utils/processData.js.map +1 -1
  135. package/lib/src/utils/processData.spec.js.map +1 -1
  136. package/lib/src/utils/processTrigger.d.ts +7 -0
  137. package/lib/src/utils/processTrigger.d.ts.map +1 -1
  138. package/lib/src/utils/processTrigger.js +17 -3
  139. package/lib/src/utils/processTrigger.js.map +1 -1
  140. package/lib/src/utils/processTrigger.spec.js.map +1 -1
  141. package/lib/src/utils.d.ts +12 -0
  142. package/lib/src/utils.d.ts.map +1 -1
  143. package/lib/src/utils.js +24 -19
  144. package/lib/src/utils.js.map +1 -1
  145. package/lib/src/utils.spec.js.map +1 -1
  146. package/lib/src/visual-embed-sdk.d.ts +664 -141
  147. package/package.json +4 -3
  148. package/src/auth.spec.ts +68 -150
  149. package/src/auth.ts +141 -101
  150. package/src/config.spec.ts +2 -4
  151. package/src/config.ts +5 -3
  152. package/src/embed/app.spec.ts +25 -14
  153. package/src/embed/app.ts +49 -37
  154. package/src/embed/base.spec.ts +6 -12
  155. package/src/embed/base.ts +74 -57
  156. package/src/embed/embed.spec.ts +5 -6
  157. package/src/embed/liveboard.spec.ts +56 -37
  158. package/src/embed/liveboard.ts +67 -65
  159. package/src/embed/pinboard.spec.ts +26 -29
  160. package/src/embed/search-bar.tsx +14 -9
  161. package/src/embed/search.spec.ts +31 -21
  162. package/src/embed/search.ts +28 -22
  163. package/src/embed/searchEmbed-basic-auth.spec.ts +22 -28
  164. package/src/embed/ts-embed.spec.ts +70 -148
  165. package/src/embed/ts-embed.ts +180 -157
  166. package/src/errors.ts +3 -6
  167. package/src/index.ts +23 -7
  168. package/src/mixpanel-service.spec.ts +1 -3
  169. package/src/mixpanel-service.ts +13 -1
  170. package/src/react/index.spec.tsx +11 -20
  171. package/src/react/index.tsx +40 -71
  172. package/src/react/util.ts +8 -4
  173. package/src/test/test-utils.ts +43 -39
  174. package/src/types.ts +427 -97
  175. package/src/utils/answerService.spec.ts +3 -5
  176. package/src/utils/answerService.ts +21 -17
  177. package/src/utils/authService.spec.ts +26 -41
  178. package/src/utils/authService.ts +47 -21
  179. package/src/utils/processData.spec.ts +26 -59
  180. package/src/utils/processData.ts +36 -14
  181. package/src/utils/processTrigger.spec.ts +1 -6
  182. package/src/utils/processTrigger.ts +18 -9
  183. package/src/utils.spec.ts +8 -12
  184. package/src/utils.ts +25 -26
package/src/auth.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import EventEmitter from 'eventemitter3';
2
2
  import { initMixpanel } from './mixpanel-service';
3
- import { AuthType, DOMSelector, EmbedConfig, EmbedEvent, Param } from './types';
3
+ import {
4
+ AuthType, DOMSelector, EmbedConfig, EmbedEvent, Param,
5
+ } from './types';
4
6
  import { getDOMNode, getRedirectUrl } from './utils';
5
7
  // eslint-disable-next-line import/no-cycle
6
8
  import {
@@ -25,20 +27,23 @@ const sessionInfoPromise = new Promise((resolve) => {
25
27
  });
26
28
  let releaseVersion = '';
27
29
 
28
- export const SSO_REDIRECTION_MARKER_GUID =
29
- '5e16222e-ef02-43e9-9fbd-24226bf3ce5b';
30
+ export const SSO_REDIRECTION_MARKER_GUID = '5e16222e-ef02-43e9-9fbd-24226bf3ce5b';
30
31
 
31
32
  export const EndPoints = {
32
33
  AUTH_VERIFICATION: '/callosum/v1/session/info',
33
- SAML_LOGIN_TEMPLATE: (targetUrl: string) =>
34
- `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
35
- OIDC_LOGIN_TEMPLATE: (targetUrl: string) =>
36
- `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
34
+ SAML_LOGIN_TEMPLATE: (targetUrl: string) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
35
+ OIDC_LOGIN_TEMPLATE: (targetUrl: string) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
37
36
  TOKEN_LOGIN: '/callosum/v1/session/login/token',
38
37
  BASIC_LOGIN: '/callosum/v1/session/login',
39
38
  LOGOUT: '/callosum/v1/session/logout',
40
39
  };
41
40
 
41
+ /**
42
+ * Enum for auth failure types. This is the parameter passed to the listner
43
+ * of {@link AuthStatus.FAILURE}.
44
+ *
45
+ * @group Authentication / Init
46
+ */
42
47
  export enum AuthFailureType {
43
48
  SDK = 'SDK',
44
49
  NO_COOKIE_ACCESS = 'NO_COOKIE_ACCESS',
@@ -46,6 +51,11 @@ export enum AuthFailureType {
46
51
  OTHER = 'OTHER',
47
52
  }
48
53
 
54
+ /**
55
+ * Enum for auth status emitted by the emitter returned from {@link init}.
56
+ *
57
+ * @group Authentication / Init
58
+ */
49
59
  export enum AuthStatus {
50
60
  /**
51
61
  * Emits when the SDK fails to authenticate
@@ -67,28 +77,71 @@ export enum AuthStatus {
67
77
  * Emitted when inPopup: true in the SAMLRedirect flow.
68
78
  * And, we are waiting for popup to be triggered either programatically
69
79
  * or by the trigger button.
80
+ *
70
81
  * @version SDK: 1.19.0
71
82
  */
72
83
  WAITING_FOR_POPUP = 'WAITING_FOR_POPUP',
73
84
  }
74
85
 
86
+ /**
87
+ * Event emitter returned from {@link init}.
88
+ *
89
+ * @group Authentication / Init
90
+ */
91
+ export interface AuthEventEmitter {
92
+ /**
93
+ * Registed a listener on Auth failure.
94
+ *
95
+ * @param event
96
+ * @param listener
97
+ */
98
+ on(event: AuthStatus.FAILURE, listener: (failureType: AuthFailureType) => void): this;
99
+ on(
100
+ event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP,
101
+ listener: () => void,
102
+ ): this;
103
+ on(event: AuthStatus.SUCCESS, listener: (sessionInfo: any) => void): this;
104
+ /**
105
+ * Trigger an event on the emitter returned from init.
106
+ *
107
+ * @param {@link AuthEvent}
108
+ */
109
+ emit(event: AuthEvent): void;
110
+ }
111
+
112
+ /**
113
+ * Events which can be triggered on the emitter returned from {@link init}.
114
+ *
115
+ * @group Authentication / Init
116
+ */
75
117
  export enum AuthEvent {
76
118
  /**
77
- * Manually trigger the SSO popup.
119
+ * Manually trigger the SSO popup. This is useful with
120
+ * authStatus: SAMLRedirect/OIDCRedicre and inPopup: true
78
121
  */
79
122
  TRIGGER_SSO_POPUP = 'TRIGGER_SSO_POPUP',
80
123
  }
81
124
 
82
- let authEE: EventEmitter;
125
+ let authEE: EventEmitter<AuthStatus | AuthEvent>;
83
126
 
84
- export function getAuthEE(): EventEmitter {
127
+ /**
128
+ *
129
+ */
130
+ export function getAuthEE(): EventEmitter<AuthStatus | AuthEvent> {
85
131
  return authEE;
86
132
  }
87
133
 
88
- export function setAuthEE(eventEmitter: EventEmitter): void {
134
+ /**
135
+ *
136
+ * @param eventEmitter
137
+ */
138
+ export function setAuthEE(eventEmitter: EventEmitter<AuthStatus | AuthEvent>): void {
89
139
  authEE = eventEmitter;
90
140
  }
91
141
 
142
+ /**
143
+ *
144
+ */
92
145
  export function notifyAuthSDKSuccess(): void {
93
146
  if (!authEE) {
94
147
  console.error('SDK not initialized');
@@ -97,6 +150,9 @@ export function notifyAuthSDKSuccess(): void {
97
150
  authEE.emit(AuthStatus.SDK_SUCCESS);
98
151
  }
99
152
 
153
+ /**
154
+ *
155
+ */
100
156
  export function notifyAuthSuccess(): void {
101
157
  if (!authEE) {
102
158
  console.error('SDK not initialized');
@@ -105,6 +161,10 @@ export function notifyAuthSuccess(): void {
105
161
  authEE.emit(AuthStatus.SUCCESS, sessionInfo);
106
162
  }
107
163
 
164
+ /**
165
+ *
166
+ * @param failureType
167
+ */
108
168
  export function notifyAuthFailure(failureType: AuthFailureType): void {
109
169
  if (!authEE) {
110
170
  console.error('SDK not initialized');
@@ -113,6 +173,9 @@ export function notifyAuthFailure(failureType: AuthFailureType): void {
113
173
  authEE.emit(AuthStatus.FAILURE, failureType);
114
174
  }
115
175
 
176
+ /**
177
+ *
178
+ */
116
179
  export function notifyLogout(): void {
117
180
  if (!authEE) {
118
181
  console.error('SDK not initialized');
@@ -123,6 +186,7 @@ export function notifyLogout(): void {
123
186
 
124
187
  /**
125
188
  * Check if we are logged into the ThoughtSpot cluster
189
+ *
126
190
  * @param thoughtSpotHost The ThoughtSpot cluster hostname or IP
127
191
  */
128
192
  async function isLoggedIn(thoughtSpotHost: string): Promise<boolean> {
@@ -146,23 +210,32 @@ export function getReleaseVersion() {
146
210
  }
147
211
 
148
212
  /**
149
- * Return a promise that resolves with the session info when authentication is
150
- * successful. And info is available.
213
+ * Return a promise that resolves with the session information when
214
+ * authentication is successful. And info is available.
215
+ *
216
+ * @group Global methods
151
217
  */
152
218
  export function getSessionInfo(): Promise<any> {
153
219
  return sessionInfoPromise;
154
220
  }
155
221
 
222
+ /**
223
+ *
224
+ * @param sessionDetails
225
+ */
156
226
  export function initSession(sessionDetails: any) {
157
227
  sessionInfo = sessionDetails;
158
228
  initMixpanel(sessionInfo);
159
229
  sessionInfoResolver(sessionInfo);
160
230
  }
161
231
 
162
- const DUPLICATE_TOKEN_ERR =
163
- 'Duplicate token, please issue a new token every time getAuthToken callback is called.' +
164
- 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
232
+ const DUPLICATE_TOKEN_ERR = 'Duplicate token, please issue a new token every time getAuthToken callback is called.'
233
+ + 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
165
234
  let prevAuthToken: string = null;
235
+ /**
236
+ *
237
+ * @param authtoken
238
+ */
166
239
  function alertForDuplicateToken(authtoken: string) {
167
240
  if (prevAuthToken === authtoken) {
168
241
  // eslint-disable-next-line no-alert
@@ -184,18 +257,14 @@ function isAtSSORedirectUrl(): boolean {
184
257
  */
185
258
  function removeSSORedirectUrlMarker(): void {
186
259
  // Note (sunny): This will leave a # around even if it was not in the URL
187
- // to begin with. Trying to remove the hash by changing window.location will reload
188
- // the page which we don't want. We'll live with adding an unnecessary hash to the
189
- // parent page URL until we find any use case where that creates an issue.
190
- window.location.hash = window.location.hash.replace(
191
- SSO_REDIRECTION_MARKER_GUID,
192
- '',
193
- );
260
+ // to begin with. Trying to remove the hash by changing window.location will
261
+ // reload the page which we don't want. We'll live with adding an
262
+ // unnecessary hash to the parent page URL until we find any use case where
263
+ // that creates an issue.
264
+ window.location.hash = window.location.hash.replace(SSO_REDIRECTION_MARKER_GUID, '');
194
265
  }
195
266
 
196
- export const getAuthenticaionToken = async (
197
- embedConfig: EmbedConfig,
198
- ): Promise<any> => {
267
+ export const getAuthenticaionToken = async (embedConfig: EmbedConfig): Promise<any> => {
199
268
  const { authEndpoint, getAuthToken } = embedConfig;
200
269
  let authToken = null;
201
270
  if (getAuthToken) {
@@ -210,40 +279,30 @@ export const getAuthenticaionToken = async (
210
279
 
211
280
  /**
212
281
  * Perform token based authentication
282
+ *
213
283
  * @param embedConfig The embed configuration
214
284
  */
215
- export const doTokenAuth = async (
216
- embedConfig: EmbedConfig,
217
- ): Promise<boolean> => {
285
+ export const doTokenAuth = async (embedConfig: EmbedConfig): Promise<boolean> => {
218
286
  const {
219
- thoughtSpotHost,
220
- username,
221
- authEndpoint,
222
- getAuthToken,
287
+ thoughtSpotHost, username, authEndpoint, getAuthToken,
223
288
  } = embedConfig;
224
289
  if (!authEndpoint && !getAuthToken) {
225
- throw new Error(
226
- 'Either auth endpoint or getAuthToken function must be provided',
227
- );
290
+ throw new Error('Either auth endpoint or getAuthToken function must be provided');
228
291
  }
229
292
  loggedInStatus = await isLoggedIn(thoughtSpotHost);
230
293
  if (!loggedInStatus) {
231
294
  const authToken = await getAuthenticaionToken(embedConfig);
232
295
  let resp;
233
296
  try {
234
- resp = await fetchAuthPostService(
235
- thoughtSpotHost,
236
- username,
237
- authToken,
238
- );
297
+ resp = await fetchAuthPostService(thoughtSpotHost, username, authToken);
239
298
  } catch (e) {
240
299
  resp = await fetchAuthService(thoughtSpotHost, username, authToken);
241
300
  }
242
301
  // token login issues a 302 when successful
243
302
  loggedInStatus = resp.ok || resp.type === 'opaqueredirect';
244
303
  if (loggedInStatus && embedConfig.detectCookieAccessSlow) {
245
- // When 3rd party cookie access is blocked, this will fail because cookies will
246
- // not be sent with the call.
304
+ // When 3rd party cookie access is blocked, this will fail because
305
+ // cookies will not be sent with the call.
247
306
  loggedInStatus = await isLoggedIn(thoughtSpotHost);
248
307
  }
249
308
  }
@@ -252,16 +311,13 @@ export const doTokenAuth = async (
252
311
 
253
312
  /**
254
313
  * Validate embedConfig parameters required for cookielessTokenAuth
314
+ *
255
315
  * @param embedConfig The embed configuration
256
316
  */
257
- export const doCookielessTokenAuth = async (
258
- embedConfig: EmbedConfig,
259
- ): Promise<boolean> => {
317
+ export const doCookielessTokenAuth = async (embedConfig: EmbedConfig): Promise<boolean> => {
260
318
  const { authEndpoint, getAuthToken } = embedConfig;
261
319
  if (!authEndpoint && !getAuthToken) {
262
- throw new Error(
263
- 'Either auth endpoint or getAuthToken function must be provided',
264
- );
320
+ throw new Error('Either auth endpoint or getAuthToken function must be provided');
265
321
  }
266
322
  return Promise.resolve(true);
267
323
  };
@@ -272,19 +328,14 @@ export const doCookielessTokenAuth = async (
272
328
  *
273
329
  * Warning: This feature is primarily intended for developer testing. It is
274
330
  * strongly advised not to use this authentication method in production.
331
+ *
275
332
  * @param embedConfig The embed configuration
276
333
  */
277
- export const doBasicAuth = async (
278
- embedConfig: EmbedConfig,
279
- ): Promise<boolean> => {
334
+ export const doBasicAuth = async (embedConfig: EmbedConfig): Promise<boolean> => {
280
335
  const { thoughtSpotHost, username, password } = embedConfig;
281
336
  const loggedIn = await isLoggedIn(thoughtSpotHost);
282
337
  if (!loggedIn) {
283
- const response = await fetchBasicAuthService(
284
- thoughtSpotHost,
285
- username,
286
- password,
287
- );
338
+ const response = await fetchBasicAuthService(thoughtSpotHost, username, password);
288
339
  loggedInStatus = response.ok;
289
340
  if (embedConfig.detectCookieAccessSlow) {
290
341
  loggedInStatus = await isLoggedIn(thoughtSpotHost);
@@ -295,11 +346,13 @@ export const doBasicAuth = async (
295
346
  return loggedInStatus;
296
347
  };
297
348
 
298
- async function samlPopupFlow(
299
- ssoURL: string,
300
- triggerContainer: DOMSelector,
301
- triggerText: string,
302
- ) {
349
+ /**
350
+ *
351
+ * @param ssoURL
352
+ * @param triggerContainer
353
+ * @param triggerText
354
+ */
355
+ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, triggerText: string) {
303
356
  const openPopup = () => {
304
357
  if (samlAuthWindow === null || samlAuthWindow.closed) {
305
358
  samlAuthWindow = window.open(
@@ -314,15 +367,13 @@ async function samlPopupFlow(
314
367
  authEE?.emit(AuthStatus.WAITING_FOR_POPUP);
315
368
  const containerEl = getDOMNode(triggerContainer);
316
369
  if (containerEl) {
317
- containerEl.innerHTML =
318
- '<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
370
+ containerEl.innerHTML = '<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
319
371
  const authElem = document.getElementById('ts-auth-btn');
320
372
  authElem.textContent = triggerText;
321
373
  authElem.addEventListener('click', openPopup, { once: true });
322
374
  }
323
- samlCompletionPromise =
324
- samlCompletionPromise ||
325
- new Promise<void>((resolve, reject) => {
375
+ samlCompletionPromise = samlCompletionPromise
376
+ || new Promise<void>((resolve, reject) => {
326
377
  window.addEventListener('message', (e) => {
327
378
  if (e.data.type === EmbedEvent.SAMLComplete) {
328
379
  (e.source as Window).close();
@@ -337,12 +388,11 @@ async function samlPopupFlow(
337
388
 
338
389
  /**
339
390
  * Perform SAML authentication
391
+ *
340
392
  * @param embedConfig The embed configuration
393
+ * @param ssoEndPoint
341
394
  */
342
- const doSSOAuth = async (
343
- embedConfig: EmbedConfig,
344
- ssoEndPoint: string,
345
- ): Promise<void> => {
395
+ const doSSOAuth = async (embedConfig: EmbedConfig, ssoEndPoint: string): Promise<void> => {
346
396
  const { thoughtSpotHost } = embedConfig;
347
397
  const loggedIn = await isLoggedIn(thoughtSpotHost);
348
398
  if (loggedIn) {
@@ -363,11 +413,7 @@ const doSSOAuth = async (
363
413
 
364
414
  const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
365
415
  if (embedConfig.inPopup) {
366
- await samlPopupFlow(
367
- ssoURL,
368
- embedConfig.authTriggerContainer,
369
- embedConfig.authTriggerText,
370
- );
416
+ await samlPopupFlow(ssoURL, embedConfig.authTriggerContainer, embedConfig.authTriggerText);
371
417
  loggedInStatus = true;
372
418
  return;
373
419
  }
@@ -377,20 +423,18 @@ const doSSOAuth = async (
377
423
 
378
424
  export const doSamlAuth = async (embedConfig: EmbedConfig) => {
379
425
  const { thoughtSpotHost } = embedConfig;
380
- // redirect for SSO, when the SSO authentication is done, this page will be loaded
381
- // again and the same JS will execute again.
426
+ // redirect for SSO, when the SSO authentication is done, this page will be
427
+ // loaded again and the same JS will execute again.
382
428
  const ssoRedirectUrl = embedConfig.inPopup
383
429
  ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
384
430
  : getRedirectUrl(
385
- window.location.href,
386
- SSO_REDIRECTION_MARKER_GUID,
387
- embedConfig.redirectPath,
388
- );
431
+ window.location.href,
432
+ SSO_REDIRECTION_MARKER_GUID,
433
+ embedConfig.redirectPath,
434
+ );
389
435
 
390
436
  // bring back the page to the same URL
391
- const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(
392
- encodeURIComponent(ssoRedirectUrl),
393
- )}`;
437
+ const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
394
438
 
395
439
  await doSSOAuth(embedConfig, ssoEndPoint);
396
440
  return loggedInStatus;
@@ -398,21 +442,18 @@ export const doSamlAuth = async (embedConfig: EmbedConfig) => {
398
442
 
399
443
  export const doOIDCAuth = async (embedConfig: EmbedConfig) => {
400
444
  const { thoughtSpotHost } = embedConfig;
401
- // redirect for SSO, when the SSO authentication is done, this page will be loaded
402
- // again and the same JS will execute again.
403
- const ssoRedirectUrl =
404
- embedConfig.noRedirect || embedConfig.inPopup
405
- ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
406
- : getRedirectUrl(
407
- window.location.href,
408
- SSO_REDIRECTION_MARKER_GUID,
409
- embedConfig.redirectPath,
410
- );
445
+ // redirect for SSO, when the SSO authentication is done, this page will be
446
+ // loaded again and the same JS will execute again.
447
+ const ssoRedirectUrl = embedConfig.noRedirect || embedConfig.inPopup
448
+ ? `${thoughtSpotHost}/v2/#/embed/saml-complete`
449
+ : getRedirectUrl(
450
+ window.location.href,
451
+ SSO_REDIRECTION_MARKER_GUID,
452
+ embedConfig.redirectPath,
453
+ );
411
454
 
412
455
  // bring back the page to the same URL
413
- const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(
414
- encodeURIComponent(ssoRedirectUrl),
415
- )}`;
456
+ const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
416
457
 
417
458
  await doSSOAuth(embedConfig, ssoEndPoint);
418
459
  return loggedInStatus;
@@ -427,11 +468,10 @@ export const logout = async (embedConfig: EmbedConfig): Promise<boolean> => {
427
468
 
428
469
  /**
429
470
  * Perform authentication on the ThoughtSpot cluster
471
+ *
430
472
  * @param embedConfig The embed configuration
431
473
  */
432
- export const authenticate = async (
433
- embedConfig: EmbedConfig,
434
- ): Promise<boolean> => {
474
+ export const authenticate = async (embedConfig: EmbedConfig): Promise<boolean> => {
435
475
  const { authType } = embedConfig;
436
476
  switch (authType) {
437
477
  case AuthType.SSO:
@@ -59,8 +59,7 @@ describe('getThoughtSpotHost', () => {
59
59
  expect(
60
60
  getThoughtSpotHost({
61
61
  ...embedConfig,
62
- thoughtSpotHost:
63
- 'http://1.2.3.4:8088/v2/?foo=bar&baz=42#myhash',
62
+ thoughtSpotHost: 'http://1.2.3.4:8088/v2/?foo=bar&baz=42#myhash',
64
63
  }),
65
64
  ).toBe('http://1.2.3.4:8088/v2');
66
65
  });
@@ -70,8 +69,7 @@ describe('getThoughtSpotHost', () => {
70
69
  getThoughtSpotHost({
71
70
  ...embedConfig,
72
71
  authType: AuthType.SAML,
73
- thoughtSpotHost:
74
- 'http://1.2.3.4:8088/v2/?foo=bar&baz=42#myhash',
72
+ thoughtSpotHost: 'http://1.2.3.4:8088/v2/?foo=bar&baz=42#myhash',
75
73
  }),
76
74
  ).toBe('http://1.2.3.4:8088/v2');
77
75
  });
package/src/config.ts CHANGED
@@ -23,6 +23,7 @@ const urlRegex = new RegExp(
23
23
  /**
24
24
  * Parse and construct the ThoughtSpot hostname or IP address
25
25
  * from the embed configuration object.
26
+ *
26
27
  * @param config
27
28
  */
28
29
  export const getThoughtSpotHost = (config: EmbedConfig): string => {
@@ -51,9 +52,10 @@ export const getV2BasePath = (config: EmbedConfig): string => {
51
52
 
52
53
  const tsHost = getThoughtSpotHost(config);
53
54
 
54
- // This is to handle when e2e's. Search is run on pods for comp-blink-test-pipeline
55
- // with baseUrl=https://localhost:8443.
56
- // This is to handle when the developer is developing in their local environment.
55
+ // This is to handle when e2e's. Search is run on pods for
56
+ // comp-blink-test-pipeline with baseUrl=https://localhost:8443.
57
+ // This is to handle when the developer is developing in their local
58
+ // environment.
57
59
  if (tsHost.includes('://localhost') && !tsHost.includes(':8443')) {
58
60
  return '';
59
61
  }
@@ -1,6 +1,8 @@
1
1
  import { AppEmbed, AppViewConfig, Page } from './app';
2
2
  import { init } from '../index';
3
- import { Action, AuthType, HostEvent, RuntimeFilterOp } from '../types';
3
+ import {
4
+ Action, AuthType, HostEvent, RuntimeFilterOp,
5
+ } from '../types';
4
6
  import {
5
7
  executeAfterWait,
6
8
  getDocumentBody,
@@ -11,6 +13,7 @@ import {
11
13
  defaultParams,
12
14
  defaultParamsForPinboardEmbed,
13
15
  defaultParamsWithoutHiddenActions,
16
+ expectUrlMatchesWithParams,
14
17
  } from '../test/test-utils';
15
18
  import { version } from '../../package.json';
16
19
  import * as config from '../config';
@@ -44,7 +47,8 @@ describe('App embed tests', () => {
44
47
  const appEmbed = new AppEmbed(getRootEl(), defaultViewConfig);
45
48
  appEmbed.render();
46
49
  await executeAfterWait(() => {
47
- expect(getIFrameSrc()).toBe(
50
+ expectUrlMatchesWithParams(
51
+ getIFrameSrc(),
48
52
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
49
53
  );
50
54
  });
@@ -57,7 +61,8 @@ describe('App embed tests', () => {
57
61
  } as AppViewConfig);
58
62
  appEmbed.render();
59
63
  await executeAfterWait(() => {
60
- expect(getIFrameSrc()).toBe(
64
+ expectUrlMatchesWithParams(
65
+ getIFrameSrc(),
61
66
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
62
67
  );
63
68
  });
@@ -70,7 +75,8 @@ describe('App embed tests', () => {
70
75
  } as AppViewConfig);
71
76
  appEmbed.render();
72
77
  await executeAfterWait(() => {
73
- expect(getIFrameSrc()).toBe(
78
+ expectUrlMatchesWithParams(
79
+ getIFrameSrc(),
74
80
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=true${defaultParams}${defaultParamsPost}#/home`,
75
81
  );
76
82
  });
@@ -101,7 +107,8 @@ describe('App embed tests', () => {
101
107
  appEmbed.render();
102
108
 
103
109
  await executeAfterWait(() => {
104
- expect(getIFrameSrc()).toBe(
110
+ expectUrlMatchesWithParams(
111
+ getIFrameSrc(),
105
112
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/${route}`,
106
113
  );
107
114
  cleanUp();
@@ -117,7 +124,8 @@ describe('App embed tests', () => {
117
124
  } as AppViewConfig);
118
125
  appEmbed.render();
119
126
  await executeAfterWait(() => {
120
- expect(getIFrameSrc()).toBe(
127
+ expectUrlMatchesWithParams(
128
+ getIFrameSrc(),
121
129
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/foo/bar`,
122
130
  );
123
131
  });
@@ -138,7 +146,8 @@ describe('App embed tests', () => {
138
146
 
139
147
  appEmbed.render();
140
148
  await executeAfterWait(() => {
141
- expect(getIFrameSrc()).toBe(
149
+ expectUrlMatchesWithParams(
150
+ getIFrameSrc(),
142
151
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false&col1=sales&op1=EQ&val1=1000${defaultParams}${defaultParamsPost}#/home`,
143
152
  );
144
153
  });
@@ -155,7 +164,8 @@ describe('App embed tests', () => {
155
164
 
156
165
  appEmbed.render();
157
166
  await executeAfterWait(() => {
158
- expect(getIFrameSrc()).toBe(
167
+ expectUrlMatchesWithParams(
168
+ getIFrameSrc(),
159
169
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false&${defaultParamsWithoutHiddenActions}&disableAction=[%22save%22,%22update%22]&disableHint=Access%20denied&hideAction=[%22${Action.ReportError}%22,%22download%22]${defaultParamsPost}#/home`,
160
170
  );
161
171
  });
@@ -170,7 +180,8 @@ describe('App embed tests', () => {
170
180
 
171
181
  appEmbed.render();
172
182
  await executeAfterWait(() => {
173
- expect(getIFrameSrc()).toBe(
183
+ expectUrlMatchesWithParams(
184
+ getIFrameSrc(),
174
185
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}&tag=Finance${defaultParamsPost}#/home`,
175
186
  );
176
187
  });
@@ -184,7 +195,8 @@ describe('App embed tests', () => {
184
195
 
185
196
  appEmbed.render();
186
197
  await executeAfterWait(() => {
187
- expect(getIFrameSrc()).toBe(
198
+ expectUrlMatchesWithParams(
199
+ getIFrameSrc(),
188
200
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&enableSearchAssist=true${defaultParams}${defaultParamsPost}#/home`,
189
201
  );
190
202
  });
@@ -193,9 +205,7 @@ describe('App embed tests', () => {
193
205
  describe('Navigate to Page API', () => {
194
206
  const path = 'pinboard/e0836cad-4fdf-42d4-bd97-567a6b2a6058';
195
207
  beforeEach(() => {
196
- jest.spyOn(config, 'getThoughtSpotHost').mockImplementation(
197
- () => 'http://tshost',
198
- );
208
+ jest.spyOn(config, 'getThoughtSpotHost').mockImplementation(() => 'http://tshost');
199
209
  });
200
210
 
201
211
  test('when app is AppEmbed after navigateToPage function call, new path should be set to iframe', async () => {
@@ -207,7 +217,8 @@ describe('App embed tests', () => {
207
217
  });
208
218
  await appEmbed.render();
209
219
  appEmbed.navigateToPage(path);
210
- expect(getIFrameSrc()).toBe(
220
+ expectUrlMatchesWithParams(
221
+ getIFrameSrc(),
211
222
  `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&${defaultParamsForPinboardEmbed}${defaultParamsPost}#/${path}`,
212
223
  );
213
224
  });