@thoughtspot/visual-embed-sdk 1.46.3 → 1.46.5-beta.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 +3 -3
- package/cjs/src/auth.d.ts +2 -1
- package/cjs/src/auth.d.ts.map +1 -1
- package/cjs/src/auth.js +2 -1
- package/cjs/src/auth.js.map +1 -1
- package/cjs/src/authToken.d.ts.map +1 -1
- package/cjs/src/authToken.js.map +1 -1
- package/cjs/src/css-variables.d.ts +51 -17
- package/cjs/src/css-variables.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +1 -0
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +10 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +46 -1
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/base.d.ts.map +1 -1
- package/cjs/src/embed/base.js.map +1 -1
- package/cjs/src/embed/base.spec.js.map +1 -1
- package/cjs/src/embed/events.spec.js +72 -0
- package/cjs/src/embed/events.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/contracts.d.ts +74 -3
- package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/contracts.js +7 -0
- package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts +10 -0
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.js +46 -9
- package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js +155 -0
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +1 -0
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +11 -2
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +96 -2
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/sage.d.ts.map +1 -1
- package/cjs/src/embed/sage.js.map +1 -1
- package/cjs/src/embed/search.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +41 -2
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +41 -2
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/react/index.d.ts.map +1 -1
- package/cjs/src/react/index.js +58 -53
- package/cjs/src/react/index.js.map +1 -1
- package/cjs/src/types.d.ts +730 -32
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +734 -3
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.d.ts +4 -2
- package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.js +4 -2
- package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/cjs/src/utils/graphql/preview-service.d.ts.map +1 -1
- package/cjs/src/utils/graphql/preview-service.js.map +1 -1
- package/cjs/src/utils/processData.d.ts.map +1 -1
- package/cjs/src/utils/processData.js.map +1 -1
- package/dist/{index-DyX-x6uN.js → index-DW2wEHqy.js} +1 -1
- package/dist/src/auth.d.ts +2 -1
- package/dist/src/auth.d.ts.map +1 -1
- package/dist/src/authToken.d.ts.map +1 -1
- package/dist/src/css-variables.d.ts +51 -17
- package/dist/src/css-variables.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +1 -0
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/base.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/contracts.d.ts +74 -3
- package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/host-event-client.d.ts +10 -0
- package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +1 -0
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/sage.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +41 -2
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/react/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +730 -32
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/graphql/answerService/answerService.d.ts +4 -2
- package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/dist/src/utils/graphql/preview-service.d.ts.map +1 -1
- package/dist/src/utils/processData.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +917 -77
- package/dist/tsembed-react.js +915 -75
- package/dist/tsembed.es.js +859 -24
- package/dist/tsembed.js +857 -22
- package/dist/visual-embed-sdk-react-full.d.ts +892 -54
- package/dist/visual-embed-sdk-react.d.ts +892 -54
- package/dist/visual-embed-sdk.d.ts +912 -56
- package/lib/package.json +3 -3
- package/lib/src/auth.d.ts +2 -1
- package/lib/src/auth.d.ts.map +1 -1
- package/lib/src/auth.js +2 -1
- package/lib/src/auth.js.map +1 -1
- package/lib/src/authToken.d.ts.map +1 -1
- package/lib/src/authToken.js.map +1 -1
- package/lib/src/css-variables.d.ts +51 -17
- package/lib/src/css-variables.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +1 -0
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +10 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +46 -1
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/base.d.ts.map +1 -1
- package/lib/src/embed/base.js.map +1 -1
- package/lib/src/embed/base.spec.js.map +1 -1
- package/lib/src/embed/events.spec.js +73 -1
- package/lib/src/embed/events.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/contracts.d.ts +74 -3
- package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/contracts.js +7 -0
- package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.d.ts +10 -0
- package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.js +46 -9
- package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.spec.js +155 -0
- package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +1 -0
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +11 -2
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +96 -2
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/sage.d.ts.map +1 -1
- package/lib/src/embed/sage.js.map +1 -1
- package/lib/src/embed/search.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +41 -2
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +42 -3
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/react/index.d.ts.map +1 -1
- package/lib/src/react/index.js +58 -53
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/types.d.ts +730 -32
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +734 -3
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.d.ts +4 -2
- package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.js +4 -2
- package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/lib/src/utils/graphql/preview-service.d.ts.map +1 -1
- package/lib/src/utils/graphql/preview-service.js.map +1 -1
- package/lib/src/utils/processData.d.ts.map +1 -1
- package/lib/src/utils/processData.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +973 -116
- package/package.json +3 -3
- package/src/auth.spec.ts +1 -1
- package/src/auth.ts +2 -1
- package/src/authToken.ts +0 -1
- package/src/css-variables.ts +51 -17
- package/src/embed/app.spec.ts +62 -3
- package/src/embed/app.ts +10 -1
- package/src/embed/base.spec.ts +1 -2
- package/src/embed/base.ts +1 -4
- package/src/embed/events.spec.ts +88 -0
- package/src/embed/hostEventClient/contracts.ts +74 -2
- package/src/embed/hostEventClient/host-event-client.spec.ts +257 -0
- package/src/embed/hostEventClient/host-event-client.ts +70 -15
- package/src/embed/liveboard.spec.ts +126 -2
- package/src/embed/liveboard.ts +11 -2
- package/src/embed/sage.ts +0 -1
- package/src/embed/search.spec.ts +0 -2
- package/src/embed/ts-embed.ts +43 -3
- package/src/react/index.tsx +76 -72
- package/src/types.ts +739 -31
- package/src/utils/graphql/answerService/answerService.ts +4 -5
- package/src/utils/graphql/preview-service.ts +0 -1
- package/src/utils/processData.ts +0 -5
|
@@ -205,6 +205,128 @@ describe('HostEventClient', () => {
|
|
|
205
205
|
expect(result).toEqual(mockResponse);
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
+
it('should route GetAnswerSession through passthrough and return data', async () => {
|
|
209
|
+
const { client, mockIframe } = createHostEventClient();
|
|
210
|
+
const mockResponse = [{ value: { session: 'testSession', embedAnswerData: { id: '1' } } }];
|
|
211
|
+
mockProcessTrigger.mockResolvedValue(mockResponse);
|
|
212
|
+
|
|
213
|
+
const result = await client.triggerHostEvent(HostEvent.GetAnswerSession, { vizId: '123' });
|
|
214
|
+
|
|
215
|
+
expect(mockProcessTrigger).toHaveBeenCalledWith(
|
|
216
|
+
mockIframe,
|
|
217
|
+
HostEvent.UIPassthrough,
|
|
218
|
+
mockThoughtSpotHost,
|
|
219
|
+
{ type: UIPassthroughEvent.GetAnswerSession, parameters: { vizId: '123' } },
|
|
220
|
+
undefined,
|
|
221
|
+
);
|
|
222
|
+
expect(result).toEqual({ session: 'testSession', embedAnswerData: { id: '1' } });
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should fall back to legacy host event when passthrough returns no data for GetAnswerSession', async () => {
|
|
226
|
+
const { client } = createHostEventClient();
|
|
227
|
+
mockProcessTrigger
|
|
228
|
+
.mockResolvedValueOnce([])
|
|
229
|
+
.mockResolvedValueOnce({ session: 'fallbackSession' });
|
|
230
|
+
|
|
231
|
+
const result = await client.triggerHostEvent(HostEvent.GetAnswerSession, { vizId: '123' });
|
|
232
|
+
|
|
233
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
|
|
234
|
+
expect(mockProcessTrigger).toHaveBeenNthCalledWith(
|
|
235
|
+
2,
|
|
236
|
+
expect.anything(),
|
|
237
|
+
HostEvent.GetAnswerSession,
|
|
238
|
+
mockThoughtSpotHost,
|
|
239
|
+
{ vizId: '123' },
|
|
240
|
+
undefined,
|
|
241
|
+
);
|
|
242
|
+
expect(result).toEqual({ session: 'fallbackSession' });
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should throw real errors from passthrough without falling back', async () => {
|
|
246
|
+
const { client } = createHostEventClient();
|
|
247
|
+
mockProcessTrigger.mockResolvedValue([{ error: 'Permission denied' }]);
|
|
248
|
+
|
|
249
|
+
await expect(client.triggerHostEvent(HostEvent.GetAnswerSession, {}))
|
|
250
|
+
.rejects.toThrow('Permission denied');
|
|
251
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should route GetFilters through passthrough and return data', async () => {
|
|
255
|
+
const { client, mockIframe } = createHostEventClient();
|
|
256
|
+
const mockResponse = [{ value: { liveboardFilters: [{ id: 'f1' }], runtimeFilters: [] as any[] } }];
|
|
257
|
+
mockProcessTrigger.mockResolvedValue(mockResponse);
|
|
258
|
+
|
|
259
|
+
const result = await client.triggerHostEvent(HostEvent.GetFilters, {});
|
|
260
|
+
|
|
261
|
+
expect(mockProcessTrigger).toHaveBeenCalledWith(
|
|
262
|
+
mockIframe,
|
|
263
|
+
HostEvent.UIPassthrough,
|
|
264
|
+
mockThoughtSpotHost,
|
|
265
|
+
{ type: UIPassthroughEvent.GetFilters, parameters: {} },
|
|
266
|
+
undefined,
|
|
267
|
+
);
|
|
268
|
+
expect(result).toEqual({ liveboardFilters: [{ id: 'f1' }], runtimeFilters: [] });
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should route GetTabs through passthrough and return data', async () => {
|
|
272
|
+
const { client } = createHostEventClient();
|
|
273
|
+
const mockResponse = [{ value: { orderedTabIds: ['t1', 't2'], numberOfTabs: 2, Tabs: [] as any[] } }];
|
|
274
|
+
mockProcessTrigger.mockResolvedValue(mockResponse);
|
|
275
|
+
|
|
276
|
+
const result = await client.triggerHostEvent(HostEvent.GetTabs, {});
|
|
277
|
+
|
|
278
|
+
expect(result).toEqual({ orderedTabIds: ['t1', 't2'], numberOfTabs: 2, Tabs: [] });
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should route GetTML through passthrough and return data', async () => {
|
|
282
|
+
const { client } = createHostEventClient();
|
|
283
|
+
const tmlData = { answer: { search_query: 'revenue by region' } };
|
|
284
|
+
mockProcessTrigger.mockResolvedValue([{ value: tmlData }]);
|
|
285
|
+
|
|
286
|
+
const result = await client.triggerHostEvent(HostEvent.GetTML, {});
|
|
287
|
+
|
|
288
|
+
expect(result).toEqual(tmlData);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should route GetIframeUrl through passthrough and return data', async () => {
|
|
292
|
+
const { client } = createHostEventClient();
|
|
293
|
+
mockProcessTrigger.mockResolvedValue([{ value: { iframeUrl: 'https://ts.example.com/embed' } }]);
|
|
294
|
+
|
|
295
|
+
const result = await client.triggerHostEvent(HostEvent.GetIframeUrl, {});
|
|
296
|
+
|
|
297
|
+
expect(result).toEqual({ iframeUrl: 'https://ts.example.com/embed' });
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should route GetParameters through passthrough and return data', async () => {
|
|
301
|
+
const { client } = createHostEventClient();
|
|
302
|
+
mockProcessTrigger.mockResolvedValue([{ value: { parameters: [{ name: 'p1' }] } }]);
|
|
303
|
+
|
|
304
|
+
const result = await client.triggerHostEvent(HostEvent.GetParameters, {});
|
|
305
|
+
|
|
306
|
+
expect(result).toEqual({ parameters: [{ name: 'p1' }] });
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should route getExportRequestForCurrentPinboard through passthrough and return data', async () => {
|
|
310
|
+
const { client } = createHostEventClient();
|
|
311
|
+
mockProcessTrigger.mockResolvedValue([{ value: { v2Content: 'exportData' } }]);
|
|
312
|
+
|
|
313
|
+
const result = await client.triggerHostEvent(HostEvent.getExportRequestForCurrentPinboard, {});
|
|
314
|
+
|
|
315
|
+
expect(result).toEqual({ v2Content: 'exportData' });
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('should fall back to legacy for GetFilters when passthrough returns null', async () => {
|
|
319
|
+
const { client } = createHostEventClient();
|
|
320
|
+
mockProcessTrigger
|
|
321
|
+
.mockResolvedValueOnce(null)
|
|
322
|
+
.mockResolvedValueOnce({ liveboardFilters: [], runtimeFilters: [] });
|
|
323
|
+
|
|
324
|
+
const result = await client.triggerHostEvent(HostEvent.GetFilters, {});
|
|
325
|
+
|
|
326
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
|
|
327
|
+
expect(result).toEqual({ liveboardFilters: [], runtimeFilters: [] });
|
|
328
|
+
});
|
|
329
|
+
|
|
208
330
|
it('should call fallback for Pin event', async () => {
|
|
209
331
|
const { client, mockIframe } = createHostEventClient();
|
|
210
332
|
const hostEvent = HostEvent.Pin;
|
|
@@ -318,4 +440,139 @@ describe('HostEventClient', () => {
|
|
|
318
440
|
});
|
|
319
441
|
});
|
|
320
442
|
});
|
|
443
|
+
|
|
444
|
+
describe('getDataWithPassthroughFallback', () => {
|
|
445
|
+
const callMethod = (client: HostEventClient, ...args: any[]) => (client as any).getDataWithPassthroughFallback(...args);
|
|
446
|
+
|
|
447
|
+
it('should return unwrapped value when passthrough succeeds', async () => {
|
|
448
|
+
const { client } = createHostEventClient();
|
|
449
|
+
mockProcessTrigger.mockResolvedValue([{ value: { session: 's1', embedAnswerData: { id: 'a1' } } }]);
|
|
450
|
+
|
|
451
|
+
const result = await callMethod(
|
|
452
|
+
client, UIPassthroughEvent.GetAnswerSession, HostEvent.GetAnswerSession, { vizId: '1' },
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
expect(result).toEqual({ session: 's1', embedAnswerData: { id: 'a1' } });
|
|
456
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('should fall back to legacy when passthrough returns empty array', async () => {
|
|
460
|
+
const { client } = createHostEventClient();
|
|
461
|
+
const legacyResponse = { session: 'legacy' };
|
|
462
|
+
mockProcessTrigger
|
|
463
|
+
.mockResolvedValueOnce([])
|
|
464
|
+
.mockResolvedValueOnce(legacyResponse);
|
|
465
|
+
|
|
466
|
+
const result = await callMethod(
|
|
467
|
+
client, UIPassthroughEvent.GetAnswerSession, HostEvent.GetAnswerSession, { vizId: '1' },
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
|
|
471
|
+
expect(result).toEqual(legacyResponse);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('should fall back to legacy when passthrough returns null', async () => {
|
|
475
|
+
const { client } = createHostEventClient();
|
|
476
|
+
const legacyResponse = { parameters: [] as any[] };
|
|
477
|
+
mockProcessTrigger
|
|
478
|
+
.mockResolvedValueOnce(null)
|
|
479
|
+
.mockResolvedValueOnce(legacyResponse);
|
|
480
|
+
|
|
481
|
+
const result = await callMethod(
|
|
482
|
+
client, UIPassthroughEvent.GetParameters, HostEvent.GetParameters, {},
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
|
|
486
|
+
expect(result).toEqual(legacyResponse);
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('should fall back to legacy when passthrough returns undefined', async () => {
|
|
490
|
+
const { client } = createHostEventClient();
|
|
491
|
+
const legacyResponse = { iframeUrl: 'https://ts.example.com' };
|
|
492
|
+
mockProcessTrigger
|
|
493
|
+
.mockResolvedValueOnce(undefined)
|
|
494
|
+
.mockResolvedValueOnce(legacyResponse);
|
|
495
|
+
|
|
496
|
+
const result = await callMethod(
|
|
497
|
+
client, UIPassthroughEvent.GetIframeUrl, HostEvent.GetIframeUrl, {},
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
|
|
501
|
+
expect(result).toEqual(legacyResponse);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should fall back when response array has no matching entries', async () => {
|
|
505
|
+
const { client } = createHostEventClient();
|
|
506
|
+
const legacyResponse = { v2Content: 'data' };
|
|
507
|
+
mockProcessTrigger
|
|
508
|
+
.mockResolvedValueOnce([{ refId: 'r1' }])
|
|
509
|
+
.mockResolvedValueOnce(legacyResponse);
|
|
510
|
+
|
|
511
|
+
const result = await callMethod(
|
|
512
|
+
client, UIPassthroughEvent.GetExportRequestForCurrentPinboard,
|
|
513
|
+
HostEvent.getExportRequestForCurrentPinboard, {},
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(2);
|
|
517
|
+
expect(result).toEqual(legacyResponse);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it('should throw when response has error field', async () => {
|
|
521
|
+
const { client } = createHostEventClient();
|
|
522
|
+
mockProcessTrigger.mockResolvedValue([{ error: 'Permission denied' }]);
|
|
523
|
+
|
|
524
|
+
await expect(callMethod(
|
|
525
|
+
client, UIPassthroughEvent.GetFilters, HostEvent.GetFilters, {},
|
|
526
|
+
)).rejects.toThrow('Permission denied');
|
|
527
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it('should throw when response value contains errors field', async () => {
|
|
531
|
+
const { client } = createHostEventClient();
|
|
532
|
+
mockProcessTrigger.mockResolvedValue([{ value: { errors: 'Invalid vizId' } }]);
|
|
533
|
+
|
|
534
|
+
await expect(callMethod(
|
|
535
|
+
client, UIPassthroughEvent.GetTML, HostEvent.GetTML, { vizId: 'bad' },
|
|
536
|
+
)).rejects.toThrow('Invalid vizId');
|
|
537
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it('should throw when response value contains error field', async () => {
|
|
541
|
+
const { client } = createHostEventClient();
|
|
542
|
+
mockProcessTrigger.mockResolvedValue([{ value: { error: 'Not found' } }]);
|
|
543
|
+
|
|
544
|
+
await expect(callMethod(
|
|
545
|
+
client, UIPassthroughEvent.GetTabs, HostEvent.GetTabs, {},
|
|
546
|
+
)).rejects.toThrow('Not found');
|
|
547
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it('should stringify object errors instead of producing [object Object]', async () => {
|
|
551
|
+
const { client } = createHostEventClient();
|
|
552
|
+
const errorObj = { code: 403, reason: 'Forbidden' };
|
|
553
|
+
mockProcessTrigger.mockResolvedValue([{ error: errorObj }]);
|
|
554
|
+
|
|
555
|
+
await expect(callMethod(
|
|
556
|
+
client, UIPassthroughEvent.GetFilters, HostEvent.GetFilters, {},
|
|
557
|
+
)).rejects.toThrow(JSON.stringify(errorObj));
|
|
558
|
+
expect(mockProcessTrigger).toHaveBeenCalledTimes(1);
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it('should default payload to empty object when null', async () => {
|
|
562
|
+
const { client, mockIframe } = createHostEventClient();
|
|
563
|
+
mockProcessTrigger.mockResolvedValue([{ value: { iframeUrl: 'https://ts.example.com' } }]);
|
|
564
|
+
|
|
565
|
+
await callMethod(
|
|
566
|
+
client, UIPassthroughEvent.GetIframeUrl, HostEvent.GetIframeUrl, null,
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
expect(mockProcessTrigger).toHaveBeenCalledWith(
|
|
570
|
+
mockIframe,
|
|
571
|
+
HostEvent.UIPassthrough,
|
|
572
|
+
mockThoughtSpotHost,
|
|
573
|
+
{ type: UIPassthroughEvent.GetIframeUrl, parameters: {} },
|
|
574
|
+
undefined,
|
|
575
|
+
);
|
|
576
|
+
});
|
|
577
|
+
});
|
|
321
578
|
});
|
|
@@ -3,18 +3,42 @@ import { processTrigger as processTriggerService } from '../../utils/processTrig
|
|
|
3
3
|
import { getEmbedConfig } from '../embedConfig';
|
|
4
4
|
import {
|
|
5
5
|
UIPassthroughArrayResponse,
|
|
6
|
-
UIPassthroughEvent,
|
|
6
|
+
UIPassthroughEvent,
|
|
7
|
+
HostEventRequest,
|
|
8
|
+
HostEventResponse,
|
|
7
9
|
UIPassthroughRequest,
|
|
8
10
|
UIPassthroughResponse,
|
|
9
11
|
TriggerPayload,
|
|
10
12
|
TriggerResponse,
|
|
11
13
|
} from './contracts';
|
|
12
14
|
|
|
15
|
+
/** Host events that use getDataWithPassthroughFallback (getter-style APIs) */
|
|
16
|
+
const HOST_EVENT_PASSTHROUGH_MAP: Partial<Record<HostEvent, UIPassthroughEvent>> = {
|
|
17
|
+
[HostEvent.GetAnswerSession]: UIPassthroughEvent.GetAnswerSession,
|
|
18
|
+
[HostEvent.GetFilters]: UIPassthroughEvent.GetFilters,
|
|
19
|
+
[HostEvent.GetIframeUrl]: UIPassthroughEvent.GetIframeUrl,
|
|
20
|
+
[HostEvent.GetParameters]: UIPassthroughEvent.GetParameters,
|
|
21
|
+
[HostEvent.GetTML]: UIPassthroughEvent.GetTML,
|
|
22
|
+
[HostEvent.GetTabs]: UIPassthroughEvent.GetTabs,
|
|
23
|
+
[HostEvent.getExportRequestForCurrentPinboard]: UIPassthroughEvent.GetExportRequestForCurrentPinboard,
|
|
24
|
+
};
|
|
25
|
+
|
|
13
26
|
export class HostEventClient {
|
|
14
27
|
iFrame: HTMLIFrameElement;
|
|
15
28
|
|
|
29
|
+
/** Host events with custom handlers
|
|
30
|
+
* (setters or special logic) -
|
|
31
|
+
* bound to instance for protected method access */
|
|
32
|
+
private readonly customHandlers: Partial<
|
|
33
|
+
Record<HostEvent, (payload: any, context?: ContextType) => Promise<any>>
|
|
34
|
+
>;
|
|
35
|
+
|
|
16
36
|
constructor(iFrame?: HTMLIFrameElement) {
|
|
17
37
|
this.iFrame = iFrame;
|
|
38
|
+
this.customHandlers = {
|
|
39
|
+
[HostEvent.Pin]: (p, c) => this.handlePinEvent(p, c),
|
|
40
|
+
[HostEvent.SaveAnswer]: (p, c) => this.handleSaveAnswerEvent(p, c),
|
|
41
|
+
};
|
|
18
42
|
}
|
|
19
43
|
|
|
20
44
|
/**
|
|
@@ -44,11 +68,10 @@ export class HostEventClient {
|
|
|
44
68
|
context?: ContextType,
|
|
45
69
|
): Promise<UIPassthroughResponse<UIPassthroughEventT>> {
|
|
46
70
|
const response = (await this.triggerUIPassthroughApi(apiName, parameters, context))
|
|
47
|
-
?.
|
|
71
|
+
?.find?.((r) => r.error || r.value);
|
|
48
72
|
|
|
49
73
|
if (!response) {
|
|
50
74
|
const error = `No answer found${parameters.vizId ? ` for vizId: ${parameters.vizId}` : ''}.`;
|
|
51
|
-
|
|
52
75
|
throw { error };
|
|
53
76
|
}
|
|
54
77
|
|
|
@@ -57,8 +80,8 @@ export class HostEventClient {
|
|
|
57
80
|
|| (response.value as any)?.error;
|
|
58
81
|
|
|
59
82
|
if (errors) {
|
|
60
|
-
|
|
61
|
-
throw { error:
|
|
83
|
+
const message = typeof errors === 'string' ? errors : JSON.stringify(errors);
|
|
84
|
+
throw { error: message };
|
|
62
85
|
}
|
|
63
86
|
|
|
64
87
|
return { ...response.value };
|
|
@@ -72,6 +95,36 @@ export class HostEventClient {
|
|
|
72
95
|
return this.processTrigger(hostEvent, data, context);
|
|
73
96
|
}
|
|
74
97
|
|
|
98
|
+
/**
|
|
99
|
+
* For getter events that return data. Tries UI passthrough first;
|
|
100
|
+
* if the app doesn't support it (no response data), falls back to
|
|
101
|
+
* the legacy host event channel. Real errors are thrown as-is.
|
|
102
|
+
*/
|
|
103
|
+
private async getDataWithPassthroughFallback<UIPassthroughEventT extends UIPassthroughEvent>(
|
|
104
|
+
passthroughEvent: UIPassthroughEventT,
|
|
105
|
+
hostEvent: HostEvent,
|
|
106
|
+
payload: any,
|
|
107
|
+
context?: ContextType,
|
|
108
|
+
): Promise<UIPassthroughResponse<UIPassthroughEventT>> {
|
|
109
|
+
const response = await this.triggerUIPassthroughApi(
|
|
110
|
+
passthroughEvent, payload || {}, context,
|
|
111
|
+
);
|
|
112
|
+
const matched = response?.find?.((r) => r.error || r.value);
|
|
113
|
+
if (!matched) {
|
|
114
|
+
return this.hostEventFallback(hostEvent, payload, context);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const errors = matched.error
|
|
118
|
+
|| (matched.value as any)?.errors
|
|
119
|
+
|| (matched.value as any)?.error;
|
|
120
|
+
if (errors) {
|
|
121
|
+
const message = typeof errors === 'string' ? errors : JSON.stringify(errors);
|
|
122
|
+
throw new Error(message);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { ...matched.value };
|
|
126
|
+
}
|
|
127
|
+
|
|
75
128
|
/**
|
|
76
129
|
* Setter for the iframe element used for host events
|
|
77
130
|
* @param {HTMLIFrameElement} iFrame - the iframe element to set
|
|
@@ -146,16 +199,18 @@ export class HostEventClient {
|
|
|
146
199
|
payload?: TriggerPayload<PayloadT, HostEventT>,
|
|
147
200
|
context?: ContextT,
|
|
148
201
|
): Promise<TriggerResponse<PayloadT, HostEventT, ContextType>> {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
202
|
+
const customHandler = this.customHandlers[hostEvent];
|
|
203
|
+
if (customHandler) {
|
|
204
|
+
return customHandler(payload, context as ContextType) as any;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const passthroughEvent = HOST_EVENT_PASSTHROUGH_MAP[hostEvent];
|
|
208
|
+
if (passthroughEvent) {
|
|
209
|
+
return this.getDataWithPassthroughFallback(
|
|
210
|
+
passthroughEvent, hostEvent, payload, context as ContextType,
|
|
211
|
+
) as any;
|
|
159
212
|
}
|
|
213
|
+
|
|
214
|
+
return this.hostEventFallback(hostEvent, payload, context);
|
|
160
215
|
}
|
|
161
216
|
}
|
|
@@ -94,6 +94,37 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
test('should set disabled actions using PersonalizedViewsDropdown alias', async () => {
|
|
98
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
99
|
+
disabledActions: [Action.PersonalizedViewsDropdown],
|
|
100
|
+
disabledActionReason: 'Action denied',
|
|
101
|
+
...defaultViewConfig,
|
|
102
|
+
liveboardId,
|
|
103
|
+
} as LiveboardViewConfig);
|
|
104
|
+
liveboardEmbed.render();
|
|
105
|
+
await executeAfterWait(() => {
|
|
106
|
+
expectUrlMatchesWithParams(
|
|
107
|
+
getIFrameSrc(),
|
|
108
|
+
`http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&disableAction=[%22${Action.PersonalisedViewsDropdown}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${liveboardId}`,
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('should set hidden actions using OrganizeFavorites alias', async () => {
|
|
114
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
115
|
+
hiddenActions: [Action.OrganizeFavorites],
|
|
116
|
+
...defaultViewConfig,
|
|
117
|
+
liveboardId,
|
|
118
|
+
} as LiveboardViewConfig);
|
|
119
|
+
liveboardEmbed.render();
|
|
120
|
+
await executeAfterWait(() => {
|
|
121
|
+
expectUrlMatchesWithParams(
|
|
122
|
+
getIFrameSrc(),
|
|
123
|
+
`http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&hideAction=[%22${Action.ReportError}%22,%22${Action.OrganiseFavourites}%22]${prefixParams}#/embed/viz/${liveboardId}`,
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
97
128
|
test('should set disabled actions', async () => {
|
|
98
129
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
99
130
|
disabledActions: [Action.DownloadAsCsv, Action.DownloadAsPdf, Action.DownloadAsXlsx],
|
|
@@ -1011,8 +1042,8 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
1011
1042
|
} as LiveboardViewConfig);
|
|
1012
1043
|
liveboardEmbed.render();
|
|
1013
1044
|
await executeAfterWait(() => {
|
|
1014
|
-
// URL: #/embed/viz/{id}/tab/{tabId}?view={viewId}
|
|
1015
|
-
// END, not middle)
|
|
1045
|
+
// URL: #/embed/viz/{id}/tab/{tabId}?view={viewId}
|
|
1046
|
+
// (view at END, not middle)
|
|
1016
1047
|
expect(getIFrameSrc()).toMatch(
|
|
1017
1048
|
new RegExp(
|
|
1018
1049
|
`#/embed/viz/${liveboardId}/tab/${activeTabId}\\?view=${workaroundViewId}`,
|
|
@@ -1944,6 +1975,99 @@ describe('Liveboard/viz embed tests', () => {
|
|
|
1944
1975
|
});
|
|
1945
1976
|
});
|
|
1946
1977
|
|
|
1978
|
+
describe('updateIFrameHeight threshold handling', () => {
|
|
1979
|
+
let mockIFrame: HTMLIFrameElement;
|
|
1980
|
+
|
|
1981
|
+
beforeEach(() => {
|
|
1982
|
+
mockIFrame = document.createElement('iframe');
|
|
1983
|
+
mockIFrame.getBoundingClientRect = jest.fn().mockReturnValue({
|
|
1984
|
+
top: 0,
|
|
1985
|
+
left: 0,
|
|
1986
|
+
bottom: 500,
|
|
1987
|
+
right: 800,
|
|
1988
|
+
width: 800,
|
|
1989
|
+
height: 500,
|
|
1990
|
+
});
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
test('should skip height update when change is below threshold', async () => {
|
|
1994
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
1995
|
+
liveboardId,
|
|
1996
|
+
...defaultViewConfig,
|
|
1997
|
+
fullHeight: true,
|
|
1998
|
+
}) as any;
|
|
1999
|
+
|
|
2000
|
+
liveboardEmbed.iFrame = mockIFrame;
|
|
2001
|
+
document.body.appendChild(mockIFrame);
|
|
2002
|
+
await liveboardEmbed.render();
|
|
2003
|
+
|
|
2004
|
+
const spySetIFrameHeight = jest.spyOn(liveboardEmbed, 'setIFrameHeight');
|
|
2005
|
+
|
|
2006
|
+
// currentHeight is 500; heightToSet = max(510, 500) = 510; change = 10 < 30
|
|
2007
|
+
liveboardEmbed.updateIFrameHeight({ data: 510, type: EmbedEvent.EmbedHeight });
|
|
2008
|
+
|
|
2009
|
+
expect(spySetIFrameHeight).not.toHaveBeenCalled();
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
test('should update height when change meets threshold', async () => {
|
|
2013
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
2014
|
+
liveboardId,
|
|
2015
|
+
...defaultViewConfig,
|
|
2016
|
+
fullHeight: true,
|
|
2017
|
+
}) as any;
|
|
2018
|
+
|
|
2019
|
+
liveboardEmbed.iFrame = mockIFrame;
|
|
2020
|
+
document.body.appendChild(mockIFrame);
|
|
2021
|
+
await liveboardEmbed.render();
|
|
2022
|
+
|
|
2023
|
+
const spySetIFrameHeight = jest.spyOn(liveboardEmbed, 'setIFrameHeight');
|
|
2024
|
+
|
|
2025
|
+
// currentHeight is 500; heightToSet = max(700, 500) = 700; change = 200 >= 30
|
|
2026
|
+
liveboardEmbed.updateIFrameHeight({ data: 700, type: EmbedEvent.EmbedHeight });
|
|
2027
|
+
|
|
2028
|
+
expect(spySetIFrameHeight).toHaveBeenCalledWith(700);
|
|
2029
|
+
});
|
|
2030
|
+
|
|
2031
|
+
test('should use defaultHeight when data is below it and apply threshold', async () => {
|
|
2032
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
2033
|
+
liveboardId,
|
|
2034
|
+
...defaultViewConfig,
|
|
2035
|
+
fullHeight: true,
|
|
2036
|
+
minimumHeight: 800,
|
|
2037
|
+
}) as any;
|
|
2038
|
+
|
|
2039
|
+
liveboardEmbed.iFrame = mockIFrame;
|
|
2040
|
+
document.body.appendChild(mockIFrame);
|
|
2041
|
+
await liveboardEmbed.render();
|
|
2042
|
+
|
|
2043
|
+
const spySetIFrameHeight = jest.spyOn(liveboardEmbed, 'setIFrameHeight');
|
|
2044
|
+
|
|
2045
|
+
// currentHeight is 500; heightToSet = max(100, 800) = 800; change = 300 >= 30
|
|
2046
|
+
liveboardEmbed.updateIFrameHeight({ data: 100, type: EmbedEvent.EmbedHeight });
|
|
2047
|
+
|
|
2048
|
+
expect(spySetIFrameHeight).toHaveBeenCalledWith(800);
|
|
2049
|
+
});
|
|
2050
|
+
|
|
2051
|
+
test('should skip update when height change is exactly at threshold boundary', async () => {
|
|
2052
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
2053
|
+
liveboardId,
|
|
2054
|
+
...defaultViewConfig,
|
|
2055
|
+
fullHeight: true,
|
|
2056
|
+
}) as any;
|
|
2057
|
+
|
|
2058
|
+
liveboardEmbed.iFrame = mockIFrame;
|
|
2059
|
+
document.body.appendChild(mockIFrame);
|
|
2060
|
+
await liveboardEmbed.render();
|
|
2061
|
+
|
|
2062
|
+
const spySetIFrameHeight = jest.spyOn(liveboardEmbed, 'setIFrameHeight');
|
|
2063
|
+
|
|
2064
|
+
// currentHeight is 500; heightToSet = max(529, 500) = 529; change = 29 < 30
|
|
2065
|
+
liveboardEmbed.updateIFrameHeight({ data: 529, type: EmbedEvent.EmbedHeight });
|
|
2066
|
+
|
|
2067
|
+
expect(spySetIFrameHeight).not.toHaveBeenCalled();
|
|
2068
|
+
});
|
|
2069
|
+
});
|
|
2070
|
+
|
|
1947
2071
|
describe('Liveboard Embed Default Height and Minimum Height Handling', () => {
|
|
1948
2072
|
test('should set default height to 800 when minimum height is provided', async () => {
|
|
1949
2073
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
package/src/embed/liveboard.ts
CHANGED
|
@@ -732,7 +732,8 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
732
732
|
personalizedViewId?: string,
|
|
733
733
|
) {
|
|
734
734
|
// Extract view from liveboardId if passed along with it (legacy
|
|
735
|
-
// approach)
|
|
735
|
+
// approach)
|
|
736
|
+
// View must be appended as query param at the end, not
|
|
736
737
|
// embedded in path
|
|
737
738
|
let liveboardGuid = liveboardId;
|
|
738
739
|
let legacyViewId: string | undefined;
|
|
@@ -805,13 +806,21 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
805
806
|
)}`;
|
|
806
807
|
}
|
|
807
808
|
|
|
809
|
+
private HEIGHT_CHANAGE_THRESHOLD = 30;
|
|
808
810
|
/**
|
|
809
811
|
* Set the iframe height as per the computed height received
|
|
810
812
|
* from the ThoughtSpot app.
|
|
811
813
|
* @param data The event payload
|
|
812
814
|
*/
|
|
813
815
|
private updateIFrameHeight = (data: MessagePayload) => {
|
|
814
|
-
this.
|
|
816
|
+
const currentHeight = this.iFrame.getBoundingClientRect().height;
|
|
817
|
+
const heightToSet = Math.max(data.data, this.defaultHeight);
|
|
818
|
+
const heightChange = Math.abs(heightToSet - currentHeight);
|
|
819
|
+
if (heightChange < this.HEIGHT_CHANAGE_THRESHOLD) {
|
|
820
|
+
logger.info('Height change is less than the threshold, skipping height update', { heightChange, heightToSet, currentHeight });
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
this.setIFrameHeight(heightToSet);
|
|
815
824
|
this.sendFullHeightLazyLoadData();
|
|
816
825
|
};
|
|
817
826
|
|
package/src/embed/sage.ts
CHANGED
|
@@ -147,7 +147,6 @@ export class SageEmbed extends V1Embed {
|
|
|
147
147
|
*/
|
|
148
148
|
protected viewConfig: SageViewConfig;
|
|
149
149
|
|
|
150
|
-
|
|
151
150
|
constructor(domSelector: DOMSelector, viewConfig: SageViewConfig) {
|
|
152
151
|
viewConfig.embedComponentType = 'SageEmbed';
|
|
153
152
|
super(domSelector, viewConfig);
|
package/src/embed/search.spec.ts
CHANGED
|
@@ -527,7 +527,6 @@ describe('Search embed tests', () => {
|
|
|
527
527
|
test('should set dataPanelCustomGroupsAccordionInitialState to EXPAND_FIRST when passed', async () => {
|
|
528
528
|
const searchEmbed = new SearchBarEmbed(getRootEl() as any, {
|
|
529
529
|
...defaultViewConfig,
|
|
530
|
-
|
|
531
530
|
});
|
|
532
531
|
searchEmbed.render();
|
|
533
532
|
await executeAfterWait(() => {
|
|
@@ -541,7 +540,6 @@ describe('Search embed tests', () => {
|
|
|
541
540
|
test('should set dataPanelCustomGroupsAccordionInitialState to EXPAND_FIRST when passed', async () => {
|
|
542
541
|
const searchEmbed = new SearchEmbed(getRootEl(), {
|
|
543
542
|
...defaultViewConfig,
|
|
544
|
-
|
|
545
543
|
dataPanelCustomGroupsAccordionInitialState:
|
|
546
544
|
DataPanelCustomColumnGroupsAccordionState.EXPAND_FIRST,
|
|
547
545
|
});
|
package/src/embed/ts-embed.ts
CHANGED
|
@@ -34,7 +34,8 @@ import {
|
|
|
34
34
|
setStyleProperties,
|
|
35
35
|
removeStyleProperties,
|
|
36
36
|
isUndefined,
|
|
37
|
-
|
|
37
|
+
getHostEventsConfig,
|
|
38
|
+
} from '../utils';
|
|
38
39
|
import { getCustomActions } from '../utils/custom-actions';
|
|
39
40
|
import {
|
|
40
41
|
getThoughtSpotHost,
|
|
@@ -1392,7 +1393,21 @@ export class TsEmbed {
|
|
|
1392
1393
|
* Triggers an event to the embedded app
|
|
1393
1394
|
* @param {HostEvent} messageType The event type
|
|
1394
1395
|
* @param {any} data The payload to send with the message
|
|
1396
|
+
* @param {ContextType} context Optional context type to specify the context from which the event is triggered.
|
|
1397
|
+
* Use ContextType.Search for search answer context, ContextType.Answer for answer/explore context,
|
|
1398
|
+
* ContextType.Liveboard for liveboard context, or ContextType.Spotter for spotter context.
|
|
1399
|
+
* Available from SDK version 1.45.2 | ThoughtSpot: 26.3.0.cl
|
|
1395
1400
|
* @returns A promise that resolves with the response from the embedded app
|
|
1401
|
+
* @example
|
|
1402
|
+
* ```js
|
|
1403
|
+
* // Trigger Pin event with context (SDK: 1.45.2+)
|
|
1404
|
+
* import { HostEvent, ContextType } from '@thoughtspot/visual-embed-sdk';
|
|
1405
|
+
* embed.trigger(HostEvent.Pin, {
|
|
1406
|
+
* vizId: "123",
|
|
1407
|
+
* liveboardId: "456"
|
|
1408
|
+
* }, ContextType.Search);
|
|
1409
|
+
* ```
|
|
1410
|
+
* @version SDK: 1.45.2 | ThoughtSpot: 26.3.0.cl (for context parameter)
|
|
1396
1411
|
*/
|
|
1397
1412
|
public async trigger<HostEventT extends HostEvent, PayloadT, ContextT extends ContextType>(
|
|
1398
1413
|
messageType: HostEventT,
|
|
@@ -1474,8 +1489,33 @@ export class TsEmbed {
|
|
|
1474
1489
|
}
|
|
1475
1490
|
|
|
1476
1491
|
/**
|
|
1477
|
-
|
|
1478
|
-
|
|
1492
|
+
* Context object for the embedded component.
|
|
1493
|
+
* @returns {ContextObject} The current context object containing the page type and object ids.
|
|
1494
|
+
* @example
|
|
1495
|
+
* ```js
|
|
1496
|
+
* const context = await embed.getCurrentContext();
|
|
1497
|
+
* console.log(context);
|
|
1498
|
+
*
|
|
1499
|
+
* // Example output
|
|
1500
|
+
* {
|
|
1501
|
+
* stack: [
|
|
1502
|
+
* {
|
|
1503
|
+
* name: 'Liveboard',
|
|
1504
|
+
* type: ContextType.Liveboard,
|
|
1505
|
+
* objectIds: {
|
|
1506
|
+
* liveboardId: '123',
|
|
1507
|
+
* },
|
|
1508
|
+
* },
|
|
1509
|
+
* ],
|
|
1510
|
+
* currentContext: {
|
|
1511
|
+
* name: 'Liveboard',
|
|
1512
|
+
* type: ContextType.Liveboard,
|
|
1513
|
+
* objectIds: {
|
|
1514
|
+
* liveboardId: '123',
|
|
1515
|
+
* },
|
|
1516
|
+
* },
|
|
1517
|
+
* }
|
|
1518
|
+
* ```
|
|
1479
1519
|
* @version SDK: 1.45.2 | ThoughtSpot: 26.3.0.cl
|
|
1480
1520
|
*/
|
|
1481
1521
|
public async getCurrentContext(): Promise<ContextObject> {
|