@thoughtspot/visual-embed-sdk 1.40.1 → 1.40.3

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 (149) 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 +5 -1
  4. package/cjs/src/embed/app.js.map +1 -1
  5. package/cjs/src/embed/app.spec.js +33 -3
  6. package/cjs/src/embed/app.spec.js.map +1 -1
  7. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  8. package/cjs/src/embed/liveboard.js +2 -1
  9. package/cjs/src/embed/liveboard.js.map +1 -1
  10. package/cjs/src/embed/liveboard.spec.js +22 -0
  11. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  12. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  13. package/cjs/src/embed/ts-embed.js +12 -0
  14. package/cjs/src/embed/ts-embed.js.map +1 -1
  15. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  16. package/cjs/src/embed/ts-embed.spec.js +122 -0
  17. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  18. package/cjs/src/errors.d.ts +10 -0
  19. package/cjs/src/errors.d.ts.map +1 -1
  20. package/cjs/src/errors.js +11 -1
  21. package/cjs/src/errors.js.map +1 -1
  22. package/cjs/src/index.d.ts +2 -2
  23. package/cjs/src/index.d.ts.map +1 -1
  24. package/cjs/src/index.js +3 -1
  25. package/cjs/src/index.js.map +1 -1
  26. package/cjs/src/react/index.d.ts +1 -1
  27. package/cjs/src/react/index.d.ts.map +1 -1
  28. package/cjs/src/react/index.js +2 -1
  29. package/cjs/src/react/index.js.map +1 -1
  30. package/cjs/src/types.d.ts +131 -5
  31. package/cjs/src/types.d.ts.map +1 -1
  32. package/cjs/src/types.js +39 -11
  33. package/cjs/src/types.js.map +1 -1
  34. package/cjs/src/utils/custom-actions.d.ts +12 -0
  35. package/cjs/src/utils/custom-actions.d.ts.map +1 -0
  36. package/cjs/src/utils/custom-actions.js +180 -0
  37. package/cjs/src/utils/custom-actions.js.map +1 -0
  38. package/cjs/src/utils/custom-actions.spec.d.ts +2 -0
  39. package/cjs/src/utils/custom-actions.spec.d.ts.map +1 -0
  40. package/cjs/src/utils/custom-actions.spec.js +399 -0
  41. package/cjs/src/utils/custom-actions.spec.js.map +1 -0
  42. package/cjs/src/utils/processData.d.ts.map +1 -1
  43. package/cjs/src/utils/processData.js +10 -0
  44. package/cjs/src/utils/processData.js.map +1 -1
  45. package/cjs/src/utils/processData.spec.js +11 -0
  46. package/cjs/src/utils/processData.spec.js.map +1 -1
  47. package/cjs/src/utils.d.ts +7 -0
  48. package/cjs/src/utils.d.ts.map +1 -1
  49. package/cjs/src/utils.js +11 -1
  50. package/cjs/src/utils.js.map +1 -1
  51. package/cjs/src/utils.spec.js +28 -0
  52. package/cjs/src/utils.spec.js.map +1 -1
  53. package/dist/{index-P5YjBOuJ.js → index-BICLzyVL.js} +1 -1
  54. package/dist/src/embed/app.d.ts.map +1 -1
  55. package/dist/src/embed/liveboard.d.ts.map +1 -1
  56. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  57. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  58. package/dist/src/errors.d.ts +10 -0
  59. package/dist/src/errors.d.ts.map +1 -1
  60. package/dist/src/index.d.ts +2 -2
  61. package/dist/src/index.d.ts.map +1 -1
  62. package/dist/src/react/index.d.ts +1 -1
  63. package/dist/src/react/index.d.ts.map +1 -1
  64. package/dist/src/types.d.ts +131 -5
  65. package/dist/src/types.d.ts.map +1 -1
  66. package/dist/src/utils/custom-actions.d.ts +12 -0
  67. package/dist/src/utils/custom-actions.d.ts.map +1 -0
  68. package/dist/src/utils/custom-actions.spec.d.ts +2 -0
  69. package/dist/src/utils/custom-actions.spec.d.ts.map +1 -0
  70. package/dist/src/utils/processData.d.ts.map +1 -1
  71. package/dist/src/utils.d.ts +7 -0
  72. package/dist/src/utils.d.ts.map +1 -1
  73. package/dist/tsembed-react.es.js +1705 -203
  74. package/dist/tsembed-react.js +1704 -202
  75. package/dist/tsembed.es.js +1653 -151
  76. package/dist/tsembed.js +1652 -150
  77. package/dist/visual-embed-sdk-react-full.d.ts +132 -6
  78. package/dist/visual-embed-sdk-react.d.ts +132 -6
  79. package/dist/visual-embed-sdk.d.ts +132 -6
  80. package/lib/package.json +1 -1
  81. package/lib/src/embed/app.d.ts.map +1 -1
  82. package/lib/src/embed/app.js +5 -1
  83. package/lib/src/embed/app.js.map +1 -1
  84. package/lib/src/embed/app.spec.js +33 -3
  85. package/lib/src/embed/app.spec.js.map +1 -1
  86. package/lib/src/embed/liveboard.d.ts.map +1 -1
  87. package/lib/src/embed/liveboard.js +2 -1
  88. package/lib/src/embed/liveboard.js.map +1 -1
  89. package/lib/src/embed/liveboard.spec.js +22 -0
  90. package/lib/src/embed/liveboard.spec.js.map +1 -1
  91. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  92. package/lib/src/embed/ts-embed.js +12 -0
  93. package/lib/src/embed/ts-embed.js.map +1 -1
  94. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  95. package/lib/src/embed/ts-embed.spec.js +123 -1
  96. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  97. package/lib/src/errors.d.ts +10 -0
  98. package/lib/src/errors.d.ts.map +1 -1
  99. package/lib/src/errors.js +10 -0
  100. package/lib/src/errors.js.map +1 -1
  101. package/lib/src/index.d.ts +2 -2
  102. package/lib/src/index.d.ts.map +1 -1
  103. package/lib/src/index.js +2 -2
  104. package/lib/src/index.js.map +1 -1
  105. package/lib/src/react/index.d.ts +1 -1
  106. package/lib/src/react/index.d.ts.map +1 -1
  107. package/lib/src/react/index.js +1 -1
  108. package/lib/src/react/index.js.map +1 -1
  109. package/lib/src/types.d.ts +131 -5
  110. package/lib/src/types.d.ts.map +1 -1
  111. package/lib/src/types.js +38 -10
  112. package/lib/src/types.js.map +1 -1
  113. package/lib/src/utils/custom-actions.d.ts +12 -0
  114. package/lib/src/utils/custom-actions.d.ts.map +1 -0
  115. package/lib/src/utils/custom-actions.js +175 -0
  116. package/lib/src/utils/custom-actions.js.map +1 -0
  117. package/lib/src/utils/custom-actions.spec.d.ts +2 -0
  118. package/lib/src/utils/custom-actions.spec.d.ts.map +1 -0
  119. package/lib/src/utils/custom-actions.spec.js +397 -0
  120. package/lib/src/utils/custom-actions.spec.js.map +1 -0
  121. package/lib/src/utils/processData.d.ts.map +1 -1
  122. package/lib/src/utils/processData.js +10 -0
  123. package/lib/src/utils/processData.js.map +1 -1
  124. package/lib/src/utils/processData.spec.js +11 -0
  125. package/lib/src/utils/processData.spec.js.map +1 -1
  126. package/lib/src/utils.d.ts +7 -0
  127. package/lib/src/utils.d.ts.map +1 -1
  128. package/lib/src/utils.js +9 -0
  129. package/lib/src/utils.js.map +1 -1
  130. package/lib/src/utils.spec.js +29 -1
  131. package/lib/src/utils.spec.js.map +1 -1
  132. package/lib/src/visual-embed-sdk.d.ts +133 -7
  133. package/package.json +1 -1
  134. package/src/embed/app.spec.ts +48 -3
  135. package/src/embed/app.ts +5 -0
  136. package/src/embed/liveboard.spec.ts +30 -0
  137. package/src/embed/liveboard.ts +2 -0
  138. package/src/embed/ts-embed.spec.ts +135 -1
  139. package/src/embed/ts-embed.ts +12 -0
  140. package/src/errors.ts +11 -0
  141. package/src/index.ts +4 -0
  142. package/src/react/index.tsx +1 -0
  143. package/src/types.ts +147 -16
  144. package/src/utils/custom-actions.spec.ts +431 -0
  145. package/src/utils/custom-actions.ts +217 -0
  146. package/src/utils/processData.spec.ts +12 -0
  147. package/src/utils/processData.ts +10 -0
  148. package/src/utils.spec.ts +34 -0
  149. package/src/utils.ts +10 -0
@@ -344,6 +344,34 @@ describe('App embed tests', () => {
344
344
  });
345
345
  });
346
346
 
347
+ test('should set liveboardXLSXCSVDownload to true in url', async () => {
348
+ const appEmbed = new AppEmbed(getRootEl(), {
349
+ ...defaultViewConfig,
350
+ liveboardXLSXCSVDownload: true,
351
+ } as AppViewConfig);
352
+ appEmbed.render();
353
+ await executeAfterWait(() => {
354
+ expectUrlMatchesWithParams(
355
+ getIFrameSrc(),
356
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&isLiveboardXLSXCSVDownloadEnabled=true${defaultParamsPost}#/home`,
357
+ );
358
+ });
359
+ });
360
+
361
+ test('should set liveboardXLSXCSVDownload to false in url', async () => {
362
+ const appEmbed = new AppEmbed(getRootEl(), {
363
+ ...defaultViewConfig,
364
+ liveboardXLSXCSVDownload: false,
365
+ } as AppViewConfig);
366
+ appEmbed.render();
367
+ await executeAfterWait(() => {
368
+ expectUrlMatchesWithParams(
369
+ getIFrameSrc(),
370
+ `http://${thoughtSpotHost}/?embedApp=true&profileAndHelpInNavBarHidden=false&isLiveboardXLSXCSVDownloadEnabled=false${defaultParamsPost}#/home`,
371
+ );
372
+ });
373
+ });
374
+
347
375
  test('Should add the tag to the iframe src', async () => {
348
376
  const appEmbed = new AppEmbed(getRootEl(), {
349
377
  ...defaultViewConfig,
@@ -694,11 +722,27 @@ describe('App embed tests', () => {
694
722
  });
695
723
  });
696
724
 
697
- test('Should not add listpageVersion when listPageVersion is List (v2) to the iframe src', async () => {
725
+
726
+ test('Should add listpageVersion=v2 by default when no discoveryExperience is provided', async () => {
727
+ const appEmbed = new AppEmbed(getRootEl(), {
728
+ ...defaultViewConfig,
729
+ } as AppViewConfig);
730
+
731
+ appEmbed.render();
732
+ await executeAfterWait(() => {
733
+ expectUrlMatchesWithParams(
734
+ getIFrameSrc(),
735
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false&navigationVersion=v2&listpageVersion=v2${defaultParams}${defaultParamsPost}#/home`,
736
+ );
737
+ });
738
+ });
739
+
740
+ test('Should add listpageVersion=v2 by default when discoveryExperience is provided but listPageVersion is not specified', async () => {
698
741
  const appEmbed = new AppEmbed(getRootEl(), {
699
742
  ...defaultViewConfig,
700
743
  discoveryExperience: {
701
- listPageVersion: ListPage.List,
744
+ primaryNavbarVersion: PrimaryNavbarVersion.Sliding,
745
+ homePage: HomePage.Modular,
702
746
  },
703
747
  } as AppViewConfig);
704
748
 
@@ -706,11 +750,12 @@ describe('App embed tests', () => {
706
750
  await executeAfterWait(() => {
707
751
  expectUrlMatchesWithParams(
708
752
  getIFrameSrc(),
709
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=false${defaultParams}${defaultParamsPost}#/home`,
753
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false&modularHomeExperience=true&navigationVersion=v3&listpageVersion=v2${defaultParams}${defaultParamsPost}#/home`,
710
754
  );
711
755
  });
712
756
  });
713
757
 
758
+
714
759
  test('Should add listpageVersion=v3 combined with other discoveryExperience options to the iframe src', async () => {
715
760
  const appEmbed = new AppEmbed(getRootEl(), {
716
761
  ...defaultViewConfig,
package/src/embed/app.ts CHANGED
@@ -643,6 +643,7 @@ export class AppEmbed extends V1Embed {
643
643
  enablePendoHelp = true,
644
644
  discoveryExperience,
645
645
  coverAndFilterOptionInPDF = false,
646
+ liveboardXLSXCSVDownload = false,
646
647
  isLiveboardStylingAndGroupingEnabled,
647
648
  } = this.viewConfig;
648
649
 
@@ -662,6 +663,7 @@ export class AppEmbed extends V1Embed {
662
663
  params[Param.HideIrrelevantFiltersInTab] = hideIrrelevantChipsInLiveboardTabs;
663
664
  params[Param.IsUnifiedSearchExperienceEnabled] = isUnifiedSearchExperienceEnabled;
664
665
  params[Param.CoverAndFilterOptionInPDF] = !!coverAndFilterOptionInPDF;
666
+ params[Param.LiveboardXLSXCSVDownload] = !!liveboardXLSXCSVDownload;
665
667
 
666
668
  params = this.getBaseQueryParams(params);
667
669
 
@@ -754,6 +756,9 @@ export class AppEmbed extends V1Embed {
754
756
  // Set homePageVersion to v2 by default to reset the LD flag value
755
757
  // for the homepageVersion.
756
758
  params[Param.HomepageVersion] = 'v2';
759
+ // Set listpageVersion to v2 by default to reset the LD flag value
760
+ // for the listpageVersion.
761
+ params[Param.ListPageVersion] = ListPage.List;
757
762
  if (discoveryExperience) {
758
763
  // primaryNavbarVersion v3 will enabled the new left navigation
759
764
  if (discoveryExperience.primaryNavbarVersion === PrimaryNavbarVersion.Sliding) {
@@ -368,6 +368,36 @@ describe('Liveboard/viz embed tests', () => {
368
368
  });
369
369
  });
370
370
 
371
+ test('should add liveboardXLSXCSVDownload flag and set value to true to the iframe src', async () => {
372
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
373
+ ...defaultViewConfig,
374
+ liveboardId,
375
+ liveboardXLSXCSVDownload: true,
376
+ } as LiveboardViewConfig);
377
+ liveboardEmbed.render();
378
+ await executeAfterWait(() => {
379
+ expectUrlMatchesWithParams(
380
+ getIFrameSrc(),
381
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardXLSXCSVDownloadEnabled=true${prefixParams}#/embed/viz/${liveboardId}`,
382
+ );
383
+ });
384
+ });
385
+
386
+ test('should add liveboardXLSXCSVDownload flag and set value to false to the iframe src', async () => {
387
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
388
+ ...defaultViewConfig,
389
+ liveboardId,
390
+ liveboardXLSXCSVDownload: false,
391
+ } as LiveboardViewConfig);
392
+ liveboardEmbed.render();
393
+ await executeAfterWait(() => {
394
+ expectUrlMatchesWithParams(
395
+ getIFrameSrc(),
396
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isLiveboardXLSXCSVDownloadEnabled=false&${prefixParams}#/embed/viz/${liveboardId}`,
397
+ );
398
+ });
399
+ });
400
+
371
401
  test('should not append runtime filters in URL if excludeRuntimeFiltersfromURL is true', async () => {
372
402
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
373
403
  ...defaultViewConfig,
@@ -435,6 +435,7 @@ export class LiveboardEmbed extends V1Embed {
435
435
  isForceRedirect,
436
436
  dataSourceId,
437
437
  coverAndFilterOptionInPDF = false,
438
+ liveboardXLSXCSVDownload = false,
438
439
  isLiveboardStylingAndGroupingEnabled,
439
440
  } = this.viewConfig;
440
441
 
@@ -511,6 +512,7 @@ export class LiveboardEmbed extends V1Embed {
511
512
  params[Param.DataPanelV2Enabled] = dataPanelV2;
512
513
  params[Param.EnableCustomColumnGroups] = enableCustomColumnGroups;
513
514
  params[Param.CoverAndFilterOptionInPDF] = coverAndFilterOptionInPDF;
515
+ params[Param.LiveboardXLSXCSVDownload] = !!liveboardXLSXCSVDownload;
514
516
  const queryParams = getQueryParamString(params, true);
515
517
 
516
518
  return queryParams;
@@ -1,4 +1,3 @@
1
-
2
1
  import { resetValueFromWindow } from '../utils';
3
2
  import { ERROR_MESSAGE } from '../errors';
4
3
  import { resetCachedAuthToken } from '../authToken';
@@ -27,6 +26,8 @@ import {
27
26
  RuntimeParameter,
28
27
  Param,
29
28
  ContextMenuTriggerOptions,
29
+ CustomActionTarget,
30
+ CustomActionsPosition,
30
31
  } from '../types';
31
32
  import {
32
33
  executeAfterWait,
@@ -346,6 +347,7 @@ describe('Unit test case for ts embed', () => {
346
347
  hiddenHomeLeftNavItems: [],
347
348
  hiddenHomepageModules: [],
348
349
  hiddenListColumns: [],
350
+ customActions: [],
349
351
  hostConfig: undefined,
350
352
  reorderedHomepageModules: [],
351
353
  customVariablesForThirdPartyTools,
@@ -382,6 +384,7 @@ describe('Unit test case for ts embed', () => {
382
384
  hiddenHomeLeftNavItems: [],
383
385
  hiddenHomepageModules: [],
384
386
  hiddenListColumns: [],
387
+ customActions: [],
385
388
  hostConfig: undefined,
386
389
  reorderedHomepageModules: [],
387
390
  customVariablesForThirdPartyTools,
@@ -424,6 +427,7 @@ describe('Unit test case for ts embed', () => {
424
427
  hiddenHomeLeftNavItems: [],
425
428
  hiddenHomepageModules: [HomepageModule.MyLibrary, HomepageModule.Learning],
426
429
  hiddenListColumns: [],
430
+ customActions: [],
427
431
  reorderedHomepageModules: [],
428
432
  customVariablesForThirdPartyTools,
429
433
  },
@@ -462,6 +466,7 @@ describe('Unit test case for ts embed', () => {
462
466
  hiddenHomeLeftNavItems: [],
463
467
  hiddenHomepageModules: [],
464
468
  hiddenListColumns: [],
469
+ customActions: [],
465
470
  reorderedHomepageModules: [],
466
471
  customVariablesForThirdPartyTools,
467
472
  },
@@ -503,6 +508,7 @@ describe('Unit test case for ts embed', () => {
503
508
  hiddenHomeLeftNavItems: [],
504
509
  hiddenHomepageModules: [],
505
510
  hiddenListColumns: [],
511
+ customActions: [],
506
512
  reorderedHomepageModules:
507
513
  [HomepageModule.MyLibrary, HomepageModule.Watchlist],
508
514
  customVariablesForThirdPartyTools,
@@ -547,6 +553,7 @@ describe('Unit test case for ts embed', () => {
547
553
  hiddenHomeLeftNavItems: [],
548
554
  hiddenHomepageModules: [],
549
555
  hiddenListColumns: [],
556
+ customActions: [],
550
557
  hostConfig: undefined,
551
558
  reorderedHomepageModules: [],
552
559
  customVariablesForThirdPartyTools,
@@ -592,6 +599,7 @@ describe('Unit test case for ts embed', () => {
592
599
  hiddenHomeLeftNavItems: [],
593
600
  hiddenHomepageModules: [],
594
601
  hiddenListColumns: [],
602
+ customActions: [],
595
603
  hostConfig: undefined,
596
604
  reorderedHomepageModules: [],
597
605
  customVariablesForThirdPartyTools,
@@ -636,6 +644,7 @@ describe('Unit test case for ts embed', () => {
636
644
  hiddenHomeLeftNavItems: [],
637
645
  hiddenHomepageModules: [],
638
646
  hiddenListColumns: [],
647
+ customActions: [],
639
648
  hostConfig: undefined,
640
649
  reorderedHomepageModules: [],
641
650
  customVariablesForThirdPartyTools,
@@ -681,6 +690,7 @@ describe('Unit test case for ts embed', () => {
681
690
  hiddenHomeLeftNavItems: [],
682
691
  hiddenHomepageModules: [],
683
692
  hiddenListColumns: [],
693
+ customActions: [],
684
694
  hostConfig: undefined,
685
695
  reorderedHomepageModules: [],
686
696
  customVariablesForThirdPartyTools,
@@ -725,6 +735,7 @@ describe('Unit test case for ts embed', () => {
725
735
  [HomeLeftNavItem.Home, HomeLeftNavItem.MonitorSubscription],
726
736
  hiddenHomepageModules: [],
727
737
  hiddenListColumns: [],
738
+ customActions: [],
728
739
  reorderedHomepageModules: [],
729
740
  customVariablesForThirdPartyTools,
730
741
  },
@@ -893,6 +904,7 @@ describe('Unit test case for ts embed', () => {
893
904
  hiddenHomeLeftNavItems: [],
894
905
  hiddenHomepageModules: [],
895
906
  hiddenListColumns: [],
907
+ customActions: [],
896
908
  hostConfig: undefined,
897
909
  reorderedHomepageModules: [],
898
910
  customVariablesForThirdPartyTools: {},
@@ -977,6 +989,7 @@ describe('Unit test case for ts embed', () => {
977
989
  hiddenHomeLeftNavItems: [],
978
990
  hiddenHomepageModules: [],
979
991
  hiddenListColumns: [],
992
+ customActions: [],
980
993
  hostConfig: undefined,
981
994
  reorderedHomepageModules: [],
982
995
  customVariablesForThirdPartyTools: {},
@@ -1011,6 +1024,127 @@ describe('Unit test case for ts embed', () => {
1011
1024
  });
1012
1025
  });
1013
1026
 
1027
+ describe('getDefaultAppInitData with CustomActionsValidationResult', () => {
1028
+ beforeEach(() => {
1029
+ jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
1030
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValue(true);
1031
+ init({
1032
+ thoughtSpotHost: 'tshost',
1033
+ authType: AuthType.TrustedAuthTokenCookieless,
1034
+ getAuthToken: () => Promise.resolve('test_auth_token1'),
1035
+ });
1036
+ });
1037
+
1038
+ afterEach(() => {
1039
+ baseInstance.reset();
1040
+ jest.clearAllMocks();
1041
+ });
1042
+
1043
+ test('should handle valid custom actions and sort them by name in getDefaultAppInitData', async () => {
1044
+ const mockEmbedEventPayload = {
1045
+ type: EmbedEvent.APP_INIT,
1046
+ data: {},
1047
+ };
1048
+
1049
+ // Create a SearchEmbed with valid custom actions to test
1050
+ // CustomActionsValidationResult
1051
+ const searchEmbed = new SearchEmbed(getRootEl(), {
1052
+ ...defaultViewConfig,
1053
+ customActions: [
1054
+ {
1055
+ id: 'action1',
1056
+ name: 'Valid Action',
1057
+ target: CustomActionTarget.LIVEBOARD,
1058
+ position: CustomActionsPosition.PRIMARY,
1059
+ metadataIds: { liveboardIds: ['lb123'] }
1060
+ },
1061
+ {
1062
+ id: 'action2',
1063
+ name: 'Another Valid Action',
1064
+ target: CustomActionTarget.VIZ,
1065
+ position: CustomActionsPosition.MENU,
1066
+ metadataIds: { vizIds: ['viz456'] }
1067
+ }
1068
+ ]
1069
+ });
1070
+
1071
+ searchEmbed.render();
1072
+ const mockPort: any = {
1073
+ postMessage: jest.fn(),
1074
+ };
1075
+
1076
+ await executeAfterWait(() => {
1077
+ const iframe = getIFrameEl();
1078
+ postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
1079
+ });
1080
+
1081
+ await executeAfterWait(() => {
1082
+ expect(mockPort.postMessage).toHaveBeenCalledWith({
1083
+ type: EmbedEvent.APP_INIT,
1084
+ data: {
1085
+ customisations: {
1086
+ content: {},
1087
+ style: {
1088
+ customCSS: {},
1089
+ customCSSUrl: undefined,
1090
+ },
1091
+ },
1092
+ authToken: 'test_auth_token1',
1093
+ runtimeFilterParams: null,
1094
+ runtimeParameterParams: null,
1095
+ hiddenHomeLeftNavItems: [],
1096
+ hiddenHomepageModules: [],
1097
+ hiddenListColumns: [],
1098
+ customActions: [
1099
+ {
1100
+ id: 'action2',
1101
+ name: 'Another Valid Action',
1102
+ target: CustomActionTarget.VIZ,
1103
+ position: CustomActionsPosition.MENU,
1104
+ metadataIds: { vizIds: ['viz456'] }
1105
+ },
1106
+ {
1107
+ id: 'action1',
1108
+ name: 'Valid Action',
1109
+ target: CustomActionTarget.LIVEBOARD,
1110
+ position: CustomActionsPosition.PRIMARY,
1111
+ metadataIds: { liveboardIds: ['lb123'] }
1112
+ }
1113
+ ], // Actions should be sorted by name
1114
+ hostConfig: undefined,
1115
+ reorderedHomepageModules: [],
1116
+ customVariablesForThirdPartyTools: {},
1117
+ },
1118
+ });
1119
+
1120
+ // Verify that CustomActionsValidationResult structure is
1121
+ // correct
1122
+ const appInitData = mockPort.postMessage.mock.calls[0][0].data;
1123
+ expect(appInitData.customActions).toHaveLength(2);
1124
+ expect(appInitData.customActions).toEqual(
1125
+ expect.arrayContaining([
1126
+ expect.objectContaining({
1127
+ id: 'action1',
1128
+ name: 'Valid Action',
1129
+ target: CustomActionTarget.LIVEBOARD,
1130
+ position: CustomActionsPosition.PRIMARY
1131
+ }),
1132
+ expect.objectContaining({
1133
+ id: 'action2',
1134
+ name: 'Another Valid Action',
1135
+ target: CustomActionTarget.VIZ,
1136
+ position: CustomActionsPosition.MENU
1137
+ })
1138
+ ])
1139
+ );
1140
+
1141
+ // Verify actions are sorted by name (alphabetically)
1142
+ expect(appInitData.customActions[0].name).toBe('Another Valid Action');
1143
+ expect(appInitData.customActions[1].name).toBe('Valid Action');
1144
+ });
1145
+ });
1146
+ });
1147
+
1014
1148
  describe('Token fetch fails in cookieless authentication authType', () => {
1015
1149
  beforeEach(() => {
1016
1150
  jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
@@ -35,6 +35,7 @@ import {
35
35
  removeStyleProperties,
36
36
  isUndefined,
37
37
  } from '../utils';
38
+ import { getCustomActions } from '../utils/custom-actions';
38
39
  import {
39
40
  getThoughtSpotHost,
40
41
  URL_MAX_LENGTH,
@@ -380,6 +381,16 @@ export class TsEmbed {
380
381
 
381
382
  protected async getDefaultAppInitData(): Promise<DefaultAppInitData> {
382
383
  const authToken = await this.getAuthTokenForCookielessInit();
384
+ const customActionsResult = getCustomActions([
385
+ ...(this.viewConfig.customActions || []),
386
+ ...(this.embedConfig.customActions || [])
387
+ ]);
388
+ if (customActionsResult.errors.length > 0) {
389
+ this.handleError({
390
+ type: 'CUSTOM_ACTION_VALIDATION',
391
+ message: customActionsResult.errors,
392
+ });
393
+ }
383
394
  return {
384
395
  customisations: getCustomisations(this.embedConfig, this.viewConfig),
385
396
  authToken,
@@ -398,6 +409,7 @@ export class TsEmbed {
398
409
  customVariablesForThirdPartyTools:
399
410
  this.embedConfig.customVariablesForThirdPartyTools || {},
400
411
  hiddenListColumns: this.viewConfig.hiddenListColumns || [],
412
+ customActions: customActionsResult.actions,
401
413
  };
402
414
  }
403
415
 
package/src/errors.ts CHANGED
@@ -19,3 +19,14 @@ export const ERROR_MESSAGE = {
19
19
  RENDER_CALLED_BEFORE_INIT: 'Looks like render was called before calling init, the render won\'t start until init is called.\nFor more info check\n1. https://developers.thoughtspot.com/docs/Function_init#_init\n2.https://developers.thoughtspot.com/docs/getting-started#initSdk',
20
20
  SPOTTER_AGENT_NOT_INITIALIZED: 'SpotterAgent not initialized',
21
21
  };
22
+
23
+ export const CUSTOM_ACTIONS_ERROR_MESSAGE = {
24
+ INVALID_ACTION_OBJECT: 'Custom Action Validation Error: Invalid action object provided',
25
+ MISSING_REQUIRED_FIELDS: (id: string, missingFields: string[]) => `Custom Action Validation Error for '${id}': Missing required fields: ${missingFields.join(', ')}`,
26
+ UNSUPPORTED_TARGET: (id: string, targetType: string) => `Custom Action Validation Error for '${id}': Target type '${targetType}' is not supported`,
27
+ INVALID_POSITION: (position: string, targetType: string, supportedPositions: string) => `Position '${position}' is not supported for ${targetType.toLowerCase()}-level custom actions. Supported positions: ${supportedPositions}`,
28
+ INVALID_METADATA_IDS: (targetType: string, invalidIds: string[], supportedIds: string) => `Invalid metadata IDs for ${targetType.toLowerCase()}-level custom actions: ${invalidIds.join(', ')}. Supported metadata IDs: ${supportedIds}`,
29
+ INVALID_DATA_MODEL_IDS: (targetType: string, invalidIds: string[], supportedIds: string) => `Invalid data model IDs for ${targetType.toLowerCase()}-level custom actions: ${invalidIds.join(', ')}. Supported data model IDs: ${supportedIds}`,
30
+ INVALID_FIELDS: (targetType: string, invalidFields: string[], supportedFields: string) => `Invalid fields for ${targetType.toLowerCase()}-level custom actions: ${invalidFields.join(', ')}. Supported fields: ${supportedFields}`,
31
+ DUPLICATE_IDS: (id: string, duplicateNames: string[], keptName: string) => `Duplicate custom action ID '${id}' found. Actions with names '${duplicateNames.join("', '")}' will be ignored. Keeping '${keptName}'.`,
32
+ };
package/src/index.ts CHANGED
@@ -62,6 +62,8 @@ import {
62
62
  VizPoint,
63
63
  CustomActionPayload,
64
64
  ListPageColumns,
65
+ CustomActionsPosition,
66
+ CustomActionTarget,
65
67
  } from './types';
66
68
  import { CustomCssVariables } from './css-variables';
67
69
  import { SageEmbed, SageViewConfig } from './embed/sage';
@@ -148,6 +150,8 @@ export {
148
150
  UIPassthroughEvent,
149
151
  ListPageColumns,
150
152
  DataPanelCustomColumnGroupsAccordionState,
153
+ CustomActionsPosition,
154
+ CustomActionTarget,
151
155
  };
152
156
 
153
157
  export { resetCachedAuthToken } from './authToken';
@@ -600,4 +600,5 @@ export {
600
600
  LogLevel,
601
601
  getSessionInfo,
602
602
  ListPageColumns,
603
+ CustomActionsPosition,
603
604
  } from '../index';