@thoughtspot/visual-embed-sdk 1.42.0 → 1.42.1-alpha.2

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.
Files changed (154) hide show
  1. package/cjs/package.json +2 -2
  2. package/cjs/src/api-intercept.d.ts +27 -0
  3. package/cjs/src/api-intercept.d.ts.map +1 -0
  4. package/cjs/src/api-intercept.js +115 -0
  5. package/cjs/src/api-intercept.js.map +1 -0
  6. package/cjs/src/api-intercept.spec.d.ts +2 -0
  7. package/cjs/src/api-intercept.spec.d.ts.map +1 -0
  8. package/cjs/src/api-intercept.spec.js +122 -0
  9. package/cjs/src/api-intercept.spec.js.map +1 -0
  10. package/cjs/src/embed/app.d.ts.map +1 -1
  11. package/cjs/src/embed/app.js +7 -2
  12. package/cjs/src/embed/app.js.map +1 -1
  13. package/cjs/src/embed/app.spec.js +20 -0
  14. package/cjs/src/embed/app.spec.js.map +1 -1
  15. package/cjs/src/embed/hostEventClient/contracts.d.ts +11 -1
  16. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  17. package/cjs/src/embed/hostEventClient/contracts.js +1 -0
  18. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  19. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  20. package/cjs/src/embed/liveboard.js +4 -1
  21. package/cjs/src/embed/liveboard.js.map +1 -1
  22. package/cjs/src/embed/liveboard.spec.js +22 -0
  23. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  24. package/cjs/src/embed/search.d.ts.map +1 -1
  25. package/cjs/src/embed/search.js +3 -1
  26. package/cjs/src/embed/search.js.map +1 -1
  27. package/cjs/src/embed/ts-embed.d.ts +15 -0
  28. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  29. package/cjs/src/embed/ts-embed.js +94 -26
  30. package/cjs/src/embed/ts-embed.js.map +1 -1
  31. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  32. package/cjs/src/embed/ts-embed.spec.js +168 -0
  33. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  34. package/cjs/src/errors.d.ts +1 -0
  35. package/cjs/src/errors.d.ts.map +1 -1
  36. package/cjs/src/errors.js +1 -0
  37. package/cjs/src/errors.js.map +1 -1
  38. package/cjs/src/index.d.ts +2 -2
  39. package/cjs/src/index.d.ts.map +1 -1
  40. package/cjs/src/index.js +2 -1
  41. package/cjs/src/index.js.map +1 -1
  42. package/cjs/src/react/all-types-export.d.ts +1 -1
  43. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  44. package/cjs/src/react/all-types-export.js +2 -1
  45. package/cjs/src/react/all-types-export.js.map +1 -1
  46. package/cjs/src/types.d.ts +100 -4
  47. package/cjs/src/types.d.ts.map +1 -1
  48. package/cjs/src/types.js +39 -1
  49. package/cjs/src/types.js.map +1 -1
  50. package/cjs/src/utils/processData.d.ts +1 -1
  51. package/cjs/src/utils/processData.d.ts.map +1 -1
  52. package/cjs/src/utils/processData.js +8 -8
  53. package/cjs/src/utils/processData.js.map +1 -1
  54. package/dist/index-BCC3Z072.js +7371 -0
  55. package/dist/index-BEzW4MDA.js +7371 -0
  56. package/dist/{index-BpSohedu.js → index-DvNA626T.js} +1 -1
  57. package/dist/src/api-intercept.d.ts +27 -0
  58. package/dist/src/api-intercept.d.ts.map +1 -0
  59. package/dist/src/api-intercept.spec.d.ts +2 -0
  60. package/dist/src/api-intercept.spec.d.ts.map +1 -0
  61. package/dist/src/embed/app.d.ts.map +1 -1
  62. package/dist/src/embed/hostEventClient/contracts.d.ts +11 -1
  63. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  64. package/dist/src/embed/liveboard.d.ts.map +1 -1
  65. package/dist/src/embed/search.d.ts.map +1 -1
  66. package/dist/src/embed/ts-embed.d.ts +15 -0
  67. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  68. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  69. package/dist/src/errors.d.ts +1 -0
  70. package/dist/src/errors.d.ts.map +1 -1
  71. package/dist/src/index.d.ts +2 -2
  72. package/dist/src/index.d.ts.map +1 -1
  73. package/dist/src/react/all-types-export.d.ts +1 -1
  74. package/dist/src/react/all-types-export.d.ts.map +1 -1
  75. package/dist/src/types.d.ts +100 -4
  76. package/dist/src/types.d.ts.map +1 -1
  77. package/dist/src/utils/processData.d.ts +1 -1
  78. package/dist/src/utils/processData.d.ts.map +1 -1
  79. package/dist/tsembed-react.es.js +266 -51
  80. package/dist/tsembed-react.js +265 -50
  81. package/dist/tsembed.es.js +267 -52
  82. package/dist/tsembed.js +265 -50
  83. package/dist/visual-embed-sdk-react-full.d.ts +124 -4
  84. package/dist/visual-embed-sdk-react.d.ts +121 -4
  85. package/dist/visual-embed-sdk.d.ts +124 -4
  86. package/lib/package.json +2 -2
  87. package/lib/src/api-intercept.d.ts +27 -0
  88. package/lib/src/api-intercept.d.ts.map +1 -0
  89. package/lib/src/api-intercept.js +108 -0
  90. package/lib/src/api-intercept.js.map +1 -0
  91. package/lib/src/api-intercept.spec.d.ts +2 -0
  92. package/lib/src/api-intercept.spec.d.ts.map +1 -0
  93. package/lib/src/api-intercept.spec.js +119 -0
  94. package/lib/src/api-intercept.spec.js.map +1 -0
  95. package/lib/src/embed/app.d.ts.map +1 -1
  96. package/lib/src/embed/app.js +7 -2
  97. package/lib/src/embed/app.js.map +1 -1
  98. package/lib/src/embed/app.spec.js +20 -0
  99. package/lib/src/embed/app.spec.js.map +1 -1
  100. package/lib/src/embed/hostEventClient/contracts.d.ts +11 -1
  101. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  102. package/lib/src/embed/hostEventClient/contracts.js +1 -0
  103. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  104. package/lib/src/embed/liveboard.d.ts.map +1 -1
  105. package/lib/src/embed/liveboard.js +4 -1
  106. package/lib/src/embed/liveboard.js.map +1 -1
  107. package/lib/src/embed/liveboard.spec.js +22 -0
  108. package/lib/src/embed/liveboard.spec.js.map +1 -1
  109. package/lib/src/embed/search.d.ts.map +1 -1
  110. package/lib/src/embed/search.js +3 -1
  111. package/lib/src/embed/search.js.map +1 -1
  112. package/lib/src/embed/ts-embed.d.ts +15 -0
  113. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  114. package/lib/src/embed/ts-embed.js +94 -26
  115. package/lib/src/embed/ts-embed.js.map +1 -1
  116. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  117. package/lib/src/embed/ts-embed.spec.js +168 -0
  118. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  119. package/lib/src/errors.d.ts +1 -0
  120. package/lib/src/errors.d.ts.map +1 -1
  121. package/lib/src/errors.js +1 -0
  122. package/lib/src/errors.js.map +1 -1
  123. package/lib/src/index.d.ts +2 -2
  124. package/lib/src/index.d.ts.map +1 -1
  125. package/lib/src/index.js +2 -2
  126. package/lib/src/index.js.map +1 -1
  127. package/lib/src/react/all-types-export.d.ts +1 -1
  128. package/lib/src/react/all-types-export.d.ts.map +1 -1
  129. package/lib/src/react/all-types-export.js +1 -1
  130. package/lib/src/react/all-types-export.js.map +1 -1
  131. package/lib/src/types.d.ts +100 -4
  132. package/lib/src/types.d.ts.map +1 -1
  133. package/lib/src/types.js +38 -0
  134. package/lib/src/types.js.map +1 -1
  135. package/lib/src/utils/processData.d.ts +1 -1
  136. package/lib/src/utils/processData.d.ts.map +1 -1
  137. package/lib/src/utils/processData.js +8 -8
  138. package/lib/src/utils/processData.js.map +1 -1
  139. package/package.json +2 -2
  140. package/src/api-intercept.spec.ts +147 -0
  141. package/src/api-intercept.ts +134 -0
  142. package/src/embed/app.spec.ts +28 -0
  143. package/src/embed/app.ts +9 -1
  144. package/src/embed/hostEventClient/contracts.ts +10 -0
  145. package/src/embed/liveboard.spec.ts +30 -0
  146. package/src/embed/liveboard.ts +5 -0
  147. package/src/embed/search.ts +3 -1
  148. package/src/embed/ts-embed.spec.ts +221 -5
  149. package/src/embed/ts-embed.ts +129 -43
  150. package/src/errors.ts +1 -0
  151. package/src/index.ts +2 -0
  152. package/src/react/all-types-export.ts +1 -0
  153. package/src/types.ts +102 -3
  154. package/src/utils/processData.ts +11 -11
@@ -0,0 +1,147 @@
1
+ import { getInterceptInitData, processApiIntercept, handleInterceptEvent, processLegacyInterceptResponse } from './api-intercept';
2
+ import { EmbedEvent, InterceptedApiType } from './types';
3
+ import * as embedCfg from './embed/embedConfig';
4
+ import * as cfg from './config';
5
+ import { logger } from './utils/logger';
6
+
7
+ describe('api-intercept', () => {
8
+ beforeEach(() => {
9
+ jest.restoreAllMocks();
10
+ jest.clearAllMocks();
11
+ });
12
+
13
+ describe('getInterceptInitData', () => {
14
+ test('returns disabled when not enabled in either config', () => {
15
+ const init = getInterceptInitData({} as any, {} as any);
16
+ expect(init).toEqual({ enableApiIntercept: false });
17
+ });
18
+
19
+ test('merges urls and expands api types, formats with host', () => {
20
+ jest.spyOn(embedCfg, 'getEmbedConfig').mockReturnValue({ thoughtSpotHost: 'http://tshost' } as any);
21
+ jest.spyOn(cfg, 'getThoughtSpotHost').mockReturnValue('http://tshost');
22
+
23
+ const embedConfig: any = { enableApiIntercept: true };
24
+ const viewConfig: any = { interceptUrls: [InterceptedApiType.METADATA, '/custom/path'] };
25
+
26
+ const init = getInterceptInitData(embedConfig, viewConfig);
27
+
28
+ expect(init.enableApiIntercept).toBe(true);
29
+ expect(init.interceptUrls).toEqual(expect.arrayContaining([
30
+ 'http://tshost/prism/?op=CreateAnswerSession',
31
+ 'http://tshost/prism/?op=GetV2SourceDetail',
32
+ 'http://tshost/custom/path',
33
+ ]));
34
+ });
35
+
36
+ test('honors InterceptedApiType.ALL and interceptTimeout', () => {
37
+ const embedConfig: any = { enableApiIntercept: true, interceptTimeout: 2500 };
38
+ const viewConfig: any = { interceptUrls: [InterceptedApiType.ALL] };
39
+
40
+ const init = getInterceptInitData(embedConfig, viewConfig);
41
+
42
+ expect(init).toEqual({
43
+ enableApiIntercept: true,
44
+ interceptUrls: [InterceptedApiType.ALL],
45
+ interceptTimeout: 2500,
46
+ });
47
+ });
48
+
49
+ test('legacy flag isOnBeforeGetVizDataInterceptEnabled adds ANSWER_DATA', () => {
50
+ jest.spyOn(embedCfg, 'getEmbedConfig').mockReturnValue({ thoughtSpotHost: 'http://tshost' } as any);
51
+ jest.spyOn(cfg, 'getThoughtSpotHost').mockReturnValue('http://tshost');
52
+
53
+ const embedConfig: any = { enableApiIntercept: true };
54
+ const viewConfig: any = { isOnBeforeGetVizDataInterceptEnabled: true, interceptUrls: [] };
55
+
56
+ const init = getInterceptInitData(embedConfig, viewConfig);
57
+
58
+ // Should expand to concrete ANSWER_DATA URLs
59
+ expect(init.interceptUrls).toEqual(expect.arrayContaining([
60
+ 'http://tshost/prism/?op=GetChartWithData',
61
+ 'http://tshost/prism/?op=GetTableWithHeadlineData',
62
+ ]));
63
+ });
64
+
65
+ test('viewConfig enableApiIntercept=false overrides embed config', () => {
66
+ const embedConfig: any = { enableApiIntercept: true };
67
+ const viewConfig: any = { enableApiIntercept: false };
68
+ const init = getInterceptInitData(embedConfig, viewConfig);
69
+ expect(init).toEqual({ enableApiIntercept: false });
70
+ });
71
+ });
72
+
73
+ describe('processApiIntercept', () => {
74
+ test('parses data JSON string', async () => {
75
+ const result = await processApiIntercept({ data: JSON.stringify({ foo: 'bar' }) });
76
+ expect(result).toEqual({ foo: 'bar' });
77
+ });
78
+ });
79
+
80
+ describe('handleInterceptEvent', () => {
81
+ test('emits error on body parse failure', async () => {
82
+ const executeEvent = jest.fn();
83
+ const loggerErrSpy = jest.spyOn(logger, 'error').mockImplementation(() => undefined as any);
84
+ await handleInterceptEvent({
85
+ eventData: { data: 'not-a-json' },
86
+ executeEvent,
87
+ embedConfig: {} as any,
88
+ viewConfig: {} as any,
89
+ getUnsavedAnswerTml: jest.fn(),
90
+ });
91
+ expect(executeEvent).toHaveBeenCalledWith(EmbedEvent.Error, { error: 'Error parsing api intercept body' });
92
+ loggerErrSpy.mockReset();
93
+ });
94
+
95
+ test('calls getUnsavedAnswerTml and emits legacy + ApiIntercept events when applicable', async () => {
96
+ const executeEvent = jest.fn();
97
+ const getUnsavedAnswerTml = jest.fn().mockResolvedValue({ tml: 'TML_STRING' });
98
+
99
+ const eventPayload = {
100
+ input: '/prism/?op=GetChartWithData',
101
+ init: {
102
+ body: JSON.stringify({
103
+ variables: {
104
+ session: { sessionId: 'S1' },
105
+ contextBookId: 'V1',
106
+ },
107
+ }),
108
+ },
109
+ };
110
+
111
+ await handleInterceptEvent({
112
+ eventData: { data: JSON.stringify(eventPayload) },
113
+ executeEvent,
114
+ embedConfig: {} as any,
115
+ viewConfig: { isOnBeforeGetVizDataInterceptEnabled: true } as any,
116
+ getUnsavedAnswerTml,
117
+ });
118
+
119
+ expect(getUnsavedAnswerTml).toHaveBeenCalledWith({ sessionId: 'S1', vizId: 'V1' });
120
+ expect(executeEvent).toHaveBeenCalledWith(
121
+ EmbedEvent.OnBeforeGetVizDataIntercept,
122
+ { data: { data: { tml: 'TML_STRING' } } },
123
+ );
124
+ expect(executeEvent).toHaveBeenCalledWith(
125
+ EmbedEvent.ApiIntercept,
126
+ expect.objectContaining({ input: '/prism/?op=GetChartWithData' }),
127
+ );
128
+ });
129
+ });
130
+
131
+ describe('processLegacyInterceptResponse', () => {
132
+ test('wraps legacy error payload as expected', () => {
133
+ const payload = { data: { errorText: 'Title', errorDescription: 'Desc' } } as any;
134
+ const res = processLegacyInterceptResponse(payload);
135
+ expect(Array.isArray(res)).toBe(true);
136
+ expect(res[0]).toEqual(expect.objectContaining({
137
+ errors: [
138
+ expect.objectContaining({
139
+ errorObj: expect.objectContaining({ title: 'Title', desc: 'Desc' }),
140
+ }),
141
+ ],
142
+ }));
143
+ });
144
+ });
145
+ });
146
+
147
+
@@ -0,0 +1,134 @@
1
+ import { getThoughtSpotHost } from "./config";
2
+ import { getEmbedConfig } from "./embed/embedConfig";
3
+ import { InterceptedApiType, BaseViewConfig, EmbedConfig, InterceptV2Flags, EmbedEvent } from "./types";
4
+ import { logger } from "./utils/logger";
5
+
6
+
7
+ const defaultUrls: Record<Exclude<InterceptedApiType, InterceptedApiType.ALL>, string[]> = {
8
+ [InterceptedApiType.METADATA]: [
9
+ '/prism/?op=CreateAnswerSession',
10
+ '/prism/?op=GetV2SourceDetail',
11
+ ] as string[],
12
+ [InterceptedApiType.ANSWER_DATA]: [
13
+ '/prism/?op=GetChartWithData',
14
+ '/prism/?op=GetTableWithHeadlineData',
15
+ ] as string[],
16
+ [InterceptedApiType.LIVEBOARD_DATA]: [
17
+ '/prism/?op=LoadContextBook'
18
+ ] as string[],
19
+ };
20
+
21
+ const formatInterceptUrl = (url: string) => {
22
+ const host = getThoughtSpotHost(getEmbedConfig());
23
+ if (url.startsWith('/')) return `${host}${url}`;
24
+ return url;
25
+ }
26
+
27
+ export const processApiIntercept = async (eventData: any) => {
28
+
29
+ return JSON.parse(eventData.data);
30
+ }
31
+
32
+ interface LegacyInterceptFlags {
33
+ isOnBeforeGetVizDataInterceptEnabled: boolean;
34
+ }
35
+
36
+ const processInterceptUrls = (interceptUrls: (string | InterceptedApiType)[]) => {
37
+ let processedUrls = [...interceptUrls];
38
+ Object.entries(defaultUrls).forEach(([apiType, apiTypeUrls]) => {
39
+ if (!processedUrls.includes(apiType)) return;
40
+ processedUrls = processedUrls.filter(url => url !== apiType);
41
+ processedUrls = [...processedUrls, ...apiTypeUrls];
42
+ })
43
+ return processedUrls.map(url => formatInterceptUrl(url));
44
+ }
45
+ export const getInterceptInitData = (embedConfig: EmbedConfig, viewConfig: BaseViewConfig): InterceptV2Flags => {
46
+
47
+ const enableApiIntercept = (embedConfig.enableApiIntercept || viewConfig.enableApiIntercept) && (viewConfig.enableApiIntercept !== false);
48
+
49
+ if (!enableApiIntercept) return {
50
+ enableApiIntercept: false,
51
+ };
52
+
53
+ const combinedUrls = [...(embedConfig.interceptUrls || []), ...(viewConfig.interceptUrls || [])];
54
+
55
+ if ((viewConfig as LegacyInterceptFlags).isOnBeforeGetVizDataInterceptEnabled) {
56
+ combinedUrls.push(InterceptedApiType.ANSWER_DATA);
57
+ }
58
+
59
+ const shouldInterceptAll = combinedUrls.includes(InterceptedApiType.ALL);
60
+ const interceptUrls = shouldInterceptAll ? [InterceptedApiType.ALL] : processInterceptUrls(combinedUrls);
61
+
62
+ const interceptTimeout = embedConfig.interceptTimeout || viewConfig.interceptTimeout;
63
+
64
+ return {
65
+ interceptUrls,
66
+ interceptTimeout,
67
+ enableApiIntercept,
68
+ };
69
+ }
70
+
71
+ /**
72
+ *
73
+ * @param fetchInit
74
+ */
75
+ const parseInterceptData = (eventDataString: any) => {
76
+
77
+ try {
78
+ const { input, init } = JSON.parse(eventDataString);
79
+
80
+ init.body = JSON.parse(init.body);
81
+
82
+ const parsedInit = { input, init };
83
+ return [parsedInit, null];
84
+ } catch (error) {
85
+ return [null, error];
86
+ }
87
+ }
88
+
89
+ export const handleInterceptEvent = async (params: { eventData: any, executeEvent: (eventType: EmbedEvent, data: any) => void, embedConfig: EmbedConfig, viewConfig: BaseViewConfig, getUnsavedAnswerTml: (props: { sessionId?: string, vizId?: string }) => Promise<{ tml: string }> }) => {
90
+
91
+ const { eventData, executeEvent, viewConfig, getUnsavedAnswerTml } = params;
92
+
93
+ const [interceptData, bodyParseError] = parseInterceptData(eventData.data);
94
+
95
+ if (bodyParseError) {
96
+ executeEvent(EmbedEvent.Error, {
97
+ error: 'Error parsing api intercept body',
98
+ });
99
+ logger.error('Error parsing request body', bodyParseError);
100
+ return;
101
+ }
102
+
103
+ const { input: requestUrl, init } = interceptData;
104
+
105
+ const sessionId = init?.body?.variables?.session?.sessionId;
106
+ const vizId = init?.body?.variables?.contextBookId;
107
+
108
+ if (defaultUrls.ANSWER_DATA.includes(requestUrl) && (viewConfig as LegacyInterceptFlags).isOnBeforeGetVizDataInterceptEnabled) {
109
+ const answerTml = await getUnsavedAnswerTml({ sessionId, vizId });
110
+ executeEvent(EmbedEvent.OnBeforeGetVizDataIntercept, { data: { data: answerTml } });
111
+ }
112
+
113
+ executeEvent(EmbedEvent.ApiIntercept, interceptData);
114
+ }
115
+
116
+ export const processLegacyInterceptResponse = (payload: any) => {
117
+
118
+ const title = payload?.data?.errorText;
119
+ const desc = payload?.data?.errorDescription;
120
+
121
+ const payloadToSend = {
122
+ execute: payload?.data?.execute,
123
+ errors: [
124
+ {
125
+ errorObj: {
126
+ title,
127
+ desc
128
+ }
129
+ }
130
+ ],
131
+ };
132
+
133
+ return { data : payloadToSend };
134
+ }
@@ -358,6 +358,34 @@ describe('App embed tests', () => {
358
358
  });
359
359
  });
360
360
 
361
+ test('should set isLinkParametersEnabled to true in url', async () => {
362
+ const appEmbed = new AppEmbed(getRootEl(), {
363
+ ...defaultViewConfig,
364
+ isLinkParametersEnabled: true,
365
+ } as AppViewConfig);
366
+ appEmbed.render();
367
+ await executeAfterWait(() => {
368
+ expectUrlMatchesWithParams(
369
+ getIFrameSrc(),
370
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&isLinkParametersEnabled=true${defaultParamsPost}#/home`,
371
+ );
372
+ });
373
+ });
374
+
375
+ test('should set isLinkParametersEnabled to false in url', async () => {
376
+ const appEmbed = new AppEmbed(getRootEl(), {
377
+ ...defaultViewConfig,
378
+ isLinkParametersEnabled: false,
379
+ } as AppViewConfig);
380
+ appEmbed.render();
381
+ await executeAfterWait(() => {
382
+ expectUrlMatchesWithParams(
383
+ getIFrameSrc(),
384
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&isLinkParametersEnabled=false${defaultParamsPost}#/home`,
385
+ );
386
+ });
387
+ });
388
+
361
389
  test('should set liveboardXLSXCSVDownload to true in url', async () => {
362
390
  const appEmbed = new AppEmbed(getRootEl(), {
363
391
  ...defaultViewConfig,
package/src/embed/app.ts CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  AllEmbedViewConfig,
20
20
  } from '../types';
21
21
  import { V1Embed } from './ts-embed';
22
+ import { getInterceptInitData } from '../api-intercept';
22
23
 
23
24
  /**
24
25
  * Pages within the ThoughtSpot app that can be embedded.
@@ -663,6 +664,7 @@ export class AppEmbed extends V1Embed {
663
664
  liveboardXLSXCSVDownload = false,
664
665
  isLiveboardStylingAndGroupingEnabled,
665
666
  isPNGInScheduledEmailsEnabled = false,
667
+ isLinkParametersEnabled,
666
668
  } = this.viewConfig;
667
669
 
668
670
  let params: any = {};
@@ -727,7 +729,9 @@ export class AppEmbed extends V1Embed {
727
729
  params[Param.enableAskSage] = enableAskSage;
728
730
  }
729
731
 
730
- if (isOnBeforeGetVizDataInterceptEnabled) {
732
+ const { enableApiIntercept } = getInterceptInitData(this.embedConfig, this.viewConfig);
733
+
734
+ if (isOnBeforeGetVizDataInterceptEnabled && !enableApiIntercept) {
731
735
 
732
736
  params[
733
737
  Param.IsOnBeforeGetVizDataInterceptEnabled
@@ -750,6 +754,10 @@ export class AppEmbed extends V1Embed {
750
754
  params[Param.isPNGInScheduledEmailsEnabled] = isPNGInScheduledEmailsEnabled;
751
755
  }
752
756
 
757
+ if (isLinkParametersEnabled !== undefined) {
758
+ params[Param.isLinkParametersEnabled] = isLinkParametersEnabled;
759
+ }
760
+
753
761
  params[Param.DataPanelV2Enabled] = dataPanelV2;
754
762
  params[Param.HideHomepageLeftNav] = hideHomepageLeftNav;
755
763
  params[Param.ModularHomeExperienceEnabled] = modularHomeExperience;
@@ -7,6 +7,7 @@ export enum UIPassthroughEvent {
7
7
  GetAvailableUIPassthroughs = 'getAvailableUiPassthroughs',
8
8
  GetAnswerConfig = 'getAnswerPageConfig',
9
9
  GetLiveboardConfig = 'getPinboardPageConfig',
10
+ GetUnsavedAnswerTML = 'getUnsavedAnswerTML',
10
11
  }
11
12
 
12
13
  // UI Passthrough Contract
@@ -63,6 +64,15 @@ export type UIPassthroughContractBase = {
63
64
  request: any;
64
65
  response: any;
65
66
  };
67
+ [UIPassthroughEvent.GetUnsavedAnswerTML]: {
68
+ request: {
69
+ sessionId?: string;
70
+ vizId?: string;
71
+ };
72
+ response: {
73
+ tml: string;
74
+ };
75
+ };
66
76
  };
67
77
 
68
78
  // UI Passthrough Request and Response
@@ -183,6 +183,36 @@ describe('Liveboard/viz embed tests', () => {
183
183
  });
184
184
  });
185
185
 
186
+ test('should set isLinkParametersEnabled to true in url', async () => {
187
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
188
+ isLinkParametersEnabled: true,
189
+ ...defaultViewConfig,
190
+ liveboardId,
191
+ } as LiveboardViewConfig);
192
+ liveboardEmbed.render();
193
+ await executeAfterWait(() => {
194
+ expectUrlMatchesWithParams(
195
+ getIFrameSrc(),
196
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLinkParametersEnabled=true${prefixParams}#/embed/viz/${liveboardId}`,
197
+ );
198
+ });
199
+ });
200
+
201
+ test('should set isLinkParametersEnabled to false in url', async () => {
202
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
203
+ isLinkParametersEnabled: false,
204
+ ...defaultViewConfig,
205
+ liveboardId,
206
+ } as LiveboardViewConfig);
207
+ liveboardEmbed.render();
208
+ await executeAfterWait(() => {
209
+ expectUrlMatchesWithParams(
210
+ getIFrameSrc(),
211
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLinkParametersEnabled=false${prefixParams}#/embed/viz/${liveboardId}`,
212
+ );
213
+ });
214
+ });
215
+
186
216
  test('should set visible actions as empty array', async () => {
187
217
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
188
218
  visibleActions: [],
@@ -477,6 +477,7 @@ export class LiveboardEmbed extends V1Embed {
477
477
  isLiveboardStylingAndGroupingEnabled,
478
478
  isPNGInScheduledEmailsEnabled = false,
479
479
  showSpotterLimitations,
480
+ isLinkParametersEnabled,
480
481
  } = this.viewConfig;
481
482
 
482
483
  const preventLiveboardFilterRemoval = this.viewConfig.preventLiveboardFilterRemoval
@@ -552,6 +553,10 @@ export class LiveboardEmbed extends V1Embed {
552
553
  params[Param.ShowSpotterLimitations] = showSpotterLimitations;
553
554
  }
554
555
 
556
+ if (isLinkParametersEnabled !== undefined) {
557
+ params[Param.isLinkParametersEnabled] = isLinkParametersEnabled;
558
+ }
559
+
555
560
  params[Param.LiveboardHeaderSticky] = isLiveboardHeaderSticky;
556
561
  params[Param.LiveboardHeaderV2] = isLiveboardCompactHeaderEnabled;
557
562
  params[Param.ShowLiveboardVerifiedBadge] = showLiveboardVerifiedBadge;
@@ -26,6 +26,7 @@ import { ERROR_MESSAGE } from '../errors';
26
26
  import { getAuthPromise } from './base';
27
27
  import { getReleaseVersion } from '../auth';
28
28
  import { getEmbedConfig } from './embedConfig';
29
+ import { getInterceptInitData } from '../api-intercept';
29
30
 
30
31
  /**
31
32
  * Configuration for search options.
@@ -442,7 +443,8 @@ export class SearchEmbed extends TsEmbed {
442
443
  queryParams[Param.HideSearchBar] = true;
443
444
  }
444
445
 
445
- if (isOnBeforeGetVizDataInterceptEnabled) {
446
+ const { enableApiIntercept } = getInterceptInitData(this.embedConfig, this.viewConfig);
447
+ if (isOnBeforeGetVizDataInterceptEnabled && !enableApiIntercept) {
446
448
 
447
449
  queryParams[Param.IsOnBeforeGetVizDataInterceptEnabled] = isOnBeforeGetVizDataInterceptEnabled;
448
450
  }