@thoughtspot/visual-embed-sdk 1.17.0-alpha.0 → 1.17.0-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 (57) hide show
  1. package/dist/src/embed/base.d.ts +1 -1
  2. package/dist/src/embed/ts-embed.d.ts +2 -8
  3. package/dist/src/test/test-utils.d.ts +4 -0
  4. package/dist/src/types.d.ts +105 -10
  5. package/dist/src/utils.d.ts +7 -1
  6. package/dist/tsembed.es.js +1099 -17069
  7. package/dist/tsembed.js +1099 -17069
  8. package/lib/package.json +2 -2
  9. package/lib/src/auth.js +11 -6
  10. package/lib/src/auth.js.map +1 -1
  11. package/lib/src/auth.spec.js +11 -3
  12. package/lib/src/auth.spec.js.map +1 -1
  13. package/lib/src/embed/app.spec.js +2 -6
  14. package/lib/src/embed/app.spec.js.map +1 -1
  15. package/lib/src/embed/base.d.ts +1 -1
  16. package/lib/src/embed/base.js +24 -6
  17. package/lib/src/embed/base.js.map +1 -1
  18. package/lib/src/embed/base.spec.js +33 -0
  19. package/lib/src/embed/base.spec.js.map +1 -1
  20. package/lib/src/embed/liveboard.spec.js +3 -6
  21. package/lib/src/embed/liveboard.spec.js.map +1 -1
  22. package/lib/src/embed/pinboard.spec.js +3 -6
  23. package/lib/src/embed/pinboard.spec.js.map +1 -1
  24. package/lib/src/embed/search.spec.js +1 -3
  25. package/lib/src/embed/search.spec.js.map +1 -1
  26. package/lib/src/embed/ts-embed.d.ts +2 -8
  27. package/lib/src/embed/ts-embed.js +12 -18
  28. package/lib/src/embed/ts-embed.js.map +1 -1
  29. package/lib/src/embed/ts-embed.spec.js +23 -4
  30. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  31. package/lib/src/react/index.spec.js +2 -2
  32. package/lib/src/react/index.spec.js.map +1 -1
  33. package/lib/src/test/test-utils.d.ts +4 -0
  34. package/lib/src/test/test-utils.js +19 -1
  35. package/lib/src/test/test-utils.js.map +1 -1
  36. package/lib/src/types.d.ts +105 -10
  37. package/lib/src/types.js +89 -7
  38. package/lib/src/types.js.map +1 -1
  39. package/lib/src/utils.d.ts +7 -1
  40. package/lib/src/utils.js +10 -0
  41. package/lib/src/utils.js.map +1 -1
  42. package/lib/src/visual-embed-sdk.d.ts +108 -13
  43. package/package.json +2 -2
  44. package/src/auth.spec.ts +11 -3
  45. package/src/auth.ts +20 -10
  46. package/src/embed/app.spec.ts +4 -4
  47. package/src/embed/base.spec.ts +38 -0
  48. package/src/embed/base.ts +33 -6
  49. package/src/embed/liveboard.spec.ts +4 -4
  50. package/src/embed/pinboard.spec.ts +4 -4
  51. package/src/embed/search.spec.ts +1 -1
  52. package/src/embed/ts-embed.spec.ts +27 -6
  53. package/src/embed/ts-embed.ts +16 -18
  54. package/src/react/index.spec.tsx +2 -2
  55. package/src/test/test-utils.ts +21 -2
  56. package/src/types.ts +103 -7
  57. package/src/utils.ts +12 -0
@@ -200,7 +200,7 @@ declare module '@thoughtspot/visual-embed-sdk/embed/base' {
200
200
  * Renders functions in a queue, resolves to next function only after the callback next is called
201
201
  * @param fn The function being registered
202
202
  */
203
- export const renderInQueue: (fn: (next?: (val?: any) => void) => void) => void;
203
+ export const renderInQueue: (fn: (next?: (val?: any) => void) => Promise<any>) => Promise<any>;
204
204
  export function reset(): void;
205
205
  }
206
206
 
@@ -526,23 +526,52 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
526
526
  * No authentication on the SDK. Passthrough to the embedded App. Alias for `Passthrough`.
527
527
  */
528
528
  None = "None",
529
+ /**
530
+ * Passthrough SSO to the embedded App within the iframe. Requires least configuration, but may not
531
+ * be supported by all IDPs. This will behave like `None` if SSO is not configured on ThoughtSpot.
532
+ * @version: SDK: 1.15.0 | ThouhgtSpot: 8.8.0.cl
533
+ */
534
+ EmbeddedSSO = "EmbeddedSSO",
529
535
  /**
530
536
  * SSO using SAML
531
- * @deprecated Use {@link SAML} instead
537
+ * @deprecated Use {@link SAMLRedirect} instead
538
+ * @hidden
532
539
  */
533
540
  SSO = "SSO_SAML",
534
541
  /**
535
542
  * SSO using SAML
543
+ * @deprecated Use {@link SAMLRedirect} instead
544
+ * @hidden
536
545
  */
537
546
  SAML = "SSO_SAML",
547
+ /**
548
+ * SSO using SAML
549
+ * Will make the host application redirect to the SAML Idp.
550
+ */
551
+ SAMLRedirect = "SSO_SAML",
538
552
  /**
539
553
  * SSO using OIDC
554
+ * @hidden
555
+ * @deprecated Use {@link OIDCRedirect} instead
540
556
  */
541
557
  OIDC = "SSO_OIDC",
558
+ /**
559
+ * SSO using OIDC
560
+ * Will make the host application redirect to the OIDC Idp.
561
+ */
562
+ OIDCRedirect = "SSO_OIDC",
542
563
  /**
543
564
  * Trusted authentication server
565
+ * @hidden
566
+ * @deprecated Use {@link TrustedAuth} instead
544
567
  */
545
568
  AuthServer = "AuthServer",
569
+ /**
570
+ * Trusted authentication server, Use you own authentication server
571
+ * which returns a bearer token, generated using the secret_key obtained from
572
+ * ThoughtSpot.
573
+ */
574
+ TrustedAuthToken = "AuthServer",
546
575
  /**
547
576
  * Use the ThoughtSpot login API to authenticate to the cluster directly.
548
577
  *
@@ -709,6 +738,20 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
709
738
  * @version SDK: 1.17.0 | ThoughtSpot: 8.9.0.cl
710
739
  */
711
740
  customisations?: CustomisationsInterface;
741
+ /**
742
+ * For noRedirect SSO Auth, we need a button which the user
743
+ * click to trigger the flow. This is the containing element
744
+ * for that button.
745
+ *
746
+ * @version SDK: 1.17.0 | ThoughtSpot: *
747
+ */
748
+ authTriggerContainer?: string | HTMLElement;
749
+ /**
750
+ * Text to show in the button which triggers the popup auth flow.
751
+ * Default: "Authorize".
752
+ * @version SDK: 1.17.0 | ThoughtSpot: *
753
+ */
754
+ authTriggerText?: string;
712
755
  }
713
756
  /**
714
757
  * MessagePayload: Embed event payload: message type, data and status (start/end)
@@ -1135,16 +1178,25 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1135
1178
  export enum HostEvent {
1136
1179
  /**
1137
1180
  * Trigger a search
1138
- * @param dataSourceIds - The list of data source GUIDs
1139
- * @param searchQuery - The search query
1181
+ * @param - dataSourceIds - The list of data source GUIDs
1182
+ * @param - searchQuery - The search query
1183
+ * @example
1184
+ * searchEmbed.trigger(HostEvent.Search, {
1185
+ * searchQuery: "[sales] by [item type],
1186
+ * "dataSourceIds: ["cd252e5c-b552-49a8-821d-3eadaa049cca"]
1187
+ * })
1140
1188
  */
1141
1189
  Search = "search",
1142
1190
  /**
1143
1191
  * Trigger a drill on certain points by certain column
1144
- * @param points - an object containing selectedPoints/clickedPoints
1192
+ * @param - points - an object containing selectedPoints/clickedPoints
1145
1193
  * eg. { selectedPoints: []}
1146
- * @param columnGuid - a string guid of the column to drill by. This is optional,
1194
+ * @param - columnGuid - a string guid of the column to drill by. This is optional,
1147
1195
  * if not provided it will auto drill by the configured column.
1196
+ * @example searchEmbed.trigger(HostEvent.DrillDown, {
1197
+ * points: clickedPointData,
1198
+ * autoDrillDown: true,
1199
+ * })
1148
1200
  * @version SDK: 1.5.0 | ThoughtSpot: ts7.oct.cl, 7.2.1
1149
1201
  */
1150
1202
  DrillDown = "triggerDrillDown",
@@ -1162,6 +1214,8 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1162
1214
  * Set the visible visualizations on a Liveboard.
1163
1215
  * @param - an array of ids of visualizations to show, the ids not passed
1164
1216
  * will be hidden.
1217
+ * @example
1218
+ * liveboardEmbed.trigger(HostEvent.SetVisibleVizs, ['730496d6-6903-4601-937e-2c691821af3c', 'd547ec54-2a37-4516-a222-2b06719af726'])
1165
1219
  * @version SDK: 1.6.0 | ThoughtSpot: ts8.nov.cl, 8.4.1-sw
1166
1220
  */
1167
1221
  SetVisibleVizs = "SetPinboardVisibleVizs",
@@ -1169,18 +1223,25 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1169
1223
  * Update the runtime filters. The runtime filters passed here are extended
1170
1224
  * on to the existing runtime filters if they exist.
1171
1225
  * @param - {@link RuntimeFilter}[] an array of {@link RuntimeFilter} Types.
1226
+ * @example
1227
+ * liveboardEmbed.trigger(HostEvent.UpdateRuntimeFilters, [
1228
+ * {columnName: "state",operator: "EQ",values: ["michigan"]},
1229
+ * {columnName: "item type",operator: "EQ",values: ["Jackets"]}
1230
+ * ])
1172
1231
  * @version SDK: 1.9.0 | ThoughtSpot: 8.1.0.cl, 8.4.1-sw
1173
1232
  */
1174
1233
  UpdateRuntimeFilters = "UpdateRuntimeFilters",
1175
1234
  /**
1176
1235
  * Navigate to a specific page in App embed without any reload.
1177
1236
  * This is the same as calling `appEmbed.navigateToPage(path, true)`
1178
- * @param path - the path to navigate to (can be a number[1/-1] to go forward/back)
1237
+ * @param - path - the path to navigate to (can be a number[1/-1] to go forward/back)
1238
+ * @example appEmbed.navigateToPage(-1)
1179
1239
  * @version SDK: 1.12.0 | ThoughtSpot 8.4.0.cl, 8.4.1-sw
1180
1240
  */
1181
1241
  Navigate = "Navigate",
1182
1242
  /**
1183
1243
  * Gets the current pinboard content.
1244
+ * @example liveboardEmbed.trigger(HostEvent.getExportRequestForCurrentPinboard)
1184
1245
  * @version SDK: 1.13.0 | ThoughtSpot: 8.5.0.cl, 8.8.1-sw
1185
1246
  */
1186
1247
  getExportRequestForCurrentPinboard = "getExportRequestForCurrentPinboard",
@@ -1188,70 +1249,82 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1188
1249
  * Triggers the Pin action on an embedded object
1189
1250
  * @param - incase of Liveboard embed, takes in an object with vizId as a key
1190
1251
  * can be left empty for search and visualization embeds
1252
+ * @example liveboardEmbed.trigger(HostEvent.Pin, {vizId: '730496d6-6903-4601-937e-2c691821af3c'})
1191
1253
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1192
1254
  */
1193
1255
  Pin = "pin",
1194
1256
  /**
1195
1257
  * Triggers the Show Liveboard details action on a Liveboard
1258
+ * @example liveboardEmbed.trigger(HostEvent.LiveboardInfo)
1196
1259
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1197
1260
  */
1198
1261
  LiveboardInfo = "pinboardInfo",
1199
1262
  /**
1200
1263
  * Triggers the Schedule action on a Liveboard
1264
+ * @example liveboardEmbed.trigger(HostEvent.Schedule)
1201
1265
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1202
1266
  */
1203
1267
  Schedule = "subscription",
1204
1268
  /**
1205
1269
  * Triggers the Manage schedule action on a Liveboard
1270
+ * @example liveboardEmbed.trigger(HostEvent.ScheduleList)
1206
1271
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1207
1272
  */
1208
1273
  SchedulesList = "schedule-list",
1209
1274
  /**
1210
1275
  * Triggers the Export TML action on a Liveboard
1276
+ * @example liveboardEmbed.trigger(HostEvent.ExportTML)
1211
1277
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1212
1278
  */
1213
1279
  ExportTML = "exportTSL",
1214
1280
  /**
1215
1281
  * Triggers the Edit TML action on a Liveboard
1282
+ * @example liveboardEmbed.trigger(HostEvent.EditTML)
1216
1283
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1217
1284
  */
1218
1285
  EditTML = "editTSL",
1219
1286
  /**
1220
1287
  * Triggers the Update TML action on a Liveboard
1288
+ * @example liveboardEmbed.trigger(HostEvent.UpdateTML)
1221
1289
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1222
1290
  */
1223
1291
  UpdateTML = "updateTSL",
1224
1292
  /**
1225
1293
  * Triggers the Download PDF action on a Liveboard
1294
+ * @example liveboardEmbed.trigger(HostEvent.DownloadAsPDF)
1226
1295
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1227
1296
  */
1228
1297
  DownloadAsPdf = "downloadAsPdf",
1229
1298
  /**
1230
1299
  * Triggers the Make a copy action on a Liveboard
1300
+ * @example liveboardEmbed.trigger(HostEvent.MakeACopy)
1231
1301
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1232
1302
  */
1233
1303
  MakeACopy = "makeACopy",
1234
1304
  /**
1235
1305
  * Triggers the Delete action on a Liveboard
1306
+ * @example appEmbed.trigger(HostEvent.Remove)
1236
1307
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1237
1308
  */
1238
1309
  Remove = "delete",
1239
1310
  /**
1240
1311
  * Triggers the Explore action on a visualization
1241
1312
  * @param - an object with vizId as a key
1242
- * eg: {vizId: '730496d6-6903-4601-937e-2c691821af3c'}
1313
+ * @example liveboardEmbed.trigger(HostEvent.Explore, {vizId: '730496d6-6903-4601-937e-2c691821af3c'})
1243
1314
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1244
1315
  */
1245
1316
  Explore = "explore",
1246
1317
  /**
1247
1318
  * Triggers the Create alert action on a visualization
1248
1319
  * @param - an object with vizId as a key
1320
+ * @example liveboardEmbed.trigger(HostEvent.CreateMonitor {vizId: '730496d6-6903-4601-937e-2c691821af3c'})
1249
1321
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1250
1322
  */
1251
1323
  CreateMonitor = "createMonitor",
1252
1324
  /**
1253
1325
  * Triggers the Manage alert action on a visualization
1254
1326
  * @param - an object with vizId as a key
1327
+ * @example liveboardEmbed.trigger(HostEvent.ManageMonitor, {vizId: '730496d6-6903-4601-937e-2c691821af3c'})
1255
1328
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1-sw
1256
1329
  */
1257
1330
  ManageMonitor = "manageMonitor",
@@ -1287,9 +1360,26 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1287
1360
  Present = "present",
1288
1361
  /**
1289
1362
  * Get TML for the current search.
1363
+ * @example searchEmbed.trigger(HostEvent.GetTML)
1290
1364
  * @version SDK: 1.18.0 | ThoughtSpot: 8.10.0.cl
1291
1365
  */
1292
- GetTML = "getTML"
1366
+ GetTML = "getTML",
1367
+ /**
1368
+ * Triggers the Share action on a liveboard or answer
1369
+ * @example
1370
+ * liveboardEmbed.trigger(HostEvent.Share)
1371
+ * searchEmbed.trigger(HostEvent.Share)
1372
+ * @version SDK: 1.18.0 | Thoughtspot: 9.0.0.cl
1373
+ */
1374
+ Share = "share",
1375
+ /**
1376
+ * Trigger the Save action on a liveboard or answer
1377
+ * @example
1378
+ * liveboardEmbed.trigger(HostEvent.Save)
1379
+ * searchEmbed.trigger(HostEvent.Save)
1380
+ * @version SDK: 1.18.0 | Thoughtspot: 9.0.0.cl
1381
+ */
1382
+ Save = "save"
1293
1383
  }
1294
1384
  /**
1295
1385
  * The different visual modes that the data sources panel within
@@ -1345,7 +1435,9 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1345
1435
  LiveboardV2Enabled = "isPinboardV2Enabled",
1346
1436
  ShowAlerts = "showAlerts",
1347
1437
  Locale = "locale",
1348
- CustomStyle = "customStyle"
1438
+ CustomStyle = "customStyle",
1439
+ ForceSAMLAutoRedirect = "forceSAMLAutoRedirect",
1440
+ AuthType = "authType"
1349
1441
  }
1350
1442
  /**
1351
1443
  * The list of actions that can be performed on visual ThoughtSpot
@@ -1489,7 +1581,10 @@ declare module '@thoughtspot/visual-embed-sdk/types' {
1489
1581
  /**
1490
1582
  * @version SDK: 1.11.1 | ThoughtSpot: 8.3.0.cl, 8.4.1-sw
1491
1583
  */
1492
- ReportError = "reportError"
1584
+ ReportError = "reportError",
1585
+ SyncToSheets = "sync-to-sheets",
1586
+ SyncToOtherApps = "sync-to-other-apps",
1587
+ ManagePipelines = "manage-pipeline"
1493
1588
  }
1494
1589
  export interface SessionInterface {
1495
1590
  sessionId: string;
@@ -1664,7 +1759,7 @@ declare module '@thoughtspot/visual-embed-sdk/embed/ts-embed' {
1664
1759
  * @param url
1665
1760
  * @param frameOptions
1666
1761
  */
1667
- protected renderIFrame(url: string, frameOptions?: FrameParams): void;
1762
+ protected renderIFrame(url: string, frameOptions?: FrameParams): Promise<any>;
1668
1763
  /**
1669
1764
  * Sets the height of the iframe
1670
1765
  * @param height The height in pixels
@@ -1745,7 +1840,7 @@ declare module '@thoughtspot/visual-embed-sdk/embed/ts-embed' {
1745
1840
  * Render the app in an iframe and set up event handlers
1746
1841
  * @param iframeSrc
1747
1842
  */
1748
- protected renderV1Embed(iframeSrc: string): void;
1843
+ protected renderV1Embed(iframeSrc: string): any;
1749
1844
  on(messageType: EmbedEvent, callback: MessageCallback, options?: MessageOptions): typeof TsEmbed.prototype;
1750
1845
  }
1751
1846
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thoughtspot/visual-embed-sdk",
3
- "version": "1.17.0-alpha.0",
3
+ "version": "1.17.0-alpha.2",
4
4
  "description": "ThoughtSpot Embed SDK",
5
5
  "module": "lib/src/index.js",
6
6
  "main": "dist/tsembed.js",
@@ -29,7 +29,7 @@
29
29
  "watch": "rollup -cw",
30
30
  "docs-cmd": "node scripts/gatsby-commands.js",
31
31
  "docgen": "typedoc --tsconfig tsconfig.json --theme typedoc-theme",
32
- "test-sdk": "jest -c jest.config.sdk.js",
32
+ "test-sdk": "jest -c jest.config.sdk.js --runInBand",
33
33
  "test-docs": "jest -c jest.config.docs.js",
34
34
  "test": "npm run test-sdk && npm run test-docs",
35
35
  "posttest": "cat ./coverage/sdk/lcov.info | coveralls",
package/src/auth.spec.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as authInstance from './auth';
2
2
  import * as authService from './utils/authService';
3
3
  import * as checkReleaseVersionInBetaInstance from './utils';
4
- import { AuthType, EmbedConfig } from './types';
4
+ import { AuthType, EmbedConfig, EmbedEvent } from './types';
5
5
  import { executeAfterWait } from './test/test-utils';
6
6
 
7
7
  const thoughtSpotHost = 'http://localhost:3000';
@@ -43,6 +43,12 @@ export const embedConfig: any = {
43
43
  doSamlAuth: {
44
44
  thoughtSpotHost,
45
45
  },
46
+ doSamlAuthNoRedirect: {
47
+ thoughtSpotHost,
48
+ noRedirect: true,
49
+ authTriggerContainer: document.body,
50
+ authTriggerText: 'auth',
51
+ },
46
52
  doOidcAuth: {
47
53
  thoughtSpotHost,
48
54
  },
@@ -393,10 +399,12 @@ describe('Unit test for auth', () => {
393
399
  expect(await authInstance.samlCompletionPromise).not.toBe(null);
394
400
  expect(
395
401
  await authInstance.doSamlAuth({
396
- ...embedConfig.doSamlAuth,
397
- noRedirect: true,
402
+ ...embedConfig.doSamlAuthNoRedirect,
398
403
  }),
399
404
  ).toBe(true);
405
+ document.getElementById('ts-auth-btn').click();
406
+ window.postMessage({ type: EmbedEvent.SAMLComplete }, '*');
407
+ await authInstance.samlCompletionPromise;
400
408
  expect(authService.fetchSessionInfoService).toBeCalled();
401
409
  });
402
410
  });
package/src/auth.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { initMixpanel } from './mixpanel-service';
2
- import { AuthType, EmbedConfig, EmbedEvent } from './types';
3
- import { getRedirectUrl } from './utils';
2
+ import { AuthType, DOMSelector, EmbedConfig, EmbedEvent, Param } from './types';
3
+ import { getDOMNode, getRedirectUrl } from './utils';
4
4
  // eslint-disable-next-line import/no-cycle
5
5
  import {
6
6
  fetchSessionInfoService,
@@ -208,12 +208,16 @@ export const doBasicAuth = async (
208
208
  return loggedInStatus;
209
209
  };
210
210
 
211
- async function samlPopupFlow(ssoURL: string) {
212
- document.body.insertAdjacentHTML(
213
- 'beforeend',
214
- '<div id="ts-saml-auth"></div>',
215
- );
216
- const authElem = document.getElementById('ts-saml-auth');
211
+ async function samlPopupFlow(
212
+ ssoURL: string,
213
+ triggerContainer: DOMSelector,
214
+ triggerText: string,
215
+ ) {
216
+ const containerEl = getDOMNode(triggerContainer);
217
+ containerEl.innerHTML =
218
+ '<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
219
+ const authElem = document.getElementById('ts-auth-btn');
220
+ authElem.textContent = triggerText;
217
221
  samlCompletionPromise =
218
222
  samlCompletionPromise ||
219
223
  new Promise<void>((resolve, reject) => {
@@ -239,7 +243,6 @@ async function samlPopupFlow(ssoURL: string) {
239
243
  },
240
244
  { once: true },
241
245
  );
242
- authElem.click();
243
246
  return samlCompletionPromise;
244
247
  }
245
248
 
@@ -271,7 +274,11 @@ const doSSOAuth = async (
271
274
 
272
275
  const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
273
276
  if (embedConfig.noRedirect) {
274
- await samlPopupFlow(ssoURL);
277
+ await samlPopupFlow(
278
+ ssoURL,
279
+ embedConfig.authTriggerContainer,
280
+ embedConfig.authTriggerText,
281
+ );
275
282
  loggedInStatus = true;
276
283
  return;
277
284
  }
@@ -338,11 +345,14 @@ export const authenticate = async (
338
345
  const { authType } = embedConfig;
339
346
  switch (authType) {
340
347
  case AuthType.SSO:
348
+ case AuthType.SAMLRedirect:
341
349
  case AuthType.SAML:
342
350
  return doSamlAuth(embedConfig);
343
351
  case AuthType.OIDC:
352
+ case AuthType.OIDCRedirect:
344
353
  return doOIDCAuth(embedConfig);
345
354
  case AuthType.AuthServer:
355
+ case AuthType.TrustedAuthToken:
346
356
  return doTokenAuth(embedConfig);
347
357
  case AuthType.Basic:
348
358
  return doBasicAuth(embedConfig);
@@ -8,6 +8,9 @@ import {
8
8
  getRootEl,
9
9
  getIFrameEl,
10
10
  mockMessageChannel,
11
+ defaultParams,
12
+ defaultParamsForPinboardEmbed,
13
+ defaultParamsWithoutHiddenActions,
11
14
  } from '../test/test-utils';
12
15
  import { version } from '../../package.json';
13
16
  import * as config from '../config';
@@ -19,9 +22,6 @@ const defaultViewConfig = {
19
22
  },
20
23
  };
21
24
  const thoughtSpotHost = 'tshost';
22
- const defaultParamsWithoutHiddenActions = `&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}`;
23
- const defaultParams = `${defaultParamsWithoutHiddenActions}&hideAction=[%22${Action.ReportError}%22]`;
24
- const defaultParamsForPinboardEmbed = `hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}&hideAction=[%22${Action.ReportError}%22]`;
25
25
  const defaultParamsPost = '';
26
26
 
27
27
  beforeAll(() => {
@@ -156,7 +156,7 @@ describe('App embed tests', () => {
156
156
  appEmbed.render();
157
157
  await executeAfterWait(() => {
158
158
  expect(getIFrameSrc()).toBe(
159
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false${defaultParamsWithoutHiddenActions}&disableAction=[%22save%22,%22update%22]&disableHint=Access%20denied&hideAction=[%22${Action.ReportError}%22,%22download%22]${defaultParamsPost}#/home`,
159
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false&${defaultParamsWithoutHiddenActions}&disableAction=[%22save%22,%22update%22]&disableHint=Access%20denied&hideAction=[%22${Action.ReportError}%22,%22download%22]${defaultParamsPost}#/home`,
160
160
  );
161
161
  });
162
162
  });
@@ -1,4 +1,5 @@
1
1
  import EventEmitter from 'eventemitter3';
2
+ import { EmbedConfig } from '../index';
2
3
  import * as auth from '../auth';
3
4
  import * as index from '../index';
4
5
  import * as base from './base';
@@ -176,6 +177,43 @@ describe('Base TS Embed', () => {
176
177
  );
177
178
  expect(base.getEmbedConfig().autoLogin).toBe(false);
178
179
  });
180
+
181
+ test('config sanity, no ts host', () => {
182
+ expect(() => {
183
+ index.init({
184
+ authType: index.AuthType.None,
185
+ } as EmbedConfig);
186
+ }).toThrowError();
187
+ });
188
+
189
+ test('config sanity, no username in trusted auth', () => {
190
+ expect(() => {
191
+ index.init({
192
+ authType: index.AuthType.TrustedAuthToken,
193
+ thoughtSpotHost,
194
+ } as EmbedConfig);
195
+ }).toThrowError();
196
+ });
197
+
198
+ test('config sanity, no authEndpoint and getAuthToken', () => {
199
+ expect(() => {
200
+ index.init({
201
+ authType: index.AuthType.TrustedAuthToken,
202
+ thoughtSpotHost,
203
+ username: 'test',
204
+ });
205
+ }).toThrowError();
206
+ });
207
+
208
+ test('config sanity, pass triggerContainer with noRedirect', () => {
209
+ expect(() => {
210
+ index.init({
211
+ thoughtSpotHost,
212
+ authType: index.AuthType.SAMLRedirect,
213
+ noRedirect: true,
214
+ });
215
+ }).toThrowError();
216
+ });
179
217
  });
180
218
 
181
219
  describe('Base without init', () => {
package/src/embed/base.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
9
9
  */
10
10
  import EventEmitter from 'eventemitter3';
11
- import _ from 'lodash';
11
+ import uniq from 'lodash/uniq';
12
12
  import { getThoughtSpotHost } from '../config';
13
13
  import { AuthType, EmbedConfig, PrefetchFeatures } from '../types';
14
14
  import {
@@ -22,6 +22,7 @@ import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
22
22
  let config = {} as EmbedConfig;
23
23
  const CONFIG_DEFAULTS: Partial<EmbedConfig> = {
24
24
  loginFailedMessage: 'Not logged in',
25
+ authTriggerText: 'Authorize',
25
26
  authType: AuthType.None,
26
27
  };
27
28
 
@@ -108,7 +109,7 @@ export const prefetch = (
108
109
  const features = prefetchFeatures || [PrefetchFeatures.FullApp];
109
110
  let hostUrl = url || config.thoughtSpotHost;
110
111
  hostUrl = hostUrl[hostUrl.length - 1] === '/' ? hostUrl : `${hostUrl}/`;
111
- _.uniq(
112
+ uniq(
112
113
  features.map((feature) => hostUrlToFeatureUrl[feature](hostUrl)),
113
114
  ).forEach((prefetchUrl, index) => {
114
115
  const iFrame = document.createElement('iframe');
@@ -123,6 +124,29 @@ export const prefetch = (
123
124
  }
124
125
  };
125
126
 
127
+ function sanity(embedConfig: EmbedConfig) {
128
+ if (embedConfig.thoughtSpotHost === undefined) {
129
+ throw new Error('ThoughtSpot host not provided');
130
+ }
131
+ if (embedConfig.authType === AuthType.TrustedAuthToken) {
132
+ if (!embedConfig.username) {
133
+ throw new Error('Username not provided with Trusted auth');
134
+ }
135
+
136
+ if (
137
+ !embedConfig.authEndpoint ||
138
+ typeof embedConfig.getAuthToken !== 'function'
139
+ ) {
140
+ throw new Error(
141
+ 'Trusted auth should provide either authEndpoint or getAuthToken',
142
+ );
143
+ }
144
+ }
145
+ if (embedConfig.noRedirect && !embedConfig.authTriggerContainer) {
146
+ throw new Error('authTriggerContainer not provided with noRedirect');
147
+ }
148
+ }
149
+
126
150
  /**
127
151
  * Initializes the Visual Embed SDK globally and perform
128
152
  * authentication if applicable.
@@ -134,6 +158,7 @@ export const prefetch = (
134
158
  * @version SDK: 1.0.0 | ThoughtSpot ts7.april.cl, 7.2.1
135
159
  */
136
160
  export const init = (embedConfig: EmbedConfig): EventEmitter => {
161
+ sanity(embedConfig);
137
162
  config = {
138
163
  ...CONFIG_DEFAULTS,
139
164
  ...embedConfig,
@@ -191,14 +216,16 @@ let renderQueue: Promise<any> = Promise.resolve();
191
216
  * Renders functions in a queue, resolves to next function only after the callback next is called
192
217
  * @param fn The function being registered
193
218
  */
194
- export const renderInQueue = (fn: (next?: (val?: any) => void) => void) => {
219
+ export const renderInQueue = (
220
+ fn: (next?: (val?: any) => void) => Promise<any>,
221
+ ): Promise<any> => {
195
222
  const { queueMultiRenders = false } = config;
196
223
  if (queueMultiRenders) {
197
224
  renderQueue = renderQueue.then(() => new Promise((res) => fn(res)));
198
- } else {
199
- // Sending an empty function to keep it consistent with the above usage.
200
- fn(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
225
+ return renderQueue;
201
226
  }
227
+ // Sending an empty function to keep it consistent with the above usage.
228
+ return fn(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
202
229
  };
203
230
 
204
231
  // For testing purposes only
@@ -12,6 +12,8 @@ import {
12
12
  getDocumentBody,
13
13
  getIFrameSrc,
14
14
  getRootEl,
15
+ defaultParams,
16
+ defaultParamsWithoutHiddenActions,
15
17
  } from '../test/test-utils';
16
18
  import { version } from '../../package.json';
17
19
  import * as processTriggerInstance from '../utils/processTrigger';
@@ -26,8 +28,6 @@ const liveboardId = 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0';
26
28
  const activeTabId = '502693ba-9818-4e71-8ecd-d1a194e46861';
27
29
  const vizId = '6e73f724-660e-11eb-ae93-0242ac130002';
28
30
  const thoughtSpotHost = 'tshost';
29
- const defaultParamsSansHideAction = `&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}`;
30
- const defaultParams = `${defaultParamsSansHideAction}&hideAction=[%22${Action.ReportError}%22]`;
31
31
  const prefixParams = '&isLiveboardEmbed=true';
32
32
  const prefixParamsVizEmbed = '&isLiveboardEmbed=true&isVizEmbed=true';
33
33
 
@@ -70,7 +70,7 @@ describe('Liveboard/viz embed tests', () => {
70
70
  liveboardEmbed.render();
71
71
  await executeAfterWait(() => {
72
72
  expect(getIFrameSrc()).toBe(
73
- `http://${thoughtSpotHost}/?embedApp=true${defaultParamsSansHideAction}&disableAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${liveboardId}`,
73
+ `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&disableAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${liveboardId}`,
74
74
  );
75
75
  });
76
76
  });
@@ -88,7 +88,7 @@ describe('Liveboard/viz embed tests', () => {
88
88
  liveboardEmbed.render();
89
89
  await executeAfterWait(() => {
90
90
  expect(getIFrameSrc()).toBe(
91
- `http://${thoughtSpotHost}/?embedApp=true${defaultParamsSansHideAction}&hideAction=[%22${Action.ReportError}%22,%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${liveboardId}`,
91
+ `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&hideAction=[%22${Action.ReportError}%22,%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${liveboardId}`,
92
92
  );
93
93
  });
94
94
  });
@@ -6,6 +6,8 @@ import {
6
6
  getDocumentBody,
7
7
  getIFrameSrc,
8
8
  getRootEl,
9
+ defaultParams,
10
+ defaultParamsWithoutHiddenActions,
9
11
  } from '../test/test-utils';
10
12
  import { version } from '../../package.json';
11
13
 
@@ -18,8 +20,6 @@ const defaultViewConfig = {
18
20
  const pinboardId = 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0';
19
21
  const vizId = '6e73f724-660e-11eb-ae93-0242ac130002';
20
22
  const thoughtSpotHost = 'tshost';
21
- const defaultParamsWithoutHideActions = `&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}`;
22
- const defaultParams = `${defaultParamsWithoutHideActions}&hideAction=[%22${Action.ReportError}%22]`;
23
23
  const prefixParams = '&isLiveboardEmbed=true';
24
24
  const prefixParamsVizEmbed = '&isLiveboardEmbed=true&isVizEmbed=true';
25
25
  beforeAll(() => {
@@ -61,7 +61,7 @@ describe('Pinboard/viz embed tests', () => {
61
61
  pinboardEmbed.render();
62
62
  await executeAfterWait(() => {
63
63
  expect(getIFrameSrc()).toBe(
64
- `http://${thoughtSpotHost}/?embedApp=true${defaultParamsWithoutHideActions}&disableAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${pinboardId}`,
64
+ `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&disableAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]&disableHint=Action%20denied&hideAction=[%22${Action.ReportError}%22]${prefixParams}#/embed/viz/${pinboardId}`,
65
65
  );
66
66
  });
67
67
  });
@@ -79,7 +79,7 @@ describe('Pinboard/viz embed tests', () => {
79
79
  pinboardEmbed.render();
80
80
  await executeAfterWait(() => {
81
81
  expect(getIFrameSrc()).toBe(
82
- `http://${thoughtSpotHost}/?embedApp=true${defaultParamsWithoutHideActions}&hideAction=[%22${Action.ReportError}%22,%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${pinboardId}`,
82
+ `http://${thoughtSpotHost}/?embedApp=true&${defaultParamsWithoutHiddenActions}&hideAction=[%22${Action.ReportError}%22,%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${pinboardId}`,
83
83
  );
84
84
  });
85
85
  });