@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.
- package/cjs/package.json +1 -1
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +2 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +18 -8
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +60 -2
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +9 -1
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +130 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/embedConfig.d.ts +9 -7
- package/cjs/src/embed/embedConfig.d.ts.map +1 -1
- package/cjs/src/embed/embedConfig.js +9 -7
- package/cjs/src/embed/embedConfig.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +0 -17
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +2 -4
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +12 -11
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +5 -0
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +16 -1
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +164 -0
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/types.d.ts +34 -2
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +17 -1
- package/cjs/src/types.js.map +1 -1
- package/dist/{index-JaFaxrvQ.js → index-CmEQfuE3.js} +1 -1
- package/dist/index-DeFzsyFF.js +7371 -0
- package/dist/index-Dpf0rd6w.js +7371 -0
- package/dist/index-UuEbsISo.js +7447 -0
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +60 -2
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/embedConfig.d.ts +9 -7
- package/dist/src/embed/embedConfig.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +0 -17
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +5 -0
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/types.d.ts +34 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +58 -18
- package/dist/tsembed-react.js +57 -17
- package/dist/tsembed.es.js +58 -18
- package/dist/tsembed.js +57 -17
- package/dist/visual-embed-sdk-react-full.d.ts +102 -27
- package/dist/visual-embed-sdk-react.d.ts +102 -27
- package/dist/visual-embed-sdk.d.ts +102 -27
- package/lib/package.json +1 -1
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +2 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +19 -9
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +60 -2
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +10 -2
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +133 -3
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/embedConfig.d.ts +9 -7
- package/lib/src/embed/embedConfig.d.ts.map +1 -1
- package/lib/src/embed/embedConfig.js +9 -7
- package/lib/src/embed/embedConfig.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +0 -17
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +2 -4
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +12 -11
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +5 -0
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +16 -1
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +164 -0
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/types.d.ts +34 -2
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +17 -1
- package/lib/src/types.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +103 -28
- package/package.json +1 -1
- package/src/embed/app.spec.ts +36 -23
- package/src/embed/app.ts +2 -0
- package/src/embed/conversation.spec.ts +170 -6
- package/src/embed/conversation.ts +82 -10
- package/src/embed/embedConfig.ts +10 -8
- package/src/embed/liveboard.spec.ts +5 -4
- package/src/embed/liveboard.ts +2 -22
- package/src/embed/ts-embed.spec.ts +225 -0
- package/src/embed/ts-embed.ts +19 -0
- 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
|
|
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
|
|
package/src/embed/embedConfig.ts
CHANGED
|
@@ -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
|
-
*
|
|
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.
|
|
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}&
|
|
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}&
|
|
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 =
|
|
774
|
-
|
|
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(),
|
package/src/embed/liveboard.ts
CHANGED
|
@@ -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({
|
package/src/embed/ts-embed.ts
CHANGED
|
@@ -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
|