@thoughtspot/visual-embed-sdk 1.39.1 → 1.39.2-alpha.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.
Files changed (98) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/embed/app.d.ts.map +1 -1
  3. package/cjs/src/embed/app.js +2 -1
  4. package/cjs/src/embed/app.js.map +1 -1
  5. package/cjs/src/embed/app.spec.js +18 -8
  6. package/cjs/src/embed/app.spec.js.map +1 -1
  7. package/cjs/src/embed/conversation.d.ts +60 -2
  8. package/cjs/src/embed/conversation.d.ts.map +1 -1
  9. package/cjs/src/embed/conversation.js +9 -1
  10. package/cjs/src/embed/conversation.js.map +1 -1
  11. package/cjs/src/embed/conversation.spec.js +130 -0
  12. package/cjs/src/embed/conversation.spec.js.map +1 -1
  13. package/cjs/src/embed/embedConfig.d.ts +9 -7
  14. package/cjs/src/embed/embedConfig.d.ts.map +1 -1
  15. package/cjs/src/embed/embedConfig.js +9 -7
  16. package/cjs/src/embed/embedConfig.js.map +1 -1
  17. package/cjs/src/embed/liveboard.d.ts +0 -17
  18. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  19. package/cjs/src/embed/liveboard.js +2 -4
  20. package/cjs/src/embed/liveboard.js.map +1 -1
  21. package/cjs/src/embed/liveboard.spec.js +12 -11
  22. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  23. package/cjs/src/embed/ts-embed.d.ts +5 -0
  24. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  25. package/cjs/src/embed/ts-embed.js +16 -1
  26. package/cjs/src/embed/ts-embed.js.map +1 -1
  27. package/cjs/src/embed/ts-embed.spec.js +164 -0
  28. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  29. package/cjs/src/types.d.ts +34 -2
  30. package/cjs/src/types.d.ts.map +1 -1
  31. package/cjs/src/types.js +17 -1
  32. package/cjs/src/types.js.map +1 -1
  33. package/dist/{index-JaFaxrvQ.js → index-CmEQfuE3.js} +1 -1
  34. package/dist/index-DeFzsyFF.js +7371 -0
  35. package/dist/index-Dpf0rd6w.js +7371 -0
  36. package/dist/index-UuEbsISo.js +7447 -0
  37. package/dist/src/embed/app.d.ts.map +1 -1
  38. package/dist/src/embed/conversation.d.ts +60 -2
  39. package/dist/src/embed/conversation.d.ts.map +1 -1
  40. package/dist/src/embed/embedConfig.d.ts +9 -7
  41. package/dist/src/embed/embedConfig.d.ts.map +1 -1
  42. package/dist/src/embed/liveboard.d.ts +0 -17
  43. package/dist/src/embed/liveboard.d.ts.map +1 -1
  44. package/dist/src/embed/ts-embed.d.ts +5 -0
  45. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  46. package/dist/src/types.d.ts +34 -2
  47. package/dist/src/types.d.ts.map +1 -1
  48. package/dist/tsembed-react.es.js +58 -18
  49. package/dist/tsembed-react.js +57 -17
  50. package/dist/tsembed.es.js +58 -18
  51. package/dist/tsembed.js +57 -17
  52. package/dist/visual-embed-sdk-react-full.d.ts +102 -27
  53. package/dist/visual-embed-sdk-react.d.ts +102 -27
  54. package/dist/visual-embed-sdk.d.ts +102 -27
  55. package/lib/package.json +1 -1
  56. package/lib/src/embed/app.d.ts.map +1 -1
  57. package/lib/src/embed/app.js +2 -1
  58. package/lib/src/embed/app.js.map +1 -1
  59. package/lib/src/embed/app.spec.js +19 -9
  60. package/lib/src/embed/app.spec.js.map +1 -1
  61. package/lib/src/embed/conversation.d.ts +60 -2
  62. package/lib/src/embed/conversation.d.ts.map +1 -1
  63. package/lib/src/embed/conversation.js +10 -2
  64. package/lib/src/embed/conversation.js.map +1 -1
  65. package/lib/src/embed/conversation.spec.js +133 -3
  66. package/lib/src/embed/conversation.spec.js.map +1 -1
  67. package/lib/src/embed/embedConfig.d.ts +9 -7
  68. package/lib/src/embed/embedConfig.d.ts.map +1 -1
  69. package/lib/src/embed/embedConfig.js +9 -7
  70. package/lib/src/embed/embedConfig.js.map +1 -1
  71. package/lib/src/embed/liveboard.d.ts +0 -17
  72. package/lib/src/embed/liveboard.d.ts.map +1 -1
  73. package/lib/src/embed/liveboard.js +2 -4
  74. package/lib/src/embed/liveboard.js.map +1 -1
  75. package/lib/src/embed/liveboard.spec.js +12 -11
  76. package/lib/src/embed/liveboard.spec.js.map +1 -1
  77. package/lib/src/embed/ts-embed.d.ts +5 -0
  78. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  79. package/lib/src/embed/ts-embed.js +16 -1
  80. package/lib/src/embed/ts-embed.js.map +1 -1
  81. package/lib/src/embed/ts-embed.spec.js +164 -0
  82. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  83. package/lib/src/types.d.ts +34 -2
  84. package/lib/src/types.d.ts.map +1 -1
  85. package/lib/src/types.js +17 -1
  86. package/lib/src/types.js.map +1 -1
  87. package/lib/src/visual-embed-sdk.d.ts +103 -28
  88. package/package.json +1 -1
  89. package/src/embed/app.spec.ts +36 -23
  90. package/src/embed/app.ts +2 -0
  91. package/src/embed/conversation.spec.ts +170 -6
  92. package/src/embed/conversation.ts +82 -10
  93. package/src/embed/embedConfig.ts +10 -8
  94. package/src/embed/liveboard.spec.ts +5 -4
  95. package/src/embed/liveboard.ts +2 -22
  96. package/src/embed/ts-embed.spec.ts +225 -0
  97. package/src/embed/ts-embed.ts +19 -0
  98. package/src/types.ts +75 -43
@@ -1,10 +1,10 @@
1
1
  import isUndefined from 'lodash/isUndefined';
2
2
  import { ERROR_MESSAGE } from '../errors';
3
- import { Param, BaseViewConfig } from '../types';
3
+ import { Param, BaseViewConfig, RuntimeFilter, RuntimeParameter } from '../types';
4
4
  import { TsEmbed } from './ts-embed';
5
- import { getQueryParamString } from '../utils';
5
+ import { getQueryParamString, getFilterQuery, getRuntimeParameters } from '../utils';
6
6
 
7
- /**
7
+ /**
8
8
  * Configuration for search options
9
9
  */
10
10
  export interface SearchOptions {
@@ -20,7 +20,8 @@ export interface SearchOptions {
20
20
  */
21
21
  export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAction'> {
22
22
  /**
23
- * The ID of the data source object. For example, Model, View, or Table. Spotter uses this object to query data and generate Answers.
23
+ * The ID of the data source object. For example, Model, View, or Table. Spotter uses
24
+ * this object to query data and generate Answers.
24
25
  */
25
26
  worksheetId: string;
26
27
  /**
@@ -30,7 +31,7 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
30
31
  /**
31
32
  * disableSourceSelection : Disables data source selection
32
33
  * but still display the selected data source.
33
- *
34
+ *
34
35
  * Supported embed types: `SpotterEmbed`
35
36
  * @example
36
37
  * ```js
@@ -44,7 +45,7 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
44
45
  disableSourceSelection?: boolean;
45
46
  /**
46
47
  * hideSourceSelection : Hide data source selection
47
- *
48
+ *
48
49
  * Supported embed types: `SpotterEmbed`
49
50
  * @example
50
51
  * ```js
@@ -58,7 +59,7 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
58
59
  hideSourceSelection?: boolean;
59
60
  /**
60
61
  * Flag to control Data panel experience
61
- *
62
+ *
62
63
  * Supported embed types: `SageEmbed`, `AppEmbed`, `SearchBarEmbed`, `LiveboardEmbed`, `SearchEmbed`
63
64
  * @default false
64
65
  * @version SDK: 1.36.0 | ThoughtSpot Cloud: 10.4.0.cl
@@ -76,7 +77,7 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
76
77
  * showSpotterLimitations : show limitation text
77
78
  * of the spotter underneath the chat input.
78
79
  * default is false.
79
- *
80
+ *
80
81
  * Supported embed types: `SpotterEmbed`
81
82
  * @example
82
83
  * ```js
@@ -91,7 +92,7 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
91
92
  /**
92
93
  * hideSampleQuestions : Hide sample questions on
93
94
  * the initial screen of the conversation.
94
- *
95
+ *
95
96
  * Supported embed types: `SpotterEmbed`
96
97
  * @example
97
98
  * ```js
@@ -103,6 +104,63 @@ export interface SpotterEmbedViewConfig extends Omit<BaseViewConfig, 'primaryAct
103
104
  * @version SDK: 1.36.0 | ThoughtSpot: 10.6.0.cl
104
105
  */
105
106
  hideSampleQuestions?: boolean;
107
+ /**
108
+ * The list of runtime filters to apply to a search Answer,
109
+ * visualization, or Liveboard.
110
+ *
111
+ * Supported embed types: `SpotterEmbed`
112
+ * @example
113
+ * ```js
114
+ * const embed = new SpotterEmbed('#tsEmbed', {
115
+ * ... // other embed view config
116
+ * runtimeFilters: [
117
+ * {
118
+ * columnName: 'value',
119
+ * operator: RuntimeFilterOp.EQ,
120
+ * values: ['string' | 123 | true],
121
+ * },
122
+ * ],
123
+ * })
124
+ * ```
125
+ */
126
+ runtimeFilters?: RuntimeFilter[];
127
+ /**
128
+ * Flag to control whether runtime filters should be included in the URL.
129
+ * If true, filters will be passed via app initialization payload instead.
130
+ * If false/undefined, filters will be added to URL (default behavior).
131
+ *
132
+ * Supported embed types: `SpotterEmbed`
133
+ * @default false
134
+ */
135
+ excludeRuntimeFiltersfromURL?: boolean;
136
+ /**
137
+ * The list of runtime parameters to apply to the conversation.
138
+ *
139
+ * Supported embed types: `SpotterEmbed`
140
+ * @example
141
+ * ```js
142
+ * const embed = new SpotterEmbed('#tsEmbed', {
143
+ * ... // other embed view config
144
+ * runtimeParameters: [
145
+ * {
146
+ * name: 'Parameter Name',
147
+ * value: 'Parameter Value',
148
+ * },
149
+ * ],
150
+ * })
151
+ * ```
152
+ */
153
+ runtimeParameters?: RuntimeParameter[];
154
+ /**
155
+ * Flag to control whether runtime parameters should be included in the URL.
156
+ * If true, parameters will be passed via app initialization payload instead.
157
+ * If false/undefined, parameters will be added to URL (default behavior).
158
+ *
159
+ * Supported embed types: `SpotterEmbed`
160
+ * @default false
161
+ *
162
+ */
163
+ excludeRuntimeParametersfromURL?: boolean;
106
164
  }
107
165
 
108
166
  /**
@@ -144,6 +202,10 @@ export class SpotterEmbed extends TsEmbed {
144
202
  dataPanelV2,
145
203
  showSpotterLimitations,
146
204
  hideSampleQuestions,
205
+ runtimeFilters,
206
+ excludeRuntimeFiltersfromURL,
207
+ runtimeParameters,
208
+ excludeRuntimeParametersfromURL,
147
209
  } = this.viewConfig;
148
210
  const path = 'insights/conv-assist';
149
211
  if (!worksheetId) {
@@ -175,11 +237,21 @@ export class SpotterEmbed extends TsEmbed {
175
237
  if (queryParamsString) {
176
238
  query = `?${queryParamsString}`;
177
239
  }
240
+
241
+ const filterQuery = getFilterQuery(runtimeFilters || []);
242
+ if (filterQuery && !excludeRuntimeFiltersfromURL) {
243
+ query += `&${filterQuery}`;
244
+ }
245
+
246
+ const parameterQuery = getRuntimeParameters(runtimeParameters || []);
247
+ if (parameterQuery && !excludeRuntimeParametersfromURL) {
248
+ query += `&${parameterQuery}`;
249
+ }
250
+
178
251
  const tsPostHashParams = this.getThoughtSpotPostUrlParams({
179
252
  worksheet: worksheetId,
180
253
  query: searchOptions?.searchQuery || '',
181
254
  });
182
-
183
255
  return `${this.getEmbedBasePath(query)}/embed/${path}${tsPostHashParams}`;
184
256
  }
185
257
 
@@ -10,13 +10,14 @@ const configKey = 'embedConfig';
10
10
  *
11
11
  * @example
12
12
  * ```js
13
+ * import { getInitConfig } from '@thoughtspot/visual-embed-sdk';
14
+ * // Call the getInitConfig method to retrieve the embed configuration
13
15
  * const config = getInitConfig();
16
+ * // Log the configuration settings
14
17
  * console.log(config);
15
18
  * ```
16
- * @example
17
- *
18
- * Returns the `EmbedConfig` object, which
19
- * contains the configuration settings used to
19
+ * Returns the link:https://developers.thoughtspot.com/docs/Interface_EmbedConfig[EmbedConfig]
20
+ * object, which contains the configuration settings used to
20
21
  * initialize the SDK, including the following:
21
22
  *
22
23
  * - `thoughtSpotHost` - ThoughtSpot host URL
@@ -24,10 +25,11 @@ const configKey = 'embedConfig';
24
25
  * `AuthServerCookieless` for `AuthType.TrustedAuthTokenCookieless`
25
26
  * - `customizations` - Style, text, and icon customization settings
26
27
  * that were applied during the SDK initialization.
27
- *
28
- * For a comprehensive list of embed configuration settings,
29
- * see link:https://developers.thoughtspot.com/docs/Interface_EmbedConfig[Developer Documentation].
30
28
  *
29
+ * The following JSON output shows the embed configuration
30
+ * settings returned from the code in the previous example:
31
+ *
32
+ * @example
31
33
  * ```json
32
34
  * {
33
35
  * "thoughtSpotHost": "https://{ThoughtSpot-Host}",
@@ -49,7 +51,7 @@ const configKey = 'embedConfig';
49
51
  * "authTriggerContainer": "#your-own-div"
50
52
  * }
51
53
  * ```
52
- * @version SDK: 1.19.0 | ThoughtSpot: 9.0.0.cl, 9.0.1.cl, and later
54
+ * @version SDK: 1.19.0 | ThoughtSpot: 9.0.0.cl, 9.0.1.sw, and later
53
55
  * @group Global methods
54
56
  */
55
57
  export const getEmbedConfig = (): EmbedConfig => getValueFromWindow(configKey) || ({} as any);
@@ -347,7 +347,7 @@ describe('Liveboard/viz embed tests', () => {
347
347
  await executeAfterWait(() => {
348
348
  expectUrlMatchesWithParams(
349
349
  getIFrameSrc(),
350
- `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&coverAndFilterOptionInPDF=true${prefixParams}#/embed/viz/${liveboardId}`,
350
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&arePdfCoverFilterPageCheckboxesEnabled=true${prefixParams}#/embed/viz/${liveboardId}`,
351
351
  );
352
352
  });
353
353
  });
@@ -362,7 +362,7 @@ describe('Liveboard/viz embed tests', () => {
362
362
  await executeAfterWait(() => {
363
363
  expectUrlMatchesWithParams(
364
364
  getIFrameSrc(),
365
- `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&coverAndFilterOptionInPDF=false&${prefixParams}#/embed/viz/${liveboardId}`,
365
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&arePdfCoverFilterPageCheckboxesEnabled=false&${prefixParams}#/embed/viz/${liveboardId}`,
366
366
  );
367
367
  });
368
368
  });
@@ -770,8 +770,9 @@ describe('Liveboard/viz embed tests', () => {
770
770
  });
771
771
 
772
772
  let resizeObserverCb: any;
773
- (window as any).ResizeObserver = window.ResizeObserver
774
- || jest.fn().mockImplementation((resizeObserverCbParam: any) => {
773
+ (window as any).ResizeObserver =
774
+ window.ResizeObserver ||
775
+ jest.fn().mockImplementation((resizeObserverCbParam: any) => {
775
776
  resizeObserverCb = resizeObserverCbParam;
776
777
  return {
777
778
  disconnect: jest.fn(),
@@ -269,24 +269,6 @@ export interface LiveboardViewConfig extends BaseViewConfig, LiveboardOtherViewC
269
269
  * })
270
270
  */
271
271
  dataSourceId?: string;
272
-
273
- /**
274
- * This flag is for show/hide checkboxes for include or exclude
275
- * cover page and filters in the Liveboard PDF.
276
- *
277
- * Supported embed types: `LiveboardEmbed`
278
- * @version SDK: 1.37.0 | ThoughtSpot:10.8.0.cl
279
- * @default true
280
- * Supported embed types: `LiveboardEmbed`
281
- * @example
282
- * ```js
283
- * const embed = new LiveboardEmbed('#tsEmbed', {
284
- * ... //other embed view config
285
- * coverAndFilterOptionInPDF: false,
286
- * })
287
- * ```
288
- */
289
- coverAndFilterOptionInPDF?: boolean;
290
272
  /**
291
273
  * The list of tab IDs to hide from the embedded.
292
274
  * This Tabs will be hidden from their respective LBs.
@@ -411,7 +393,7 @@ export class LiveboardEmbed extends V1Embed {
411
393
  oAuthPollingInterval,
412
394
  isForceRedirect,
413
395
  dataSourceId,
414
- coverAndFilterOptionInPDF,
396
+ coverAndFilterOptionInPDF = false,
415
397
  isLiveboardStylingAndGroupingEnabled,
416
398
  } = this.viewConfig;
417
399
 
@@ -471,9 +453,6 @@ export class LiveboardEmbed extends V1Embed {
471
453
  params[Param.DataSourceId] = dataSourceId;
472
454
  }
473
455
 
474
- if (coverAndFilterOptionInPDF !== undefined) {
475
- params[Param.CoverAndFilterOptionInPDF] = coverAndFilterOptionInPDF;
476
- }
477
456
 
478
457
  if (isLiveboardStylingAndGroupingEnabled !== undefined) {
479
458
  params[Param.IsLiveboardStylingAndGroupingEnabled] = isLiveboardStylingAndGroupingEnabled;
@@ -486,6 +465,7 @@ export class LiveboardEmbed extends V1Embed {
486
465
  params[Param.HideIrrelevantFiltersInTab] = hideIrrelevantChipsInLiveboardTabs;
487
466
  params[Param.DataPanelV2Enabled] = dataPanelV2;
488
467
  params[Param.EnableCustomColumnGroups] = enableCustomColumnGroups;
468
+ params[Param.CoverAndFilterOptionInPDF] = coverAndFilterOptionInPDF;
489
469
  const queryParams = getQueryParamString(params, true);
490
470
 
491
471
  return queryParams;
@@ -1360,6 +1360,231 @@ describe('Unit test case for ts embed', () => {
1360
1360
  });
1361
1361
  });
1362
1362
 
1363
+ describe('Preauth Cache for FullAppEmbed with PrimaryNavBar', () => {
1364
+ beforeAll(() => {
1365
+ jest.clearAllMocks();
1366
+ init({
1367
+ thoughtSpotHost,
1368
+ authType: AuthType.None,
1369
+ });
1370
+ });
1371
+ afterEach(() => {
1372
+ jest.clearAllMocks();
1373
+ });
1374
+
1375
+ afterAll(() => {
1376
+ jest.clearAllMocks();
1377
+ });
1378
+
1379
+ const setupPreauthTest = async (
1380
+ embedType: 'AppEmbed' | 'SearchEmbed',
1381
+ showPrimaryNavbar?: boolean,
1382
+ overrideOrgId?: number,
1383
+ disablePreauthCache?: boolean
1384
+ ) => {
1385
+ jest.spyOn(window, 'addEventListener').mockImplementationOnce(
1386
+ (event, handler, options) => {
1387
+ handler({
1388
+ data: { type: 'xyz' },
1389
+ ports: [3000],
1390
+ source: null,
1391
+ });
1392
+ },
1393
+ );
1394
+ mockProcessTrigger.mockResolvedValueOnce({ session: 'test' });
1395
+ jest.spyOn(baseInstance, 'getAuthPromise').mockResolvedValueOnce(true);
1396
+
1397
+ let mockGetPreauthInfo = null;
1398
+
1399
+ // Determine if preauth cache should be enabled
1400
+ const isAppEmbedWithPrimaryNavbar = embedType === 'AppEmbed' && showPrimaryNavbar === true;
1401
+ const shouldDisableCache = overrideOrgId || disablePreauthCache || isAppEmbedWithPrimaryNavbar;
1402
+
1403
+ if (shouldDisableCache) {
1404
+ mockGetPreauthInfo = jest.spyOn(sessionInfoService, 'getPreauthInfo')
1405
+ .mockImplementation(jest.fn());
1406
+ } else {
1407
+ mockGetPreauthInfo = jest.spyOn(sessionInfoService, 'getPreauthInfo')
1408
+ .mockResolvedValue({ info: { test: 'data' } });
1409
+ }
1410
+
1411
+ const mockPreauthInfoFetch = jest.spyOn(authService, 'fetchPreauthInfoService')
1412
+ .mockResolvedValueOnce({
1413
+ ok: true,
1414
+ headers: new Headers({ 'content-type': 'application/json' }),
1415
+ json: async () => ({
1416
+ info: { test: 'data' },
1417
+ }),
1418
+ } as any);
1419
+
1420
+ const viewConfig: any = {
1421
+ frameParams: { width: 1280, height: 720 },
1422
+ };
1423
+
1424
+ if (showPrimaryNavbar !== undefined) {
1425
+ viewConfig.showPrimaryNavbar = showPrimaryNavbar;
1426
+ }
1427
+ if (overrideOrgId !== undefined) {
1428
+ viewConfig.overrideOrgId = overrideOrgId;
1429
+ }
1430
+
1431
+ // Mock getEmbedConfig for disablePreauthCache
1432
+ if (disablePreauthCache !== undefined) {
1433
+ jest.spyOn(embedConfig, 'getEmbedConfig').mockReturnValueOnce({
1434
+ thoughtSpotHost,
1435
+ authType: AuthType.None,
1436
+ disablePreauthCache,
1437
+ });
1438
+ }
1439
+
1440
+ let embed;
1441
+ if (embedType === 'AppEmbed') {
1442
+ embed = new AppEmbed(getRootEl(), viewConfig);
1443
+ } else {
1444
+ embed = new SearchEmbed(getRootEl(), viewConfig);
1445
+ }
1446
+
1447
+ const iFrame: any = document.createElement('div');
1448
+ iFrame.contentWindow = {
1449
+ postMessage: jest.fn(),
1450
+ };
1451
+ jest.spyOn(iFrame, 'addEventListener').mockImplementationOnce(
1452
+ (event, handler, options) => {
1453
+ handler({});
1454
+ },
1455
+ );
1456
+ jest.spyOn(document, 'createElement').mockReturnValueOnce(iFrame);
1457
+
1458
+ await embed.render();
1459
+
1460
+ return {
1461
+ embed,
1462
+ mockGetPreauthInfo,
1463
+ mockPreauthInfoFetch,
1464
+ iFrame,
1465
+ };
1466
+ };
1467
+
1468
+ test('should disable preauth cache for FullAppEmbed with showPrimaryNavbar = true (default)', async () => {
1469
+ const { mockGetPreauthInfo } = await setupPreauthTest('AppEmbed', true);
1470
+
1471
+ // Wait for any async operations
1472
+ await executeAfterWait(() => {
1473
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
1474
+ });
1475
+ });
1476
+
1477
+ test('should enable preauth cache for FullAppEmbed with showPrimaryNavbar = undefined (no longer defaults to true)', async () => {
1478
+ const { mockGetPreauthInfo } = await setupPreauthTest('AppEmbed', undefined);
1479
+
1480
+ await executeAfterWait(() => {
1481
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(1);
1482
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
1483
+ expect.any(Object),
1484
+ HostEvent.InfoSuccess,
1485
+ 'http://tshost',
1486
+ expect.objectContaining({ info: expect.any(Object) }),
1487
+ );
1488
+ });
1489
+ });
1490
+
1491
+ test('should enable preauth cache for FullAppEmbed with showPrimaryNavbar = false', async () => {
1492
+ const { mockGetPreauthInfo } = await setupPreauthTest('AppEmbed', false);
1493
+
1494
+ await executeAfterWait(() => {
1495
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(1);
1496
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
1497
+ expect.any(Object),
1498
+ HostEvent.InfoSuccess,
1499
+ 'http://tshost',
1500
+ expect.objectContaining({ info: expect.any(Object) }),
1501
+ );
1502
+ });
1503
+ });
1504
+
1505
+ test('should enable preauth cache for SearchEmbed regardless of showPrimaryNavbar', async () => {
1506
+ const { mockGetPreauthInfo } = await setupPreauthTest('SearchEmbed', true);
1507
+
1508
+ await executeAfterWait(() => {
1509
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(1);
1510
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
1511
+ expect.any(Object),
1512
+ HostEvent.InfoSuccess,
1513
+ 'http://tshost',
1514
+ expect.objectContaining({ info: expect.any(Object) }),
1515
+ );
1516
+ });
1517
+ });
1518
+
1519
+ test('should enable preauth cache for SearchEmbed (verifies fix for embed type regression)', async () => {
1520
+ const { mockGetPreauthInfo } = await setupPreauthTest('SearchEmbed', false);
1521
+
1522
+ await executeAfterWait(() => {
1523
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(1);
1524
+ expect(mockProcessTrigger).toHaveBeenCalledWith(
1525
+ expect.any(Object),
1526
+ HostEvent.InfoSuccess,
1527
+ 'http://tshost',
1528
+ expect.objectContaining({ info: expect.any(Object) }),
1529
+ );
1530
+ });
1531
+ });
1532
+
1533
+ test('should disable preauth cache for FullAppEmbed with overrideOrgId (combined condition)', async () => {
1534
+ const { mockGetPreauthInfo } = await setupPreauthTest('AppEmbed', false, 123);
1535
+
1536
+ await executeAfterWait(() => {
1537
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
1538
+ });
1539
+ });
1540
+
1541
+ test('should disable preauth cache for FullAppEmbed with disablePreauthCache = true', async () => {
1542
+ const { mockGetPreauthInfo } = await setupPreauthTest('AppEmbed', false, undefined, true);
1543
+
1544
+ await executeAfterWait(() => {
1545
+ expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
1546
+ });
1547
+ });
1548
+ });
1549
+
1550
+ describe('isFullAppEmbedWithVisiblePrimaryNavbar helper method', () => {
1551
+ beforeAll(() => {
1552
+ init({
1553
+ thoughtSpotHost,
1554
+ authType: AuthType.None,
1555
+ });
1556
+ });
1557
+
1558
+ afterEach(() => {
1559
+ jest.clearAllMocks();
1560
+ });
1561
+
1562
+ test('should return true for AppEmbed with showPrimaryNavbar = true', () => {
1563
+ const appEmbed = new AppEmbed(getRootEl(), { showPrimaryNavbar: true });
1564
+ expect(appEmbed['isFullAppEmbedWithVisiblePrimaryNavbar']()).toBe(true);
1565
+ });
1566
+
1567
+ test('should return false for AppEmbed with showPrimaryNavbar = undefined (no longer defaults to true)', () => {
1568
+ const appEmbed = new AppEmbed(getRootEl(), {});
1569
+ expect(appEmbed['isFullAppEmbedWithVisiblePrimaryNavbar']()).toBe(false);
1570
+ });
1571
+
1572
+ test('should return false for AppEmbed with showPrimaryNavbar = false', () => {
1573
+ const appEmbed = new AppEmbed(getRootEl(), { showPrimaryNavbar: false });
1574
+ expect(appEmbed['isFullAppEmbedWithVisiblePrimaryNavbar']()).toBe(false);
1575
+ });
1576
+
1577
+ test('should return false for SearchEmbed (not FullAppEmbed)', () => {
1578
+ const searchEmbed = new SearchEmbed(getRootEl(), {});
1579
+ expect(searchEmbed['isFullAppEmbedWithVisiblePrimaryNavbar']()).toBe(false);
1580
+ });
1581
+
1582
+ test('should return false for LiveboardEmbed (not FullAppEmbed)', () => {
1583
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), { liveboardId: 'test-id' });
1584
+ expect(liveboardEmbed['isFullAppEmbedWithVisiblePrimaryNavbar']()).toBe(false);
1585
+ });
1586
+ });
1587
+
1363
1588
  describe('when thoughtSpotHost have value and authPromise return error', () => {
1364
1589
  beforeAll(() => {
1365
1590
  init({
@@ -264,13 +264,32 @@ export class TsEmbed {
264
264
  // - cached auth info would be for wrong org
265
265
  // - info call response changes for each different overrideOrgId
266
266
  // 2. disablePreauthCache is explicitly set to true
267
+ // 3. FullAppEmbed has primary navbar visible since:
268
+ // - primary navbar requires fresh auth state for navigation
269
+ // - cached auth may not reflect current user permissions
267
270
  const isDisabled = (
268
271
  this.viewConfig.overrideOrgId !== undefined
269
272
  || this.embedConfig.disablePreauthCache === true
273
+ || this.isFullAppEmbedWithVisiblePrimaryNavbar()
270
274
  );
271
275
  return !isDisabled;
272
276
  }
273
277
 
278
+ /**
279
+ * Checks if current embed is FullAppEmbed with visible primary navbar
280
+ * @returns boolean
281
+ */
282
+ private isFullAppEmbedWithVisiblePrimaryNavbar(): boolean {
283
+ const appViewConfig = this.viewConfig as any;
284
+
285
+ // Check if this is a FullAppEmbed (AppEmbed)
286
+ // showPrimaryNavbar defaults to true if not explicitly set to false
287
+ return (
288
+ appViewConfig.embedComponentType === 'AppEmbed'
289
+ && appViewConfig.showPrimaryNavbar === true
290
+ );
291
+ }
292
+
274
293
  /**
275
294
  * fix for ts7.sep.cl
276
295
  * will be removed for ts7.oct.cl