@thoughtspot/visual-embed-sdk 1.48.0 → 1.49.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/cjs/package.json +1 -1
- package/cjs/src/css-variables.d.ts +140 -0
- package/cjs/src/css-variables.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +62 -1
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +57 -6
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +191 -1
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.js +7 -2
- package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.spec.js +385 -6
- package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/cjs/src/embed/base.d.ts +1 -0
- package/cjs/src/embed/base.d.ts.map +1 -1
- package/cjs/src/embed/base.js +13 -1
- package/cjs/src/embed/base.js.map +1 -1
- package/cjs/src/embed/base.spec.js +21 -0
- package/cjs/src/embed/base.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.spec.js +86 -0
- package/cjs/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +16 -1
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +5 -1
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +26 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +47 -1
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +47 -6
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +129 -1
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.d.ts +85 -0
- package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -0
- package/cjs/src/embed/spotter-viz-utils.js +17 -0
- package/cjs/src/embed/spotter-viz-utils.js.map +1 -0
- package/cjs/src/embed/spotter-viz-utils.spec.d.ts +2 -0
- package/cjs/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
- package/cjs/src/embed/spotter-viz-utils.spec.js +31 -0
- package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -0
- package/cjs/src/embed/ts-embed.d.ts +58 -38
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +247 -151
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +369 -123
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +2 -1
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/mixpanel-service.js +2 -2
- package/cjs/src/mixpanel-service.js.map +1 -1
- package/cjs/src/react/index.d.ts.map +1 -1
- package/cjs/src/react/index.js +3 -0
- package/cjs/src/react/index.js.map +1 -1
- package/cjs/src/types.d.ts +267 -27
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +223 -19
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js +6 -7
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/cjs/src/utils/logger.js +2 -1
- package/cjs/src/utils/logger.js.map +1 -1
- package/cjs/src/utils/logger.spec.d.ts +1 -0
- package/cjs/src/utils/logger.spec.d.ts.map +1 -1
- package/cjs/src/utils/logger.spec.js +10 -9
- package/cjs/src/utils/logger.spec.js.map +1 -1
- package/cjs/src/utils/sdk-version.d.ts +2 -0
- package/cjs/src/utils/sdk-version.d.ts.map +1 -0
- package/cjs/src/utils/sdk-version.js +7 -0
- package/cjs/src/utils/sdk-version.js.map +1 -0
- package/cjs/src/utils.d.ts +4 -1
- package/cjs/src/utils.d.ts.map +1 -1
- package/cjs/src/utils.js +107 -10
- package/cjs/src/utils.js.map +1 -1
- package/cjs/src/utils.spec.js +163 -4
- package/cjs/src/utils.spec.js.map +1 -1
- package/dist/{index-Ck-r09gt.js → index-B6Rn561t.js} +1 -1
- package/dist/src/css-variables.d.ts +140 -0
- package/dist/src/css-variables.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +62 -1
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/base.d.ts +1 -0
- package/dist/src/embed/base.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +16 -1
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +47 -1
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-viz-utils.d.ts +85 -0
- package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -0
- package/dist/src/embed/spotter-viz-utils.spec.d.ts +2 -0
- package/dist/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
- package/dist/src/embed/ts-embed.d.ts +58 -38
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/react/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +267 -27
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/logger.spec.d.ts +1 -0
- package/dist/src/utils/logger.spec.d.ts.map +1 -1
- package/dist/src/utils/sdk-version.d.ts +2 -0
- package/dist/src/utils/sdk-version.d.ts.map +1 -0
- package/dist/src/utils.d.ts +4 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +3710 -3226
- package/dist/tsembed-react.js +3360 -2876
- package/dist/tsembed.es.js +3715 -3229
- package/dist/tsembed.js +3710 -3224
- package/dist/visual-embed-sdk-react-full.d.ts +643 -63
- package/dist/visual-embed-sdk-react.d.ts +643 -63
- package/dist/visual-embed-sdk.d.ts +658 -65
- package/lib/package.json +1 -1
- package/lib/src/css-variables.d.ts +140 -0
- package/lib/src/css-variables.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +62 -1
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +58 -7
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +192 -2
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.js +7 -2
- package/lib/src/embed/auto-frame-renderer.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.spec.js +387 -8
- package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/lib/src/embed/base.d.ts +1 -0
- package/lib/src/embed/base.d.ts.map +1 -1
- package/lib/src/embed/base.js +11 -0
- package/lib/src/embed/base.js.map +1 -1
- package/lib/src/embed/base.spec.js +22 -1
- package/lib/src/embed/base.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.spec.js +86 -0
- package/lib/src/embed/bodyless-conversation.spec.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +16 -1
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +5 -1
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +27 -1
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +47 -1
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +48 -7
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +129 -1
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.d.ts +85 -0
- package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -0
- package/lib/src/embed/spotter-viz-utils.js +13 -0
- package/lib/src/embed/spotter-viz-utils.js.map +1 -0
- package/lib/src/embed/spotter-viz-utils.spec.d.ts +2 -0
- package/lib/src/embed/spotter-viz-utils.spec.d.ts.map +1 -0
- package/lib/src/embed/spotter-viz-utils.spec.js +29 -0
- package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -0
- package/lib/src/embed/ts-embed.d.ts +58 -38
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +249 -153
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +369 -123
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/mixpanel-service.js +1 -1
- package/lib/src/mixpanel-service.js.map +1 -1
- package/lib/src/react/index.d.ts.map +1 -1
- package/lib/src/react/index.js +3 -0
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/types.d.ts +267 -27
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +223 -19
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/authService/tokenizedAuthService.spec.js +6 -7
- package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/lib/src/utils/logger.js +2 -1
- package/lib/src/utils/logger.js.map +1 -1
- package/lib/src/utils/logger.spec.d.ts +1 -0
- package/lib/src/utils/logger.spec.d.ts.map +1 -1
- package/lib/src/utils/logger.spec.js +10 -9
- package/lib/src/utils/logger.spec.js.map +1 -1
- package/lib/src/utils/sdk-version.d.ts +2 -0
- package/lib/src/utils/sdk-version.d.ts.map +1 -0
- package/lib/src/utils/sdk-version.js +3 -0
- package/lib/src/utils/sdk-version.js.map +1 -0
- package/lib/src/utils.d.ts +4 -1
- package/lib/src/utils.d.ts.map +1 -1
- package/lib/src/utils.js +103 -9
- package/lib/src/utils.js.map +1 -1
- package/lib/src/utils.spec.js +164 -5
- package/lib/src/utils.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +658 -65
- package/package.json +1 -1
- package/src/css-variables.ts +175 -1
- package/src/embed/app.spec.ts +247 -3
- package/src/embed/app.ts +125 -5
- package/src/embed/auto-frame-renderer.spec.ts +457 -58
- package/src/embed/auto-frame-renderer.ts +7 -2
- package/src/embed/base.spec.ts +25 -1
- package/src/embed/base.ts +19 -5
- package/src/embed/bodyless-conversation.spec.ts +93 -0
- package/src/embed/conversation.spec.ts +34 -0
- package/src/embed/conversation.ts +22 -1
- package/src/embed/liveboard.spec.ts +149 -1
- package/src/embed/liveboard.ts +102 -6
- package/src/embed/spotter-viz-utils.spec.ts +30 -0
- package/src/embed/spotter-viz-utils.ts +94 -0
- package/src/embed/ts-embed.spec.ts +532 -234
- package/src/embed/ts-embed.ts +384 -258
- package/src/index.ts +3 -0
- package/src/mixpanel-service.ts +1 -1
- package/src/react/index.tsx +3 -0
- package/src/types.ts +284 -23
- package/src/utils/authService/tokenizedAuthService.spec.ts +6 -6
- package/src/utils/logger.spec.ts +11 -9
- package/src/utils/logger.ts +2 -2
- package/src/utils/sdk-version.ts +3 -0
- package/src/utils.spec.ts +200 -4
- package/src/utils.ts +128 -9
|
@@ -115,8 +115,9 @@ class AutoFrameRenderer extends TsEmbed {
|
|
|
115
115
|
delete existingQueryParamsObject[Param.Tsmcp];
|
|
116
116
|
|
|
117
117
|
const mergedQueryParams = { ...queryParams, ...existingQueryParamsObject };
|
|
118
|
-
const mergedQueryParamsString = getQueryParamString(mergedQueryParams);
|
|
119
|
-
const
|
|
118
|
+
const mergedQueryParamsString = getQueryParamString(mergedQueryParams, true);
|
|
119
|
+
const queryString = mergedQueryParamsString ? `?${mergedQueryParamsString}` : '';
|
|
120
|
+
const frameSrc = `${this.getEmbedBasePath(queryString)}${sourceURL.hash.replace('#', '')}`;
|
|
120
121
|
return frameSrc;
|
|
121
122
|
}
|
|
122
123
|
|
|
@@ -145,8 +146,12 @@ class AutoFrameRenderer extends TsEmbed {
|
|
|
145
146
|
*/
|
|
146
147
|
public async replaceIframe(iframe: HTMLIFrameElement): Promise<void> {
|
|
147
148
|
this.frameToReplace = iframe;
|
|
149
|
+
if (this.shouldWaitForRenderPromise) {
|
|
150
|
+
await this.isReadyForRenderPromise;
|
|
151
|
+
}
|
|
148
152
|
const src = this.getMCPIframeSrc(iframe.src);
|
|
149
153
|
await this.renderIFrame(src);
|
|
154
|
+
this.isRendered = true;
|
|
150
155
|
}
|
|
151
156
|
}
|
|
152
157
|
|
package/src/embed/base.spec.ts
CHANGED
|
@@ -10,7 +10,7 @@ import * as base from './base';
|
|
|
10
10
|
import * as embedConfigInstance from './embedConfig';
|
|
11
11
|
import * as resetService from '../utils/resetServices';
|
|
12
12
|
import * as processTrigger from '../utils/processTrigger';
|
|
13
|
-
import { createAndSetInitPromise, getInitPromise, getIsInitCalled, reloadIframe } from './base';
|
|
13
|
+
import { createAndSetInitPromise, getInitPromise, getIsInitCalled, getIsInitCompleted, reloadIframe } from './base';
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
16
|
executeAfterWait,
|
|
@@ -607,4 +607,28 @@ describe('Init Promise Functions', () => {
|
|
|
607
607
|
const secondPromise = getInitPromise();
|
|
608
608
|
expect(firstPromise).toBe(secondPromise);
|
|
609
609
|
});
|
|
610
|
+
|
|
611
|
+
test('getIsInitCompleted returns false (not undefined) before init resolves', () => {
|
|
612
|
+
// fresh store via beforeEach; init not yet called
|
|
613
|
+
const result = getIsInitCompleted();
|
|
614
|
+
expect(result).toBe(false);
|
|
615
|
+
expect(typeof result).toBe('boolean');
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test('getIsInitCompleted returns true after init resolves', async () => {
|
|
619
|
+
base.init({
|
|
620
|
+
thoughtSpotHost: 'tshost',
|
|
621
|
+
authType: index.AuthType.None,
|
|
622
|
+
});
|
|
623
|
+
await getInitPromise();
|
|
624
|
+
// flush the finally() microtask
|
|
625
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
626
|
+
expect(getIsInitCompleted()).toBe(true);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
test('getIsInitCompleted returns false when window store is absent', () => {
|
|
630
|
+
// clear the store from window
|
|
631
|
+
(window as any)._tsEmbedSDK = {};
|
|
632
|
+
expect(getIsInitCompleted()).toBe(false);
|
|
633
|
+
});
|
|
610
634
|
});
|
package/src/embed/base.ts
CHANGED
|
@@ -182,9 +182,10 @@ function backwardCompat(embedConfig: EmbedConfig): EmbedConfig {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
type InitFlagStore = {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
initPromise: Promise<ReturnType<typeof init>>;
|
|
186
|
+
isInitCalled: boolean;
|
|
187
|
+
isInitCompleted: boolean;
|
|
188
|
+
initPromiseResolve: (value: ReturnType<typeof init>) => void;
|
|
188
189
|
}
|
|
189
190
|
const initFlagKey = 'initFlagKey';
|
|
190
191
|
|
|
@@ -199,21 +200,34 @@ export const createAndSetInitPromise = (): void => {
|
|
|
199
200
|
const initFlagStore: InitFlagStore = {
|
|
200
201
|
initPromise,
|
|
201
202
|
isInitCalled: false,
|
|
203
|
+
isInitCompleted: false,
|
|
202
204
|
initPromiseResolve,
|
|
203
205
|
};
|
|
204
206
|
storeValueInWindow(initFlagKey, initFlagStore, {
|
|
205
207
|
// In case of diff imports the promise might be already set
|
|
206
208
|
ignoreIfAlreadyExists: true,
|
|
207
209
|
});
|
|
210
|
+
initPromise.finally(() => {
|
|
211
|
+
const curVal = getValueFromWindow<InitFlagStore>(initFlagKey);
|
|
212
|
+
if (!curVal) {
|
|
213
|
+
logger.error('initFlagStore missing when marking init complete');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
curVal.isInitCompleted = true;
|
|
217
|
+
storeValueInWindow(initFlagKey, curVal);
|
|
218
|
+
});
|
|
208
219
|
};
|
|
209
220
|
|
|
210
221
|
createAndSetInitPromise();
|
|
211
222
|
|
|
212
223
|
export const getInitPromise = ():
|
|
213
224
|
Promise<
|
|
214
|
-
|
|
225
|
+
ReturnType<typeof init>
|
|
215
226
|
> => getValueFromWindow<InitFlagStore>(initFlagKey)?.initPromise;
|
|
216
227
|
|
|
228
|
+
export const getIsInitCompleted = (): boolean =>
|
|
229
|
+
!!getValueFromWindow<InitFlagStore>(initFlagKey)?.isInitCompleted;
|
|
230
|
+
|
|
217
231
|
export const getIsInitCalled = (): boolean => !!getValueFromWindow(initFlagKey)?.isInitCalled;
|
|
218
232
|
|
|
219
233
|
/**
|
|
@@ -319,7 +333,7 @@ export const renderInQueue = (fn: (next?: (val?: any) => void) => Promise<any>):
|
|
|
319
333
|
return renderQueue;
|
|
320
334
|
}
|
|
321
335
|
// Sending an empty function to keep it consistent with the above usage.
|
|
322
|
-
return fn(() => {});
|
|
336
|
+
return fn(() => { });
|
|
323
337
|
};
|
|
324
338
|
|
|
325
339
|
/**
|
|
@@ -238,6 +238,99 @@ describe('SpotterAgentEmbed', () => {
|
|
|
238
238
|
expect(iframeSrc).toContain('hideAction');
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
+
test('should handle disabledActions and disabledActionReason parameters correctly', async () => {
|
|
242
|
+
fetchMock.mockResponses(
|
|
243
|
+
JSON.stringify({
|
|
244
|
+
data: {
|
|
245
|
+
ConvAssist__createConversation: {
|
|
246
|
+
convId: 'conversationId',
|
|
247
|
+
initialCtx: {
|
|
248
|
+
type: 'TS_ANSWER',
|
|
249
|
+
tsAnsCtx: {
|
|
250
|
+
sessionId: 'sessionId',
|
|
251
|
+
genNo: 1,
|
|
252
|
+
stateKey: {
|
|
253
|
+
transactionId: 'transactionId',
|
|
254
|
+
generationNumber: 1,
|
|
255
|
+
},
|
|
256
|
+
worksheet: {
|
|
257
|
+
worksheetId: 'worksheetId',
|
|
258
|
+
worksheetName: 'GTM',
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
}),
|
|
265
|
+
JSON.stringify({
|
|
266
|
+
data: {
|
|
267
|
+
ConvAssist__sendMessage: {
|
|
268
|
+
responses: [
|
|
269
|
+
{
|
|
270
|
+
msgId: 'msgId',
|
|
271
|
+
data: {
|
|
272
|
+
asstRespData: {
|
|
273
|
+
tool: 'TS_NLS',
|
|
274
|
+
asstRespText: '',
|
|
275
|
+
nlsAnsData: {
|
|
276
|
+
sageQuerySuggestions: [
|
|
277
|
+
{
|
|
278
|
+
llmReasoning: {
|
|
279
|
+
assumptions: '',
|
|
280
|
+
clarifications: '',
|
|
281
|
+
interpretation: '',
|
|
282
|
+
__typename: 'eureka_SageQuerySuggestion_LLMReasoning',
|
|
283
|
+
},
|
|
284
|
+
tokens: [],
|
|
285
|
+
tmlTokens: [],
|
|
286
|
+
worksheetId: 'worksheetId',
|
|
287
|
+
description: '',
|
|
288
|
+
title: '',
|
|
289
|
+
cached: false,
|
|
290
|
+
sqlQuery: '',
|
|
291
|
+
sessionId: 'sessionId',
|
|
292
|
+
genNo: 2,
|
|
293
|
+
formulaInfo: [],
|
|
294
|
+
tmlPhrases: [],
|
|
295
|
+
stateKey: {
|
|
296
|
+
transactionId: 'transactionId',
|
|
297
|
+
generationNumber: 1,
|
|
298
|
+
__typename: 'sage_auto_complete_v2_ACStateKey',
|
|
299
|
+
},
|
|
300
|
+
__typename: 'eureka_SageQuerySuggestion',
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
responseType: 'ANSWER',
|
|
304
|
+
__typename: 'convassist_nls_tool_NLSToolAsstRespData',
|
|
305
|
+
},
|
|
306
|
+
__typename: 'convassist_AsstResponseData',
|
|
307
|
+
},
|
|
308
|
+
__typename: 'convassist_MessageData',
|
|
309
|
+
},
|
|
310
|
+
type: 'ASST_RESPONSE',
|
|
311
|
+
__typename: 'convassist_MessagePayload',
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
__typename: 'convassist_SendMessageResponse',
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
}),
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
const viewConfig: SpotterAgentEmbedViewConfig = {
|
|
321
|
+
worksheetId: 'worksheetId',
|
|
322
|
+
disabledActions: [Action.Download, Action.Save],
|
|
323
|
+
disabledActionReason: 'Upgrade to Pro!',
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const spotterAgentEmbed = new SpotterAgentEmbed(viewConfig);
|
|
327
|
+
const result = await spotterAgentEmbed.sendMessage('userMessage');
|
|
328
|
+
|
|
329
|
+
const iframeSrc = getIFrameSrc(result.container);
|
|
330
|
+
expect(iframeSrc).toContain('disableAction');
|
|
331
|
+
expect(iframeSrc).toContain('disableHint');
|
|
332
|
+
});
|
|
333
|
+
|
|
241
334
|
test('should have sendMessageData method', () => {
|
|
242
335
|
const viewConfig: SpotterAgentEmbedViewConfig = {
|
|
243
336
|
worksheetId: 'worksheetId',
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getRootEl,
|
|
11
11
|
defaultParamsWithoutHiddenActions as defaultParams,
|
|
12
12
|
expectUrlMatchesWithParams,
|
|
13
|
+
expectUrlToHaveParamsWithValues,
|
|
13
14
|
postMessageToParent,
|
|
14
15
|
executeAfterWait,
|
|
15
16
|
} from '../test/test-utils';
|
|
@@ -351,6 +352,39 @@ describe('ConversationEmbed', () => {
|
|
|
351
352
|
);
|
|
352
353
|
});
|
|
353
354
|
|
|
355
|
+
it('should render the conversation embed with spotterFileUploadEnabled', async () => {
|
|
356
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
357
|
+
worksheetId: 'worksheetId',
|
|
358
|
+
searchOptions: {
|
|
359
|
+
searchQuery: 'searchQuery',
|
|
360
|
+
},
|
|
361
|
+
spotterChatConfig: { spotterFileUploadEnabled: true },
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
365
|
+
await conversationEmbed.render();
|
|
366
|
+
expectUrlMatchesWithParams(
|
|
367
|
+
getIFrameSrc(),
|
|
368
|
+
`http://${thoughtSpotHost}/v2/?${defaultParams}&isSpotterExperienceEnabled=true&spotterFileUploadEnabled=true#/embed/insights/conv-assist?worksheet=worksheetId&query=searchQuery`,
|
|
369
|
+
);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should render the conversation embed with spotterFileUploadFileTypes', async () => {
|
|
373
|
+
const viewConfig: SpotterEmbedViewConfig = {
|
|
374
|
+
worksheetId: 'worksheetId',
|
|
375
|
+
searchOptions: {
|
|
376
|
+
searchQuery: 'searchQuery',
|
|
377
|
+
},
|
|
378
|
+
spotterChatConfig: { spotterFileUploadFileTypes: { types: ['image/png', 'application/pdf'] } },
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const conversationEmbed = new SpotterEmbed(getRootEl(), viewConfig);
|
|
382
|
+
await conversationEmbed.render();
|
|
383
|
+
expectUrlToHaveParamsWithValues(getIFrameSrc(), {
|
|
384
|
+
spotterFileUploadFileTypes: JSON.stringify({ types: ['image/png', 'application/pdf'] }),
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
354
388
|
it('should ensure deprecated ConversationEmbed class maintains same functionality as SpotterEmbed', async () => {
|
|
355
389
|
const viewConfig: SpotterEmbedViewConfig = {
|
|
356
390
|
worksheetId: 'worksheetId',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import isUndefined from 'lodash/isUndefined';
|
|
2
2
|
import { ERROR_MESSAGE } from '../errors';
|
|
3
|
-
import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter, ErrorDetailsTypes, EmbedErrorCodes, DefaultAppInitData, VisualizationOverrides } from '../types';
|
|
3
|
+
import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter, ErrorDetailsTypes, EmbedErrorCodes, DefaultAppInitData, VisualizationOverrides, SpotterFileUploadFileTypes } from '../types';
|
|
4
4
|
import { TsEmbed } from './ts-embed';
|
|
5
5
|
import { buildSpotterSidebarAppInitData } from './spotter-utils';
|
|
6
6
|
import { getQueryParamString, getFilterQuery, getRuntimeParameters, setParamIfDefined } from '../utils';
|
|
@@ -113,6 +113,21 @@ export interface SpotterChatViewConfig {
|
|
|
113
113
|
* External MCP tool branding is not affected.
|
|
114
114
|
*/
|
|
115
115
|
toolResponseCardBrandingLabel?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Enables file upload in the Spotter chat interface.
|
|
118
|
+
*
|
|
119
|
+
* Supported embed types: `SpotterEmbed`, `LiveboardEmbed`, `AppEmbed`
|
|
120
|
+
* @version SDK: 1.49.0 | ThoughtSpot: 26.6.0.cl
|
|
121
|
+
* @default false
|
|
122
|
+
*/
|
|
123
|
+
spotterFileUploadEnabled?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Restricts the allowed file types for Spotter file upload.
|
|
126
|
+
*
|
|
127
|
+
* Supported embed types: `SpotterEmbed`, `LiveboardEmbed`, `AppEmbed`
|
|
128
|
+
* @version SDK: 1.49.0 | ThoughtSpot: 26.6.0.cl
|
|
129
|
+
*/
|
|
130
|
+
spotterFileUploadFileTypes?: SpotterFileUploadFileTypes;
|
|
116
131
|
}
|
|
117
132
|
|
|
118
133
|
/**
|
|
@@ -450,10 +465,16 @@ export class SpotterEmbed extends TsEmbed {
|
|
|
450
465
|
const {
|
|
451
466
|
hideToolResponseCardBranding,
|
|
452
467
|
toolResponseCardBrandingLabel,
|
|
468
|
+
spotterFileUploadEnabled,
|
|
469
|
+
spotterFileUploadFileTypes,
|
|
453
470
|
} = spotterChatConfig;
|
|
454
471
|
|
|
455
472
|
setParamIfDefined(queryParams, Param.HideToolResponseCardBranding, hideToolResponseCardBranding, true);
|
|
456
473
|
setParamIfDefined(queryParams, Param.ToolResponseCardBrandingLabel, toolResponseCardBrandingLabel);
|
|
474
|
+
setParamIfDefined(queryParams, Param.SpotterFileUploadEnabled, spotterFileUploadEnabled, true);
|
|
475
|
+
if (spotterFileUploadFileTypes !== undefined) {
|
|
476
|
+
queryParams[Param.SpotterFileUploadFileTypes] = JSON.stringify(spotterFileUploadFileTypes);
|
|
477
|
+
}
|
|
457
478
|
}
|
|
458
479
|
|
|
459
480
|
return queryParams;
|
|
@@ -1266,6 +1266,35 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
1266
1266
|
});
|
|
1267
1267
|
});
|
|
1268
1268
|
|
|
1269
|
+
test('should set spotterFileUploadEnabled parameter in url params', async () => {
|
|
1270
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1271
|
+
...defaultViewConfig,
|
|
1272
|
+
liveboardId,
|
|
1273
|
+
spotterChatConfig: { spotterFileUploadEnabled: true },
|
|
1274
|
+
} as LiveboardViewConfig);
|
|
1275
|
+
await liveboardEmbed.render();
|
|
1276
|
+
await executeAfterWait(() => {
|
|
1277
|
+
expectUrlMatchesWithParams(
|
|
1278
|
+
getIFrameSrc(),
|
|
1279
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&spotterFileUploadEnabled=true#/embed/viz/${liveboardId}`,
|
|
1280
|
+
);
|
|
1281
|
+
});
|
|
1282
|
+
});
|
|
1283
|
+
|
|
1284
|
+
test('should set spotterFileUploadFileTypes parameter in url params', async () => {
|
|
1285
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1286
|
+
...defaultViewConfig,
|
|
1287
|
+
liveboardId,
|
|
1288
|
+
spotterChatConfig: { spotterFileUploadFileTypes: { types: ['image/png', 'application/pdf'] } },
|
|
1289
|
+
} as LiveboardViewConfig);
|
|
1290
|
+
await liveboardEmbed.render();
|
|
1291
|
+
await executeAfterWait(() => {
|
|
1292
|
+
expectUrlToHaveParamsWithValues(getIFrameSrc(), {
|
|
1293
|
+
spotterFileUploadFileTypes: JSON.stringify({ types: ['image/png', 'application/pdf'] }),
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1269
1298
|
test('should render the liveboard embed with updatedSpotterChatPrompt', async () => {
|
|
1270
1299
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1271
1300
|
...defaultViewConfig,
|
|
@@ -1329,6 +1358,94 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
1329
1358
|
});
|
|
1330
1359
|
});
|
|
1331
1360
|
|
|
1361
|
+
test('should include spotterVizConfig in APP_INIT embedParams when spotterViz is provided', async () => {
|
|
1362
|
+
const spotterViz = {
|
|
1363
|
+
brandName: 'MyBrand',
|
|
1364
|
+
brandHeadline: "Hi, there! I'm",
|
|
1365
|
+
description: 'Ask questions about your data',
|
|
1366
|
+
inputChatPlaceholder: 'Ask a question...',
|
|
1367
|
+
hideStarterPrompts: false,
|
|
1368
|
+
customStarterPrompts: [
|
|
1369
|
+
{ id: '1', displayText: 'Show revenue by region', fullPrompt: 'Show revenue by region' },
|
|
1370
|
+
{ id: '2', displayText: 'Top customers', fullPrompt: 'Top customers by sales' },
|
|
1371
|
+
],
|
|
1372
|
+
};
|
|
1373
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1374
|
+
...defaultViewConfig,
|
|
1375
|
+
liveboardId,
|
|
1376
|
+
spotterViz,
|
|
1377
|
+
} as LiveboardViewConfig);
|
|
1378
|
+
|
|
1379
|
+
mockMessageChannel();
|
|
1380
|
+
await liveboardEmbed.render();
|
|
1381
|
+
|
|
1382
|
+
const mockPort: any = { postMessage: jest.fn() };
|
|
1383
|
+
await executeAfterWait(() => {
|
|
1384
|
+
postMessageToParent(getIFrameEl().contentWindow, { type: EmbedEvent.APP_INIT, data: {} }, mockPort);
|
|
1385
|
+
});
|
|
1386
|
+
await executeAfterWait(() => {
|
|
1387
|
+
expect(mockPort.postMessage).toHaveBeenCalledWith({
|
|
1388
|
+
type: EmbedEvent.APP_INIT,
|
|
1389
|
+
data: expect.objectContaining({
|
|
1390
|
+
embedParams: expect.objectContaining({
|
|
1391
|
+
spotterVizConfig: spotterViz,
|
|
1392
|
+
}),
|
|
1393
|
+
}),
|
|
1394
|
+
});
|
|
1395
|
+
});
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
test('should pass brandHeadline through spotterVizConfig in APP_INIT', async () => {
|
|
1399
|
+
const spotterViz = { brandName: 'MyBrand', brandHeadline: "Hi, there! I'm" };
|
|
1400
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1401
|
+
...defaultViewConfig,
|
|
1402
|
+
liveboardId,
|
|
1403
|
+
spotterViz,
|
|
1404
|
+
} as LiveboardViewConfig);
|
|
1405
|
+
|
|
1406
|
+
mockMessageChannel();
|
|
1407
|
+
await liveboardEmbed.render();
|
|
1408
|
+
|
|
1409
|
+
const mockPort: any = { postMessage: jest.fn() };
|
|
1410
|
+
await executeAfterWait(() => {
|
|
1411
|
+
postMessageToParent(getIFrameEl().contentWindow, { type: EmbedEvent.APP_INIT, data: {} }, mockPort);
|
|
1412
|
+
});
|
|
1413
|
+
await executeAfterWait(() => {
|
|
1414
|
+
expect(mockPort.postMessage).toHaveBeenCalledWith({
|
|
1415
|
+
type: EmbedEvent.APP_INIT,
|
|
1416
|
+
data: expect.objectContaining({
|
|
1417
|
+
embedParams: expect.objectContaining({
|
|
1418
|
+
spotterVizConfig: expect.objectContaining({
|
|
1419
|
+
brandHeadline: "Hi, there! I'm",
|
|
1420
|
+
}),
|
|
1421
|
+
}),
|
|
1422
|
+
}),
|
|
1423
|
+
});
|
|
1424
|
+
});
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
test('should not include spotterVizConfig in APP_INIT when spotterViz is not provided', async () => {
|
|
1428
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1429
|
+
...defaultViewConfig,
|
|
1430
|
+
liveboardId,
|
|
1431
|
+
} as LiveboardViewConfig);
|
|
1432
|
+
|
|
1433
|
+
mockMessageChannel();
|
|
1434
|
+
await liveboardEmbed.render();
|
|
1435
|
+
|
|
1436
|
+
const mockPort: any = { postMessage: jest.fn() };
|
|
1437
|
+
await executeAfterWait(() => {
|
|
1438
|
+
postMessageToParent(getIFrameEl().contentWindow, { type: EmbedEvent.APP_INIT, data: {} }, mockPort);
|
|
1439
|
+
});
|
|
1440
|
+
await executeAfterWait(() => {
|
|
1441
|
+
const callArgs = mockPort.postMessage.mock.calls[0][0];
|
|
1442
|
+
expect(callArgs.type).toBe(EmbedEvent.APP_INIT);
|
|
1443
|
+
if (callArgs.data.embedParams) {
|
|
1444
|
+
expect(callArgs.data.embedParams.spotterVizConfig).toBeUndefined();
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1332
1449
|
test('SetActiveTab Hostevent should not trigger the navigate event with the correct path, for vizEmbed', async () => {
|
|
1333
1450
|
const mockProcessTrigger = jest.spyOn(tsEmbed.TsEmbed.prototype, 'trigger');
|
|
1334
1451
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
@@ -1835,6 +1952,37 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
1835
1952
|
addEventListenerSpy.mockRestore();
|
|
1836
1953
|
});
|
|
1837
1954
|
|
|
1955
|
+
test('should listen to scroll and resize changes from scrollable iframe ancestors', async () => {
|
|
1956
|
+
const scrollContainer = getRootEl();
|
|
1957
|
+
scrollContainer.style.overflow = 'auto';
|
|
1958
|
+
|
|
1959
|
+
const scrollContainerAddEventListenerSpy = jest.spyOn(scrollContainer, 'addEventListener');
|
|
1960
|
+
const resizeObserveSpy = jest.fn();
|
|
1961
|
+
const resizeDisconnectSpy = jest.fn();
|
|
1962
|
+
(window as any).ResizeObserver = jest.fn().mockImplementation(() => ({
|
|
1963
|
+
observe: resizeObserveSpy,
|
|
1964
|
+
disconnect: resizeDisconnectSpy,
|
|
1965
|
+
}));
|
|
1966
|
+
|
|
1967
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1968
|
+
...defaultViewConfig,
|
|
1969
|
+
liveboardId,
|
|
1970
|
+
fullHeight: true,
|
|
1971
|
+
lazyLoadingForFullHeight: true,
|
|
1972
|
+
enableScrollableContainerLazyLoading: true,
|
|
1973
|
+
} as LiveboardViewConfig);
|
|
1974
|
+
|
|
1975
|
+
await liveboardEmbed.render();
|
|
1976
|
+
|
|
1977
|
+
await executeAfterWait(() => {
|
|
1978
|
+
expect(scrollContainerAddEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function));
|
|
1979
|
+
expect(resizeObserveSpy).toHaveBeenCalledWith(scrollContainer);
|
|
1980
|
+
}, 100);
|
|
1981
|
+
|
|
1982
|
+
liveboardEmbed.destroy();
|
|
1983
|
+
expect(resizeDisconnectSpy).toHaveBeenCalled();
|
|
1984
|
+
});
|
|
1985
|
+
|
|
1838
1986
|
test('should remove window event listeners on destroy when fullHeight and lazyLoadingForFullHeight are enabled', async () => {
|
|
1839
1987
|
const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
|
|
1840
1988
|
|
|
@@ -1850,7 +1998,7 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
1850
1998
|
liveboardEmbed.destroy();
|
|
1851
1999
|
|
|
1852
2000
|
expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.anything());
|
|
1853
|
-
expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.anything());
|
|
2001
|
+
expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.anything(), true);
|
|
1854
2002
|
|
|
1855
2003
|
removeEventListenerSpy.mockRestore();
|
|
1856
2004
|
});
|