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