@thoughtspot/visual-embed-sdk 1.37.0 → 1.37.1-spotter-embed
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/cjs/package.json +3 -3
- package/cjs/src/auth.d.ts +9 -4
- package/cjs/src/auth.d.ts.map +1 -1
- package/cjs/src/auth.js +21 -0
- package/cjs/src/auth.js.map +1 -1
- package/cjs/src/auth.spec.js +48 -0
- package/cjs/src/auth.spec.js.map +1 -1
- package/cjs/src/embed/app.d.ts +59 -0
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +13 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +44 -0
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.d.ts +39 -9
- package/cjs/src/embed/bodyless-conversation.d.ts.map +1 -1
- package/cjs/src/embed/bodyless-conversation.js +32 -5
- package/cjs/src/embed/bodyless-conversation.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.spec.js +4 -4
- package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +38 -11
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +28 -4
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +7 -7
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +4 -1
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +3 -3
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +5 -3
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/pages/embed-test.page.d.ts +8 -0
- package/cjs/src/pages/embed-test.page.d.ts.map +1 -0
- package/cjs/src/pages/embed-test.page.js +20 -0
- package/cjs/src/pages/embed-test.page.js.map +1 -0
- package/cjs/src/pages/home.page.d.ts +6 -0
- package/cjs/src/pages/home.page.d.ts.map +1 -0
- package/cjs/src/pages/home.page.js +12 -0
- package/cjs/src/pages/home.page.js.map +1 -0
- package/cjs/src/pages/login.page.d.ts +15 -0
- package/cjs/src/pages/login.page.d.ts.map +1 -0
- package/cjs/src/pages/login.page.js +22 -0
- package/cjs/src/pages/login.page.js.map +1 -0
- package/cjs/src/react/all-types-export.d.ts +1 -1
- package/cjs/src/react/all-types-export.d.ts.map +1 -1
- package/cjs/src/react/all-types-export.js +2 -1
- package/cjs/src/react/all-types-export.js.map +1 -1
- package/cjs/src/react/index.d.ts +24 -5
- package/cjs/src/react/index.d.ts.map +1 -1
- package/cjs/src/react/index.js +21 -4
- package/cjs/src/react/index.js.map +1 -1
- package/cjs/src/tests/auth.test.d.ts +1 -0
- package/cjs/src/tests/auth.test.d.ts.map +1 -0
- package/cjs/src/tests/auth.test.js +1 -0
- package/cjs/src/tests/auth.test.js.map +1 -0
- package/cjs/src/tests/e2e/auth.spec.d.ts +2 -0
- package/cjs/src/tests/e2e/auth.spec.d.ts.map +1 -0
- package/cjs/src/tests/e2e/auth.spec.js +54 -0
- package/cjs/src/tests/e2e/auth.spec.js.map +1 -0
- package/cjs/src/types.d.ts +95 -3
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +79 -0
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.d.ts +35 -15
- package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.js +35 -15
- package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/cjs/src/utils/processData.js +6 -4
- package/cjs/src/utils/processData.js.map +1 -1
- package/dist/index-Cj4BVGHL.js +7371 -0
- package/dist/index-DUaG1OG2.js +7447 -0
- package/dist/index-Fhk1V_Gw.js +7371 -0
- package/dist/index-OuiZF3zE.js +7371 -0
- package/dist/src/auth.d.ts +9 -4
- package/dist/src/auth.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +59 -0
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/bodyless-conversation.d.ts +39 -9
- package/dist/src/embed/bodyless-conversation.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +38 -11
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/react/all-types-export.d.ts +1 -1
- package/dist/src/react/all-types-export.d.ts.map +1 -1
- package/dist/src/react/index.d.ts +24 -5
- package/dist/src/react/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +95 -3
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/graphql/answerService/answerService.d.ts +35 -15
- package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +208 -31
- package/dist/tsembed-react.js +428 -174
- package/dist/tsembed.es.js +170 -32
- package/dist/tsembed.js +392 -176
- package/dist/visual-embed-sdk-react-full.d.ts +299 -47
- package/dist/visual-embed-sdk-react.d.ts +299 -47
- package/dist/visual-embed-sdk.d.ts +276 -43
- package/lib/package.json +3 -3
- package/lib/src/auth.d.ts +9 -4
- package/lib/src/auth.d.ts.map +1 -1
- package/lib/src/auth.js +21 -0
- package/lib/src/auth.js.map +1 -1
- package/lib/src/auth.spec.js +48 -0
- package/lib/src/auth.spec.js.map +1 -1
- package/lib/src/embed/app.d.ts +59 -0
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +13 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +44 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.d.ts +39 -9
- package/lib/src/embed/bodyless-conversation.d.ts.map +1 -1
- package/lib/src/embed/bodyless-conversation.js +30 -4
- package/lib/src/embed/bodyless-conversation.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.spec.js +5 -5
- package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +38 -11
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +26 -3
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +8 -8
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +4 -1
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +3 -3
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +3 -3
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/all-types-export.d.ts +1 -1
- package/lib/src/react/all-types-export.d.ts.map +1 -1
- package/lib/src/react/all-types-export.js +1 -1
- package/lib/src/react/all-types-export.js.map +1 -1
- package/lib/src/react/index.d.ts +24 -5
- package/lib/src/react/index.d.ts.map +1 -1
- package/lib/src/react/index.js +21 -4
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/types.d.ts +95 -3
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +79 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.d.ts +35 -15
- package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.js +35 -15
- package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/lib/src/utils/processData.js +6 -4
- package/lib/src/utils/processData.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +278 -45
- package/package.json +3 -3
- package/src/auth.spec.ts +52 -0
- package/src/auth.ts +25 -3
- package/src/embed/app.spec.ts +64 -0
- package/src/embed/app.ts +80 -0
- package/src/embed/bodyless-conversation.spec.ts +6 -6
- package/src/embed/bodyless-conversation.ts +43 -8
- package/src/embed/conversation.spec.ts +16 -16
- package/src/embed/conversation.ts +42 -11
- package/src/embed/ts-embed.spec.ts +0 -2
- package/src/embed/ts-embed.ts +4 -0
- package/src/index.ts +8 -4
- package/src/react/all-types-export.ts +1 -0
- package/src/react/index.tsx +36 -10
- package/src/types.ts +99 -1
- package/src/utils/graphql/answerService/answerService.ts +35 -15
- package/src/utils/processData.ts +6 -6
package/src/auth.spec.ts
CHANGED
|
@@ -385,6 +385,45 @@ describe('Unit test for auth', () => {
|
|
|
385
385
|
expect(global.window.location.href).toBe(samalLoginUrl);
|
|
386
386
|
});
|
|
387
387
|
|
|
388
|
+
it('should emit SAML_POPUP_CLOSED_NO_AUTH when popup window is closed', async () => {
|
|
389
|
+
jest.useFakeTimers();
|
|
390
|
+
const mockPopupWindow = {
|
|
391
|
+
closed: false,
|
|
392
|
+
focus: jest.fn(),
|
|
393
|
+
close: jest.fn()
|
|
394
|
+
};
|
|
395
|
+
global.window.open = jest.fn().mockReturnValue(mockPopupWindow);
|
|
396
|
+
Object.defineProperty(window, 'location', {
|
|
397
|
+
value: {
|
|
398
|
+
href: '',
|
|
399
|
+
hash: '',
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
spyOn(authInstance, 'samlCompletionPromise').and.returnValue(Promise.resolve(false));
|
|
403
|
+
const emitSpy = jest.fn();
|
|
404
|
+
const mockEventEmitter = {
|
|
405
|
+
emit: emitSpy,
|
|
406
|
+
once: jest.fn(),
|
|
407
|
+
on: jest.fn()
|
|
408
|
+
};
|
|
409
|
+
authInstance.setAuthEE(mockEventEmitter as any);
|
|
410
|
+
jest.spyOn(tokenAuthService, 'isActiveService')
|
|
411
|
+
.mockReturnValueOnce(false)
|
|
412
|
+
.mockReturnValueOnce(true);
|
|
413
|
+
expect(
|
|
414
|
+
await authInstance.doSamlAuth({
|
|
415
|
+
...embedConfig.doSamlAuthNoRedirect,
|
|
416
|
+
}),
|
|
417
|
+
).toBe(true);
|
|
418
|
+
document.getElementById('ts-auth-btn').click();
|
|
419
|
+
mockPopupWindow.closed = true;
|
|
420
|
+
jest.advanceTimersByTime(1000);
|
|
421
|
+
window.postMessage({ type: EmbedEvent.SAMLComplete }, '*');
|
|
422
|
+
await authInstance.samlCompletionPromise;
|
|
423
|
+
expect(emitSpy).toHaveBeenCalledWith(authInstance.AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
|
|
424
|
+
jest.useRealTimers();
|
|
425
|
+
authInstance.setAuthEE(null);
|
|
426
|
+
});
|
|
388
427
|
it('when user is not loggedIn, in config noRedirect is true and isAtSSORedirectUrl is false', async () => {
|
|
389
428
|
Object.defineProperty(window, 'location', {
|
|
390
429
|
value: {
|
|
@@ -408,6 +447,19 @@ describe('Unit test for auth', () => {
|
|
|
408
447
|
await authInstance.samlCompletionPromise;
|
|
409
448
|
expect(authInstance.loggedInStatus).toBe(true);
|
|
410
449
|
});
|
|
450
|
+
|
|
451
|
+
it('should support emitting SAML_POPUP_CLOSED_NO_AUTH event', () => {
|
|
452
|
+
const emitSpy = jest.fn();
|
|
453
|
+
const mockEventEmitter = {
|
|
454
|
+
emit: emitSpy,
|
|
455
|
+
once: jest.fn()
|
|
456
|
+
};
|
|
457
|
+
authInstance.setAuthEE(mockEventEmitter as any);
|
|
458
|
+
authInstance.getAuthEE().emit(authInstance.AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
|
|
459
|
+
expect(emitSpy).toHaveBeenCalledWith(authInstance.AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
|
|
460
|
+
authInstance.setAuthEE(null);
|
|
461
|
+
});
|
|
462
|
+
|
|
411
463
|
});
|
|
412
464
|
|
|
413
465
|
describe('doOIDCAuth', () => {
|
package/src/auth.ts
CHANGED
|
@@ -40,7 +40,8 @@ export enum AuthFailureType {
|
|
|
40
40
|
NO_COOKIE_ACCESS = 'NO_COOKIE_ACCESS',
|
|
41
41
|
EXPIRY = 'EXPIRY',
|
|
42
42
|
OTHER = 'OTHER',
|
|
43
|
-
IDLE_SESSION_TIMEOUT = 'IDLE_SESSION_TIMEOUT'
|
|
43
|
+
IDLE_SESSION_TIMEOUT = 'IDLE_SESSION_TIMEOUT',
|
|
44
|
+
UNAUTHENTICATED_FAILURE = 'UNAUTHENTICATED_FAILURE',
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/**
|
|
@@ -76,6 +77,11 @@ export enum AuthStatus {
|
|
|
76
77
|
* @version SDK: 1.19.0
|
|
77
78
|
*/
|
|
78
79
|
WAITING_FOR_POPUP = 'WAITING_FOR_POPUP',
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Emitted when the SAML popup is closed without authentication
|
|
83
|
+
*/
|
|
84
|
+
SAML_POPUP_CLOSED_NO_AUTH = 'SAML_POPUP_CLOSED_NO_AUTH',
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
/**
|
|
@@ -95,13 +101,13 @@ export interface AuthEventEmitter {
|
|
|
95
101
|
* @param listener
|
|
96
102
|
*/
|
|
97
103
|
on(
|
|
98
|
-
event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP,
|
|
104
|
+
event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP | AuthStatus.SAML_POPUP_CLOSED_NO_AUTH,
|
|
99
105
|
listener: () => void,
|
|
100
106
|
): this;
|
|
101
107
|
on(event: AuthStatus.SUCCESS, listener: (sessionInfo: any) => void): this;
|
|
102
108
|
once(event: AuthStatus.FAILURE, listener: (failureType: AuthFailureType) => void): this;
|
|
103
109
|
once(
|
|
104
|
-
event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP,
|
|
110
|
+
event: AuthStatus.SDK_SUCCESS | AuthStatus.LOGOUT | AuthStatus.WAITING_FOR_POPUP | AuthStatus.SAML_POPUP_CLOSED_NO_AUTH,
|
|
105
111
|
listener: () => void,
|
|
106
112
|
): this;
|
|
107
113
|
once(event: AuthStatus.SUCCESS, listener: (sessionInfo: any) => void): this;
|
|
@@ -363,6 +369,7 @@ export const doBasicAuth = async (embedConfig: EmbedConfig): Promise<boolean> =>
|
|
|
363
369
|
* @param triggerText
|
|
364
370
|
*/
|
|
365
371
|
async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, triggerText: string) {
|
|
372
|
+
let popupClosedCheck: NodeJS.Timeout;
|
|
366
373
|
const openPopup = () => {
|
|
367
374
|
if (samlAuthWindow === null || samlAuthWindow.closed) {
|
|
368
375
|
samlAuthWindow = window.open(
|
|
@@ -370,10 +377,21 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
|
|
|
370
377
|
'_blank',
|
|
371
378
|
'location=no,height=570,width=520,scrollbars=yes,status=yes',
|
|
372
379
|
);
|
|
380
|
+
if (samlAuthWindow) {
|
|
381
|
+
popupClosedCheck = setInterval(() => {
|
|
382
|
+
if (samlAuthWindow.closed) {
|
|
383
|
+
clearInterval(popupClosedCheck);
|
|
384
|
+
if (samlCompletionPromise && !samlCompletionResolved) {
|
|
385
|
+
authEE?.emit(AuthStatus.SAML_POPUP_CLOSED_NO_AUTH);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}, 500);
|
|
389
|
+
}
|
|
373
390
|
} else {
|
|
374
391
|
samlAuthWindow.focus();
|
|
375
392
|
}
|
|
376
393
|
};
|
|
394
|
+
let samlCompletionResolved = false;
|
|
377
395
|
authEE?.emit(AuthStatus.WAITING_FOR_POPUP);
|
|
378
396
|
const containerEl = getDOMNode(triggerContainer);
|
|
379
397
|
if (containerEl) {
|
|
@@ -385,6 +403,10 @@ async function samlPopupFlow(ssoURL: string, triggerContainer: DOMSelector, trig
|
|
|
385
403
|
samlCompletionPromise = samlCompletionPromise || new Promise<void>((resolve, reject) => {
|
|
386
404
|
window.addEventListener('message', (e) => {
|
|
387
405
|
if (e.data.type === EmbedEvent.SAMLComplete) {
|
|
406
|
+
samlCompletionResolved = true;
|
|
407
|
+
if (popupClosedCheck) {
|
|
408
|
+
clearInterval(popupClosedCheck);
|
|
409
|
+
}
|
|
388
410
|
(e.source as Window).close();
|
|
389
411
|
resolve();
|
|
390
412
|
}
|
package/src/embed/app.spec.ts
CHANGED
|
@@ -494,6 +494,70 @@ describe('App embed tests', () => {
|
|
|
494
494
|
});
|
|
495
495
|
});
|
|
496
496
|
|
|
497
|
+
test('Should add hideHamburger, hideObjectSearch, hideNotification flags to the iframe src', async () => {
|
|
498
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
499
|
+
...defaultViewConfig,
|
|
500
|
+
hideHamburger: true,
|
|
501
|
+
hideObjectSearch: true,
|
|
502
|
+
hideNotification: true,
|
|
503
|
+
} as AppViewConfig);
|
|
504
|
+
|
|
505
|
+
appEmbed.render();
|
|
506
|
+
await executeAfterWait(() => {
|
|
507
|
+
expectUrlMatchesWithParams(
|
|
508
|
+
getIFrameSrc(),
|
|
509
|
+
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&hideHamburger=true&hideObjectSearch=true&hideNotification=true${defaultParams}${defaultParamsPost}#/home`,
|
|
510
|
+
);
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
test('Should not add when hideHamburger, hideObjectSearch, hideNotification values are not true to the iframe src', async () => {
|
|
515
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
516
|
+
...defaultViewConfig,
|
|
517
|
+
hideHamburger: false,
|
|
518
|
+
hideObjectSearch: undefined,
|
|
519
|
+
hideNotification: null,
|
|
520
|
+
} as AppViewConfig);
|
|
521
|
+
|
|
522
|
+
appEmbed.render();
|
|
523
|
+
await executeAfterWait(() => {
|
|
524
|
+
expectUrlMatchesWithParams(
|
|
525
|
+
getIFrameSrc(),
|
|
526
|
+
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false${defaultParams}${defaultParamsPost}#/home`,
|
|
527
|
+
);
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
test('Should add navigationVersion=v3 when modularHomeExperienceV3 is true to the iframe src', async () => {
|
|
532
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
533
|
+
...defaultViewConfig,
|
|
534
|
+
modularHomeExperienceV3: true,
|
|
535
|
+
} as AppViewConfig);
|
|
536
|
+
|
|
537
|
+
appEmbed.render();
|
|
538
|
+
await executeAfterWait(() => {
|
|
539
|
+
expectUrlMatchesWithParams(
|
|
540
|
+
getIFrameSrc(),
|
|
541
|
+
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&navigationVersion=v3${defaultParams}${defaultParamsPost}#/home`,
|
|
542
|
+
);
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test('Should not add navigationVersion when modularHomeExperienceV3 is false to the iframe src', async () => {
|
|
547
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
548
|
+
...defaultViewConfig,
|
|
549
|
+
modularHomeExperienceV3: false,
|
|
550
|
+
} as AppViewConfig);
|
|
551
|
+
|
|
552
|
+
appEmbed.render();
|
|
553
|
+
await executeAfterWait(() => {
|
|
554
|
+
expectUrlMatchesWithParams(
|
|
555
|
+
getIFrameSrc(),
|
|
556
|
+
`http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false${defaultParams}${defaultParamsPost}#/home`,
|
|
557
|
+
);
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
|
|
497
561
|
test('Should add enableAskSage flag to the iframe src', async () => {
|
|
498
562
|
const appEmbed = new AppEmbed(getRootEl(), {
|
|
499
563
|
...defaultViewConfig,
|
package/src/embed/app.ts
CHANGED
|
@@ -151,6 +151,51 @@ export interface AppViewConfig extends Omit<ViewConfig, 'visibleTabs'> {
|
|
|
151
151
|
* ```
|
|
152
152
|
*/
|
|
153
153
|
enablePendoHelp?: boolean
|
|
154
|
+
/**
|
|
155
|
+
* Control the visibility of the hamburger icon on the top nav bar
|
|
156
|
+
* available when new navigation V3 is enabled.
|
|
157
|
+
*
|
|
158
|
+
* @default false
|
|
159
|
+
* @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
|
|
160
|
+
* @example
|
|
161
|
+
* ```js
|
|
162
|
+
* const embed = new AppEmbed('#tsEmbed', {
|
|
163
|
+
* ... // other options
|
|
164
|
+
* hideHamburger : true,
|
|
165
|
+
* })
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
hideHamburger?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Control the visibility of the Eureka search on the top nav bar
|
|
171
|
+
* this will control for both new V2 and new navigation V3.
|
|
172
|
+
*
|
|
173
|
+
* @default true
|
|
174
|
+
* @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
|
|
175
|
+
* @example
|
|
176
|
+
* ```js
|
|
177
|
+
* const embed = new AppEmbed('#tsEmbed', {
|
|
178
|
+
* ... // other options
|
|
179
|
+
* hideObjectSearch: false,
|
|
180
|
+
* })
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
hideObjectSearch?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* Control the visibility of the notification on the top nav bar V3,
|
|
186
|
+
* available when new navigation V3 is enabled.
|
|
187
|
+
*
|
|
188
|
+
* @default true
|
|
189
|
+
* @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
|
|
190
|
+
* @example
|
|
191
|
+
* ```js
|
|
192
|
+
* const embed = new AppEmbed('#tsEmbed', {
|
|
193
|
+
* ... // other options
|
|
194
|
+
* hideNotification: false,
|
|
195
|
+
* })
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
hideNotification?: boolean;
|
|
154
199
|
/**
|
|
155
200
|
* Control the visibility of the application switcher button on the nav-bar.
|
|
156
201
|
* By default, the application switcher is shown.
|
|
@@ -344,6 +389,20 @@ export interface AppViewConfig extends Omit<ViewConfig, 'visibleTabs'> {
|
|
|
344
389
|
* ```
|
|
345
390
|
*/
|
|
346
391
|
modularHomeExperience?: boolean;
|
|
392
|
+
/**
|
|
393
|
+
* Flag to control new navigation v3 home experience.
|
|
394
|
+
*
|
|
395
|
+
* @default false
|
|
396
|
+
* @version SDK: 1.39.0 | Thoughtspot: 10.10.0.cl
|
|
397
|
+
* @example
|
|
398
|
+
* ```js
|
|
399
|
+
* const embed = new AppEmbed('#tsEmbed', {
|
|
400
|
+
* ... // other options
|
|
401
|
+
* modularHomeExperienceV3 : true,
|
|
402
|
+
* })
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
modularHomeExperienceV3?: boolean;
|
|
347
406
|
/**
|
|
348
407
|
* Boolean to control if Liveboard header is sticky or not.
|
|
349
408
|
* @example
|
|
@@ -515,6 +574,9 @@ export class AppEmbed extends V1Embed {
|
|
|
515
574
|
liveboardV2,
|
|
516
575
|
showPrimaryNavbar,
|
|
517
576
|
disableProfileAndHelp,
|
|
577
|
+
hideHamburger,
|
|
578
|
+
hideObjectSearch,
|
|
579
|
+
hideNotification,
|
|
518
580
|
hideApplicationSwitcher,
|
|
519
581
|
hideOrgSwitcher,
|
|
520
582
|
enableSearchAssist,
|
|
@@ -525,6 +587,7 @@ export class AppEmbed extends V1Embed {
|
|
|
525
587
|
showLiveboardDescription = true,
|
|
526
588
|
hideHomepageLeftNav = false,
|
|
527
589
|
modularHomeExperience = false,
|
|
590
|
+
modularHomeExperienceV3 = false,
|
|
528
591
|
isLiveboardHeaderSticky = true,
|
|
529
592
|
enableAskSage,
|
|
530
593
|
collapseSearchBarInitially = false,
|
|
@@ -561,6 +624,22 @@ export class AppEmbed extends V1Embed {
|
|
|
561
624
|
|
|
562
625
|
params = this.getBaseQueryParams(params);
|
|
563
626
|
|
|
627
|
+
if (modularHomeExperienceV3) {
|
|
628
|
+
params[Param.NavigationVersion] = 'v3';
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (hideObjectSearch) {
|
|
632
|
+
params[Param.HideObjectSearch] = !!hideObjectSearch;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (hideHamburger) {
|
|
636
|
+
params[Param.HideHamburger] = !!hideHamburger;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (hideNotification) {
|
|
640
|
+
params[Param.HideNotification] = !!hideNotification;
|
|
641
|
+
}
|
|
642
|
+
|
|
564
643
|
if (fullHeight === true) {
|
|
565
644
|
params[Param.fullHeight] = true;
|
|
566
645
|
}
|
|
@@ -620,6 +699,7 @@ export class AppEmbed extends V1Embed {
|
|
|
620
699
|
/* eslint-disable-next-line max-len */
|
|
621
700
|
params[Param.DataPanelCustomGroupsAccordionInitialState] = DataPanelCustomColumnGroupsAccordionState.EXPAND_ALL;
|
|
622
701
|
}
|
|
702
|
+
|
|
623
703
|
const queryParams = getQueryParamString(params, true);
|
|
624
704
|
|
|
625
705
|
return queryParams;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'jest-fetch-mock';
|
|
2
|
-
import {
|
|
2
|
+
import { SpotterAgentEmbed, SpotterAgentEmbedViewConfig } from './bodyless-conversation';
|
|
3
3
|
import * as authInstance from '../auth';
|
|
4
4
|
import { init } from '../index';
|
|
5
5
|
import { Action, AuthType, RuntimeFilterOp } from '../types';
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
expectUrlToHaveParamsWithValues,
|
|
15
15
|
} from '../test/test-utils';
|
|
16
16
|
|
|
17
|
-
describe('
|
|
17
|
+
describe('SpotterAgentEmbed', () => {
|
|
18
18
|
const thoughtSpotHost = 'tshost';
|
|
19
19
|
|
|
20
20
|
beforeAll(() => {
|
|
@@ -117,12 +117,12 @@ describe('BodylessConversation', () => {
|
|
|
117
117
|
},
|
|
118
118
|
}),
|
|
119
119
|
);
|
|
120
|
-
const viewConfig:
|
|
120
|
+
const viewConfig: SpotterAgentEmbedViewConfig = {
|
|
121
121
|
worksheetId: 'worksheetId',
|
|
122
122
|
};
|
|
123
123
|
|
|
124
|
-
const
|
|
125
|
-
const result = await
|
|
124
|
+
const spotterEmbed = new SpotterAgentEmbed(viewConfig);
|
|
125
|
+
const result = await spotterEmbed.sendMessage('userMessage');
|
|
126
126
|
const iframeSrc = getIFrameSrc(result.container);
|
|
127
127
|
expectUrlToHaveParamsWithValues(iframeSrc, {
|
|
128
128
|
sessionId: 'sessionId',
|
|
@@ -134,7 +134,7 @@ describe('BodylessConversation', () => {
|
|
|
134
134
|
fetchMock.mockRejectOnce(
|
|
135
135
|
new Error('error'),
|
|
136
136
|
);
|
|
137
|
-
const errorResult = await
|
|
137
|
+
const errorResult = await spotterEmbed.sendMessage('userMessage');
|
|
138
138
|
expect(errorResult.error instanceof Error).toBeTruthy();
|
|
139
139
|
});
|
|
140
140
|
});
|
|
@@ -8,14 +8,22 @@ import { getQueryParamString } from '../utils';
|
|
|
8
8
|
* Configuration for bodyless conversation options.
|
|
9
9
|
* @group Embed components
|
|
10
10
|
*/
|
|
11
|
-
export interface
|
|
11
|
+
export interface SpotterAgentEmbedViewConfig extends ViewConfig {
|
|
12
12
|
/**
|
|
13
13
|
* The ID of the worksheet to use for the conversation.
|
|
14
14
|
*/
|
|
15
15
|
worksheetId: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Configuration for conversation options.
|
|
20
|
+
* @deprecated Renamed to SpotterAgentEmbedViewConfig
|
|
21
|
+
* @group Embed components
|
|
22
|
+
*/
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
24
|
+
export interface BodylessConversationViewConfig extends SpotterAgentEmbedViewConfig {}
|
|
25
|
+
|
|
26
|
+
interface SpotterAgentMessageViewConfig extends SpotterAgentEmbedViewConfig {
|
|
19
27
|
sessionId: string;
|
|
20
28
|
genNo: number;
|
|
21
29
|
acSessionId: string;
|
|
@@ -23,7 +31,7 @@ interface ConversationMessageViewConfig extends BodylessConversationViewConfig {
|
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
class ConversationMessage extends TsEmbed {
|
|
26
|
-
constructor(container: HTMLElement, protected viewConfig:
|
|
34
|
+
constructor(container: HTMLElement, protected viewConfig: SpotterAgentMessageViewConfig) {
|
|
27
35
|
viewConfig.embedComponentType = 'bodyless-conversation';
|
|
28
36
|
super(container, viewConfig);
|
|
29
37
|
}
|
|
@@ -39,6 +47,7 @@ class ConversationMessage extends TsEmbed {
|
|
|
39
47
|
const queryParams = this.getBaseQueryParams();
|
|
40
48
|
|
|
41
49
|
queryParams[Param.HideActions] = [...(queryParams[Param.HideActions] ?? [])];
|
|
50
|
+
queryParams[Param.isSpotterAgentEmbed] = true;
|
|
42
51
|
let query = '';
|
|
43
52
|
const queryParamsString = getQueryParamString(queryParams, true);
|
|
44
53
|
if (queryParamsString) {
|
|
@@ -68,9 +77,9 @@ class ConversationMessage extends TsEmbed {
|
|
|
68
77
|
* chatbots or other conversational interfaces.
|
|
69
78
|
* @example
|
|
70
79
|
* ```js
|
|
71
|
-
* import {
|
|
80
|
+
* import { SpotterAgentEmbed } from '@thoughtspot/visual-embed-sdk';
|
|
72
81
|
*
|
|
73
|
-
* const conversation = new
|
|
82
|
+
* const conversation = new SpotterAgentEmbed({
|
|
74
83
|
* worksheetId: 'worksheetId',
|
|
75
84
|
* });
|
|
76
85
|
*
|
|
@@ -80,12 +89,12 @@ class ConversationMessage extends TsEmbed {
|
|
|
80
89
|
* document.body.appendChild(container); // or to any other element
|
|
81
90
|
* ```
|
|
82
91
|
* @group Embed components
|
|
83
|
-
* @version SDK: 1.
|
|
92
|
+
* @version SDK: 1.37.0 | ThoughtSpot: 10.9.0.cl
|
|
84
93
|
*/
|
|
85
|
-
export class
|
|
94
|
+
export class SpotterAgentEmbed {
|
|
86
95
|
private conversationService: ConversationService;
|
|
87
96
|
|
|
88
|
-
constructor(private viewConfig:
|
|
97
|
+
constructor(private viewConfig: SpotterAgentEmbedViewConfig) {
|
|
89
98
|
const embedConfig = getEmbedConfig();
|
|
90
99
|
|
|
91
100
|
this.conversationService = new ConversationService(
|
|
@@ -112,3 +121,29 @@ export class BodylessConversation {
|
|
|
112
121
|
return { container, viz: embed };
|
|
113
122
|
}
|
|
114
123
|
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Create a conversation embed, which can be integrated inside
|
|
127
|
+
* chatbots or other conversational interfaces.
|
|
128
|
+
* @deprecated Renamed to SpotterAgentEmbed
|
|
129
|
+
* @example
|
|
130
|
+
* ```js
|
|
131
|
+
* import { SpotterAgentEmbed } from '@thoughtspot/visual-embed-sdk';
|
|
132
|
+
*
|
|
133
|
+
* const conversation = new SpotterAgentEmbed({
|
|
134
|
+
* worksheetId: 'worksheetId',
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* const { container, error } = await conversation.sendMessage('show me sales by region');
|
|
138
|
+
*
|
|
139
|
+
* // append the container to the DOM
|
|
140
|
+
* document.body.appendChild(container); // or to any other element
|
|
141
|
+
* ```
|
|
142
|
+
* @group Embed components
|
|
143
|
+
* @version SDK: 1.37.0 | ThoughtSpot: 10.9.0.cl
|
|
144
|
+
*/
|
|
145
|
+
export class BodylessConversation extends SpotterAgentEmbed {
|
|
146
|
+
constructor(viewConfig: BodylessConversationViewConfig) {
|
|
147
|
+
super(viewConfig);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
SpotterEmbed,
|
|
3
|
+
SpotterEmbedViewConfig,
|
|
4
4
|
} from './conversation';
|
|
5
5
|
import * as authInstance from '../auth';
|
|
6
6
|
import { init } from '../index';
|
|
@@ -28,14 +28,14 @@ beforeAll(() => {
|
|
|
28
28
|
|
|
29
29
|
describe('ConversationEmbed', () => {
|
|
30
30
|
it('should render the conversation embed', async () => {
|
|
31
|
-
const viewConfig:
|
|
31
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
32
32
|
worksheetId: 'worksheetId',
|
|
33
33
|
searchOptions: {
|
|
34
34
|
searchQuery: 'searchQuery',
|
|
35
35
|
},
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
const conversationEmbed = new
|
|
38
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
39
39
|
await conversationEmbed.render();
|
|
40
40
|
expectUrlMatchesWithParams(
|
|
41
41
|
getIFrameSrc(),
|
|
@@ -44,7 +44,7 @@ describe('ConversationEmbed', () => {
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
it('should render the conversation embed with worksheets disabled', async () => {
|
|
47
|
-
const viewConfig:
|
|
47
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
48
48
|
worksheetId: 'worksheetId',
|
|
49
49
|
searchOptions: {
|
|
50
50
|
searchQuery: 'searchQuery',
|
|
@@ -52,7 +52,7 @@ describe('ConversationEmbed', () => {
|
|
|
52
52
|
disableSourceSelection: true,
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
const conversationEmbed = new
|
|
55
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
56
56
|
await conversationEmbed.render();
|
|
57
57
|
expectUrlMatchesWithParams(
|
|
58
58
|
getIFrameSrc(),
|
|
@@ -61,7 +61,7 @@ describe('ConversationEmbed', () => {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
it('should render the conversation embed with spotter limitations text if flag is set', async () => {
|
|
64
|
-
const viewConfig:
|
|
64
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
65
65
|
worksheetId: 'worksheetId',
|
|
66
66
|
searchOptions: {
|
|
67
67
|
searchQuery: 'searchQuery',
|
|
@@ -69,7 +69,7 @@ describe('ConversationEmbed', () => {
|
|
|
69
69
|
showSpotterLimitations: true,
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
const conversationEmbed = new
|
|
72
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
73
73
|
await conversationEmbed.render();
|
|
74
74
|
expectUrlMatchesWithParams(
|
|
75
75
|
getIFrameSrc(),
|
|
@@ -78,7 +78,7 @@ describe('ConversationEmbed', () => {
|
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
it('should render the conversation embed with sample questions hidden', async () => {
|
|
81
|
-
const viewConfig:
|
|
81
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
82
82
|
worksheetId: 'worksheetId',
|
|
83
83
|
searchOptions: {
|
|
84
84
|
searchQuery: 'searchQuery',
|
|
@@ -86,7 +86,7 @@ describe('ConversationEmbed', () => {
|
|
|
86
86
|
hideSampleQuestions: true,
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
const conversationEmbed = new
|
|
89
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
90
90
|
await conversationEmbed.render();
|
|
91
91
|
expectUrlMatchesWithParams(
|
|
92
92
|
getIFrameSrc(),
|
|
@@ -95,7 +95,7 @@ describe('ConversationEmbed', () => {
|
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
it('should render the conversation embed with worksheets hidden', async () => {
|
|
98
|
-
const viewConfig:
|
|
98
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
99
99
|
worksheetId: 'worksheetId',
|
|
100
100
|
searchOptions: {
|
|
101
101
|
searchQuery: 'searchQuery',
|
|
@@ -103,7 +103,7 @@ describe('ConversationEmbed', () => {
|
|
|
103
103
|
hideSourceSelection: true,
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
-
const conversationEmbed = new
|
|
106
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
107
107
|
await conversationEmbed.render();
|
|
108
108
|
expectUrlMatchesWithParams(
|
|
109
109
|
getIFrameSrc(),
|
|
@@ -112,13 +112,13 @@ describe('ConversationEmbed', () => {
|
|
|
112
112
|
});
|
|
113
113
|
|
|
114
114
|
it('should handle error when worksheetId is not provided', async () => {
|
|
115
|
-
const viewConfig:
|
|
115
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
116
116
|
worksheetId: '',
|
|
117
117
|
searchOptions: {
|
|
118
118
|
searchQuery: 'searchQuery',
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
|
-
const conversationEmbed = new
|
|
121
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
122
122
|
(conversationEmbed as any).handleError = jest.fn();
|
|
123
123
|
await conversationEmbed.render();
|
|
124
124
|
expect((conversationEmbed as any).handleError).toHaveBeenCalledWith(
|
|
@@ -127,7 +127,7 @@ describe('ConversationEmbed', () => {
|
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
it('should render the conversation embed if data panel v2 flag is true', async () => {
|
|
130
|
-
const viewConfig:
|
|
130
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
131
131
|
worksheetId: 'worksheetId',
|
|
132
132
|
searchOptions: {
|
|
133
133
|
searchQuery: 'searchQuery',
|
|
@@ -135,7 +135,7 @@ describe('ConversationEmbed', () => {
|
|
|
135
135
|
dataPanelV2: true,
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
const conversationEmbed = new
|
|
138
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
139
139
|
await conversationEmbed.render();
|
|
140
140
|
expectUrlMatchesWithParams(
|
|
141
141
|
getIFrameSrc(),
|