@thoughtspot/visual-embed-sdk 1.10.0 → 1.10.1
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.
- package/dist/src/auth.d.ts +18 -5
- package/dist/src/embed/base.d.ts +21 -5
- package/dist/src/embed/pinboard.d.ts +91 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/types.d.ts +15 -0
- package/dist/src/utils/authService.d.ts +1 -0
- package/dist/src/utils/plugin.d.ts +0 -0
- package/dist/src/utils/processData.d.ts +1 -1
- package/dist/src/v1/api.d.ts +19 -0
- package/dist/tsembed.es.js +521 -32
- package/dist/tsembed.js +519 -31
- package/lib/package.json +2 -1
- package/lib/src/auth.d.ts +18 -5
- package/lib/src/auth.js +48 -9
- package/lib/src/auth.js.map +1 -1
- package/lib/src/auth.spec.js +69 -11
- package/lib/src/auth.spec.js.map +1 -1
- package/lib/src/embed/base.d.ts +21 -5
- package/lib/src/embed/base.js +64 -10
- package/lib/src/embed/base.js.map +1 -1
- package/lib/src/embed/base.spec.js +49 -3
- package/lib/src/embed/base.spec.js.map +1 -1
- package/lib/src/embed/embed.spec.js +1 -1
- package/lib/src/embed/embed.spec.js.map +1 -1
- package/lib/src/embed/pinboard.d.ts +91 -0
- package/lib/src/embed/pinboard.js +110 -0
- package/lib/src/embed/pinboard.js.map +1 -0
- package/lib/src/embed/ts-embed.js +9 -10
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +16 -6
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +3 -2
- package/lib/src/index.js +3 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/test/test-utils.js +1 -1
- package/lib/src/test/test-utils.js.map +1 -1
- package/lib/src/types.d.ts +15 -0
- package/lib/src/types.js +10 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/authService.d.ts +1 -0
- package/lib/src/utils/authService.js +21 -3
- package/lib/src/utils/authService.js.map +1 -1
- package/lib/src/utils/authService.spec.js +21 -5
- package/lib/src/utils/authService.spec.js.map +1 -1
- package/lib/src/utils/plugin.d.ts +0 -0
- package/lib/src/utils/plugin.js +1 -0
- package/lib/src/utils/plugin.js.map +1 -0
- package/lib/src/utils/processData.d.ts +1 -1
- package/lib/src/utils/processData.js +37 -3
- package/lib/src/utils/processData.js.map +1 -1
- package/lib/src/utils/processData.spec.js +106 -4
- package/lib/src/utils/processData.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +100 -7
- package/package.json +2 -1
- package/src/auth.spec.ts +90 -11
- package/src/auth.ts +63 -13
- package/src/embed/base.spec.ts +56 -4
- package/src/embed/base.ts +83 -16
- package/src/embed/embed.spec.ts +1 -1
- package/src/embed/ts-embed.spec.ts +19 -9
- package/src/embed/ts-embed.ts +15 -12
- package/src/index.ts +5 -1
- package/src/test/test-utils.ts +1 -1
- package/src/types.ts +16 -0
- package/src/utils/authService.spec.ts +31 -5
- package/src/utils/authService.ts +27 -3
- package/src/utils/processData.spec.ts +139 -4
- package/src/utils/processData.ts +54 -4
package/src/embed/ts-embed.ts
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
MessageCallbackObj,
|
|
35
35
|
} from '../types';
|
|
36
36
|
import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
|
|
37
|
-
import {
|
|
37
|
+
import { processEventData } from '../utils/processData';
|
|
38
38
|
import { processTrigger } from '../utils/processTrigger';
|
|
39
39
|
import pkgInfo from '../../package.json';
|
|
40
40
|
import { getAuthPromise, getEmbedConfig, renderInQueue } from './base';
|
|
@@ -212,14 +212,6 @@ export class TsEmbed {
|
|
|
212
212
|
this.isError = false;
|
|
213
213
|
this.viewConfig = viewConfig;
|
|
214
214
|
this.shouldEncodeUrlQueryParams = this.embedConfig.shouldEncodeUrlQueryParams;
|
|
215
|
-
if (!this.embedConfig.suppressNoCookieAccessAlert) {
|
|
216
|
-
this.on(EmbedEvent.NoCookieAccess, () => {
|
|
217
|
-
// eslint-disable-next-line no-alert
|
|
218
|
-
alert(
|
|
219
|
-
'Third party cookie access is blocked on this browser, please allow third party cookies for ThoughtSpot to work properly',
|
|
220
|
-
);
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
215
|
}
|
|
224
216
|
|
|
225
217
|
/**
|
|
@@ -304,7 +296,12 @@ export class TsEmbed {
|
|
|
304
296
|
if (event.source === this.iFrame.contentWindow) {
|
|
305
297
|
this.executeCallbacks(
|
|
306
298
|
eventType,
|
|
307
|
-
|
|
299
|
+
processEventData(
|
|
300
|
+
eventType,
|
|
301
|
+
eventData,
|
|
302
|
+
this.thoughtSpotHost,
|
|
303
|
+
this.el,
|
|
304
|
+
),
|
|
308
305
|
eventPort,
|
|
309
306
|
);
|
|
310
307
|
}
|
|
@@ -464,7 +461,12 @@ export class TsEmbed {
|
|
|
464
461
|
uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_RENDER_START);
|
|
465
462
|
|
|
466
463
|
getAuthPromise()
|
|
467
|
-
?.then(() => {
|
|
464
|
+
?.then((isLoggedIn: boolean) => {
|
|
465
|
+
if (!isLoggedIn) {
|
|
466
|
+
this.el.innerHTML = this.embedConfig.loginFailedMessage;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
468
470
|
uploadMixpanelEvent(
|
|
469
471
|
MIXPANEL_EVENT.VISUAL_SDK_RENDER_COMPLETE,
|
|
470
472
|
);
|
|
@@ -492,7 +494,7 @@ export class TsEmbed {
|
|
|
492
494
|
frameWidth || DEFAULT_EMBED_WIDTH,
|
|
493
495
|
);
|
|
494
496
|
const height = getCssDimension(
|
|
495
|
-
|
|
497
|
+
frameHeight || DEFAULT_EMBED_HEIGHT,
|
|
496
498
|
);
|
|
497
499
|
setAttributes(this.iFrame, restParams);
|
|
498
500
|
|
|
@@ -536,6 +538,7 @@ export class TsEmbed {
|
|
|
536
538
|
uploadMixpanelEvent(
|
|
537
539
|
MIXPANEL_EVENT.VISUAL_SDK_RENDER_FAILED,
|
|
538
540
|
);
|
|
541
|
+
this.el.innerHTML = this.embedConfig.loginFailedMessage;
|
|
539
542
|
this.handleError(error);
|
|
540
543
|
});
|
|
541
544
|
});
|
package/src/index.ts
CHANGED
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { AppEmbed, Page, AppViewConfig } from './embed/app';
|
|
12
|
-
import { init, prefetch } from './embed/base';
|
|
12
|
+
import { init, prefetch, logout } from './embed/base';
|
|
13
13
|
import {
|
|
14
14
|
PinboardEmbed,
|
|
15
15
|
LiveboardViewConfig,
|
|
16
16
|
LiveboardEmbed,
|
|
17
17
|
} from './embed/liveboard';
|
|
18
18
|
import { SearchEmbed, SearchViewConfig } from './embed/search';
|
|
19
|
+
import { AuthFailureType, AuthStatus } from './auth';
|
|
19
20
|
import {
|
|
20
21
|
AuthType,
|
|
21
22
|
RuntimeFilter,
|
|
@@ -29,11 +30,14 @@ import {
|
|
|
29
30
|
|
|
30
31
|
export {
|
|
31
32
|
init,
|
|
33
|
+
logout,
|
|
32
34
|
prefetch,
|
|
33
35
|
SearchEmbed,
|
|
34
36
|
PinboardEmbed,
|
|
35
37
|
LiveboardEmbed,
|
|
36
38
|
AppEmbed,
|
|
39
|
+
AuthFailureType,
|
|
40
|
+
AuthStatus,
|
|
37
41
|
// types
|
|
38
42
|
Page,
|
|
39
43
|
AuthType,
|
package/src/test/test-utils.ts
CHANGED
|
@@ -14,7 +14,7 @@ type DOMElement = HTMLElement | Document;
|
|
|
14
14
|
|
|
15
15
|
export const getRootEl = () => document.getElementById('embed');
|
|
16
16
|
|
|
17
|
-
export const getRootEl2 = () => document.getElementById('
|
|
17
|
+
export const getRootEl2 = () => document.getElementById('embed-2');
|
|
18
18
|
|
|
19
19
|
export const getIFrameEl = (container: DOMElement = document) =>
|
|
20
20
|
container.querySelector('iframe');
|
package/src/types.ts
CHANGED
|
@@ -131,6 +131,12 @@ export interface EmbedConfig {
|
|
|
131
131
|
*/
|
|
132
132
|
disableLoginRedirect?: boolean;
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* This message is displayed on the embed view when the login fails.
|
|
136
|
+
* @version 1.10.1 | ThoughtSpot: *
|
|
137
|
+
*/
|
|
138
|
+
loginFailedMessage?: string;
|
|
139
|
+
|
|
134
140
|
/**
|
|
135
141
|
* Calls the prefetch method internally when set to true
|
|
136
142
|
* @default false
|
|
@@ -365,6 +371,16 @@ export enum EmbedEvent {
|
|
|
365
371
|
* The ThoughtSpot auth session has expired.
|
|
366
372
|
*/
|
|
367
373
|
AuthExpire = 'ThoughtspotAuthExpired',
|
|
374
|
+
/**
|
|
375
|
+
* ThoughtSpot failed to validate the auth session.
|
|
376
|
+
* @hidden
|
|
377
|
+
*/
|
|
378
|
+
AuthFailure = 'ThoughtspotAuthFailure',
|
|
379
|
+
/**
|
|
380
|
+
* ThoughtSpot failed to validate the auth session.
|
|
381
|
+
* @hidden
|
|
382
|
+
*/
|
|
383
|
+
AuthLogout = 'ThoughtspotAuthLogout',
|
|
368
384
|
/**
|
|
369
385
|
* The height of the embedded Liveboard or visualization has been computed.
|
|
370
386
|
* @return data - The height of the embedded Liveboard or visualization
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
fetchAuthService,
|
|
5
5
|
fetchBasicAuthService,
|
|
6
6
|
} from './authService';
|
|
7
|
+
import { EndPoints } from '../auth';
|
|
7
8
|
|
|
8
9
|
const thoughtSpotHost = 'http://10.79.135.124:3000';
|
|
9
10
|
|
|
@@ -21,6 +22,7 @@ describe('Unit test for authService', () => {
|
|
|
21
22
|
Promise.resolve({
|
|
22
23
|
json: () => ({ success: true }),
|
|
23
24
|
status: 200,
|
|
25
|
+
ok: true,
|
|
24
26
|
}),
|
|
25
27
|
);
|
|
26
28
|
const response = await fetchSessionInfoService(authVerificationUrl);
|
|
@@ -32,6 +34,7 @@ describe('Unit test for authService', () => {
|
|
|
32
34
|
global.fetch = jest.fn(() =>
|
|
33
35
|
Promise.resolve({
|
|
34
36
|
text: () => ({ success: true }),
|
|
37
|
+
ok: true,
|
|
35
38
|
}),
|
|
36
39
|
);
|
|
37
40
|
const response = await fetchAuthTokenService(authEndpoint);
|
|
@@ -40,14 +43,37 @@ describe('Unit test for authService', () => {
|
|
|
40
43
|
});
|
|
41
44
|
|
|
42
45
|
test('fetchAuthService', async () => {
|
|
43
|
-
global.fetch = jest.fn(() =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
global.fetch = jest.fn(() =>
|
|
47
|
+
Promise.resolve({ success: true, ok: true }),
|
|
48
|
+
);
|
|
49
|
+
await fetchAuthService(thoughtSpotHost, username, authToken);
|
|
50
|
+
expect(fetch).toBeCalledWith(
|
|
51
|
+
`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}?username=${username}&auth_token=${authToken}`,
|
|
52
|
+
{
|
|
53
|
+
credentials: 'include',
|
|
54
|
+
redirect: 'manual',
|
|
55
|
+
},
|
|
56
|
+
);
|
|
46
57
|
});
|
|
47
58
|
|
|
48
|
-
test('fetchBasicAuthService', async () => {
|
|
49
|
-
global.fetch = jest.fn(() =>
|
|
59
|
+
test('fetchBasicAuthService called with manual redirect', async () => {
|
|
60
|
+
global.fetch = jest.fn(() =>
|
|
61
|
+
Promise.resolve({ success: true, ok: true }),
|
|
62
|
+
);
|
|
50
63
|
await fetchBasicAuthService(thoughtSpotHost, username, password);
|
|
51
64
|
expect(fetch).toBeCalled();
|
|
52
65
|
});
|
|
66
|
+
|
|
67
|
+
test('log error on API failures', async () => {
|
|
68
|
+
jest.spyOn(global.console, 'error').mockImplementation(() => undefined);
|
|
69
|
+
global.fetch = jest.fn(() =>
|
|
70
|
+
Promise.resolve({
|
|
71
|
+
text: () => Promise.resolve('error'),
|
|
72
|
+
status: 500,
|
|
73
|
+
ok: false,
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
await fetchSessionInfoService(authVerificationUrl);
|
|
77
|
+
expect(global.console.error).toHaveBeenCalledWith('Failure', 'error');
|
|
78
|
+
});
|
|
53
79
|
});
|
package/src/utils/authService.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
// eslint-disable-next-line import/no-cycle
|
|
2
2
|
import { EndPoints } from '../auth';
|
|
3
3
|
|
|
4
|
+
function failureLoggedFetch(
|
|
5
|
+
url: string,
|
|
6
|
+
options: RequestInit = {},
|
|
7
|
+
): Promise<Response> {
|
|
8
|
+
return fetch(url, options).then(async (r) => {
|
|
9
|
+
if (!r.ok && r.type !== 'opaqueredirect' && r.type !== 'opaque') {
|
|
10
|
+
console.error('Failure', await r.text?.());
|
|
11
|
+
}
|
|
12
|
+
return r;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
4
16
|
export function fetchSessionInfoService(
|
|
5
17
|
authVerificationUrl: string,
|
|
6
18
|
): Promise<any> {
|
|
7
|
-
return
|
|
19
|
+
return failureLoggedFetch(authVerificationUrl, {
|
|
8
20
|
credentials: 'include',
|
|
9
21
|
});
|
|
10
22
|
}
|
|
@@ -20,10 +32,12 @@ export async function fetchAuthService(
|
|
|
20
32
|
username: string,
|
|
21
33
|
authToken: string,
|
|
22
34
|
): Promise<any> {
|
|
23
|
-
return
|
|
35
|
+
return failureLoggedFetch(
|
|
24
36
|
`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}?username=${username}&auth_token=${authToken}`,
|
|
25
37
|
{
|
|
26
38
|
credentials: 'include',
|
|
39
|
+
// We do not want to follow the redirect, as it starts giving a CORS error
|
|
40
|
+
redirect: 'manual',
|
|
27
41
|
},
|
|
28
42
|
);
|
|
29
43
|
}
|
|
@@ -33,7 +47,7 @@ export async function fetchBasicAuthService(
|
|
|
33
47
|
username: string,
|
|
34
48
|
password: string,
|
|
35
49
|
): Promise<any> {
|
|
36
|
-
return
|
|
50
|
+
return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.BASIC_LOGIN}`, {
|
|
37
51
|
method: 'POST',
|
|
38
52
|
headers: {
|
|
39
53
|
'content-type': 'application/x-www-form-urlencoded',
|
|
@@ -45,3 +59,13 @@ export async function fetchBasicAuthService(
|
|
|
45
59
|
credentials: 'include',
|
|
46
60
|
});
|
|
47
61
|
}
|
|
62
|
+
|
|
63
|
+
export async function fetchLogoutService(
|
|
64
|
+
thoughtSpotHost: string,
|
|
65
|
+
): Promise<any> {
|
|
66
|
+
return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.LOGOUT}`, {
|
|
67
|
+
credentials: 'include',
|
|
68
|
+
mode: 'no-cors',
|
|
69
|
+
method: 'POST',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import * as processDataInstance from './processData';
|
|
2
2
|
import * as answerServiceInstance from './answerService';
|
|
3
3
|
import * as auth from '../auth';
|
|
4
|
-
import
|
|
4
|
+
import * as base from '../embed/base';
|
|
5
|
+
import { EmbedEvent, OperationType, AuthType } from '../types';
|
|
5
6
|
|
|
6
7
|
describe('Unit test for process data', () => {
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
base.init({
|
|
10
|
+
thoughtSpotHost: '',
|
|
11
|
+
authType: AuthType.None,
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
jest.resetAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
7
18
|
const thoughtSpotHost = 'http://localhost';
|
|
8
19
|
test('processDataInstance, when operation is GetChartWithData', () => {
|
|
9
20
|
const answerService = {};
|
|
@@ -34,10 +45,11 @@ describe('Unit test for process data', () => {
|
|
|
34
45
|
'processCustomAction',
|
|
35
46
|
).mockImplementation(async () => ({}));
|
|
36
47
|
expect(
|
|
37
|
-
processDataInstance.
|
|
48
|
+
processDataInstance.processEventData(
|
|
38
49
|
EmbedEvent.CustomAction,
|
|
39
50
|
processedData,
|
|
40
51
|
thoughtSpotHost,
|
|
52
|
+
null,
|
|
41
53
|
),
|
|
42
54
|
).toStrictEqual(processedData);
|
|
43
55
|
});
|
|
@@ -52,10 +64,11 @@ describe('Unit test for process data', () => {
|
|
|
52
64
|
answerServiceInstance,
|
|
53
65
|
'getAnswerServiceInstance',
|
|
54
66
|
).mockImplementation(async () => ({}));
|
|
55
|
-
processDataInstance.
|
|
67
|
+
processDataInstance.processEventData(
|
|
56
68
|
EmbedEvent.Data,
|
|
57
69
|
processedData,
|
|
58
70
|
thoughtSpotHost,
|
|
71
|
+
null,
|
|
59
72
|
);
|
|
60
73
|
expect(processDataInstance.processCustomAction).not.toBeCalled();
|
|
61
74
|
});
|
|
@@ -68,12 +81,134 @@ describe('Unit test for process data', () => {
|
|
|
68
81
|
};
|
|
69
82
|
const e = { type: EmbedEvent.AuthInit, data: sessionInfo };
|
|
70
83
|
jest.spyOn(auth, 'initSession').mockReturnValue(null);
|
|
71
|
-
|
|
84
|
+
jest.spyOn(base, 'notifyAuthSuccess');
|
|
85
|
+
expect(
|
|
86
|
+
processDataInstance.processEventData(e.type, e, '', null),
|
|
87
|
+
).toEqual({
|
|
72
88
|
type: e.type,
|
|
73
89
|
data: {
|
|
74
90
|
userGUID: sessionInfo.userGUID,
|
|
75
91
|
},
|
|
76
92
|
});
|
|
77
93
|
expect(auth.initSession).toBeCalledWith(sessionInfo);
|
|
94
|
+
expect(base.notifyAuthSuccess).toBeCalled();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('AuthExpire autoLogin false', () => {
|
|
98
|
+
const e = { type: EmbedEvent.AuthExpire };
|
|
99
|
+
jest.spyOn(base, 'notifyAuthFailure');
|
|
100
|
+
jest.spyOn(base, 'handleAuth');
|
|
101
|
+
jest.spyOn(base, 'getEmbedConfig').mockReturnValue({
|
|
102
|
+
autoLogin: false,
|
|
103
|
+
});
|
|
104
|
+
expect(
|
|
105
|
+
processDataInstance.processEventData(e.type, e, '', null),
|
|
106
|
+
).toEqual({
|
|
107
|
+
type: e.type,
|
|
108
|
+
});
|
|
109
|
+
expect(base.notifyAuthFailure).toBeCalledWith(
|
|
110
|
+
auth.AuthFailureType.EXPIRY,
|
|
111
|
+
);
|
|
112
|
+
expect(base.handleAuth).not.toHaveBeenCalled();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('AuthExpire autoLogin true', () => {
|
|
116
|
+
const e = { type: EmbedEvent.AuthExpire };
|
|
117
|
+
jest.spyOn(base, 'notifyAuthFailure');
|
|
118
|
+
jest.spyOn(base, 'handleAuth').mockResolvedValue(true);
|
|
119
|
+
jest.spyOn(base, 'getEmbedConfig').mockReturnValue({
|
|
120
|
+
autoLogin: true,
|
|
121
|
+
});
|
|
122
|
+
expect(
|
|
123
|
+
processDataInstance.processEventData(e.type, e, '', null),
|
|
124
|
+
).toEqual({
|
|
125
|
+
type: e.type,
|
|
126
|
+
});
|
|
127
|
+
expect(base.notifyAuthFailure).toBeCalledWith(
|
|
128
|
+
auth.AuthFailureType.EXPIRY,
|
|
129
|
+
);
|
|
130
|
+
expect(base.handleAuth).toBeCalled();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('NoCookieAccess no suppress alert', () => {
|
|
134
|
+
const e = { type: EmbedEvent.NoCookieAccess };
|
|
135
|
+
jest.spyOn(base, 'notifyAuthFailure');
|
|
136
|
+
jest.spyOn(base, 'getEmbedConfig').mockReturnValue({
|
|
137
|
+
loginFailedMessage: 'Hello',
|
|
138
|
+
suppressNoCookieAccessAlert: false,
|
|
139
|
+
});
|
|
140
|
+
jest.spyOn(window, 'alert').mockImplementation(() => undefined);
|
|
141
|
+
const el: any = {};
|
|
142
|
+
expect(processDataInstance.processEventData(e.type, e, '', el)).toEqual(
|
|
143
|
+
{
|
|
144
|
+
type: e.type,
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
expect(base.notifyAuthFailure).toBeCalledWith(
|
|
148
|
+
auth.AuthFailureType.NO_COOKIE_ACCESS,
|
|
149
|
+
);
|
|
150
|
+
expect(window.alert).toBeCalled();
|
|
151
|
+
expect(el.innerHTML).toBe('Hello');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test('NoCookieAccess suppressAlert=true', () => {
|
|
155
|
+
const e = { type: EmbedEvent.NoCookieAccess };
|
|
156
|
+
jest.spyOn(base, 'notifyAuthFailure');
|
|
157
|
+
jest.spyOn(base, 'getEmbedConfig').mockReturnValue({
|
|
158
|
+
loginFailedMessage: 'Hello',
|
|
159
|
+
suppressNoCookieAccessAlert: true,
|
|
160
|
+
});
|
|
161
|
+
jest.spyOn(window, 'alert').mockReset();
|
|
162
|
+
jest.spyOn(window, 'alert').mockImplementation(() => undefined);
|
|
163
|
+
const el: any = {};
|
|
164
|
+
expect(processDataInstance.processEventData(e.type, e, '', el)).toEqual(
|
|
165
|
+
{
|
|
166
|
+
type: e.type,
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
expect(base.notifyAuthFailure).toBeCalledWith(
|
|
170
|
+
auth.AuthFailureType.NO_COOKIE_ACCESS,
|
|
171
|
+
);
|
|
172
|
+
expect(window.alert).not.toBeCalled();
|
|
173
|
+
expect(el.innerHTML).toBe('Hello');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('process authFailure', () => {
|
|
177
|
+
const e = { type: EmbedEvent.AuthFailure };
|
|
178
|
+
jest.spyOn(base, 'notifyAuthFailure');
|
|
179
|
+
jest.spyOn(base, 'getEmbedConfig').mockReturnValue({
|
|
180
|
+
loginFailedMessage: 'Hello',
|
|
181
|
+
});
|
|
182
|
+
const el: any = {};
|
|
183
|
+
expect(processDataInstance.processEventData(e.type, e, '', el)).toEqual(
|
|
184
|
+
{
|
|
185
|
+
type: e.type,
|
|
186
|
+
},
|
|
187
|
+
);
|
|
188
|
+
expect(base.notifyAuthFailure).toBeCalledWith(
|
|
189
|
+
auth.AuthFailureType.OTHER,
|
|
190
|
+
);
|
|
191
|
+
expect(el.innerHTML).toBe('Hello');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('process authLogout', () => {
|
|
195
|
+
base.init({
|
|
196
|
+
loginFailedMessage: 'Hello',
|
|
197
|
+
autoLogin: true,
|
|
198
|
+
thoughtSpotHost: '',
|
|
199
|
+
authType: AuthType.None,
|
|
200
|
+
});
|
|
201
|
+
jest.spyOn(base, 'getEmbedConfig').mockRestore();
|
|
202
|
+
const e = { type: EmbedEvent.AuthLogout };
|
|
203
|
+
jest.spyOn(base, 'notifyLogout');
|
|
204
|
+
const el: any = {};
|
|
205
|
+
expect(processDataInstance.processEventData(e.type, e, '', el)).toEqual(
|
|
206
|
+
{
|
|
207
|
+
type: e.type,
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
expect(base.notifyLogout).toBeCalled();
|
|
211
|
+
expect(el.innerHTML).toBe('Hello');
|
|
212
|
+
expect(base.getEmbedConfig().autoLogin).toBe(false);
|
|
78
213
|
});
|
|
79
214
|
});
|
package/src/utils/processData.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
disableAutoLogin,
|
|
3
|
+
getEmbedConfig,
|
|
4
|
+
handleAuth,
|
|
5
|
+
notifyAuthFailure,
|
|
6
|
+
notifyAuthSuccess,
|
|
7
|
+
notifyLogout,
|
|
8
|
+
} from '../embed/base';
|
|
9
|
+
import { AuthFailureType, initSession } from '../auth';
|
|
3
10
|
import { EmbedEvent, OperationType } from '../types';
|
|
4
11
|
import { getAnswerServiceInstance } from './answerService';
|
|
5
12
|
|
|
@@ -28,6 +35,7 @@ export function processCustomAction(e: any, thoughtSpotHost: string) {
|
|
|
28
35
|
function processAuthInit(e: any) {
|
|
29
36
|
// Store user session details sent by app.
|
|
30
37
|
initSession(e.data);
|
|
38
|
+
notifyAuthSuccess();
|
|
31
39
|
|
|
32
40
|
// Expose only allowed details (eg: userGUID) back to SDK users.
|
|
33
41
|
return {
|
|
@@ -43,14 +51,50 @@ function processAuthExpire(e: any) {
|
|
|
43
51
|
if (autoLogin) {
|
|
44
52
|
handleAuth();
|
|
45
53
|
}
|
|
54
|
+
notifyAuthFailure(AuthFailureType.EXPIRY);
|
|
46
55
|
return e;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
|
|
58
|
+
function processNoCookieAccess(e: any, containerEl: Element) {
|
|
59
|
+
const {
|
|
60
|
+
loginFailedMessage,
|
|
61
|
+
suppressNoCookieAccessAlert,
|
|
62
|
+
} = getEmbedConfig();
|
|
63
|
+
if (!suppressNoCookieAccessAlert) {
|
|
64
|
+
// eslint-disable-next-line no-alert
|
|
65
|
+
alert(
|
|
66
|
+
'Third party cookie access is blocked on this browser, please allow third party cookies for this to work properly. \nYou can use `suppressNoCookieAccessAlert` to suppress this message.',
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
// eslint-disable-next-line no-param-reassign
|
|
70
|
+
containerEl.innerHTML = loginFailedMessage;
|
|
71
|
+
notifyAuthFailure(AuthFailureType.NO_COOKIE_ACCESS);
|
|
72
|
+
return e;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function processAuthFailure(e: any, containerEl: Element) {
|
|
76
|
+
const { loginFailedMessage } = getEmbedConfig();
|
|
77
|
+
// eslint-disable-next-line no-param-reassign
|
|
78
|
+
containerEl.innerHTML = loginFailedMessage;
|
|
79
|
+
notifyAuthFailure(AuthFailureType.OTHER);
|
|
80
|
+
return e;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function processAuthLogout(e: any, containerEl: Element) {
|
|
84
|
+
const { loginFailedMessage } = getEmbedConfig();
|
|
85
|
+
// eslint-disable-next-line no-param-reassign
|
|
86
|
+
containerEl.innerHTML = loginFailedMessage;
|
|
87
|
+
disableAutoLogin();
|
|
88
|
+
notifyLogout();
|
|
89
|
+
return e;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function processEventData(
|
|
50
93
|
type: EmbedEvent,
|
|
51
94
|
e: any,
|
|
52
95
|
thoughtSpotHost: string,
|
|
53
|
-
|
|
96
|
+
containerEl: Element,
|
|
97
|
+
): any {
|
|
54
98
|
switch (type) {
|
|
55
99
|
case EmbedEvent.CustomAction:
|
|
56
100
|
return processCustomAction(e, thoughtSpotHost);
|
|
@@ -58,6 +102,12 @@ export function getProcessData(
|
|
|
58
102
|
return processAuthInit(e);
|
|
59
103
|
case EmbedEvent.AuthExpire:
|
|
60
104
|
return processAuthExpire(e);
|
|
105
|
+
case EmbedEvent.NoCookieAccess:
|
|
106
|
+
return processNoCookieAccess(e, containerEl);
|
|
107
|
+
case EmbedEvent.AuthFailure:
|
|
108
|
+
return processAuthFailure(e, containerEl);
|
|
109
|
+
case EmbedEvent.AuthLogout:
|
|
110
|
+
return processAuthLogout(e, containerEl);
|
|
61
111
|
default:
|
|
62
112
|
}
|
|
63
113
|
return e;
|