@thoughtspot/visual-embed-sdk 1.52.2-beta.1 → 1.53.0

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 (237) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/css-variables.d.ts +373 -5
  3. package/cjs/src/css-variables.d.ts.map +1 -1
  4. package/cjs/src/embed/app.d.ts +14 -0
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +6 -3
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +28 -0
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/auto-frame-renderer.d.ts.map +1 -1
  11. package/cjs/src/embed/auto-frame-renderer.js +244 -4
  12. package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
  13. package/cjs/src/embed/auto-frame-renderer.spec.js +389 -0
  14. package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
  15. package/cjs/src/embed/bodyless-conversation.js +1 -1
  16. package/cjs/src/embed/bodyless-conversation.js.map +1 -1
  17. package/cjs/src/embed/conversation.d.ts +15 -0
  18. package/cjs/src/embed/conversation.d.ts.map +1 -1
  19. package/cjs/src/embed/conversation.js +7 -3
  20. package/cjs/src/embed/conversation.js.map +1 -1
  21. package/cjs/src/embed/conversation.spec.js +66 -0
  22. package/cjs/src/embed/conversation.spec.js.map +1 -1
  23. package/cjs/src/embed/liveboard-override-utils.d.ts +59 -0
  24. package/cjs/src/embed/liveboard-override-utils.d.ts.map +1 -0
  25. package/cjs/src/embed/liveboard-override-utils.js +19 -0
  26. package/cjs/src/embed/liveboard-override-utils.js.map +1 -0
  27. package/cjs/src/embed/liveboard-override-utils.spec.d.ts +2 -0
  28. package/cjs/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
  29. package/cjs/src/embed/liveboard-override-utils.spec.js +34 -0
  30. package/cjs/src/embed/liveboard-override-utils.spec.js.map +1 -0
  31. package/cjs/src/embed/liveboard.d.ts +43 -1
  32. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  33. package/cjs/src/embed/liveboard.js +11 -18
  34. package/cjs/src/embed/liveboard.js.map +1 -1
  35. package/cjs/src/embed/liveboard.spec.js +104 -54
  36. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  37. package/cjs/src/embed/search-bar.js +1 -1
  38. package/cjs/src/embed/search-bar.js.map +1 -1
  39. package/cjs/src/embed/search.js +1 -1
  40. package/cjs/src/embed/search.js.map +1 -1
  41. package/cjs/src/embed/search.spec.js +20 -0
  42. package/cjs/src/embed/search.spec.js.map +1 -1
  43. package/cjs/src/embed/spotter-utils.d.ts +11 -0
  44. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  45. package/cjs/src/embed/spotter-utils.js +13 -1
  46. package/cjs/src/embed/spotter-utils.js.map +1 -1
  47. package/cjs/src/embed/spotter-viz-utils.d.ts +15 -0
  48. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
  49. package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
  50. package/cjs/src/embed/spotter-viz-utils.spec.js +11 -0
  51. package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -1
  52. package/cjs/src/embed/ts-embed.d.ts +27 -34
  53. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  54. package/cjs/src/embed/ts-embed.js +224 -102
  55. package/cjs/src/embed/ts-embed.js.map +1 -1
  56. package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
  57. package/cjs/src/embed/ts-embed.spec.js +543 -171
  58. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  59. package/cjs/src/index.d.ts +4 -2
  60. package/cjs/src/index.d.ts.map +1 -1
  61. package/cjs/src/index.js +4 -2
  62. package/cjs/src/index.js.map +1 -1
  63. package/cjs/src/mixpanel-service.d.ts +1 -0
  64. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  65. package/cjs/src/mixpanel-service.js +1 -0
  66. package/cjs/src/mixpanel-service.js.map +1 -1
  67. package/cjs/src/react/all-types-export.d.ts +1 -1
  68. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  69. package/cjs/src/react/all-types-export.js +2 -1
  70. package/cjs/src/react/all-types-export.js.map +1 -1
  71. package/cjs/src/types.d.ts +182 -2
  72. package/cjs/src/types.d.ts.map +1 -1
  73. package/cjs/src/types.js +109 -0
  74. package/cjs/src/types.js.map +1 -1
  75. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  76. package/cjs/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  77. package/cjs/src/utils/graphql/answerService/answer-queries.js +8 -1
  78. package/cjs/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  79. package/cjs/src/utils/graphql/answerService/answerService.d.ts +28 -4
  80. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  81. package/cjs/src/utils/graphql/answerService/answerService.js +39 -4
  82. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  83. package/cjs/src/utils/graphql/answerService/answerService.spec.js +124 -0
  84. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  85. package/dist/{index-Bt56pC82.js → index-CyDR8j_0.js} +1 -1
  86. package/dist/src/css-variables.d.ts +373 -5
  87. package/dist/src/css-variables.d.ts.map +1 -1
  88. package/dist/src/embed/app.d.ts +14 -0
  89. package/dist/src/embed/app.d.ts.map +1 -1
  90. package/dist/src/embed/auto-frame-renderer.d.ts.map +1 -1
  91. package/dist/src/embed/conversation.d.ts +15 -0
  92. package/dist/src/embed/conversation.d.ts.map +1 -1
  93. package/dist/src/embed/liveboard-override-utils.d.ts +59 -0
  94. package/dist/src/embed/liveboard-override-utils.d.ts.map +1 -0
  95. package/dist/src/embed/liveboard-override-utils.spec.d.ts +2 -0
  96. package/dist/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
  97. package/dist/src/embed/liveboard.d.ts +43 -1
  98. package/dist/src/embed/liveboard.d.ts.map +1 -1
  99. package/dist/src/embed/spotter-utils.d.ts +11 -0
  100. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  101. package/dist/src/embed/spotter-viz-utils.d.ts +15 -0
  102. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
  103. package/dist/src/embed/ts-embed.d.ts +27 -34
  104. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  105. package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
  106. package/dist/src/index.d.ts +4 -2
  107. package/dist/src/index.d.ts.map +1 -1
  108. package/dist/src/mixpanel-service.d.ts +1 -0
  109. package/dist/src/mixpanel-service.d.ts.map +1 -1
  110. package/dist/src/react/all-types-export.d.ts +1 -1
  111. package/dist/src/react/all-types-export.d.ts.map +1 -1
  112. package/dist/src/types.d.ts +182 -2
  113. package/dist/src/types.d.ts.map +1 -1
  114. package/dist/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  115. package/dist/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  116. package/dist/src/utils/graphql/answerService/answerService.d.ts +28 -4
  117. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  118. package/dist/tsembed-react.es.js +437 -175
  119. package/dist/tsembed-react.js +436 -174
  120. package/dist/tsembed.es.js +680 -180
  121. package/dist/tsembed.js +678 -178
  122. package/dist/visual-embed-sdk-react-full.d.ts +702 -44
  123. package/dist/visual-embed-sdk-react.d.ts +697 -44
  124. package/dist/visual-embed-sdk.d.ts +729 -45
  125. package/lib/package.json +1 -1
  126. package/lib/src/css-variables.d.ts +373 -5
  127. package/lib/src/css-variables.d.ts.map +1 -1
  128. package/lib/src/embed/app.d.ts +14 -0
  129. package/lib/src/embed/app.d.ts.map +1 -1
  130. package/lib/src/embed/app.js +7 -4
  131. package/lib/src/embed/app.js.map +1 -1
  132. package/lib/src/embed/app.spec.js +28 -0
  133. package/lib/src/embed/app.spec.js.map +1 -1
  134. package/lib/src/embed/auto-frame-renderer.d.ts.map +1 -1
  135. package/lib/src/embed/auto-frame-renderer.js +244 -4
  136. package/lib/src/embed/auto-frame-renderer.js.map +1 -1
  137. package/lib/src/embed/auto-frame-renderer.spec.js +389 -0
  138. package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
  139. package/lib/src/embed/bodyless-conversation.js +1 -1
  140. package/lib/src/embed/bodyless-conversation.js.map +1 -1
  141. package/lib/src/embed/conversation.d.ts +15 -0
  142. package/lib/src/embed/conversation.d.ts.map +1 -1
  143. package/lib/src/embed/conversation.js +8 -4
  144. package/lib/src/embed/conversation.js.map +1 -1
  145. package/lib/src/embed/conversation.spec.js +67 -1
  146. package/lib/src/embed/conversation.spec.js.map +1 -1
  147. package/lib/src/embed/liveboard-override-utils.d.ts +59 -0
  148. package/lib/src/embed/liveboard-override-utils.d.ts.map +1 -0
  149. package/lib/src/embed/liveboard-override-utils.js +15 -0
  150. package/lib/src/embed/liveboard-override-utils.js.map +1 -0
  151. package/lib/src/embed/liveboard-override-utils.spec.d.ts +2 -0
  152. package/lib/src/embed/liveboard-override-utils.spec.d.ts.map +1 -0
  153. package/lib/src/embed/liveboard-override-utils.spec.js +32 -0
  154. package/lib/src/embed/liveboard-override-utils.spec.js.map +1 -0
  155. package/lib/src/embed/liveboard.d.ts +43 -1
  156. package/lib/src/embed/liveboard.d.ts.map +1 -1
  157. package/lib/src/embed/liveboard.js +11 -17
  158. package/lib/src/embed/liveboard.js.map +1 -1
  159. package/lib/src/embed/liveboard.spec.js +104 -54
  160. package/lib/src/embed/liveboard.spec.js.map +1 -1
  161. package/lib/src/embed/search-bar.js +1 -1
  162. package/lib/src/embed/search-bar.js.map +1 -1
  163. package/lib/src/embed/search.js +1 -1
  164. package/lib/src/embed/search.js.map +1 -1
  165. package/lib/src/embed/search.spec.js +20 -0
  166. package/lib/src/embed/search.spec.js.map +1 -1
  167. package/lib/src/embed/spotter-utils.d.ts +11 -0
  168. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  169. package/lib/src/embed/spotter-utils.js +12 -0
  170. package/lib/src/embed/spotter-utils.js.map +1 -1
  171. package/lib/src/embed/spotter-viz-utils.d.ts +15 -0
  172. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
  173. package/lib/src/embed/spotter-viz-utils.js.map +1 -1
  174. package/lib/src/embed/spotter-viz-utils.spec.js +11 -0
  175. package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -1
  176. package/lib/src/embed/ts-embed.d.ts +27 -34
  177. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  178. package/lib/src/embed/ts-embed.js +224 -102
  179. package/lib/src/embed/ts-embed.js.map +1 -1
  180. package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
  181. package/lib/src/embed/ts-embed.spec.js +544 -172
  182. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  183. package/lib/src/index.d.ts +4 -2
  184. package/lib/src/index.d.ts.map +1 -1
  185. package/lib/src/index.js +3 -2
  186. package/lib/src/index.js.map +1 -1
  187. package/lib/src/mixpanel-service.d.ts +1 -0
  188. package/lib/src/mixpanel-service.d.ts.map +1 -1
  189. package/lib/src/mixpanel-service.js +1 -0
  190. package/lib/src/mixpanel-service.js.map +1 -1
  191. package/lib/src/react/all-types-export.d.ts +1 -1
  192. package/lib/src/react/all-types-export.d.ts.map +1 -1
  193. package/lib/src/react/all-types-export.js +1 -1
  194. package/lib/src/react/all-types-export.js.map +1 -1
  195. package/lib/src/types.d.ts +182 -2
  196. package/lib/src/types.d.ts.map +1 -1
  197. package/lib/src/types.js +109 -0
  198. package/lib/src/types.js.map +1 -1
  199. package/lib/src/utils/graphql/answerService/answer-queries.d.ts +1 -0
  200. package/lib/src/utils/graphql/answerService/answer-queries.d.ts.map +1 -1
  201. package/lib/src/utils/graphql/answerService/answer-queries.js +7 -0
  202. package/lib/src/utils/graphql/answerService/answer-queries.js.map +1 -1
  203. package/lib/src/utils/graphql/answerService/answerService.d.ts +28 -4
  204. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  205. package/lib/src/utils/graphql/answerService/answerService.js +39 -4
  206. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  207. package/lib/src/utils/graphql/answerService/answerService.spec.js +125 -1
  208. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  209. package/lib/src/visual-embed-sdk.d.ts +729 -45
  210. package/package.json +1 -1
  211. package/src/css-variables.ts +475 -26
  212. package/src/embed/app.spec.ts +32 -0
  213. package/src/embed/app.ts +28 -4
  214. package/src/embed/auto-frame-renderer.spec.ts +464 -0
  215. package/src/embed/auto-frame-renderer.ts +305 -6
  216. package/src/embed/bodyless-conversation.ts +1 -1
  217. package/src/embed/conversation.spec.ts +94 -1
  218. package/src/embed/conversation.ts +28 -3
  219. package/src/embed/liveboard-override-utils.spec.ts +38 -0
  220. package/src/embed/liveboard-override-utils.ts +71 -0
  221. package/src/embed/liveboard.spec.ts +119 -62
  222. package/src/embed/liveboard.ts +56 -21
  223. package/src/embed/search-bar.tsx +1 -1
  224. package/src/embed/search.spec.ts +23 -0
  225. package/src/embed/search.ts +1 -1
  226. package/src/embed/spotter-utils.ts +12 -0
  227. package/src/embed/spotter-viz-utils.spec.ts +11 -0
  228. package/src/embed/spotter-viz-utils.ts +15 -0
  229. package/src/embed/ts-embed.spec.ts +684 -213
  230. package/src/embed/ts-embed.ts +227 -97
  231. package/src/index.ts +16 -1
  232. package/src/mixpanel-service.ts +1 -0
  233. package/src/react/all-types-export.ts +6 -0
  234. package/src/types.ts +186 -5
  235. package/src/utils/graphql/answerService/answer-queries.ts +8 -0
  236. package/src/utils/graphql/answerService/answerService.spec.ts +145 -1
  237. package/src/utils/graphql/answerService/answerService.ts +65 -3
package/dist/tsembed.js CHANGED
@@ -1,4 +1,4 @@
1
- /* @thoughtspot/visual-embed-sdk version 1.52.2-beta.1 */
1
+ /* @thoughtspot/visual-embed-sdk version 1.53.0 */
2
2
  'use client';
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
@@ -1214,6 +1214,36 @@
1214
1214
  * ```
1215
1215
  */
1216
1216
  EmbedEvent["Edit"] = "edit";
1217
+ /**
1218
+ * Emitted when a user clicks **Edit** on a Liveboard.
1219
+ *
1220
+ * Fired alongside {@link EmbedEvent.Edit} for backward compatibility;
1221
+ * listen to this instead of `Edit` to target the Liveboard surface only.
1222
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
1223
+ * @example
1224
+ * ```js
1225
+ * liveboardEmbed.on(EmbedEvent.EditLiveboard, payload => {
1226
+ * console.log('Liveboard edit', payload);
1227
+ * })
1228
+ * ```
1229
+ */
1230
+ EmbedEvent["EditLiveboard"] = "editLiveboard";
1231
+ /**
1232
+ * Emitted when a user clicks **Edit** on a visualization inside a
1233
+ * Liveboard.
1234
+ *
1235
+ * Fired alongside {@link EmbedEvent.Edit} for backward compatibility;
1236
+ * listen to this instead of `Edit` to target the visualization surface
1237
+ * only.
1238
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
1239
+ * @example
1240
+ * ```js
1241
+ * liveboardEmbed.on(EmbedEvent.EditVisualization, payload => {
1242
+ * console.log('visualization edit', payload);
1243
+ * })
1244
+ * ```
1245
+ */
1246
+ EmbedEvent["EditVisualization"] = "editVisualization";
1217
1247
  /**
1218
1248
  * Emitted when a user clicks *Make a copy* on a Liveboard
1219
1249
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1.sw
@@ -3185,6 +3215,35 @@
3185
3215
  * @version SDK: 1.15.0 | ThoughtSpot: 8.7.0.cl, 8.8.1.sw
3186
3216
  */
3187
3217
  HostEvent["Edit"] = "edit";
3218
+ /**
3219
+ * Trigger the **Edit** action on a Liveboard only — does not affect a
3220
+ * visualization's edit surface.
3221
+ *
3222
+ * Behaves like {@link HostEvent.Edit} restricted to the Liveboard
3223
+ * surface. Use {@link HostEvent.EditVisualization} to target a
3224
+ * visualization instead, or `HostEvent.Edit` to control whichever
3225
+ * surface applies contextually (unchanged, existing behavior).
3226
+ * @example
3227
+ * ```js
3228
+ * liveboardEmbed.trigger(HostEvent.EditLiveboard)
3229
+ * ```
3230
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
3231
+ */
3232
+ HostEvent["EditLiveboard"] = "editLiveboard";
3233
+ /**
3234
+ * Trigger the **Edit** action on a specific visualization inside a
3235
+ * Liveboard only — does not affect the Liveboard-level edit surface.
3236
+ * @param - Object parameter. Includes the following keys:
3237
+ * - `vizId`: **Required.** The visualization to edit.
3238
+ *
3239
+ * @example
3240
+ * ```js
3241
+ * liveboardEmbed.trigger(HostEvent.EditVisualization, {vizId:
3242
+ * '730496d6-6903-4601-937e-2c691821af3c'})
3243
+ * ```
3244
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
3245
+ */
3246
+ HostEvent["EditVisualization"] = "editVisualization";
3188
3247
  /**
3189
3248
  * Trigger the **Copy link** action on a Liveboard or visualization
3190
3249
  * Payload: {@link VizScopedRequest}.
@@ -4747,6 +4806,22 @@
4747
4806
  var Param;
4748
4807
  (function (Param) {
4749
4808
  Param["Tsmcp"] = "tsmcp";
4809
+ /**
4810
+ * Marker added by a host app replaying a stored conversation. Carries the
4811
+ * analytical session (conversation) identifier, from which the renderer
4812
+ * resolves the answer's current session parameters. Stripped before the
4813
+ * URL reaches the ThoughtSpot application.
4814
+ * @version SDK: 1.52.2 | ThoughtSpot Cloud: 26.9.0.cl
4815
+ */
4816
+ Param["TsmcpConversationId"] = "tsmcpConversationId";
4817
+ /**
4818
+ * Zero-based position of the answer within the conversation, counting only
4819
+ * non-thinking answer items in message order. Accompanies
4820
+ * {@link TsmcpConversationId}; defaults to 0 when absent. Stripped before
4821
+ * the URL reaches the ThoughtSpot application.
4822
+ * @version SDK: 1.52.2 | ThoughtSpot Cloud: 26.9.0.cl
4823
+ */
4824
+ Param["TsmcpAnswerIndex"] = "tsmcpAnswerIndex";
4750
4825
  Param["EmbedApp"] = "embedApp";
4751
4826
  Param["DataSources"] = "dataSources";
4752
4827
  Param["DataSourceMode"] = "dataSourceMode";
@@ -4910,6 +4985,9 @@
4910
4985
  Param["SpotterDataSources"] = "spotterDataSources";
4911
4986
  Param["OpenSpotterOnLiveboardByDefault"] = "openSpotterOnLiveboardByDefault";
4912
4987
  Param["ShowAnswerEditPanel"] = "showAnswerEditPanel";
4988
+ Param["IsDarkMode"] = "isDarkMode";
4989
+ Param["RadiantThemeEnabled"] = "radiantThemeEnabled";
4990
+ Param["SpotterExperienceVersion"] = "spotterExperienceVersion";
4913
4991
  })(Param || (Param = {}));
4914
4992
  /**
4915
4993
  * ThoughtSpot application pages include actions and menu commands
@@ -5364,12 +5442,43 @@
5364
5442
  * The *Edit* action on the Liveboard page and in the
5365
5443
  * visualization menu.
5366
5444
  * Opens a Liveboard or visualization in edit mode.
5445
+ *
5446
+ * Controls both surfaces together. To target one surface only, use
5447
+ * {@link Action.EditLiveboard} or {@link Action.EditVisualization}.
5367
5448
  * @example
5368
5449
  * ```js
5369
5450
  * disabledActions: [Action.Edit]
5370
5451
  * ```
5371
5452
  */
5372
5453
  Action["Edit"] = "edit";
5454
+ /**
5455
+ * The *Edit* action on the Liveboard page only.
5456
+ * Opens a Liveboard in edit mode.
5457
+ *
5458
+ * Does not affect the *Edit* action in the visualization menu; use
5459
+ * {@link Action.EditVisualization} for that, or {@link Action.Edit} to
5460
+ * control both surfaces together.
5461
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
5462
+ * @example
5463
+ * ```js
5464
+ * disabledActions: [Action.EditLiveboard]
5465
+ * ```
5466
+ */
5467
+ Action["EditLiveboard"] = "editLiveboard";
5468
+ /**
5469
+ * The *Edit* action in the visualization `...` menu only.
5470
+ * Opens a visualization in the editor.
5471
+ *
5472
+ * Does not affect the *Edit* action on the Liveboard page; use
5473
+ * {@link Action.EditLiveboard} for that, or {@link Action.Edit} to
5474
+ * control both surfaces together.
5475
+ * @version SDK: 1.54.0 | ThoughtSpot Cloud: 26.11.0.cl
5476
+ * @example
5477
+ * ```js
5478
+ * disabledActions: [Action.EditVisualization]
5479
+ * ```
5480
+ */
5481
+ Action["EditVisualization"] = "editVisualization";
5373
5482
  /**
5374
5483
  * The text edit option for Liveboard and visualization titles.
5375
5484
  * @example
@@ -7649,7 +7758,7 @@
7649
7758
  TableContentDensity["Compact"] = "COMPACT";
7650
7759
  })(exports.TableContentDensity || (exports.TableContentDensity = {}));
7651
7760
 
7652
- var version$1="1.52.2-beta.1";var pkg = {version:version$1};
7761
+ var version$1="1.53.0";var pkg = {version:version$1};
7653
7762
 
7654
7763
  const { version } = pkg;
7655
7764
 
@@ -10316,6 +10425,13 @@ mutation RemoveColumns($session: BachSessionIdInput!, $logicalColumnIds: [GUID!]
10316
10425
  ${bachSessionId}
10317
10426
  }
10318
10427
  }
10428
+ `;
10429
+ const updateSort = `
10430
+ mutation UpdateSort($session: BachSessionIdInput!, $sortOrder: [AnswerColumnSortInput!]!) {
10431
+ Answer__updateSort(session: $session, sortOrder: $sortOrder) {
10432
+ ${bachSessionId}
10433
+ }
10434
+ }
10319
10435
  `;
10320
10436
  const getAnswer = `
10321
10437
  query GetAnswer($session: BachSessionIdInput!) {
@@ -10621,6 +10737,26 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
10621
10737
  },
10622
10738
  });
10623
10739
  }
10740
+ /**
10741
+ * Adapt the sort options into the `updateSort` payload and send it.
10742
+ * @param sortOptions Columns to sort by, each with a direction.
10743
+ * @param sourceDetail
10744
+ */
10745
+ async adaptSorting(sortOptions, sourceDetail) {
10746
+ const { answer } = await this.executeQuery(getAnswer, {});
10747
+ const guidToColumnId = getGuidToColumnIdMap(answer);
10748
+ const sortOrder = sortOptions.map((sort) => {
10749
+ const guid = getGuidsFromColumnNames(sourceDetail, [sort.columnName])
10750
+ .values().next().value;
10751
+ return {
10752
+ columnId: guidToColumnId.get(guid),
10753
+ sortType: sort.ascending ? 'ASCENDING' : 'DESCENDING',
10754
+ };
10755
+ });
10756
+ return this.executeQuery(updateSort, {
10757
+ sortOrder,
10758
+ });
10759
+ }
10624
10760
  async updateDisplayMode(displayMode = "TABLE_MODE") {
10625
10761
  return this.executeQuery(updateDisplayMode, {
10626
10762
  displayMode,
@@ -10708,18 +10844,21 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
10708
10844
  * automatically passed.
10709
10845
  * @param outputColumnNames
10710
10846
  * @param selectedPoints
10847
+ * @param sortOptions Optional columns to sort the underlying data by.
10711
10848
  * @example
10712
10849
  * ```js
10713
10850
  * embed.on(EmbedEvent.CustomAction, e => {
10714
- * const underlying = await e.answerService.getUnderlyingDataForPoint([
10715
- * 'col name 1' // The column should exist in the data source.
10716
- * ]);
10851
+ * const underlying = await e.answerService.getUnderlyingDataForPoint(
10852
+ * ['col name 1'], // The column should exist in the data source.
10853
+ * undefined,
10854
+ * [{ columnName: 'col name 1', ascending: true }],
10855
+ * );
10717
10856
  * const data = await underlying.fetchData(0, 100);
10718
10857
  * })
10719
10858
  * ```
10720
10859
  * @version SDK: 1.25.0 | ThoughtSpot: 9.10.0.cl
10721
10860
  */
10722
- async getUnderlyingDataForPoint(outputColumnNames, selectedPoints) {
10861
+ async getUnderlyingDataForPoint(outputColumnNames, selectedPoints, sortOptions) {
10723
10862
  if (!selectedPoints && !this.selectedPoints) {
10724
10863
  throw new Error('Needs to be triggered in context of a point');
10725
10864
  }
@@ -10747,6 +10886,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
10747
10886
  if (columnsToRemove.length) {
10748
10887
  await unaggAnswerSession.removeColumns(columnsToRemove);
10749
10888
  }
10889
+ if (sortOptions === null || sortOptions === void 0 ? void 0 : sortOptions.length) {
10890
+ await unaggAnswerSession.adaptSorting(sortOptions, sourceDetail);
10891
+ }
10750
10892
  return unaggAnswerSession;
10751
10893
  }
10752
10894
  /**
@@ -10806,6 +10948,15 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
10806
10948
  this.tmlOverride = override;
10807
10949
  }
10808
10950
  }
10951
+ /**
10952
+ * Build a map from a source column guid to the answer's viz column id, using
10953
+ * the `referencedColumns` link on each viz column.
10954
+ * @param answer
10955
+ */
10956
+ function getGuidToColumnIdMap(answer) {
10957
+ const tableViz = answer.visualizations.find((viz) => viz.columns);
10958
+ return new Map(tableViz.columns.map((col) => [col.column.referencedColumns[0].guid, col.column.id]));
10959
+ }
10809
10960
  /**
10810
10961
  *
10811
10962
  * @param sourceDetail
@@ -19820,6 +19971,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
19820
19971
  const MIXPANEL_EVENT = {
19821
19972
  VISUAL_SDK_RENDER_START: 'visual-sdk-render-start',
19822
19973
  VISUAL_SDK_CALLED_INIT: 'visual-sdk-called-init',
19974
+ VISUAL_SDK_INIT_ACTIONS: 'visual-sdk-init-actions',
19823
19975
  VISUAL_SDK_RENDER_COMPLETE: 'visual-sdk-render-complete',
19824
19976
  VISUAL_SDK_RENDER_FAILED: 'visual-sdk-render-failed',
19825
19977
  VISUAL_SDK_TRIGGER: 'visual-sdk-trigger',
@@ -22202,9 +22354,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22202
22354
  */
22203
22355
  const PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY = 'tsEmbedOriginalPosition';
22204
22356
  const PRERENDER_WRAPPER_ID_PREFIX = 'tsEmbed-pre-render-wrapper-';
22205
- const PRERENDER_PARKED_TRANSFORM = 'translateY(-100%)';
22206
- /** The height createPreRenderWrapper() seeds before anything is measured. */
22207
- const UNMEASURED_WRAPPER_HEIGHT = '100vh';
22208
22357
  // The container applies UpdateEmbedParams through React state, so a delivered
22209
22358
  // post is not the same as the params being in effect.
22210
22359
  const UPDATE_EMBED_PARAMS_SETTLE_MS = 200;
@@ -22212,6 +22361,97 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22212
22361
  // truthy, so null or '' leaves the previous embed's values in place. '&' is
22213
22362
  // truthy and parses to {}.
22214
22363
  const NO_RUNTIME_PARAMS = '&';
22364
+ /**
22365
+ * Params kept on the iframe `src` when `excludeConfigFromURL` is set. The rest
22366
+ * are sent in the APP_INIT payload.
22367
+ * @internal
22368
+ */
22369
+ const BOOTSTRAP_URL_PARAMS = new Set([
22370
+ // Marks the app as embedded.
22371
+ Param.EmbedApp,
22372
+ // The host page URL, used to validate the postMessage origin.
22373
+ Param.HostAppUrl,
22374
+ // The SDK version.
22375
+ Param.Version,
22376
+ // The authentication type set in init.
22377
+ Param.AuthType,
22378
+ // Whether the app signs the user in automatically.
22379
+ Param.AutoLogin,
22380
+ // Stops the app from redirecting to its login page.
22381
+ Param.DisableLoginRedirect,
22382
+ // Forces the SAML redirect for EmbeddedSSO.
22383
+ Param.ForceSAMLAutoRedirect,
22384
+ // Set for cookieless trusted authentication.
22385
+ Param.cookieless,
22386
+ // Lets the app use the pre-fetched auth info.
22387
+ Param.preAuthCache,
22388
+ // Blocks access to the full app outside the embed.
22389
+ Param.blockNonEmbedFullAppAccess,
22390
+ // The org to load, which the auth info depends on.
22391
+ Param.OverrideOrgId,
22392
+ // The host window height when the iframe loads.
22393
+ Param.ViewPortHeight,
22394
+ // The host window width when the iframe loads.
22395
+ Param.ViewPortWidth,
22396
+ // The app's client log level.
22397
+ Param.ClientLogLevel,
22398
+ // Lets the app override the native console.
22399
+ Param.OverrideNativeConsole,
22400
+ // An extra Pendo tracking key.
22401
+ Param.PendoTrackingKey,
22402
+ // The locale for number formatting.
22403
+ Param.NumberFormatLocale,
22404
+ // The locale for date formatting.
22405
+ Param.DateFormatLocale,
22406
+ // The currency format.
22407
+ Param.CurrencyFormat,
22408
+ // The UI language.
22409
+ Param.Locale,
22410
+ // Turns on dark mode.
22411
+ Param.IsDarkMode,
22412
+ // Turns on the radiant theme that dark mode needs.
22413
+ Param.RadiantThemeEnabled,
22414
+ // Marks a SearchEmbed or SearchBarEmbed.
22415
+ Param.searchEmbed,
22416
+ // Marks a LiveboardEmbed.
22417
+ Param.livedBoardEmbed,
22418
+ // Marks a SpotterAgentEmbed.
22419
+ Param.isSpotterAgentEmbed,
22420
+ // Marks a SpotterEmbed.
22421
+ Param.SpotterEnabled,
22422
+ // Marks an AppEmbed.
22423
+ Param.IsFullAppEmbed,
22424
+ // Legacy flag for the onBeforeGetVizData API intercept.
22425
+ Param.IsOnBeforeGetVizDataInterceptEnabled,
22426
+ // Lets the host override links in the app.
22427
+ Param.LinkOverride,
22428
+ // Turns on version 2 of the link overrides.
22429
+ Param.EnableLinkOverridesV2,
22430
+ // Stops links from opening in a new tab.
22431
+ Param.DisableRedirectionLinksInNewTab,
22432
+ // Uses replaceState instead of pushState for app navigation.
22433
+ Param.OverrideHistoryState,
22434
+ // Shows search results as a table.
22435
+ Param.ForceTable,
22436
+ // The URL of the custom string IDs file.
22437
+ Param.StringIDsUrl,
22438
+ // The data sources that search opens with.
22439
+ Param.DataSources,
22440
+ // Exposes translation IDs in the app.
22441
+ Param.ExposeTranslationIDs,
22442
+ // The URL of the custom icon sprite.
22443
+ Param.IconSpriteUrl,
22444
+ // The tag that filters the metadata lists in an AppEmbed.
22445
+ Param.Tag,
22446
+ // Set when a Liveboard embed shows a single visualization (vizId).
22447
+ Param.vizEmbed,
22448
+ // Whether search opens with the last-selected data sources.
22449
+ Param.UseLastSelectedDataSource,
22450
+ // The query mode Spotter opens in.
22451
+ Param.DefaultQueryMode,
22452
+ // The initial search query. Omitted with excludeSearchTokenStringFromURL.
22453
+ Param.searchTokenString,
22454
+ ]);
22215
22455
  /**
22216
22456
  * The event id map from v2 event names to v1 event id
22217
22457
  * v1 events are the classic embed events implemented in Blink v1
@@ -22240,6 +22480,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22240
22480
  this.embedNodeKey = '__tsEmbed';
22241
22481
  this.embedContainerLoadedKey = '__tsEmbedContainerLoaded';
22242
22482
  this.isAppInitialized = false;
22483
+ this.initDataParams = {};
22243
22484
  /**
22244
22485
  * Should we encode URL Query Params using base64 encoding which ThoughtSpot
22245
22486
  * will generate for embedding. This provides additional security to
@@ -22249,6 +22490,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22249
22490
  this.shouldEncodeUrlQueryParams = false;
22250
22491
  this.defaultHiddenActions = [exports.Action.ReportError];
22251
22492
  this.preRenderContainerEl = document.body;
22493
+ this.containerScrollListener = null;
22252
22494
  /**
22253
22495
  * Handler for fullscreen change events
22254
22496
  */
@@ -22274,7 +22516,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22274
22516
  */
22275
22517
  this.appInitCb = async (_, responder) => {
22276
22518
  try {
22277
- const appInitData = await this.getAppInitData();
22519
+ const appInitData = this.withInitDataParams(await this.getAppInitData());
22278
22520
  this.isAppInitialized = true;
22279
22521
  responder({
22280
22522
  type: exports.EmbedEvent.APP_INIT,
@@ -22702,6 +22944,18 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22702
22944
  async getAppInitData() {
22703
22945
  return this.getDefaultAppInitData();
22704
22946
  }
22947
+ withInitDataParams(appInitData) {
22948
+ if (isEmpty_1(this.initDataParams)) {
22949
+ return appInitData;
22950
+ }
22951
+ return {
22952
+ ...appInitData,
22953
+ embedParams: {
22954
+ ...this.initDataParams,
22955
+ ...(appInitData.embedParams || {}),
22956
+ },
22957
+ };
22958
+ }
22705
22959
  /**
22706
22960
  * Helper method to refresh/update auth token for TrustedAuthTokenCookieless auth type
22707
22961
  * @param responder - Function to send response back
@@ -22761,7 +23015,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22761
23015
  * @returns queryParams
22762
23016
  */
22763
23017
  getBaseQueryParams(queryParams = {}) {
22764
- var _a, _b, _c, _d;
23018
+ var _a, _b, _c, _d, _e;
22765
23019
  let hostAppUrl = ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.host) || '';
22766
23020
  // The below check is needed because TS Cloud firewall, blocks
22767
23021
  // localhost/127.0.0.1 in any url param.
@@ -22798,6 +23052,15 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22798
23052
  if (this.embedConfig.currencyFormat) {
22799
23053
  queryParams[Param.CurrencyFormat] = this.embedConfig.currencyFormat;
22800
23054
  }
23055
+ // The view config wins over init, so an embed can opt out of a dark
23056
+ // mode set in `init`. `??` and not `||`, so that an explicit `false`
23057
+ // overrides an init-level `true`.
23058
+ const isDarkMode = (_c = this.viewConfig.isDarkMode) !== null && _c !== void 0 ? _c : this.embedConfig.isDarkMode;
23059
+ setParamIfDefined(queryParams, Param.IsDarkMode, isDarkMode, true);
23060
+ // The app's dark mode lives in its radiant theme, so turn that on too.
23061
+ if (isDarkMode) {
23062
+ queryParams[Param.RadiantThemeEnabled] = true;
23063
+ }
22801
23064
  const { disabledActions, disabledActionReason, hiddenActions, visibleActions, hiddenTabs, visibleTabs, showAlerts, additionalFlags: additionalFlagsFromView, locale, customizations, contextMenuTrigger, linkOverride, enableLinkOverridesV2, insertInToSlide, disableRedirectionLinksInNewTab, overrideOrgId, overrideHistoryState, exposeTranslationIDs, primaryAction, } = this.viewConfig;
22802
23065
  const { additionalFlags: additionalFlagsFromInit } = this.embedConfig;
22803
23066
  const additionalFlags = {
@@ -22863,7 +23126,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22863
23126
  if (spriteUrl) {
22864
23127
  queryParams[Param.IconSpriteUrl] = spriteUrl.replace('https://', '');
22865
23128
  }
22866
- const stringIDsUrl = ((_c = customizations === null || customizations === void 0 ? void 0 : customizations.content) === null || _c === void 0 ? void 0 : _c.stringIDsUrl) || ((_d = embedCustomizations === null || embedCustomizations === void 0 ? void 0 : embedCustomizations.content) === null || _d === void 0 ? void 0 : _d.stringIDsUrl);
23129
+ const stringIDsUrl = ((_d = customizations === null || customizations === void 0 ? void 0 : customizations.content) === null || _d === void 0 ? void 0 : _d.stringIDsUrl) || ((_e = embedCustomizations === null || embedCustomizations === void 0 ? void 0 : embedCustomizations.content) === null || _e === void 0 ? void 0 : _e.stringIDsUrl);
22867
23130
  if (stringIDsUrl) {
22868
23131
  queryParams[Param.StringIDsUrl] = stringIDsUrl;
22869
23132
  }
@@ -22917,13 +23180,32 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
22917
23180
  return path;
22918
23181
  }
22919
23182
  getEmbedParams() {
22920
- const queryParams = this.getEmbedParamsObject();
23183
+ const queryParams = this.getUrlQueryParamsObject();
22921
23184
  return getQueryParamString(queryParams);
22922
23185
  }
22923
23186
  getEmbedParamsObject() {
22924
23187
  const params = this.getBaseQueryParams();
22925
23188
  return params;
22926
23189
  }
23190
+ getUrlQueryParamsObject() {
23191
+ const queryParams = this.getEmbedParamsObject();
23192
+ if (!this.isConfigExcludedFromUrl()) {
23193
+ this.initDataParams = {};
23194
+ return queryParams;
23195
+ }
23196
+ const urlParams = {};
23197
+ const excludedParams = {};
23198
+ Object.entries(queryParams).forEach(([key, value]) => {
23199
+ if (BOOTSTRAP_URL_PARAMS.has(key)) {
23200
+ urlParams[key] = value;
23201
+ }
23202
+ else {
23203
+ excludedParams[key] = deserializeParam(value);
23204
+ }
23205
+ });
23206
+ this.initDataParams = excludedParams;
23207
+ return urlParams;
23208
+ }
22927
23209
  getRootIframeSrc() {
22928
23210
  const query = this.getEmbedParams();
22929
23211
  return this.getEmbedBasePath(query);
@@ -23094,7 +23376,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23094
23376
  top: '0',
23095
23377
  left: '0',
23096
23378
  width: '100vw',
23097
- height: UNMEASURED_WRAPPER_HEIGHT,
23379
+ height: '100vh',
23098
23380
  };
23099
23381
  setStyleProperties(preRenderWrapper, initialPreRenderWrapperStyle);
23100
23382
  return preRenderWrapper;
@@ -23162,26 +23444,10 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23162
23444
  return placeholder;
23163
23445
  }
23164
23446
  /**
23165
- * Resolves the configured preRenderContainer to a live element. A string
23166
- * selector is re-queried on every call so a remounted container (E.g.: React
23167
- * replacing the node) resolves to the fresh element; an element passed
23168
- * directly cannot be re-resolved.
23169
- *
23170
- * With nothing configured the frame goes into the host element's nearest
23171
- * scrolling ancestor, falling back to `document.body`.
23172
- *
23173
- * The wrapper is absolutely positioned, so it follows the page for free —
23174
- * but only while it sits inside whatever scrolls. `document.body` is right
23175
- * only when the document itself is the scroller; an app that scrolls an
23176
- * inner element instead left the frame pinned to the viewport while the page
23177
- * moved under it (SCAL-338563). Being inside the scroller also lets wheel
23178
- * events chain out of the frame into it, which they cannot do from
23179
- * `document.body`.
23180
- *
23181
- * A scrolling ancestor is layout chrome rather than route content, so it
23182
- * outlives the embed in practice; and if it does go, the host element goes
23183
- * with it and this instance is remounting anyway.
23184
- * `reconcilePreRenderContainer` re-runs this on a detached container.
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.
23185
23451
  */
23186
23452
  resolvePreRenderContainerTarget() {
23187
23453
  var _a;
@@ -23201,13 +23467,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23201
23467
  else if (containerConfig) {
23202
23468
  container = containerConfig;
23203
23469
  }
23204
- if (container) {
23205
- return container;
23206
- }
23207
- if (!this.hostElement) {
23208
- return document.body;
23209
- }
23210
- return (_a = getScrollableAncestors(this.hostElement)[0]) !== null && _a !== void 0 ? _a : document.body;
23470
+ return (_a = container) !== null && _a !== void 0 ? _a : document.body;
23211
23471
  }
23212
23472
  inheritPreRenderContainer() {
23213
23473
  var _a;
@@ -23252,9 +23512,8 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23252
23512
  * Re-attaches the wrapper to a live container when the previously resolved
23253
23513
  * one has been detached or no longer holds the wrapper — e.g. the host app
23254
23514
  * remounted a custom preRenderContainer, which would otherwise leave a stale
23255
- * reference and collapse the wrapper. Selectors and the auto-resolved
23256
- * scrolling ancestor are both re-resolved; a container passed as an element
23257
- * is left untouched, as there is nothing to re-query.
23515
+ * reference and collapse the wrapper. Only string selectors can be
23516
+ * re-resolved; a container passed as an element is left untouched.
23258
23517
  */
23259
23518
  reconcilePreRenderContainer() {
23260
23519
  const wrapper = this.preRenderWrapper;
@@ -23273,6 +23532,14 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23273
23532
  if (resolved === stored && stored.contains(wrapper)) {
23274
23533
  return;
23275
23534
  }
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
+ }
23276
23543
  this.preRenderContainerEl = resolved;
23277
23544
  this.applyPreRenderContainerPositioning();
23278
23545
  if (wrapper.parentNode !== resolved) {
@@ -23334,12 +23601,11 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23334
23601
  */
23335
23602
  setIFrameHeight(height) {
23336
23603
  if (this.isPreRendered) {
23337
- const next = getCssDimension(height);
23338
23604
  if (this.insertedDomEl) {
23339
- this.insertedDomEl.style.height = next;
23605
+ this.insertedDomEl.style.height = getCssDimension(height);
23340
23606
  }
23341
23607
  else if (this.preRenderWrapper) {
23342
- this.preRenderWrapper.style.height = next;
23608
+ this.preRenderWrapper.style.height = getCssDimension(height);
23343
23609
  }
23344
23610
  }
23345
23611
  else {
@@ -23623,9 +23889,16 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23623
23889
  * @param args
23624
23890
  */
23625
23891
  async render() {
23892
+ var _a, _b, _c;
23626
23893
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_RENDER_CALLED, {
23627
23894
  embedComponentType: this.viewConfig.embedComponentType,
23628
23895
  });
23896
+ uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_INIT_ACTIONS, {
23897
+ embedComponentType: this.viewConfig.embedComponentType,
23898
+ hiddenActions: (_a = this.viewConfig.hiddenActions) !== null && _a !== void 0 ? _a : [],
23899
+ visibleActions: (_b = this.viewConfig.visibleActions) !== null && _b !== void 0 ? _b : [],
23900
+ disabledActions: (_c = this.viewConfig.disabledActions) !== null && _c !== void 0 ? _c : [],
23901
+ });
23629
23902
  if (!getIsInitCalled()) {
23630
23903
  logger$3.error(ERROR_MESSAGE.RENDER_CALLED_BEFORE_INIT);
23631
23904
  }
@@ -23774,47 +24047,34 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23774
24047
  delete container.dataset[PRERENDER_CONTAINER_ORIGINAL_POSITION_KEY];
23775
24048
  }
23776
24049
  /**
23777
- * Re-sizes the wrapper when its placeholder changes size.
23778
- *
23779
- * Position deliberately has no equivalent. An absolutely positioned wrapper
23780
- * follows its containing block for free, so a correctly placed frame is the
23781
- * browser's job and costs nothing; repositioning it on scroll would mean a
23782
- * layout read and a style write per frame to compensate for placing it in
23783
- * the wrong box. Size is the one thing the browser will not do for us: the
23784
- * placeholder grows when the embedded app reports a new height, and the
23785
- * wrapper has to be told.
23786
- */
23787
- observePreRenderSize() {
23788
- var _a;
23789
- if (this.getPreRenderConfig().doNotTrackSize || typeof ResizeObserver === 'undefined') {
23790
- return;
23791
- }
23792
- const placeholder = this.getPreRenderPlaceHolderElement();
23793
- if (!placeholder) {
24050
+ * Detaches and clears the container scroll listener, if one is attached.
24051
+ */
24052
+ removeContainerScrollListener() {
24053
+ if (!this.containerScrollListener) {
23794
24054
  return;
23795
24055
  }
23796
- (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
23797
- this.resizeObserver = new ResizeObserver(() => this.syncPreRenderStyle());
23798
- this.resizeObserver.observe(placeholder);
24056
+ const customContainer = this.getCustomPreRenderContainer();
24057
+ customContainer === null || customContainer === void 0 ? void 0 : customContainer.removeEventListener('scroll', this.containerScrollListener);
24058
+ this.containerScrollListener = null;
23799
24059
  }
23800
24060
  /**
23801
24061
  * Destroys the ThoughtSpot embed, and remove any nodes from the DOM.
23802
24062
  * @version SDK: 1.19.1 | ThoughtSpot: *
23803
24063
  */
23804
24064
  destroy() {
23805
- var _a, _b, _c, _d;
24065
+ var _a, _b, _c;
23806
24066
  try {
23807
24067
  this.removeFullscreenChangeHandler();
23808
- (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
24068
+ this.removeContainerScrollListener();
23809
24069
  this.unsubscribeToEvents();
23810
- (_b = this.preRenderWrapper) === null || _b === void 0 ? void 0 : _b.remove();
24070
+ (_a = this.preRenderWrapper) === null || _a === void 0 ? void 0 : _a.remove();
23811
24071
  this.restorePreRenderContainerPosition();
23812
24072
  if (!this.isRendered) {
23813
24073
  return;
23814
24074
  }
23815
24075
  if (!getEmbedConfig().waitForCleanupOnDestroy) {
23816
24076
  this.trigger(exports.HostEvent.DestroyEmbed);
23817
- (_d = (_c = this.insertedDomEl) === null || _c === void 0 ? void 0 : _c.parentNode) === null || _d === void 0 ? void 0 : _d.removeChild(this.insertedDomEl);
24077
+ (_c = (_b = this.insertedDomEl) === null || _b === void 0 ? void 0 : _b.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(this.insertedDomEl);
23818
24078
  }
23819
24079
  else {
23820
24080
  const cleanupTimeout = getEmbedConfig().cleanupTimeout;
@@ -23860,6 +24120,26 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23860
24120
  this.isRendered = true;
23861
24121
  return this.renderIFrame(prerenderFrameSrc);
23862
24122
  }
24123
+ isConfigExcludedFromUrl() {
24124
+ var _a, _b, _c;
24125
+ const flag = (_b = (_a = this.viewConfig.additionalFlags) === null || _a === void 0 ? void 0 : _a.excludeConfigFromURL) !== null && _b !== void 0 ? _b : (_c = this.embedConfig.additionalFlags) === null || _c === void 0 ? void 0 : _c.excludeConfigFromURL;
24126
+ return flag === true || flag === 'true';
24127
+ }
24128
+ async triggerUpdateEmbedParams() {
24129
+ try {
24130
+ const params = await this.getUpdateEmbedParamsObject();
24131
+ this.trigger(exports.HostEvent.UpdateEmbedParams, params);
24132
+ }
24133
+ catch (error) {
24134
+ logger$3.error(ERROR_MESSAGE.UPDATE_PARAMS_FAILED, error);
24135
+ this.handleError({
24136
+ errorType: exports.ErrorDetailsTypes.API,
24137
+ message: (error === null || error === void 0 ? void 0 : error.message) || ERROR_MESSAGE.UPDATE_PARAMS_FAILED,
24138
+ code: exports.EmbedErrorCodes.UPDATE_PARAMS_FAILED,
24139
+ error: (error === null || error === void 0 ? void 0 : error.message) || error,
24140
+ });
24141
+ }
24142
+ }
23863
24143
  beforePrerenderVisible() {
23864
24144
  // We can ignore this as its a bit expensive and the newer customers
23865
24145
  // have moved on to UpdateEmbedParams supported clusters
@@ -23870,17 +24150,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23870
24150
  this.preRenderParamsApplied = new Promise((resolve) => {
23871
24151
  this.executeAfterEmbedContainerLoaded(async () => {
23872
24152
  try {
23873
- const params = await this.getUpdateEmbedParamsObject();
23874
- this.trigger(exports.HostEvent.UpdateEmbedParams, params);
23875
- }
23876
- catch (error) {
23877
- logger$3.error(ERROR_MESSAGE.UPDATE_PARAMS_FAILED, error);
23878
- this.handleError({
23879
- errorType: exports.ErrorDetailsTypes.API,
23880
- message: (error === null || error === void 0 ? void 0 : error.message) || ERROR_MESSAGE.UPDATE_PARAMS_FAILED,
23881
- code: exports.EmbedErrorCodes.UPDATE_PARAMS_FAILED,
23882
- error: (error === null || error === void 0 ? void 0 : error.message) || error,
23883
- });
24153
+ await this.triggerUpdateEmbedParams();
23884
24154
  }
23885
24155
  finally {
23886
24156
  setTimeout(resolve, UPDATE_EMBED_PARAMS_SETTLE_MS);
@@ -23895,7 +24165,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23895
24165
  * wrapper to overlay it.
23896
24166
  */
23897
24167
  async showPreRender() {
23898
- var _a;
24168
+ var _a, _b;
23899
24169
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_SHOW_PRE_RENDER, {
23900
24170
  preRenderId: this.getPreRenderConfig().id,
23901
24171
  embedComponentType: this.viewConfig.embedComponentType,
@@ -23914,16 +24184,14 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23914
24184
  this.beforePrerenderVisible();
23915
24185
  if (this.hostElement) {
23916
24186
  this.insertedDomEl = this.createPreRenderPlaceholder();
23917
- // Carry a height fullHeight has already measured onto the fresh
23918
- // placeholder, so a re-show does not flash at frameParams height.
23919
- // UNMEASURED_WRAPPER_HEIGHT is what createPreRenderWrapper() seeds
23920
- // before anything has been measured; treating that as a measurement
23921
- // is what made a first reveal overshoot to a full viewport.
23922
- const wrapperHeight = this.preRenderWrapper.style.height;
23923
- if (this.viewConfig.fullHeight
23924
- && wrapperHeight
23925
- && wrapperHeight !== UNMEASURED_WRAPPER_HEIGHT) {
23926
- this.insertedDomEl.style.height = wrapperHeight;
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
+ }
23927
24195
  }
23928
24196
  const placeHolderId = this.getPreRenderIds().placeHolder;
23929
24197
  // Remove any stale placeholder from a previous cycle. It is located
@@ -23937,19 +24205,29 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
23937
24205
  (_a = this.hostElement.querySelector(`#${placeHolderId}`)) === null || _a === void 0 ? void 0 : _a.remove();
23938
24206
  this.hostElement.appendChild(this.insertedDomEl);
23939
24207
  this.syncPreRenderStyle();
23940
- this.observePreRenderSize();
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
+ }
23941
24224
  }
23942
24225
  removeStyleProperties(this.preRenderWrapper, [
23943
24226
  'z-index',
23944
24227
  'opacity',
24228
+ 'pointer-events',
23945
24229
  'overflow',
23946
- 'transform',
23947
24230
  ]);
23948
- // Set rather than removed: a container that carries `pointer-events:
23949
- // none` — the usual styling for a parking root that must not swallow
23950
- // clicks — passes it down, and dropping the property here would leave
23951
- // the inherited `none` in force and the frame dead to input.
23952
- setStyleProperties(this.preRenderWrapper, { pointerEvents: 'auto' });
23953
24231
  this.subscribeToEvents();
23954
24232
  // Setup fullscreen change handler for prerendered components
23955
24233
  if (this.iFrame) {
@@ -24002,7 +24280,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24002
24280
  * If the component is not preRendered, it issues a warning.
24003
24281
  */
24004
24282
  hidePreRender() {
24005
- var _a;
24006
24283
  uploadMixpanelEvent(MIXPANEL_EVENT.VISUAL_SDK_HIDE_PRE_RENDER, {
24007
24284
  preRenderId: this.getPreRenderConfig().id,
24008
24285
  embedComponentType: this.viewConfig.embedComponentType,
@@ -24022,15 +24299,12 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24022
24299
  top: '0',
24023
24300
  left: '0',
24024
24301
  overflow: 'hidden',
24025
- // Keeps the measured size — so the next show needs no resize, which
24026
- // is the point of pre-rendering — while lifting the box out of
24027
- // the container's scrollable area. Overflow only extends
24028
- // downwards, so a hidden frame parked above the top edge adds
24029
- // none, where one left at full height shows as blank scroll space.
24030
- transform: PRERENDER_PARKED_TRANSFORM,
24031
24302
  };
24032
24303
  setStyleProperties(this.preRenderWrapper, preRenderHideStyles);
24033
- (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
24304
+ this.removeContainerScrollListener();
24305
+ if (this.resizeObserver) {
24306
+ this.resizeObserver.disconnect();
24307
+ }
24034
24308
  const placeHolderEle = this.getPreRenderPlaceHolderElement();
24035
24309
  if (placeHolderEle) {
24036
24310
  placeHolderEle.parentElement.removeChild(placeHolderEle);
@@ -24259,7 +24533,19 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24259
24533
  spotterAnalystConfig,
24260
24534
  },
24261
24535
  };
24262
- }
24536
+ }
24537
+ /**
24538
+ * The Spotter experience version to load in the embedded view.
24539
+ * @version SDK: 1.53.0 | ThoughtSpot Cloud: 26.11.0.cl
24540
+ * @group Embed components
24541
+ */
24542
+ exports.SpotterExperienceVersion = void 0;
24543
+ (function (SpotterExperienceVersion) {
24544
+ /**
24545
+ * The Spotter experience version introduced in ThoughtSpot 26.11.
24546
+ */
24547
+ SpotterExperienceVersion["SPOTTER_2026_11"] = "spotter_2026_11";
24548
+ })(exports.SpotterExperienceVersion || (exports.SpotterExperienceVersion = {}));
24263
24549
 
24264
24550
  function buildSpotterVizAppInitData(initData, viewConfig) {
24265
24551
  const { spotterViz } = viewConfig;
@@ -24456,12 +24742,12 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24456
24742
  * embedded Liveboard or visualization.
24457
24743
  */
24458
24744
  getEmbedParams() {
24459
- const params = this.getEmbedParamsObject();
24745
+ const params = this.getUrlQueryParamsObject();
24460
24746
  return getQueryParamString(params, true);
24461
24747
  }
24462
24748
  getEmbedParamsObject() {
24463
24749
  var _a;
24464
- const { tag, hideTagFilterChips, hideObjects, liveboardV2, showPrimaryNavbar, disableProfileAndHelp, hideHamburger, hideObjectSearch, hideNotification, hideApplicationSwitcher, hideOrgSwitcher, enableSearchAssist, newConnectionsExperience, dataPanelV2 = true, updatedSpotterExperience, hideLiveboardHeader = false, showLiveboardTitle = true, showLiveboardDescription = true, showMaskedFilterChip = false, isLiveboardMasterpiecesEnabled, newChartsLibrary, hideHomepageLeftNav = false, modularHomeExperience, isLiveboardHeaderSticky = true, enableAskSage, collapseSearchBarInitially = false, enable2ColumnLayout, isLiveboardAlwaysOn12ColLayout, enableCustomColumnGroups = false, dataPanelCustomGroupsAccordionInitialState = exports.DataPanelCustomColumnGroupsAccordionState.EXPAND_ALL, collapseSearchBar = true, isLiveboardCompactHeaderEnabled, showLiveboardVerifiedBadge = true, showLiveboardReverifyBanner = true, hideIrrelevantChipsInLiveboardTabs, isEnhancedFilterInteractivityEnabled, homePageSearchBarMode, isUnifiedSearchExperienceEnabled = true, enablePendoHelp = true, discoveryExperience, coverAndFilterOptionInPDF, isLiveboardStylingAndGroupingEnabled, liveboardGutter, isPNGInScheduledEmailsEnabled = false, isLiveboardXLSXCSVDownloadEnabled, isGranularXLSXCSVSchedulesEnabled, isCentralizedLiveboardFilterUXEnabled = false, isScopedLiveboardFilteringEnabled, isLinkParametersEnabled, updatedSpotterChatPrompt, showSpotterRadiance, defaultQueryMode, enableStopAnswerGenerationEmbed, spotterChatConfig, spotterDataSources, isThisPeriodInDateFiltersEnabled, enableHomepageAnnouncement = false, isContinuousLiveboardPDFEnabled, enableLiveboardDataCache, hideAnswerEditPanel, } = this.viewConfig;
24750
+ const { tag, hideTagFilterChips, hideObjects, liveboardV2, showPrimaryNavbar, disableProfileAndHelp, hideHamburger, hideObjectSearch, hideNotification, hideApplicationSwitcher, hideOrgSwitcher, enableSearchAssist, newConnectionsExperience, dataPanelV2 = true, updatedSpotterExperience, hideLiveboardHeader = false, showLiveboardTitle = true, showLiveboardDescription = true, showMaskedFilterChip = false, isLiveboardMasterpiecesEnabled, newChartsLibrary, hideHomepageLeftNav = false, modularHomeExperience, isLiveboardHeaderSticky = true, enableAskSage, collapseSearchBarInitially = false, enable2ColumnLayout, isLiveboardAlwaysOn12ColLayout, enableCustomColumnGroups = false, dataPanelCustomGroupsAccordionInitialState = exports.DataPanelCustomColumnGroupsAccordionState.EXPAND_ALL, collapseSearchBar = true, isLiveboardCompactHeaderEnabled, showLiveboardVerifiedBadge = true, showLiveboardReverifyBanner = true, hideIrrelevantChipsInLiveboardTabs, isEnhancedFilterInteractivityEnabled, homePageSearchBarMode, isUnifiedSearchExperienceEnabled = true, enablePendoHelp = true, discoveryExperience, coverAndFilterOptionInPDF, isLiveboardStylingAndGroupingEnabled, liveboardGutter, isPNGInScheduledEmailsEnabled = false, isLiveboardXLSXCSVDownloadEnabled, isGranularXLSXCSVSchedulesEnabled, isCentralizedLiveboardFilterUXEnabled = false, isScopedLiveboardFilteringEnabled, isLinkParametersEnabled, updatedSpotterChatPrompt, showSpotterRadiance, defaultQueryMode, enableStopAnswerGenerationEmbed, spotterChatConfig, spotterDataSources, isThisPeriodInDateFiltersEnabled, enableHomepageAnnouncement = false, isContinuousLiveboardPDFEnabled, enableLiveboardDataCache, hideAnswerEditPanel, spotterExperienceVersion, } = this.viewConfig;
24465
24751
  let params = {};
24466
24752
  params[Param.PrimaryNavHidden] = !showPrimaryNavbar;
24467
24753
  params[Param.HideProfleAndHelp] = !!disableProfileAndHelp;
@@ -24516,6 +24802,9 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24516
24802
  if (spotterDataSources && spotterDataSources.length) {
24517
24803
  params[Param.SpotterDataSources] = JSON.stringify(spotterDataSources);
24518
24804
  }
24805
+ if (spotterExperienceVersion !== undefined) {
24806
+ params[Param.SpotterExperienceVersion] = spotterExperienceVersion;
24807
+ }
24519
24808
  // Handle spotterChatConfig params
24520
24809
  if (spotterChatConfig) {
24521
24810
  const { hideToolResponseCardBranding, toolResponseCardBrandingLabel, spotterFileUploadEnabled, spotterFileUploadFileTypes, enableStarterPrompts, openSpotterOnLiveboardByDefault, } = spotterChatConfig;
@@ -24634,7 +24923,7 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24634
24923
  }
24635
24924
  // Navigation V1/V2 and home page V1/V2 are deprecated. V3 is now the
24636
24925
  // default experience, Need to send navigationVersion=v3 and
24637
- // homepageVersion=v3 even when the no discoveryExperience /
24926
+ // homepageVersion=v3 even when the no discoveryExperience /
24638
24927
  // modularHomeExperience config is set. Without these
24639
24928
  // params, older TSA versions (< 26.7) fall back to V2 for nav and
24640
24929
  // home page, so the defaults must be sent explicitly from the SDK.
@@ -24773,46 +25062,6 @@ mutation GetUnsavedAnswerTML($session: BachSessionIdInput!, $exportDependencies:
24773
25062
  }
24774
25063
  }
24775
25064
 
24776
- /**
24777
- * This method is like `_.isEqual` except that it accepts `customizer` which
24778
- * is invoked to compare values. If `customizer` returns `undefined`, comparisons
24779
- * are handled by the method instead. The `customizer` is invoked with up to
24780
- * six arguments: (objValue, othValue [, index|key, object, other, stack]).
24781
- *
24782
- * @static
24783
- * @memberOf _
24784
- * @since 4.0.0
24785
- * @category Lang
24786
- * @param {*} value The value to compare.
24787
- * @param {*} other The other value to compare.
24788
- * @param {Function} [customizer] The function to customize comparisons.
24789
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
24790
- * @example
24791
- *
24792
- * function isGreeting(value) {
24793
- * return /^h(?:i|ello)$/.test(value);
24794
- * }
24795
- *
24796
- * function customizer(objValue, othValue) {
24797
- * if (isGreeting(objValue) && isGreeting(othValue)) {
24798
- * return true;
24799
- * }
24800
- * }
24801
- *
24802
- * var array = ['hello', 'goodbye'];
24803
- * var other = ['hi', 'goodbye'];
24804
- *
24805
- * _.isEqualWith(array, other, customizer);
24806
- * // => true
24807
- */
24808
- function isEqualWith(value, other, customizer) {
24809
- customizer = typeof customizer == 'function' ? customizer : undefined;
24810
- var result = customizer ? customizer(value, other) : undefined;
24811
- return result === undefined ? _baseIsEqual(value, other, undefined, customizer) : !!result;
24812
- }
24813
-
24814
- var isEqualWith_1 = isEqualWith;
24815
-
24816
25065
  const getPreviewQuery = `
24817
25066
  query GetEurekaVizSnapshots(
24818
25067
  $vizId: String!, $liveboardId: String!) {
@@ -24883,6 +25132,21 @@ query GetEurekaVizSnapshots(
24883
25132
  document.head.insertAdjacentHTML('beforeend', previewStyles);
24884
25133
  };
24885
25134
 
25135
+ function buildLiveboardOverrideAppInitData(initData, viewConfig) {
25136
+ var _a;
25137
+ const { liveboardOverride } = viewConfig;
25138
+ // ThoughtSpot ignores an override with no data source entries; skip it.
25139
+ if (!((_a = liveboardOverride === null || liveboardOverride === void 0 ? void 0 : liveboardOverride.dataSourceOverride) === null || _a === void 0 ? void 0 : _a.length))
25140
+ return initData;
25141
+ return {
25142
+ ...initData,
25143
+ embedParams: {
25144
+ ...(initData.embedParams || {}),
25145
+ liveboardOverride,
25146
+ },
25147
+ };
25148
+ }
25149
+
24886
25150
  /**
24887
25151
  * Copyright (c) 2022
24888
25152
  *
@@ -24947,14 +25211,15 @@ query GetEurekaVizSnapshots(
24947
25211
  async getAppInitData() {
24948
25212
  const defaultAppInitData = await super.getAppInitData();
24949
25213
  const vizInitData = buildSpotterVizAppInitData(defaultAppInitData, this.viewConfig);
24950
- return buildStarterPromptsAppInitData(vizInitData, this.viewConfig);
25214
+ const starterPromptsInitData = buildStarterPromptsAppInitData(vizInitData, this.viewConfig);
25215
+ return buildLiveboardOverrideAppInitData(starterPromptsInitData, this.viewConfig);
24951
25216
  }
24952
25217
  /**
24953
25218
  * Construct a map of params to be passed on to the
24954
25219
  * embedded Liveboard or visualization.
24955
25220
  */
24956
25221
  getEmbedParams() {
24957
- const params = this.getEmbedParamsObject();
25222
+ const params = this.getUrlQueryParamsObject();
24958
25223
  const queryParams = getQueryParamString(params, true);
24959
25224
  return queryParams;
24960
25225
  }
@@ -24962,7 +25227,7 @@ query GetEurekaVizSnapshots(
24962
25227
  var _a;
24963
25228
  let params = {};
24964
25229
  params = this.getBaseQueryParams(params);
24965
- const { enableVizTransformations, visibleVizs, liveboardV2, vizId, hideTabPanel, activeTabId, hideLiveboardHeader, showLiveboardDescription, showLiveboardTitle, isLiveboardHeaderSticky = true, isLiveboardCompactHeaderEnabled, showLiveboardVerifiedBadge = true, showLiveboardReverifyBanner = true, hideIrrelevantChipsInLiveboardTabs, showMaskedFilterChip = false, isLiveboardMasterpiecesEnabled, newChartsLibrary, isEnhancedFilterInteractivityEnabled, enableAskSage, enable2ColumnLayout, isLiveboardAlwaysOn12ColLayout, dataPanelV2 = true, updatedSpotterExperience, enableCustomColumnGroups = false, oAuthPollingInterval, isForceRedirect, dataSourceId, coverAndFilterOptionInPDF, isLiveboardStylingAndGroupingEnabled, liveboardGutter, isPNGInScheduledEmailsEnabled = false, isLiveboardXLSXCSVDownloadEnabled, isGranularXLSXCSVSchedulesEnabled, showSpotterLimitations, isCentralizedLiveboardFilterUXEnabled = false, isScopedLiveboardFilteringEnabled, isLinkParametersEnabled, updatedSpotterChatPrompt, showSpotterRadiance, enableStopAnswerGenerationEmbed, spotterChatConfig, isThisPeriodInDateFiltersEnabled, isContinuousLiveboardPDFEnabled, enableLiveboardDataCache, } = this.viewConfig;
25230
+ const { enableVizTransformations, visibleVizs, liveboardV2, vizId, hideTabPanel, activeTabId, hideLiveboardHeader, showLiveboardDescription, showLiveboardTitle, isLiveboardHeaderSticky = true, isLiveboardCompactHeaderEnabled, showLiveboardVerifiedBadge = true, showLiveboardReverifyBanner = true, hideIrrelevantChipsInLiveboardTabs, showMaskedFilterChip = false, isLiveboardMasterpiecesEnabled, newChartsLibrary, isEnhancedFilterInteractivityEnabled, enableAskSage, enable2ColumnLayout, isLiveboardAlwaysOn12ColLayout, dataPanelV2 = true, updatedSpotterExperience, enableCustomColumnGroups = false, oAuthPollingInterval, isForceRedirect, dataSourceId, coverAndFilterOptionInPDF, isLiveboardStylingAndGroupingEnabled, liveboardGutter, isPNGInScheduledEmailsEnabled = false, isLiveboardXLSXCSVDownloadEnabled, isGranularXLSXCSVSchedulesEnabled, showSpotterLimitations, isCentralizedLiveboardFilterUXEnabled = false, isScopedLiveboardFilteringEnabled, isLinkParametersEnabled, updatedSpotterChatPrompt, showSpotterRadiance, enableStopAnswerGenerationEmbed, spotterChatConfig, isThisPeriodInDateFiltersEnabled, isContinuousLiveboardPDFEnabled, enableLiveboardDataCache, spotterExperienceVersion, } = this.viewConfig;
24966
25231
  const preventLiveboardFilterRemoval = this.viewConfig.preventLiveboardFilterRemoval
24967
25232
  || this.viewConfig.preventPinboardFilterRemoval;
24968
25233
  (_a = this.fullHeightController) === null || _a === void 0 ? void 0 : _a.addQueryParams(params);
@@ -25024,6 +25289,9 @@ query GetEurekaVizSnapshots(
25024
25289
  if (isLiveboardStylingAndGroupingEnabled !== undefined) {
25025
25290
  params[Param.IsLiveboardStylingAndGroupingEnabled] = isLiveboardStylingAndGroupingEnabled;
25026
25291
  }
25292
+ if (spotterExperienceVersion !== undefined) {
25293
+ params[Param.SpotterExperienceVersion] = spotterExperienceVersion;
25294
+ }
25027
25295
  if (liveboardGutter !== undefined) {
25028
25296
  params[Param.LiveboardGutter] = liveboardGutter;
25029
25297
  }
@@ -25193,12 +25461,10 @@ query GetEurekaVizSnapshots(
25193
25461
  beforePrerenderVisible() {
25194
25462
  super.beforePrerenderVisible();
25195
25463
  // Captured before showPreRender() hands the wrapper over to this
25196
- // instance. React builds a new instance per mount, so an equal config
25197
- // is a hide/show, not a hand-over: there is nothing stale to clear.
25464
+ // instance. Itself means a hide/show, not a hand-over, so there is
25465
+ // nothing stale to clear.
25198
25466
  const previous = this.getPreRenderObj();
25199
- const showing = this.isSameEmbedConfig(previous)
25200
- ? undefined
25201
- : previous === null || previous === void 0 ? void 0 : previous.currentLiveboardState;
25467
+ const showing = previous === this ? undefined : previous === null || previous === void 0 ? void 0 : previous.currentLiveboardState;
25202
25468
  this.executeAfterEmbedContainerLoaded(async () => {
25203
25469
  // Without this the params callback suspends on its await and
25204
25470
  // Navigate goes out first, so the container loads with the previous
@@ -25225,14 +25491,6 @@ query GetEurekaVizSnapshots(
25225
25491
  };
25226
25492
  });
25227
25493
  }
25228
- // Callbacks are compared as equal: React passes a fresh closure per render.
25229
- isSameEmbedConfig(previous) {
25230
- if (!previous)
25231
- return false;
25232
- if (previous === this)
25233
- return true;
25234
- return isEqualWith_1(previous.viewConfig, this.viewConfig, (a, b) => (typeof a === 'function' && typeof b === 'function' ? true : undefined));
25235
- }
25236
25494
  // The whole route, not just the liveboard id: the path is built from the
25237
25495
  // viz, tab and view too, so a same-liveboard show onto another tab is a
25238
25496
  // real navigation.
@@ -25495,7 +25753,7 @@ query GetEurekaVizSnapshots(
25495
25753
  }
25496
25754
  getEmbedParams() {
25497
25755
  const { runtimeParameters, runtimeFilters, excludeRuntimeParametersfromURL, excludeRuntimeFiltersfromURL, } = this.viewConfig;
25498
- const queryParams = this.getEmbedParamsObject();
25756
+ const queryParams = this.getUrlQueryParamsObject();
25499
25757
  let query = '';
25500
25758
  const queryParamsString = getQueryParamString(queryParams, true);
25501
25759
  if (queryParamsString) {
@@ -25583,7 +25841,7 @@ query GetEurekaVizSnapshots(
25583
25841
  * @param dataSources A list of data source GUIDs
25584
25842
  */
25585
25843
  getIFrameSrc() {
25586
- const queryParams = this.getEmbedParamsObject();
25844
+ const queryParams = this.getUrlQueryParamsObject();
25587
25845
  const path = 'search-bar-embed';
25588
25846
  let query = '';
25589
25847
  const queryParamsString = getQueryParamString(queryParams, true);
@@ -26017,7 +26275,7 @@ query SendMessage($params: Input_convassist_SendMessageRequest) {
26017
26275
  getIframeSrc() {
26018
26276
  const { sessionId, genNo, acSessionId, acGenNo, convId, messageId, } = this.viewConfig;
26019
26277
  const path = 'conv-assist-answer';
26020
- const queryParams = this.getEmbedParamsObject();
26278
+ const queryParams = this.getUrlQueryParamsObject();
26021
26279
  let query = '';
26022
26280
  const queryParamsString = getQueryParamString(queryParams, true);
26023
26281
  if (queryParamsString) {
@@ -26214,18 +26472,22 @@ query SendMessage($params: Input_convassist_SendMessageRequest) {
26214
26472
  }
26215
26473
  }
26216
26474
  setParamIfDefined(queryParams, Param.UpdatedSpotterExperience, updatedSpotterExperience, true);
26475
+ setParamIfDefined(queryParams, Param.SpotterExperienceVersion, this.viewConfig.spotterExperienceVersion);
26217
26476
  return queryParams;
26218
26477
  }
26219
26478
  getIframeSrc() {
26220
- const { worksheetId, searchOptions, runtimeFilters, excludeRuntimeFiltersfromURL, runtimeParameters, excludeRuntimeParametersfromURL, sharedConversationId, dataSources, } = this.viewConfig;
26479
+ const { worksheetId, searchOptions, runtimeFilters, excludeRuntimeFiltersfromURL, runtimeParameters, excludeRuntimeParametersfromURL, sharedConversationId, dataSources, spotterExperienceVersion, } = this.viewConfig;
26221
26480
  // Deep-link into the read-only shared-conversation reader view when a
26222
26481
  // shared conversation id is supplied (e.g. a recipient landing from a
26223
26482
  // host-configured CONVERSATION_URL share link); otherwise the normal
26224
26483
  // Spotter conversation surface.
26225
- const path = sharedConversationId
26484
+ let path = sharedConversationId
26226
26485
  ? `insights/conv-assist/s/${encodeURIComponent(sharedConversationId)}`
26227
26486
  : 'insights/conv-assist';
26228
- const queryParams = this.getEmbedParamsObject();
26487
+ if (spotterExperienceVersion === exports.SpotterExperienceVersion.SPOTTER_2026_11) {
26488
+ path = path.replace('insights/conv-assist', 'insights/spotter');
26489
+ }
26490
+ const queryParams = this.getUrlQueryParamsObject();
26229
26491
  let query = '';
26230
26492
  const queryParamsString = getQueryParamString(queryParams, true);
26231
26493
  if (queryParamsString) {
@@ -27015,6 +27277,20 @@ query GetEurekaResults($params: Input_eureka_SearchRequest) {
27015
27277
  return { filters: [...liveboardFilterParams, ...runtimeFilterParams] };
27016
27278
  }
27017
27279
 
27280
+ /**
27281
+ * Route the ThoughtSpot application uses to render a single conversational
27282
+ * answer. Used when a replayed frame carries no route of its own.
27283
+ */
27284
+ const CONV_ASSIST_ANSWER_ROUTE = '/embed/conv-assist-answer';
27285
+ /**
27286
+ * Base path of the conversation service, proxied by the cluster's nginx as
27287
+ * the `convex` upstream. These are the same handlers the public
27288
+ * `/api/rest/2.0/ai/agent/conversations/...` endpoints proxy to, so the
27289
+ * response shapes are identical, but calling them directly skips the prism
27290
+ * hop and its error re-wrapping.
27291
+ */
27292
+ const CONVERSATION_SERVICE_PATH = '/conversation/v2';
27293
+ const DEFAULT_STALE_ANSWER_NOTICE = 'This data may have changed since the last time you had a chat.';
27018
27294
  /**
27019
27295
  * Starts an automatic renderer that watches the DOM for iframes containing
27020
27296
  * the `tsmcp=true` query parameter and replaces them with fully configured
@@ -27077,6 +27353,111 @@ query GetEurekaResults($params: Input_eureka_SearchRequest) {
27077
27353
  observer.observe(document.body, { childList: true, subtree: true });
27078
27354
  return observer;
27079
27355
  }
27356
+ /**
27357
+ * Writes resolved session parameters into the route's hash query string,
27358
+ * preserving the route and any other hash params the source URL carried.
27359
+ *
27360
+ * @param sourceHash - The source URL's hash, with or without a leading `#`.
27361
+ * Falls back to the conversational-answer route when empty, so a host app
27362
+ * replaying a chat need only supply the conversation identifier.
27363
+ */
27364
+ function buildAnswerHash(sourceHash, resolved) {
27365
+ const withoutHash = (sourceHash || '').replace('#', '');
27366
+ const [route, existingQuery] = withoutHash.split('?');
27367
+ const params = new URLSearchParams(existingQuery || '');
27368
+ Object.entries(resolved).forEach(([key, value]) => params.set(key, value));
27369
+ return `${route || CONV_ASSIST_ANSWER_ROUTE}?${params.toString()}`;
27370
+ }
27371
+ /**
27372
+ * Reads {@link Param.TsmcpAnswerIndex} as a whole, non-negative array index.
27373
+ *
27374
+ * Anything else - absent, malformed, fractional, negative - falls back to the
27375
+ * first answer rather than indexing with a value that can never match.
27376
+ */
27377
+ function answerIndexFromParam(raw) {
27378
+ const parsed = Number(raw);
27379
+ return Number.isInteger(parsed) && parsed >= 0 ? parsed : 0;
27380
+ }
27381
+ /**
27382
+ * In-flight answer-id list requests, keyed by conversation-service URL.
27383
+ *
27384
+ * Replaying a stored chat mounts every one of its frames at once, and each
27385
+ * frame resolves on its own. Without this, N frames from one conversation make
27386
+ * N identical list calls. Sharing the in-flight request collapses them to one.
27387
+ *
27388
+ * Only the id list is shared, and only while its request is in flight: the
27389
+ * entry is dropped once the request settles, whether it succeeded or not. A
27390
+ * failed response is therefore never reused, and a frame mounted later always
27391
+ * reads a fresh list. The per-answer load call is never shared - it returns
27392
+ * live session state with its own expiry.
27393
+ */
27394
+ const answerIdListRequests = new Map();
27395
+ /**
27396
+ * Lists a conversation's answer ids: its non-thinking `answer` items, in
27397
+ * message order. The host app counts answers the same way, so the Nth id here
27398
+ * is the Nth stored answer.
27399
+ *
27400
+ * @param conversationUrl - The conversation's base URL on the conversation
27401
+ * service, `{host}/conversation/v2/{encoded id}`.
27402
+ * @param conversationId - The conversation identifier, used in log messages.
27403
+ * @returns The ids, or `null` when the conversation cannot be read. Never
27404
+ * rejects, so callers sharing the request need no error handling of their own.
27405
+ */
27406
+ async function fetchAnswerIds(conversationUrl, conversationId) {
27407
+ try {
27408
+ const messagesResponse = await tokenizedFetch(`${conversationUrl}/public`, {
27409
+ credentials: 'include',
27410
+ headers: { Accept: 'application/json' },
27411
+ });
27412
+ if (!messagesResponse.ok) {
27413
+ logger$3.warn(`[AutoFrameRenderer] Conversation fetch failed for ${conversationId}: ${messagesResponse.status}`);
27414
+ return null;
27415
+ }
27416
+ const messagesBody = await messagesResponse.json();
27417
+ const messages = messagesBody === null || messagesBody === void 0 ? void 0 : messagesBody.messages;
27418
+ const answerIds = [];
27419
+ for (const message of Array.isArray(messages) ? messages : []) {
27420
+ for (const item of (message === null || message === void 0 ? void 0 : message.response_items) || []) {
27421
+ if ((item === null || item === void 0 ? void 0 : item.type) === 'answer' && (item === null || item === void 0 ? void 0 : item.is_thinking) === false && (item === null || item === void 0 ? void 0 : item.answer_id)) {
27422
+ answerIds.push(item.answer_id);
27423
+ }
27424
+ }
27425
+ }
27426
+ return answerIds;
27427
+ }
27428
+ catch (e) {
27429
+ logger$3.warn(`[AutoFrameRenderer] Failed to list answers for ${conversationId}: ${e}`);
27430
+ return null;
27431
+ }
27432
+ }
27433
+ /**
27434
+ * The answer-id list for a conversation, joining a request already in flight
27435
+ * for it.
27436
+ *
27437
+ * @param conversationUrl - The conversation's base URL on the conversation
27438
+ * service. Also the key requests are shared under.
27439
+ * @param conversationId - The conversation identifier, used in log messages.
27440
+ * @param stale - A request the caller already read and found too short. It is
27441
+ * not reused; the first caller to pass it starts a new request, and the
27442
+ * others join that one.
27443
+ * @returns The shared request: the ids, or `null` when the conversation cannot
27444
+ * be read. Never rejects.
27445
+ */
27446
+ function getAnswerIds(conversationUrl, conversationId, stale) {
27447
+ const inFlight = answerIdListRequests.get(conversationUrl);
27448
+ if (inFlight && inFlight !== stale) {
27449
+ return inFlight;
27450
+ }
27451
+ const request = fetchAnswerIds(conversationUrl, conversationId);
27452
+ answerIdListRequests.set(conversationUrl, request);
27453
+ const release = () => {
27454
+ if (answerIdListRequests.get(conversationUrl) === request) {
27455
+ answerIdListRequests.delete(conversationUrl);
27456
+ }
27457
+ };
27458
+ request.then(release, release);
27459
+ return request;
27460
+ }
27080
27461
  function isTSMCPIframe(iframe) {
27081
27462
  try {
27082
27463
  const url = new URL(iframe.src);
@@ -27110,20 +27491,112 @@ query GetEurekaResults($params: Input_eureka_SearchRequest) {
27110
27491
  * ThoughtSpot application.
27111
27492
  *
27112
27493
  * @param sourceSrc - The original iframe's `src` URL string.
27494
+ * @param preserveSourceUrl - When true, return the source URL unchanged.
27113
27495
  * @returns The constructed URL to use for the ThoughtSpot embed iframe.
27114
27496
  */
27115
- getMCPIframeSrc(sourceSrc) {
27116
- const queryParams = this.getEmbedParamsObject();
27497
+ getMCPIframeSrc(sourceSrc, resolved, preserveSourceUrl = false) {
27498
+ if (preserveSourceUrl) {
27499
+ return sourceSrc;
27500
+ }
27501
+ const queryParams = this.getUrlQueryParamsObject();
27117
27502
  const sourceURL = new URL(sourceSrc);
27118
27503
  const existingQueryParams = sourceURL.searchParams;
27119
27504
  const existingQueryParamsObject = Object.fromEntries(existingQueryParams);
27120
27505
  delete existingQueryParamsObject[Param.Tsmcp];
27506
+ // Replay markers address the SDK, not the ThoughtSpot application.
27507
+ delete existingQueryParamsObject[Param.TsmcpConversationId];
27508
+ delete existingQueryParamsObject[Param.TsmcpAnswerIndex];
27121
27509
  const mergedQueryParams = { ...queryParams, ...existingQueryParamsObject };
27122
27510
  const mergedQueryParamsString = getQueryParamString(mergedQueryParams, true);
27123
27511
  const queryString = mergedQueryParamsString ? `?${mergedQueryParamsString}` : '';
27124
- const frameSrc = `${this.getEmbedBasePath(queryString)}${sourceURL.hash.replace('#', '')}`;
27512
+ const hash = resolved
27513
+ ? buildAnswerHash(sourceURL.hash, resolved)
27514
+ : sourceURL.hash.replace('#', '');
27515
+ const frameSrc = `${this.getEmbedBasePath(queryString)}${hash}`;
27125
27516
  return frameSrc;
27126
27517
  }
27518
+ /**
27519
+ * Resolves the current session parameters for an answer stored only as a
27520
+ * conversation identifier plus an ordinal position.
27521
+ *
27522
+ * The answer object behind `sessionId`/`genNo` expires (roughly 8 hours),
27523
+ * so a host app replaying a stored chat cannot persist those values. It
27524
+ * persists the conversation identifier instead, and this walks the two
27525
+ * conversation-service APIs to rebuild them:
27526
+ *
27527
+ * 1. `GET {conv}/public` lists the conversation's messages; the
27528
+ * non-thinking `answer` items, in message order, give the answer ids.
27529
+ * Frames from the same conversation share one in-flight call - see
27530
+ * {@link getAnswerIds}.
27531
+ * 2. `POST {conv}/message/{id}/load/public` turns the answer id at
27532
+ * `answerIndex` into a live session identifier, generation number and
27533
+ * agent-context state.
27534
+ *
27535
+ * @returns The resolved parameters, or `null` when resolution fails - the
27536
+ * caller then falls back to whatever the source URL already carried.
27537
+ */
27538
+ async resolveAnswerSessionParams(conversationId, answerIndex) {
27539
+ const base = `${this.thoughtSpotHost}${CONVERSATION_SERVICE_PATH}/${encodeURIComponent(conversationId)}`;
27540
+ try {
27541
+ const listRequest = getAnswerIds(base, conversationId);
27542
+ let answerIds = await listRequest;
27543
+ if (answerIds && !answerIds[answerIndex]) {
27544
+ // The list only grows, so a short one may predate this answer:
27545
+ // a frame that joined a request started before it was added.
27546
+ // Read the list once more before giving up.
27547
+ answerIds = await getAnswerIds(base, conversationId, listRequest);
27548
+ }
27549
+ if (!answerIds) {
27550
+ return null;
27551
+ }
27552
+ const answerId = answerIds[answerIndex];
27553
+ if (!answerId) {
27554
+ logger$3.warn(`[AutoFrameRenderer] No answer at index ${answerIndex} in conversation ${conversationId} (found ${answerIds.length}).`);
27555
+ return null;
27556
+ }
27557
+ // The load handler is a POST upstream; the public REST endpoint
27558
+ // exposed it as a GET and supplied this body on the caller's
27559
+ // behalf.
27560
+ const detailsResponse = await tokenizedFetch(`${base}/message/${encodeURIComponent(answerId)}/load/public`, {
27561
+ credentials: 'include',
27562
+ method: 'POST',
27563
+ headers: {
27564
+ Accept: 'application/json',
27565
+ 'Content-Type': 'application/json',
27566
+ 'x-requested-by': 'ThoughtSpot',
27567
+ },
27568
+ body: JSON.stringify({ type: 'TS_ANSWER' }),
27569
+ });
27570
+ if (!detailsResponse.ok) {
27571
+ logger$3.warn(`[AutoFrameRenderer] Answer load failed for ${answerId}: ${detailsResponse.status}`);
27572
+ return null;
27573
+ }
27574
+ const detailsBody = await detailsResponse.json();
27575
+ const answer = detailsBody === null || detailsBody === void 0 ? void 0 : detailsBody.answer;
27576
+ const acState = answer === null || answer === void 0 ? void 0 : answer.ac_state;
27577
+ // All four are nullable in the load-answer response. A missing
27578
+ // generation number is as unusable as a missing session id:
27579
+ // stringifying it would put a literal "null" in the hash. Fail
27580
+ // the resolve instead and let the caller fall back.
27581
+ if (!(answer === null || answer === void 0 ? void 0 : answer.session_identifier)
27582
+ || !(acState === null || acState === void 0 ? void 0 : acState.transaction_identifier)
27583
+ || !(Number.isInteger(answer.generation_number) && answer.generation_number > 0)
27584
+ || !(Number.isInteger(acState.generation_number) && acState.generation_number > 0)) {
27585
+ logger$3.warn(`[AutoFrameRenderer] Answer load returned incomplete session state for ${answerId}.`);
27586
+ return null;
27587
+ }
27588
+ return {
27589
+ sessionId: answer.session_identifier,
27590
+ genNo: String(answer.generation_number),
27591
+ acSessionId: acState.transaction_identifier,
27592
+ acGenNo: String(acState.generation_number),
27593
+ };
27594
+ }
27595
+ catch (e) {
27596
+ logger$3.warn(`[AutoFrameRenderer] Failed to resolve stored answer: ${e}`);
27597
+ return null;
27598
+ }
27599
+ }
27127
27600
  /**
27128
27601
  * Overrides the base insertion behavior so the new embed iframe
27129
27602
  * replaces the original iframe in-place rather than being appended
@@ -27152,10 +27625,37 @@ query GetEurekaResults($params: Input_eureka_SearchRequest) {
27152
27625
  if (this.shouldWaitForRenderPromise) {
27153
27626
  await this.isReadyForRenderPromise;
27154
27627
  }
27155
- const src = this.getMCPIframeSrc(iframe.src);
27628
+ // Only frames that ask for it take the replay path. A frame straight
27629
+ // from the MCP server carries its own session params and no
27630
+ // conversation id, so it renders exactly as it always has.
27631
+ const sourceParams = new URL(iframe.src).searchParams;
27632
+ const conversationId = sourceParams.get(Param.TsmcpConversationId);
27633
+ let resolved = null;
27634
+ if (conversationId) {
27635
+ resolved = await this.resolveAnswerSessionParams(conversationId, answerIndexFromParam(sourceParams.get(Param.TsmcpAnswerIndex)));
27636
+ }
27637
+ const src = this.getMCPIframeSrc(iframe.src, resolved !== null && resolved !== void 0 ? resolved : undefined, Boolean(conversationId) && !resolved);
27156
27638
  await this.renderIFrame(src);
27639
+ // Mark only answers actually re-resolved: their numbers were computed
27640
+ // now, not when the conversation happened.
27641
+ if (resolved && !this.viewConfig.suppressStaleAnswerNotice) {
27642
+ this.markAsStaleAnswer();
27643
+ }
27157
27644
  this.isRendered = true;
27158
27645
  }
27646
+ /**
27647
+ * Adds the "data may have changed" notice to the rendered frame as a
27648
+ * native tooltip, so it needs no stylesheet and cannot disturb the host
27649
+ * app's layout.
27650
+ */
27651
+ markAsStaleAnswer() {
27652
+ if (!this.iFrame) {
27653
+ return;
27654
+ }
27655
+ this.iFrame.title = this.viewConfig.staleAnswerNoticeText || DEFAULT_STALE_ANSWER_NOTICE;
27656
+ // Exposed so a host app can style or replace the native tooltip.
27657
+ this.iFrame.dataset.tsStaleAnswer = 'true';
27658
+ }
27159
27659
  }
27160
27660
 
27161
27661
  const ALIAS = Symbol.for('yaml.alias');