@thoughtspot/visual-embed-sdk 1.53.0 → 1.53.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 (151) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/contracts/contracts.spec.js +4 -0
  3. package/cjs/src/contracts/contracts.spec.js.map +1 -1
  4. package/cjs/src/contracts/host-event-contracts.d.ts +10 -0
  5. package/cjs/src/contracts/host-event-contracts.d.ts.map +1 -1
  6. package/cjs/src/embed/app.d.ts +1 -0
  7. package/cjs/src/embed/app.d.ts.map +1 -1
  8. package/cjs/src/embed/app.js.map +1 -1
  9. package/cjs/src/embed/conversation.d.ts +14 -0
  10. package/cjs/src/embed/conversation.d.ts.map +1 -1
  11. package/cjs/src/embed/conversation.js.map +1 -1
  12. package/cjs/src/embed/conversation.spec.js +22 -0
  13. package/cjs/src/embed/conversation.spec.js.map +1 -1
  14. package/cjs/src/embed/host-events.spec.js +32 -0
  15. package/cjs/src/embed/host-events.spec.js.map +1 -1
  16. package/cjs/src/embed/liveboard.d.ts +2 -16
  17. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  18. package/cjs/src/embed/liveboard.js +29 -10
  19. package/cjs/src/embed/liveboard.js.map +1 -1
  20. package/cjs/src/embed/liveboard.spec.js +97 -0
  21. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  22. package/cjs/src/embed/spotter-utils.d.ts +1 -0
  23. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  24. package/cjs/src/embed/spotter-utils.js +7 -1
  25. package/cjs/src/embed/spotter-utils.js.map +1 -1
  26. package/cjs/src/embed/spotter-utils.spec.js +19 -0
  27. package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
  28. package/cjs/src/embed/ts-embed.d.ts +21 -16
  29. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  30. package/cjs/src/embed/ts-embed.js +77 -63
  31. package/cjs/src/embed/ts-embed.js.map +1 -1
  32. package/cjs/src/embed/ts-embed.spec.js +240 -7
  33. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  34. package/cjs/src/index.d.ts +2 -2
  35. package/cjs/src/index.d.ts.map +1 -1
  36. package/cjs/src/index.js.map +1 -1
  37. package/cjs/src/react/all-types-export.d.ts +1 -1
  38. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  39. package/cjs/src/react/all-types-export.js.map +1 -1
  40. package/cjs/src/types.d.ts +69 -2
  41. package/cjs/src/types.d.ts.map +1 -1
  42. package/cjs/src/types.js +67 -0
  43. package/cjs/src/types.js.map +1 -1
  44. package/cjs/src/utils/runtimeTelemetry.d.ts +11 -0
  45. package/cjs/src/utils/runtimeTelemetry.d.ts.map +1 -0
  46. package/cjs/src/utils/runtimeTelemetry.js +34 -0
  47. package/cjs/src/utils/runtimeTelemetry.js.map +1 -0
  48. package/cjs/src/utils/runtimeTelemetry.spec.d.ts +2 -0
  49. package/cjs/src/utils/runtimeTelemetry.spec.d.ts.map +1 -0
  50. package/cjs/src/utils/runtimeTelemetry.spec.js +124 -0
  51. package/cjs/src/utils/runtimeTelemetry.spec.js.map +1 -0
  52. package/dist/{index-CyDR8j_0.js → index-CrBnZBZv.js} +1 -1
  53. package/dist/src/contracts/host-event-contracts.d.ts +10 -0
  54. package/dist/src/contracts/host-event-contracts.d.ts.map +1 -1
  55. package/dist/src/embed/app.d.ts +1 -0
  56. package/dist/src/embed/app.d.ts.map +1 -1
  57. package/dist/src/embed/conversation.d.ts +14 -0
  58. package/dist/src/embed/conversation.d.ts.map +1 -1
  59. package/dist/src/embed/liveboard.d.ts +2 -16
  60. package/dist/src/embed/liveboard.d.ts.map +1 -1
  61. package/dist/src/embed/spotter-utils.d.ts +1 -0
  62. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  63. package/dist/src/embed/ts-embed.d.ts +21 -16
  64. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  65. package/dist/src/index.d.ts +2 -2
  66. package/dist/src/index.d.ts.map +1 -1
  67. package/dist/src/react/all-types-export.d.ts +1 -1
  68. package/dist/src/react/all-types-export.d.ts.map +1 -1
  69. package/dist/src/types.d.ts +69 -2
  70. package/dist/src/types.d.ts.map +1 -1
  71. package/dist/src/utils/runtimeTelemetry.d.ts +11 -0
  72. package/dist/src/utils/runtimeTelemetry.d.ts.map +1 -0
  73. package/dist/src/utils/runtimeTelemetry.spec.d.ts +2 -0
  74. package/dist/src/utils/runtimeTelemetry.spec.d.ts.map +1 -0
  75. package/dist/tsembed-react.es.js +247 -78
  76. package/dist/tsembed-react.js +246 -77
  77. package/dist/tsembed.es.js +247 -78
  78. package/dist/tsembed.js +246 -77
  79. package/dist/visual-embed-sdk-react-full.d.ts +116 -18
  80. package/dist/visual-embed-sdk-react.d.ts +116 -18
  81. package/dist/visual-embed-sdk.d.ts +116 -33
  82. package/lib/package.json +1 -1
  83. package/lib/src/contracts/contracts.spec.js +4 -0
  84. package/lib/src/contracts/contracts.spec.js.map +1 -1
  85. package/lib/src/contracts/host-event-contracts.d.ts +10 -0
  86. package/lib/src/contracts/host-event-contracts.d.ts.map +1 -1
  87. package/lib/src/embed/app.d.ts +1 -0
  88. package/lib/src/embed/app.d.ts.map +1 -1
  89. package/lib/src/embed/app.js.map +1 -1
  90. package/lib/src/embed/conversation.d.ts +14 -0
  91. package/lib/src/embed/conversation.d.ts.map +1 -1
  92. package/lib/src/embed/conversation.js.map +1 -1
  93. package/lib/src/embed/conversation.spec.js +22 -0
  94. package/lib/src/embed/conversation.spec.js.map +1 -1
  95. package/lib/src/embed/host-events.spec.js +32 -0
  96. package/lib/src/embed/host-events.spec.js.map +1 -1
  97. package/lib/src/embed/liveboard.d.ts +2 -16
  98. package/lib/src/embed/liveboard.d.ts.map +1 -1
  99. package/lib/src/embed/liveboard.js +28 -10
  100. package/lib/src/embed/liveboard.js.map +1 -1
  101. package/lib/src/embed/liveboard.spec.js +97 -0
  102. package/lib/src/embed/liveboard.spec.js.map +1 -1
  103. package/lib/src/embed/spotter-utils.d.ts +1 -0
  104. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  105. package/lib/src/embed/spotter-utils.js +7 -1
  106. package/lib/src/embed/spotter-utils.js.map +1 -1
  107. package/lib/src/embed/spotter-utils.spec.js +19 -0
  108. package/lib/src/embed/spotter-utils.spec.js.map +1 -1
  109. package/lib/src/embed/ts-embed.d.ts +21 -16
  110. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  111. package/lib/src/embed/ts-embed.js +78 -64
  112. package/lib/src/embed/ts-embed.js.map +1 -1
  113. package/lib/src/embed/ts-embed.spec.js +240 -7
  114. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  115. package/lib/src/index.d.ts +2 -2
  116. package/lib/src/index.d.ts.map +1 -1
  117. package/lib/src/index.js.map +1 -1
  118. package/lib/src/react/all-types-export.d.ts +1 -1
  119. package/lib/src/react/all-types-export.d.ts.map +1 -1
  120. package/lib/src/react/all-types-export.js.map +1 -1
  121. package/lib/src/types.d.ts +69 -2
  122. package/lib/src/types.d.ts.map +1 -1
  123. package/lib/src/types.js +67 -0
  124. package/lib/src/types.js.map +1 -1
  125. package/lib/src/utils/runtimeTelemetry.d.ts +11 -0
  126. package/lib/src/utils/runtimeTelemetry.d.ts.map +1 -0
  127. package/lib/src/utils/runtimeTelemetry.js +28 -0
  128. package/lib/src/utils/runtimeTelemetry.js.map +1 -0
  129. package/lib/src/utils/runtimeTelemetry.spec.d.ts +2 -0
  130. package/lib/src/utils/runtimeTelemetry.spec.d.ts.map +1 -0
  131. package/lib/src/utils/runtimeTelemetry.spec.js +122 -0
  132. package/lib/src/utils/runtimeTelemetry.spec.js.map +1 -0
  133. package/lib/src/visual-embed-sdk.d.ts +116 -33
  134. package/package.json +1 -1
  135. package/src/contracts/contracts.spec.ts +4 -0
  136. package/src/contracts/host-event-contracts.ts +13 -0
  137. package/src/embed/app.ts +1 -0
  138. package/src/embed/conversation.spec.ts +24 -0
  139. package/src/embed/conversation.ts +14 -0
  140. package/src/embed/host-events.spec.ts +44 -0
  141. package/src/embed/liveboard.spec.ts +111 -0
  142. package/src/embed/liveboard.ts +34 -10
  143. package/src/embed/spotter-utils.spec.ts +20 -0
  144. package/src/embed/spotter-utils.ts +12 -1
  145. package/src/embed/ts-embed.spec.ts +297 -8
  146. package/src/embed/ts-embed.ts +79 -64
  147. package/src/index.ts +2 -0
  148. package/src/react/all-types-export.ts +1 -0
  149. package/src/types.ts +68 -0
  150. package/src/utils/runtimeTelemetry.spec.ts +148 -0
  151. package/src/utils/runtimeTelemetry.ts +50 -0
package/dist/tsembed.js CHANGED
@@ -1,4 +1,4 @@
1
- /* @thoughtspot/visual-embed-sdk version 1.53.0 */
1
+ /* @thoughtspot/visual-embed-sdk version 1.53.1 */
2
2
  'use client';
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
@@ -3244,6 +3244,17 @@
3244
3244
  * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
3245
3245
  */
3246
3246
  HostEvent["EditVisualization"] = "editVisualization";
3247
+ /**
3248
+ * Exits Liveboard edit mode , equivalent to clicking the
3249
+ * *Cancel* button in the Liveboard edit header. The Liveboard returns to
3250
+ * view mode and the embedded app emits the {@link EmbedEvent.Cancel} event.
3251
+ * @version SDK: 1.55.0 | ThoughtSpot Cloud: 26.12.0.cl
3252
+ * @example
3253
+ * ```js
3254
+ * liveboardEmbed.trigger(HostEvent.ExitEditMode);
3255
+ * ```
3256
+ */
3257
+ HostEvent["ExitEditMode"] = "exitEditMode";
3247
3258
  /**
3248
3259
  * Trigger the **Copy link** action on a Liveboard or visualization
3249
3260
  * Payload: {@link VizScopedRequest}.
@@ -4779,6 +4790,39 @@
4779
4790
  * @version SDK: 1.49.0 | ThoughtSpot Cloud: 26.6.0.cl
4780
4791
  */
4781
4792
  HostEvent["RefreshLiveboardBrowserCache"] = "refreshLiveboardBrowserCache";
4793
+ /**
4794
+ * Switch the embed between dark appearance and its default appearance
4795
+ * while it is open, without reloading it.
4796
+ * Payload: {@link UpdateThemeRequest}.
4797
+ *
4798
+ * Use it to keep the embed in step with a theme switch in your
4799
+ * application; the appearance the embed loads with is set by `isDarkMode`.
4800
+ * The event resolves with the applied value, such as `{ isDarkMode: true }`.
4801
+ * When dark appearance is not available in the embed, the embed does not
4802
+ * change and the event rejects with an error message instead.
4803
+ * @version SDK: 1.55.0 | ThoughtSpot Cloud: 26.12.0.cl
4804
+ * @param - `isDarkMode` - `true` for dark appearance, `false` for the
4805
+ * default appearance.
4806
+ * @example
4807
+ * ```js
4808
+ * appEmbed.trigger(HostEvent.UpdateTheme, { isDarkMode: true });
4809
+ * ```
4810
+ * @example
4811
+ * ```js
4812
+ * // Follow a theme switch in your application
4813
+ * const themeSwitch = document.querySelector('#theme-switch');
4814
+ * themeSwitch.addEventListener('change', async (event) => {
4815
+ * try {
4816
+ * await appEmbed.trigger(HostEvent.UpdateTheme, {
4817
+ * isDarkMode: event.target.checked,
4818
+ * });
4819
+ * } catch (error) {
4820
+ * console.warn(error);
4821
+ * }
4822
+ * });
4823
+ * ```
4824
+ */
4825
+ HostEvent["UpdateTheme"] = "UpdateTheme";
4782
4826
  })(exports.HostEvent || (exports.HostEvent = {}));
4783
4827
  /**
4784
4828
  * The different visual modes that the data sources panel within
@@ -7254,6 +7298,29 @@
7254
7298
  * ```
7255
7299
  */
7256
7300
  Action["CustomizeHomepage"] = "customizeHomepage";
7301
+ /**
7302
+ * Controls the visibility and disabled state of the *Cancel* button in the
7303
+ * Liveboard edit header, the button that discards the changes made in edit
7304
+ * mode and returns the Liveboard to view mode. The button is shown only
7305
+ * while the Liveboard is in edit mode.
7306
+ * @version SDK: 1.55.0 | ThoughtSpot Cloud: 26.12.0.cl
7307
+ * @example
7308
+ * ```js
7309
+ * const liveboardEmbed = new LiveboardEmbed('#tsEmbed', {
7310
+ * ... // other embed view config
7311
+ * hiddenActions: [Action.Cancel],
7312
+ * });
7313
+ * ```
7314
+ * @example
7315
+ * ```js
7316
+ * const liveboardEmbed = new LiveboardEmbed('#tsEmbed', {
7317
+ * ... // other embed view config
7318
+ * disabledActions: [Action.Cancel],
7319
+ * disabledActionReason: 'Save your changes to leave edit mode',
7320
+ * });
7321
+ * ```
7322
+ */
7323
+ Action["Cancel"] = "cancel";
7257
7324
  })(exports.Action || (exports.Action = {}));
7258
7325
  exports.PrefetchFeatures = void 0;
7259
7326
  (function (PrefetchFeatures) {
@@ -7758,7 +7825,7 @@
7758
7825
  TableContentDensity["Compact"] = "COMPACT";
7759
7826
  })(exports.TableContentDensity || (exports.TableContentDensity = {}));
7760
7827
 
7761
- var version$1="1.53.0";var pkg = {version:version$1};
7828
+ var version$1="1.53.1";var pkg = {version:version$1};
7762
7829
 
7763
7830
  const { version } = pkg;
7764
7831
 
@@ -20046,6 +20113,32 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
20046
20113
  }
20047
20114
  }
20048
20115
 
20116
+ // Membership is checked, not just the key: a bare key allowlist would upload an
20117
+ // arbitrary customer string sitting under `operator` verbatim.
20118
+ const isEnumMember = (enumObject, value) => typeof value === 'string' && Object.values(enumObject).includes(value);
20119
+ const uniqueEnumMembers = (enumObject, values) => Array.from(new Set(values.filter((v) => isEnumMember(enumObject, v))));
20120
+ const describeRuntimeFilters = (runtimeFilters) => ({
20121
+ count: runtimeFilters.length,
20122
+ operators: uniqueEnumMembers(exports.RuntimeFilterOp, runtimeFilters.map((filter) => filter === null || filter === void 0 ? void 0 : filter.operator)),
20123
+ });
20124
+ const describeRuntimeParameters = (runtimeParameters) => ({
20125
+ count: runtimeParameters.length,
20126
+ applicabilityLevels: uniqueEnumMembers(exports.ApplicabilityLevel, runtimeParameters.map((parameter) => { var _a; return (_a = parameter === null || parameter === void 0 ? void 0 : parameter.applicability) === null || _a === void 0 ? void 0 : _a.level; })),
20127
+ });
20128
+ // Column names, parameter names and operands are customer data and must never
20129
+ // reach Mixpanel; an unrecognized shape is dropped rather than forwarded.
20130
+ const summarizeRuntimeDataForTelemetry = (viewConfig) => {
20131
+ const { runtimeFilters, runtimeParameters, ...rest } = viewConfig !== null && viewConfig !== void 0 ? viewConfig : {};
20132
+ const telemetryProps = { ...rest };
20133
+ if (Array.isArray(runtimeFilters)) {
20134
+ telemetryProps.runtimeFilters = describeRuntimeFilters(runtimeFilters);
20135
+ }
20136
+ if (Array.isArray(runtimeParameters)) {
20137
+ telemetryProps.runtimeParameters = describeRuntimeParameters(runtimeParameters);
20138
+ }
20139
+ return telemetryProps;
20140
+ };
20141
+
20049
20142
  var eventemitter3 = createCommonjsModule(function (module) {
20050
20143
 
20051
20144
  var has = Object.prototype.hasOwnProperty
@@ -22354,6 +22447,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22354
22447
  */
22355
22448
  const PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY = 'tsEmbedOriginalPosition';
22356
22449
  const PRERENDER_WRAPPER_ID_PREFIX = 'tsEmbed-pre-render-wrapper-';
22450
+ const PRERENDER_PARKED_TRANSFORM = 'translateY(-100%)';
22451
+ /** The height createPreRenderWrapper() seeds before anything is measured. */
22452
+ const UNMEASURED_WRAPPER_HEIGHT = '100vh';
22357
22453
  // The container applies UpdateEmbedParams through React state, so a delivered
22358
22454
  // post is not the same as the params being in effect.
22359
22455
  const UPDATE_EMBED_PARAMS_SETTLE_MS = 200;
@@ -22490,7 +22586,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22490
22586
  this.shouldEncodeUrlQueryParams = false;
22491
22587
  this.defaultHiddenActions = [exports.Action.ReportError];
22492
22588
  this.preRenderContainerEl = document.body;
22493
- this.containerScrollListener = null;
22494
22589
  /**
22495
22590
  * Handler for fullscreen change events
22496
22591
  */
@@ -22670,9 +22765,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22670
22765
  ...viewConfig,
22671
22766
  };
22672
22767
  this.registerAppInit();
22673
- uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_EMBED_CREATE, {
22674
- ...viewConfig,
22675
- });
22768
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_EMBED_CREATE, summarizeRuntimeDataForTelemetry(viewConfig));
22676
22769
  const embedConfig = getEmbedConfig();
22677
22770
  if (embedConfig) {
22678
22771
  this.embedConfig = embedConfig;
@@ -23376,7 +23469,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23376
23469
  top: '0',
23377
23470
  left: '0',
23378
23471
  width: '100vw',
23379
- height: '100vh',
23472
+ height: UNMEASURED_WRAPPER_HEIGHT,
23380
23473
  };
23381
23474
  setStyleProperties(preRenderWrapper, initialPreRenderWrapperStyle);
23382
23475
  return preRenderWrapper;
@@ -23444,10 +23537,12 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23444
23537
  return placeholder;
23445
23538
  }
23446
23539
  /**
23447
- * Resolves the configured preRenderContainer to a live element, falling
23448
- * back to `document.body`. A string selector is re-queried on every call so
23449
- * a remounted container (E.g.: React replacing the node) resolves to the
23450
- * fresh element; an element passed directly cannot be re-resolved.
23540
+ * Resolves the configured preRenderContainer, or defaults to the host's
23541
+ * nearest scrolling ancestor (document.body if none). The absolutely
23542
+ * positioned wrapper only follows the page while it sits inside what
23543
+ * scrolls, so body is right only when the document itself scrolls — an inner
23544
+ * scroller left the frame pinned to the viewport (SCAL-338563). A string
23545
+ * selector is re-queried each call so a remounted container resolves fresh.
23451
23546
  */
23452
23547
  resolvePreRenderContainerTarget() {
23453
23548
  var _a;
@@ -23467,7 +23562,13 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23467
23562
  else if (containerConfig) {
23468
23563
  container = containerConfig;
23469
23564
  }
23470
- return (_a = container) !== null && _a !== void 0 ? _a : document.body;
23565
+ if (container) {
23566
+ return container;
23567
+ }
23568
+ if (!this.hostElement) {
23569
+ return document.body;
23570
+ }
23571
+ return (_a = getScrollableAncestors(this.hostElement)[0]) !== null && _a !== void 0 ? _a : document.body;
23471
23572
  }
23472
23573
  inheritPreRenderContainer() {
23473
23574
  var _a;
@@ -23512,8 +23613,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23512
23613
  * Re-attaches the wrapper to a live container when the previously resolved
23513
23614
  * one has been detached or no longer holds the wrapper — e.g. the host app
23514
23615
  * remounted a custom preRenderContainer, which would otherwise leave a stale
23515
- * reference and collapse the wrapper. Only string selectors can be
23516
- * re-resolved; a container passed as an element is left untouched.
23616
+ * reference and collapse the wrapper. Selectors and the auto-resolved
23617
+ * scrolling ancestor are both re-resolved; a container passed as an element
23618
+ * is left untouched, as there is nothing to re-query.
23517
23619
  */
23518
23620
  reconcilePreRenderContainer() {
23519
23621
  const wrapper = this.preRenderWrapper;
@@ -23532,14 +23634,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23532
23634
  if (resolved === stored && stored.contains(wrapper)) {
23533
23635
  return;
23534
23636
  }
23535
- if (this.containerScrollListener && stored !== resolved) {
23536
- if (stored !== document.body) {
23537
- stored.removeEventListener('scroll', this.containerScrollListener);
23538
- }
23539
- if (resolved !== document.body) {
23540
- resolved.addEventListener('scroll', this.containerScrollListener);
23541
- }
23542
- }
23543
23637
  this.preRenderContainerEl = resolved;
23544
23638
  this.applyPreRenderContainerPositioning();
23545
23639
  if (wrapper.parentNode !== resolved) {
@@ -23601,11 +23695,12 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23601
23695
  */
23602
23696
  setIFrameHeight(height) {
23603
23697
  if (this.isPreRendered) {
23698
+ const next = getCssDimension(height);
23604
23699
  if (this.insertedDomEl) {
23605
- this.insertedDomEl.style.height = getCssDimension(height);
23700
+ this.insertedDomEl.style.height = next;
23606
23701
  }
23607
23702
  else if (this.preRenderWrapper) {
23608
- this.preRenderWrapper.style.height = getCssDimension(height);
23703
+ this.preRenderWrapper.style.height = next;
23609
23704
  }
23610
23705
  }
23611
23706
  else {
@@ -24047,34 +24142,47 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24047
24142
  delete container.dataset[PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY];
24048
24143
  }
24049
24144
  /**
24050
- * Detaches and clears the container scroll listener, if one is attached.
24051
- */
24052
- removeContainerScrollListener() {
24053
- if (!this.containerScrollListener) {
24145
+ * Re-sizes the wrapper when its placeholder changes size.
24146
+ *
24147
+ * Position deliberately has no equivalent. An absolutely positioned wrapper
24148
+ * follows its containing block for free, so a correctly placed frame is the
24149
+ * browser's job and costs nothing; repositioning it on scroll would mean a
24150
+ * layout read and a style write per frame to compensate for placing it in
24151
+ * the wrong box. Size is the one thing the browser will not do for us: the
24152
+ * placeholder grows when the embedded app reports a new height, and the
24153
+ * wrapper has to be told.
24154
+ */
24155
+ observePreRenderSize() {
24156
+ var _a;
24157
+ if (this.getPreRenderConfig().doNotTrackSize || typeof ResizeObserver === 'undefined') {
24054
24158
  return;
24055
24159
  }
24056
- const customContainer = this.getCustomPreRenderContainer();
24057
- customContainer === null || customContainer === void 0 ? void 0 : customContainer.removeEventListener('scroll', this.containerScrollListener);
24058
- this.containerScrollListener = null;
24160
+ const placeholder = this.getPreRenderPlaceHolderElement();
24161
+ if (!placeholder) {
24162
+ return;
24163
+ }
24164
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
24165
+ this.resizeObserver = new ResizeObserver(() => this.syncPreRenderStyle());
24166
+ this.resizeObserver.observe(placeholder);
24059
24167
  }
24060
24168
  /**
24061
24169
  * Destroys the ThoughtSpot embed, and remove any nodes from the DOM.
24062
24170
  * @version SDK: 1.19.1 | ThoughtSpot: *
24063
24171
  */
24064
24172
  destroy() {
24065
- var _a, _b, _c;
24173
+ var _a, _b, _c, _d;
24066
24174
  try {
24067
24175
  this.removeFullscreenChangeHandler();
24068
- this.removeContainerScrollListener();
24176
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
24069
24177
  this.unsubscribeToEvents();
24070
- (_a = this.preRenderWrapper) === null || _a === void 0 ? void 0 : _a.remove();
24178
+ (_b = this.preRenderWrapper) === null || _b === void 0 ? void 0 : _b.remove();
24071
24179
  this.restorePreRenderContainerPosition();
24072
24180
  if (!this.isRendered) {
24073
24181
  return;
24074
24182
  }
24075
24183
  if (!getEmbedConfig().waitForCleanupOnDestroy) {
24076
24184
  this.trigger(exports.HostEvent.DestroyEmbed);
24077
- (_c = (_b = this.insertedDomEl) === null || _b === void 0 ? void 0 : _b.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(this.insertedDomEl);
24185
+ (_d = (_c = this.insertedDomEl) === null || _c === void 0 ? void 0 : _c.parentNode) === null || _d === void 0 ? void 0 : _d.removeChild(this.insertedDomEl);
24078
24186
  }
24079
24187
  else {
24080
24188
  const cleanupTimeout = getEmbedConfig().cleanupTimeout;
@@ -24165,7 +24273,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24165
24273
  * wrapper to overlay it.
24166
24274
  */
24167
24275
  async showPreRender() {
24168
- var _a, _b;
24276
+ var _a;
24169
24277
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_SHOW_PRE_RENDER, {
24170
24278
  preRenderId: this.getPreRenderConfig().id,
24171
24279
  embedComponentType: this.viewConfig.embedComponentType,
@@ -24184,14 +24292,16 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24184
24292
  this.beforePrerenderVisible();
24185
24293
  if (this.hostElement) {
24186
24294
  this.insertedDomEl = this.createPreRenderPlaceholder();
24187
- if (this.viewConfig.fullHeight) {
24188
- // If fullHeight has already sized the wrapper, seed the
24189
- // placeholder with the same height so syncPreRenderStyle gets
24190
- // an accurate rect.
24191
- const existingHeight = this.preRenderWrapper.style.height;
24192
- if (existingHeight) {
24193
- this.insertedDomEl.style.height = existingHeight;
24194
- }
24295
+ // Carry a height fullHeight has already measured onto the fresh
24296
+ // placeholder, so a re-show does not flash at frameParams height.
24297
+ // UNMEASURED_WRAPPER_HEIGHT is what createPreRenderWrapper() seeds
24298
+ // before anything has been measured; treating that as a measurement
24299
+ // is what made a first reveal overshoot to a full viewport.
24300
+ const wrapperHeight = this.preRenderWrapper.style.height;
24301
+ if (this.viewConfig.fullHeight
24302
+ && wrapperHeight
24303
+ && wrapperHeight !== UNMEASURED_WRAPPER_HEIGHT) {
24304
+ this.insertedDomEl.style.height = wrapperHeight;
24195
24305
  }
24196
24306
  const placeHolderId = this.getPreRenderIds().placeHolder;
24197
24307
  // Remove any stale placeholder from a previous cycle. It is located
@@ -24205,29 +24315,19 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24205
24315
  (_a = this.hostElement.querySelector(`#${placeHolderId}`)) === null || _a === void 0 ? void 0 : _a.remove();
24206
24316
  this.hostElement.appendChild(this.insertedDomEl);
24207
24317
  this.syncPreRenderStyle();
24208
- const customContainer = this.getCustomPreRenderContainer();
24209
- if (customContainer && !this.containerScrollListener) {
24210
- this.containerScrollListener = () => this.syncPreRenderStyle();
24211
- customContainer.addEventListener('scroll', this.containerScrollListener);
24212
- }
24213
- if (!this.getPreRenderConfig().doNotTrackSize) {
24214
- const observeTarget = (_b = this.insertedDomEl) !== null && _b !== void 0 ? _b : this.hostElement;
24215
- this.resizeObserver = new ResizeObserver((entries) => {
24216
- entries.forEach((entry) => {
24217
- if (entry.target === observeTarget) {
24218
- this.syncPreRenderStyle();
24219
- }
24220
- });
24221
- });
24222
- this.resizeObserver.observe(observeTarget);
24223
- }
24318
+ this.observePreRenderSize();
24224
24319
  }
24225
24320
  removeStyleProperties(this.preRenderWrapper, [
24226
24321
  'z-index',
24227
24322
  'opacity',
24228
- 'pointer-events',
24229
24323
  'overflow',
24324
+ 'transform',
24230
24325
  ]);
24326
+ // Set rather than removed: a container that carries `pointer-events:
24327
+ // none` — the usual styling for a parking root that must not swallow
24328
+ // clicks — passes it down, and dropping the property here would leave
24329
+ // the inherited `none` in force and the frame dead to input.
24330
+ setStyleProperties(this.preRenderWrapper, { pointerEvents: 'auto' });
24231
24331
  this.subscribeToEvents();
24232
24332
  // Setup fullscreen change handler for prerendered components
24233
24333
  if (this.iFrame) {
@@ -24280,6 +24380,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24280
24380
  * If the component is not preRendered, it issues a warning.
24281
24381
  */
24282
24382
  hidePreRender() {
24383
+ var _a;
24283
24384
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_HIDE_PRE_RENDER, {
24284
24385
  preRenderId: this.getPreRenderConfig().id,
24285
24386
  embedComponentType: this.viewConfig.embedComponentType,
@@ -24291,20 +24392,25 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24291
24392
  return;
24292
24393
  }
24293
24394
  const { zIndex } = this.getPreRenderConfig();
24395
+ // A hidden pre-render frame must add no scroll space to the host page.
24294
24396
  const preRenderHideStyles = {
24295
24397
  opacity: '0',
24296
24398
  pointerEvents: 'none',
24297
24399
  zIndex: zIndex !== undefined ? String(zIndex) : '-1000',
24298
- position: 'absolute',
24400
+ // Resolves to the viewport, so the hidden frame belongs to no
24401
+ // scroll container's overflow; syncPreRenderStyle restores absolute
24402
+ // on show.
24403
+ position: 'fixed',
24299
24404
  top: '0',
24300
24405
  left: '0',
24301
24406
  overflow: 'hidden',
24407
+ // The one exception: a transformed or contained ancestor captures
24408
+ // `fixed`; parking above the top edge keeps it out of that
24409
+ // overflow.
24410
+ transform: PRERENDER_PARKED_TRANSFORM,
24302
24411
  };
24303
24412
  setStyleProperties(this.preRenderWrapper, preRenderHideStyles);
24304
- this.removeContainerScrollListener();
24305
- if (this.resizeObserver) {
24306
- this.resizeObserver.disconnect();
24307
- }
24413
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
24308
24414
  const placeHolderEle = this.getPreRenderPlaceHolderElement();
24309
24415
  if (placeHolderEle) {
24310
24416
  placeHolderEle.parentElement.removeChild(placeHolderEle);
@@ -24470,8 +24576,11 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24470
24576
  embedParams: { visualOverridesParams: visualOverrides },
24471
24577
  };
24472
24578
  }
24579
+ // The app reads enableSpotterInstructionAndMoreSettings from the top level
24580
+ // of embedParams, so lift it out of the sidebar config.
24581
+ const { enableSpotterInstructionAndMoreSettings, ...sidebarConfigRest } = spotterSidebarConfig || {};
24473
24582
  const resolvedSidebarConfig = {
24474
- ...spotterSidebarConfig,
24583
+ ...sidebarConfigRest,
24475
24584
  ...(resolvedEnablePastConversations !== undefined && {
24476
24585
  enablePastConversationsSidebar: resolvedEnablePastConversations,
24477
24586
  }),
@@ -24493,6 +24602,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24493
24602
  embedParams: {
24494
24603
  ...(defaultAppInitData.embedParams || {}),
24495
24604
  spotterSidebarConfig: resolvedSidebarConfig,
24605
+ ...(enableSpotterInstructionAndMoreSettings !== undefined
24606
+ ? { enableSpotterInstructionAndMoreSettings }
24607
+ : {}),
24496
24608
  ...(visualOverrides !== undefined ? { visualOverridesParams: visualOverrides } : {}),
24497
24609
  },
24498
24610
  };
@@ -25062,6 +25174,46 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
25062
25174
  }
25063
25175
  }
25064
25176
 
25177
+ /**
25178
+ * This method is like `_.isEqual` except that it accepts `customizer` which
25179
+ * is invoked to compare values. If `customizer` returns `undefined`, comparisons
25180
+ * are handled by the method instead. The `customizer` is invoked with up to
25181
+ * six arguments: (objValue, othValue [, index|key, object, other, stack]).
25182
+ *
25183
+ * @static
25184
+ * @memberOf _
25185
+ * @since 4.0.0
25186
+ * @category Lang
25187
+ * @param {*} value The value to compare.
25188
+ * @param {*} other The other value to compare.
25189
+ * @param {Function} [customizer] The function to customize comparisons.
25190
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
25191
+ * @example
25192
+ *
25193
+ * function isGreeting(value) {
25194
+ * return /^h(?:i|ello)$/.test(value);
25195
+ * }
25196
+ *
25197
+ * function customizer(objValue, othValue) {
25198
+ * if (isGreeting(objValue) && isGreeting(othValue)) {
25199
+ * return true;
25200
+ * }
25201
+ * }
25202
+ *
25203
+ * var array = ['hello', 'goodbye'];
25204
+ * var other = ['hi', 'goodbye'];
25205
+ *
25206
+ * _.isEqualWith(array, other, customizer);
25207
+ * // => true
25208
+ */
25209
+ function isEqualWith(value, other, customizer) {
25210
+ customizer = typeof customizer == 'function' ? customizer : undefined;
25211
+ var result = customizer ? customizer(value, other) : undefined;
25212
+ return result === undefined ? _baseIsEqual(value, other, undefined, customizer) : !!result;
25213
+ }
25214
+
25215
+ var isEqualWith_1 = isEqualWith;
25216
+
25065
25217
  const getPreviewQuery = `
25066
25218
  query GetEurekaVizSnapshots(
25067
25219
  $vizId: String!, $liveboardId: String!) {
@@ -25176,6 +25328,11 @@ query GetEurekaVizSnapshots(
25176
25328
  * })
25177
25329
  * ```
25178
25330
  */
25331
+ /**
25332
+ * A shallow copy without the keys whose value is `undefined`, so a key that was
25333
+ * assigned `undefined` compares equal to one that was never set.
25334
+ */
25335
+ const definedEntries = (config = {}) => Object.fromEntries(Object.entries(config).filter(([, value]) => value !== undefined));
25179
25336
  class LiveboardEmbed extends V1Embed {
25180
25337
  constructor(domSelector, viewConfig) {
25181
25338
  viewConfig.embedComponentType = 'LiveboardEmbed';
@@ -25461,16 +25618,18 @@ query GetEurekaVizSnapshots(
25461
25618
  beforePrerenderVisible() {
25462
25619
  super.beforePrerenderVisible();
25463
25620
  // Captured before showPreRender() hands the wrapper over to this
25464
- // instance. Itself means a hide/show, not a hand-over, so there is
25465
- // nothing stale to clear.
25621
+ // instance. React builds a new instance per mount, so an equal config
25622
+ // is a hide/show, not a hand-over: there is nothing stale to clear.
25466
25623
  const previous = this.getPreRenderObj();
25467
- const showing = previous === this ? undefined : previous === null || previous === void 0 ? void 0 : previous.currentLiveboardState;
25624
+ const previousRoute = this.isSameEmbedConfig(previous)
25625
+ ? undefined
25626
+ : previous === null || previous === void 0 ? void 0 : previous.currentLiveboardState;
25468
25627
  this.executeAfterEmbedContainerLoaded(async () => {
25469
25628
  // Without this the params callback suspends on its await and
25470
25629
  // Navigate goes out first, so the container loads with the previous
25471
25630
  // config's filters.
25472
25631
  await this.preRenderParamsApplied;
25473
- if (this.isShowingLiveboardRoute(showing)) {
25632
+ if (this.isAlreadyOnSameRoute(previousRoute)) {
25474
25633
  // Navigate to the route we are already on is a no-op, so the
25475
25634
  // liveboard keeps its state. Home unmounts the container, which
25476
25635
  // clears it.
@@ -25491,17 +25650,27 @@ query GetEurekaVizSnapshots(
25491
25650
  };
25492
25651
  });
25493
25652
  }
25653
+ // definedEntries drops undefined-valued keys: a shown instance carries
25654
+ // vizId/activeTabId/etc as undefined, so a raw isEqual never matches again.
25655
+ // Functions compare equal, since React passes a fresh closure per render.
25656
+ isSameEmbedConfig(previous) {
25657
+ if (!previous)
25658
+ return false;
25659
+ if (previous === this)
25660
+ return true;
25661
+ return isEqualWith_1(definedEntries(previous.viewConfig), definedEntries(this.viewConfig), (a, b) => (typeof a === 'function' && typeof b === 'function' ? true : undefined));
25662
+ }
25494
25663
  // The whole route, not just the liveboard id: the path is built from the
25495
25664
  // viz, tab and view too, so a same-liveboard show onto another tab is a
25496
25665
  // real navigation.
25497
- isShowingLiveboardRoute(showing) {
25498
- if (!(showing === null || showing === void 0 ? void 0 : showing.liveboardId))
25666
+ isAlreadyOnSameRoute(previousRoute) {
25667
+ if (!(previousRoute === null || previousRoute === void 0 ? void 0 : previousRoute.liveboardId))
25499
25668
  return false;
25500
25669
  const { liveboardId, vizId, activeTabId, personalizedViewId, } = this.viewConfig;
25501
- return showing.liveboardId === liveboardId
25502
- && showing.vizId === vizId
25503
- && showing.activeTabId === activeTabId
25504
- && showing.personalizedViewId === personalizedViewId;
25670
+ return previousRoute.liveboardId === liveboardId
25671
+ && previousRoute.vizId === vizId
25672
+ && previousRoute.activeTabId === activeTabId
25673
+ && previousRoute.personalizedViewId === personalizedViewId;
25505
25674
  }
25506
25675
  async handleRenderForPrerender() {
25507
25676
  if (isUndefined$1(this.viewConfig.liveboardId)) {