@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
@@ -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, require('react')) :
@@ -3445,6 +3445,17 @@
3445
3445
  * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
3446
3446
  */
3447
3447
  HostEvent["EditVisualization"] = "editVisualization";
3448
+ /**
3449
+ * Exits Liveboard edit mode , equivalent to clicking the
3450
+ * *Cancel* button in the Liveboard edit header. The Liveboard returns to
3451
+ * view mode and the embedded app emits the {@link EmbedEvent.Cancel} event.
3452
+ * @version SDK: 1.55.0 | ThoughtSpot Cloud: 26.12.0.cl
3453
+ * @example
3454
+ * ```js
3455
+ * liveboardEmbed.trigger(HostEvent.ExitEditMode);
3456
+ * ```
3457
+ */
3458
+ HostEvent["ExitEditMode"] = "exitEditMode";
3448
3459
  /**
3449
3460
  * Trigger the **Copy link** action on a Liveboard or visualization
3450
3461
  * Payload: {@link VizScopedRequest}.
@@ -4980,6 +4991,39 @@
4980
4991
  * @version SDK: 1.49.0 | ThoughtSpot Cloud: 26.6.0.cl
4981
4992
  */
4982
4993
  HostEvent["RefreshLiveboardBrowserCache"] = "refreshLiveboardBrowserCache";
4994
+ /**
4995
+ * Switch the embed between dark appearance and its default appearance
4996
+ * while it is open, without reloading it.
4997
+ * Payload: {@link UpdateThemeRequest}.
4998
+ *
4999
+ * Use it to keep the embed in step with a theme switch in your
5000
+ * application; the appearance the embed loads with is set by `isDarkMode`.
5001
+ * The event resolves with the applied value, such as `{ isDarkMode: true }`.
5002
+ * When dark appearance is not available in the embed, the embed does not
5003
+ * change and the event rejects with an error message instead.
5004
+ * @version SDK: 1.55.0 | ThoughtSpot Cloud: 26.12.0.cl
5005
+ * @param - `isDarkMode` - `true` for dark appearance, `false` for the
5006
+ * default appearance.
5007
+ * @example
5008
+ * ```js
5009
+ * appEmbed.trigger(HostEvent.UpdateTheme, { isDarkMode: true });
5010
+ * ```
5011
+ * @example
5012
+ * ```js
5013
+ * // Follow a theme switch in your application
5014
+ * const themeSwitch = document.querySelector('#theme-switch');
5015
+ * themeSwitch.addEventListener('change', async (event) => {
5016
+ * try {
5017
+ * await appEmbed.trigger(HostEvent.UpdateTheme, {
5018
+ * isDarkMode: event.target.checked,
5019
+ * });
5020
+ * } catch (error) {
5021
+ * console.warn(error);
5022
+ * }
5023
+ * });
5024
+ * ```
5025
+ */
5026
+ HostEvent["UpdateTheme"] = "UpdateTheme";
4983
5027
  })(exports.HostEvent || (exports.HostEvent = {}));
4984
5028
  /**
4985
5029
  * The different visual modes that the data sources panel within
@@ -7455,6 +7499,29 @@
7455
7499
  * ```
7456
7500
  */
7457
7501
  Action["CustomizeHomepage"] = "customizeHomepage";
7502
+ /**
7503
+ * Controls the visibility and disabled state of the *Cancel* button in the
7504
+ * Liveboard edit header, the button that discards the changes made in edit
7505
+ * mode and returns the Liveboard to view mode. The button is shown only
7506
+ * while the Liveboard is in edit mode.
7507
+ * @version SDK: 1.55.0 | ThoughtSpot Cloud: 26.12.0.cl
7508
+ * @example
7509
+ * ```js
7510
+ * const liveboardEmbed = new LiveboardEmbed('#tsEmbed', {
7511
+ * ... // other embed view config
7512
+ * hiddenActions: [Action.Cancel],
7513
+ * });
7514
+ * ```
7515
+ * @example
7516
+ * ```js
7517
+ * const liveboardEmbed = new LiveboardEmbed('#tsEmbed', {
7518
+ * ... // other embed view config
7519
+ * disabledActions: [Action.Cancel],
7520
+ * disabledActionReason: 'Save your changes to leave edit mode',
7521
+ * });
7522
+ * ```
7523
+ */
7524
+ Action["Cancel"] = "cancel";
7458
7525
  })(exports.Action || (exports.Action = {}));
7459
7526
  var PrefetchFeatures;
7460
7527
  (function (PrefetchFeatures) {
@@ -7959,7 +8026,7 @@
7959
8026
  TableContentDensity["Compact"] = "COMPACT";
7960
8027
  })(TableContentDensity || (TableContentDensity = {}));
7961
8028
 
7962
- var version$1="1.53.0";var pkg = {version:version$1};
8029
+ var version$1="1.53.1";var pkg = {version:version$1};
7963
8030
 
7964
8031
  const { version } = pkg;
7965
8032
 
@@ -19912,6 +19979,32 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
19912
19979
  }
19913
19980
  }
19914
19981
 
19982
+ // Membership is checked, not just the key: a bare key allowlist would upload an
19983
+ // arbitrary customer string sitting under `operator` verbatim.
19984
+ const isEnumMember = (enumObject, value) => typeof value === 'string' && Object.values(enumObject).includes(value);
19985
+ const uniqueEnumMembers = (enumObject, values) => Array.from(new Set(values.filter((v) => isEnumMember(enumObject, v))));
19986
+ const describeRuntimeFilters = (runtimeFilters) => ({
19987
+ count: runtimeFilters.length,
19988
+ operators: uniqueEnumMembers(exports.RuntimeFilterOp, runtimeFilters.map((filter) => filter === null || filter === void 0 ? void 0 : filter.operator)),
19989
+ });
19990
+ const describeRuntimeParameters = (runtimeParameters) => ({
19991
+ count: runtimeParameters.length,
19992
+ applicabilityLevels: uniqueEnumMembers(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; })),
19993
+ });
19994
+ // Column names, parameter names and operands are customer data and must never
19995
+ // reach Mixpanel; an unrecognized shape is dropped rather than forwarded.
19996
+ const summarizeRuntimeDataForTelemetry = (viewConfig) => {
19997
+ const { runtimeFilters, runtimeParameters, ...rest } = viewConfig !== null && viewConfig !== void 0 ? viewConfig : {};
19998
+ const telemetryProps = { ...rest };
19999
+ if (Array.isArray(runtimeFilters)) {
20000
+ telemetryProps.runtimeFilters = describeRuntimeFilters(runtimeFilters);
20001
+ }
20002
+ if (Array.isArray(runtimeParameters)) {
20003
+ telemetryProps.runtimeParameters = describeRuntimeParameters(runtimeParameters);
20004
+ }
20005
+ return telemetryProps;
20006
+ };
20007
+
19915
20008
  var eventemitter3 = createCommonjsModule(function (module) {
19916
20009
 
19917
20010
  var has = Object.prototype.hasOwnProperty
@@ -22041,6 +22134,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22041
22134
  */
22042
22135
  const PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY = 'tsEmbedOriginalPosition';
22043
22136
  const PRERENDER_WRAPPER_ID_PREFIX = 'tsEmbed-pre-render-wrapper-';
22137
+ const PRERENDER_PARKED_TRANSFORM = 'translateY(-100%)';
22138
+ /** The height createPreRenderWrapper() seeds before anything is measured. */
22139
+ const UNMEASURED_WRAPPER_HEIGHT = '100vh';
22044
22140
  // The container applies UpdateEmbedParams through React state, so a delivered
22045
22141
  // post is not the same as the params being in effect.
22046
22142
  const UPDATE_EMBED_PARAMS_SETTLE_MS = 200;
@@ -22177,7 +22273,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22177
22273
  this.shouldEncodeUrlQueryParams = false;
22178
22274
  this.defaultHiddenActions = [exports.Action.ReportError];
22179
22275
  this.preRenderContainerEl = document.body;
22180
- this.containerScrollListener = null;
22181
22276
  /**
22182
22277
  * Handler for fullscreen change events
22183
22278
  */
@@ -22357,9 +22452,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22357
22452
  ...viewConfig,
22358
22453
  };
22359
22454
  this.registerAppInit();
22360
- uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_EMBED_CREATE, {
22361
- ...viewConfig,
22362
- });
22455
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_EMBED_CREATE, summarizeRuntimeDataForTelemetry(viewConfig));
22363
22456
  const embedConfig = getEmbedConfig();
22364
22457
  if (embedConfig) {
22365
22458
  this.embedConfig = embedConfig;
@@ -23063,7 +23156,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23063
23156
  top: '0',
23064
23157
  left: '0',
23065
23158
  width: '100vw',
23066
- height: '100vh',
23159
+ height: UNMEASURED_WRAPPER_HEIGHT,
23067
23160
  };
23068
23161
  setStyleProperties(preRenderWrapper, initialPreRenderWrapperStyle);
23069
23162
  return preRenderWrapper;
@@ -23131,10 +23224,12 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23131
23224
  return placeholder;
23132
23225
  }
23133
23226
  /**
23134
- * Resolves the configured preRenderContainer to a live element, falling
23135
- * back to `document.body`. A string selector is re-queried on every call so
23136
- * a remounted container (E.g.: React replacing the node) resolves to the
23137
- * fresh element; an element passed directly cannot be re-resolved.
23227
+ * Resolves the configured preRenderContainer, or defaults to the host's
23228
+ * nearest scrolling ancestor (document.body if none). The absolutely
23229
+ * positioned wrapper only follows the page while it sits inside what
23230
+ * scrolls, so body is right only when the document itself scrolls — an inner
23231
+ * scroller left the frame pinned to the viewport (SCAL-338563). A string
23232
+ * selector is re-queried each call so a remounted container resolves fresh.
23138
23233
  */
23139
23234
  resolvePreRenderContainerTarget() {
23140
23235
  var _a;
@@ -23154,7 +23249,13 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23154
23249
  else if (containerConfig) {
23155
23250
  container = containerConfig;
23156
23251
  }
23157
- return (_a = container) !== null && _a !== void 0 ? _a : document.body;
23252
+ if (container) {
23253
+ return container;
23254
+ }
23255
+ if (!this.hostElement) {
23256
+ return document.body;
23257
+ }
23258
+ return (_a = getScrollableAncestors(this.hostElement)[0]) !== null && _a !== void 0 ? _a : document.body;
23158
23259
  }
23159
23260
  inheritPreRenderContainer() {
23160
23261
  var _a;
@@ -23199,8 +23300,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23199
23300
  * Re-attaches the wrapper to a live container when the previously resolved
23200
23301
  * one has been detached or no longer holds the wrapper — e.g. the host app
23201
23302
  * remounted a custom preRenderContainer, which would otherwise leave a stale
23202
- * reference and collapse the wrapper. Only string selectors can be
23203
- * re-resolved; a container passed as an element is left untouched.
23303
+ * reference and collapse the wrapper. Selectors and the auto-resolved
23304
+ * scrolling ancestor are both re-resolved; a container passed as an element
23305
+ * is left untouched, as there is nothing to re-query.
23204
23306
  */
23205
23307
  reconcilePreRenderContainer() {
23206
23308
  const wrapper = this.preRenderWrapper;
@@ -23219,14 +23321,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23219
23321
  if (resolved === stored && stored.contains(wrapper)) {
23220
23322
  return;
23221
23323
  }
23222
- if (this.containerScrollListener && stored !== resolved) {
23223
- if (stored !== document.body) {
23224
- stored.removeEventListener('scroll', this.containerScrollListener);
23225
- }
23226
- if (resolved !== document.body) {
23227
- resolved.addEventListener('scroll', this.containerScrollListener);
23228
- }
23229
- }
23230
23324
  this.preRenderContainerEl = resolved;
23231
23325
  this.applyPreRenderContainerPositioning();
23232
23326
  if (wrapper.parentNode !== resolved) {
@@ -23288,11 +23382,12 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23288
23382
  */
23289
23383
  setIFrameHeight(height) {
23290
23384
  if (this.isPreRendered) {
23385
+ const next = getCssDimension(height);
23291
23386
  if (this.insertedDomEl) {
23292
- this.insertedDomEl.style.height = getCssDimension(height);
23387
+ this.insertedDomEl.style.height = next;
23293
23388
  }
23294
23389
  else if (this.preRenderWrapper) {
23295
- this.preRenderWrapper.style.height = getCssDimension(height);
23390
+ this.preRenderWrapper.style.height = next;
23296
23391
  }
23297
23392
  }
23298
23393
  else {
@@ -23734,34 +23829,47 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23734
23829
  delete container.dataset[PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY];
23735
23830
  }
23736
23831
  /**
23737
- * Detaches and clears the container scroll listener, if one is attached.
23738
- */
23739
- removeContainerScrollListener() {
23740
- if (!this.containerScrollListener) {
23832
+ * Re-sizes the wrapper when its placeholder changes size.
23833
+ *
23834
+ * Position deliberately has no equivalent. An absolutely positioned wrapper
23835
+ * follows its containing block for free, so a correctly placed frame is the
23836
+ * browser's job and costs nothing; repositioning it on scroll would mean a
23837
+ * layout read and a style write per frame to compensate for placing it in
23838
+ * the wrong box. Size is the one thing the browser will not do for us: the
23839
+ * placeholder grows when the embedded app reports a new height, and the
23840
+ * wrapper has to be told.
23841
+ */
23842
+ observePreRenderSize() {
23843
+ var _a;
23844
+ if (this.getPreRenderConfig().doNotTrackSize || typeof ResizeObserver === 'undefined') {
23741
23845
  return;
23742
23846
  }
23743
- const customContainer = this.getCustomPreRenderContainer();
23744
- customContainer === null || customContainer === void 0 ? void 0 : customContainer.removeEventListener('scroll', this.containerScrollListener);
23745
- this.containerScrollListener = null;
23847
+ const placeholder = this.getPreRenderPlaceHolderElement();
23848
+ if (!placeholder) {
23849
+ return;
23850
+ }
23851
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
23852
+ this.resizeObserver = new ResizeObserver(() => this.syncPreRenderStyle());
23853
+ this.resizeObserver.observe(placeholder);
23746
23854
  }
23747
23855
  /**
23748
23856
  * Destroys the ThoughtSpot embed, and remove any nodes from the DOM.
23749
23857
  * @version SDK: 1.19.1 | ThoughtSpot: *
23750
23858
  */
23751
23859
  destroy() {
23752
- var _a, _b, _c;
23860
+ var _a, _b, _c, _d;
23753
23861
  try {
23754
23862
  this.removeFullscreenChangeHandler();
23755
- this.removeContainerScrollListener();
23863
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
23756
23864
  this.unsubscribeToEvents();
23757
- (_a = this.preRenderWrapper) === null || _a === void 0 ? void 0 : _a.remove();
23865
+ (_b = this.preRenderWrapper) === null || _b === void 0 ? void 0 : _b.remove();
23758
23866
  this.restorePreRenderContainerPosition();
23759
23867
  if (!this.isRendered) {
23760
23868
  return;
23761
23869
  }
23762
23870
  if (!getEmbedConfig().waitForCleanupOnDestroy) {
23763
23871
  this.trigger(exports.HostEvent.DestroyEmbed);
23764
- (_c = (_b = this.insertedDomEl) === null || _b === void 0 ? void 0 : _b.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(this.insertedDomEl);
23872
+ (_d = (_c = this.insertedDomEl) === null || _c === void 0 ? void 0 : _c.parentNode) === null || _d === void 0 ? void 0 : _d.removeChild(this.insertedDomEl);
23765
23873
  }
23766
23874
  else {
23767
23875
  const cleanupTimeout = getEmbedConfig().cleanupTimeout;
@@ -23852,7 +23960,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23852
23960
  * wrapper to overlay it.
23853
23961
  */
23854
23962
  async showPreRender() {
23855
- var _a, _b;
23963
+ var _a;
23856
23964
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_SHOW_PRE_RENDER, {
23857
23965
  preRenderId: this.getPreRenderConfig().id,
23858
23966
  embedComponentType: this.viewConfig.embedComponentType,
@@ -23871,14 +23979,16 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23871
23979
  this.beforePrerenderVisible();
23872
23980
  if (this.hostElement) {
23873
23981
  this.insertedDomEl = this.createPreRenderPlaceholder();
23874
- if (this.viewConfig.fullHeight) {
23875
- // If fullHeight has already sized the wrapper, seed the
23876
- // placeholder with the same height so syncPreRenderStyle gets
23877
- // an accurate rect.
23878
- const existingHeight = this.preRenderWrapper.style.height;
23879
- if (existingHeight) {
23880
- this.insertedDomEl.style.height = existingHeight;
23881
- }
23982
+ // Carry a height fullHeight has already measured onto the fresh
23983
+ // placeholder, so a re-show does not flash at frameParams height.
23984
+ // UNMEASURED_WRAPPER_HEIGHT is what createPreRenderWrapper() seeds
23985
+ // before anything has been measured; treating that as a measurement
23986
+ // is what made a first reveal overshoot to a full viewport.
23987
+ const wrapperHeight = this.preRenderWrapper.style.height;
23988
+ if (this.viewConfig.fullHeight
23989
+ && wrapperHeight
23990
+ && wrapperHeight !== UNMEASURED_WRAPPER_HEIGHT) {
23991
+ this.insertedDomEl.style.height = wrapperHeight;
23882
23992
  }
23883
23993
  const placeHolderId = this.getPreRenderIds().placeHolder;
23884
23994
  // Remove any stale placeholder from a previous cycle. It is located
@@ -23892,29 +24002,19 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23892
24002
  (_a = this.hostElement.querySelector(`#${placeHolderId}`)) === null || _a === void 0 ? void 0 : _a.remove();
23893
24003
  this.hostElement.appendChild(this.insertedDomEl);
23894
24004
  this.syncPreRenderStyle();
23895
- const customContainer = this.getCustomPreRenderContainer();
23896
- if (customContainer && !this.containerScrollListener) {
23897
- this.containerScrollListener = () => this.syncPreRenderStyle();
23898
- customContainer.addEventListener('scroll', this.containerScrollListener);
23899
- }
23900
- if (!this.getPreRenderConfig().doNotTrackSize) {
23901
- const observeTarget = (_b = this.insertedDomEl) !== null && _b !== void 0 ? _b : this.hostElement;
23902
- this.resizeObserver = new ResizeObserver((entries) => {
23903
- entries.forEach((entry) => {
23904
- if (entry.target === observeTarget) {
23905
- this.syncPreRenderStyle();
23906
- }
23907
- });
23908
- });
23909
- this.resizeObserver.observe(observeTarget);
23910
- }
24005
+ this.observePreRenderSize();
23911
24006
  }
23912
24007
  removeStyleProperties(this.preRenderWrapper, [
23913
24008
  'z-index',
23914
24009
  'opacity',
23915
- 'pointer-events',
23916
24010
  'overflow',
24011
+ 'transform',
23917
24012
  ]);
24013
+ // Set rather than removed: a container that carries `pointer-events:
24014
+ // none` — the usual styling for a parking root that must not swallow
24015
+ // clicks — passes it down, and dropping the property here would leave
24016
+ // the inherited `none` in force and the frame dead to input.
24017
+ setStyleProperties(this.preRenderWrapper, { pointerEvents: 'auto' });
23918
24018
  this.subscribeToEvents();
23919
24019
  // Setup fullscreen change handler for prerendered components
23920
24020
  if (this.iFrame) {
@@ -23967,6 +24067,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23967
24067
  * If the component is not preRendered, it issues a warning.
23968
24068
  */
23969
24069
  hidePreRender() {
24070
+ var _a;
23970
24071
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_HIDE_PRE_RENDER, {
23971
24072
  preRenderId: this.getPreRenderConfig().id,
23972
24073
  embedComponentType: this.viewConfig.embedComponentType,
@@ -23978,20 +24079,25 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23978
24079
  return;
23979
24080
  }
23980
24081
  const { zIndex } = this.getPreRenderConfig();
24082
+ // A hidden pre-render frame must add no scroll space to the host page.
23981
24083
  const preRenderHideStyles = {
23982
24084
  opacity: '0',
23983
24085
  pointerEvents: 'none',
23984
24086
  zIndex: zIndex !== undefined ? String(zIndex) : '-1000',
23985
- position: 'absolute',
24087
+ // Resolves to the viewport, so the hidden frame belongs to no
24088
+ // scroll container's overflow; syncPreRenderStyle restores absolute
24089
+ // on show.
24090
+ position: 'fixed',
23986
24091
  top: '0',
23987
24092
  left: '0',
23988
24093
  overflow: 'hidden',
24094
+ // The one exception: a transformed or contained ancestor captures
24095
+ // `fixed`; parking above the top edge keeps it out of that
24096
+ // overflow.
24097
+ transform: PRERENDER_PARKED_TRANSFORM,
23989
24098
  };
23990
24099
  setStyleProperties(this.preRenderWrapper, preRenderHideStyles);
23991
- this.removeContainerScrollListener();
23992
- if (this.resizeObserver) {
23993
- this.resizeObserver.disconnect();
23994
- }
24100
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
23995
24101
  const placeHolderEle = this.getPreRenderPlaceHolderElement();
23996
24102
  if (placeHolderEle) {
23997
24103
  placeHolderEle.parentElement.removeChild(placeHolderEle);
@@ -24696,8 +24802,11 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24696
24802
  embedParams: { visualOverridesParams: visualOverrides },
24697
24803
  };
24698
24804
  }
24805
+ // The app reads enableSpotterInstructionAndMoreSettings from the top level
24806
+ // of embedParams, so lift it out of the sidebar config.
24807
+ const { enableSpotterInstructionAndMoreSettings, ...sidebarConfigRest } = spotterSidebarConfig || {};
24699
24808
  const resolvedSidebarConfig = {
24700
- ...spotterSidebarConfig,
24809
+ ...sidebarConfigRest,
24701
24810
  ...(resolvedEnablePastConversations !== undefined && {
24702
24811
  enablePastConversationsSidebar: resolvedEnablePastConversations,
24703
24812
  }),
@@ -24719,6 +24828,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24719
24828
  embedParams: {
24720
24829
  ...(defaultAppInitData.embedParams || {}),
24721
24830
  spotterSidebarConfig: resolvedSidebarConfig,
24831
+ ...(enableSpotterInstructionAndMoreSettings !== undefined
24832
+ ? { enableSpotterInstructionAndMoreSettings }
24833
+ : {}),
24722
24834
  ...(visualOverrides !== undefined ? { visualOverridesParams: visualOverrides } : {}),
24723
24835
  },
24724
24836
  };
@@ -25288,6 +25400,46 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
25288
25400
  }
25289
25401
  };
25290
25402
 
25403
+ /**
25404
+ * This method is like `_.isEqual` except that it accepts `customizer` which
25405
+ * is invoked to compare values. If `customizer` returns `undefined`, comparisons
25406
+ * are handled by the method instead. The `customizer` is invoked with up to
25407
+ * six arguments: (objValue, othValue [, index|key, object, other, stack]).
25408
+ *
25409
+ * @static
25410
+ * @memberOf _
25411
+ * @since 4.0.0
25412
+ * @category Lang
25413
+ * @param {*} value The value to compare.
25414
+ * @param {*} other The other value to compare.
25415
+ * @param {Function} [customizer] The function to customize comparisons.
25416
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
25417
+ * @example
25418
+ *
25419
+ * function isGreeting(value) {
25420
+ * return /^h(?:i|ello)$/.test(value);
25421
+ * }
25422
+ *
25423
+ * function customizer(objValue, othValue) {
25424
+ * if (isGreeting(objValue) && isGreeting(othValue)) {
25425
+ * return true;
25426
+ * }
25427
+ * }
25428
+ *
25429
+ * var array = ['hello', 'goodbye'];
25430
+ * var other = ['hi', 'goodbye'];
25431
+ *
25432
+ * _.isEqualWith(array, other, customizer);
25433
+ * // => true
25434
+ */
25435
+ function isEqualWith(value, other, customizer) {
25436
+ customizer = typeof customizer == 'function' ? customizer : undefined;
25437
+ var result = customizer ? customizer(value, other) : undefined;
25438
+ return result === undefined ? _baseIsEqual(value, other, undefined, customizer) : !!result;
25439
+ }
25440
+
25441
+ var isEqualWith_1 = isEqualWith;
25442
+
25291
25443
  const getPreviewQuery = `
25292
25444
  query GetEurekaVizSnapshots(
25293
25445
  $vizId: String!, $liveboardId: String!) {
@@ -25402,6 +25554,11 @@ query GetEurekaVizSnapshots(
25402
25554
  * })
25403
25555
  * ```
25404
25556
  */
25557
+ /**
25558
+ * A shallow copy without the keys whose value is `undefined`, so a key that was
25559
+ * assigned `undefined` compares equal to one that was never set.
25560
+ */
25561
+ const definedEntries = (config = {}) => Object.fromEntries(Object.entries(config).filter(([, value]) => value !== undefined));
25405
25562
  let LiveboardEmbed$1 = class LiveboardEmbed extends V1Embed {
25406
25563
  constructor(domSelector, viewConfig) {
25407
25564
  viewConfig.embedComponentType = 'LiveboardEmbed';
@@ -25687,16 +25844,18 @@ query GetEurekaVizSnapshots(
25687
25844
  beforePrerenderVisible() {
25688
25845
  super.beforePrerenderVisible();
25689
25846
  // Captured before showPreRender() hands the wrapper over to this
25690
- // instance. Itself means a hide/show, not a hand-over, so there is
25691
- // nothing stale to clear.
25847
+ // instance. React builds a new instance per mount, so an equal config
25848
+ // is a hide/show, not a hand-over: there is nothing stale to clear.
25692
25849
  const previous = this.getPreRenderObj();
25693
- const showing = previous === this ? undefined : previous === null || previous === void 0 ? void 0 : previous.currentLiveboardState;
25850
+ const previousRoute = this.isSameEmbedConfig(previous)
25851
+ ? undefined
25852
+ : previous === null || previous === void 0 ? void 0 : previous.currentLiveboardState;
25694
25853
  this.executeAfterEmbedContainerLoaded(async () => {
25695
25854
  // Without this the params callback suspends on its await and
25696
25855
  // Navigate goes out first, so the container loads with the previous
25697
25856
  // config's filters.
25698
25857
  await this.preRenderParamsApplied;
25699
- if (this.isShowingLiveboardRoute(showing)) {
25858
+ if (this.isAlreadyOnSameRoute(previousRoute)) {
25700
25859
  // Navigate to the route we are already on is a no-op, so the
25701
25860
  // liveboard keeps its state. Home unmounts the container, which
25702
25861
  // clears it.
@@ -25717,17 +25876,27 @@ query GetEurekaVizSnapshots(
25717
25876
  };
25718
25877
  });
25719
25878
  }
25879
+ // definedEntries drops undefined-valued keys: a shown instance carries
25880
+ // vizId/activeTabId/etc as undefined, so a raw isEqual never matches again.
25881
+ // Functions compare equal, since React passes a fresh closure per render.
25882
+ isSameEmbedConfig(previous) {
25883
+ if (!previous)
25884
+ return false;
25885
+ if (previous === this)
25886
+ return true;
25887
+ return isEqualWith_1(definedEntries(previous.viewConfig), definedEntries(this.viewConfig), (a, b) => (typeof a === 'function' && typeof b === 'function' ? true : undefined));
25888
+ }
25720
25889
  // The whole route, not just the liveboard id: the path is built from the
25721
25890
  // viz, tab and view too, so a same-liveboard show onto another tab is a
25722
25891
  // real navigation.
25723
- isShowingLiveboardRoute(showing) {
25724
- if (!(showing === null || showing === void 0 ? void 0 : showing.liveboardId))
25892
+ isAlreadyOnSameRoute(previousRoute) {
25893
+ if (!(previousRoute === null || previousRoute === void 0 ? void 0 : previousRoute.liveboardId))
25725
25894
  return false;
25726
25895
  const { liveboardId, vizId, activeTabId, personalizedViewId, } = this.viewConfig;
25727
- return showing.liveboardId === liveboardId
25728
- && showing.vizId === vizId
25729
- && showing.activeTabId === activeTabId
25730
- && showing.personalizedViewId === personalizedViewId;
25896
+ return previousRoute.liveboardId === liveboardId
25897
+ && previousRoute.vizId === vizId
25898
+ && previousRoute.activeTabId === activeTabId
25899
+ && previousRoute.personalizedViewId === personalizedViewId;
25731
25900
  }
25732
25901
  async handleRenderForPrerender() {
25733
25902
  if (isUndefined$1(this.viewConfig.liveboardId)) {