@thoughtspot/visual-embed-sdk 1.50.0 → 1.51.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 (222) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/css-variables.d.ts +95 -0
  3. package/cjs/src/css-variables.d.ts.map +1 -1
  4. package/cjs/src/embed/app.d.ts +136 -15
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +59 -37
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +419 -149
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/conversation.d.ts +230 -1
  11. package/cjs/src/embed/conversation.d.ts.map +1 -1
  12. package/cjs/src/embed/conversation.js +30 -16
  13. package/cjs/src/embed/conversation.js.map +1 -1
  14. package/cjs/src/embed/conversation.spec.js +221 -17
  15. package/cjs/src/embed/conversation.spec.js.map +1 -1
  16. package/cjs/src/embed/events.spec.js +635 -0
  17. package/cjs/src/embed/events.spec.js.map +1 -1
  18. package/cjs/src/embed/host-events.spec.js +151 -0
  19. package/cjs/src/embed/host-events.spec.js.map +1 -1
  20. package/cjs/src/embed/hostEventClient/contracts.d.ts +51 -14
  21. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  22. package/cjs/src/embed/hostEventClient/contracts.js +11 -1
  23. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  24. package/cjs/src/embed/hostEventClient/host-event-client.d.ts +1 -0
  25. package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  26. package/cjs/src/embed/hostEventClient/host-event-client.js +9 -0
  27. package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
  28. package/cjs/src/embed/hostEventClient/host-event-client.spec.js +218 -0
  29. package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  30. package/cjs/src/embed/hostEventClient/utils.d.ts +2 -0
  31. package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -1
  32. package/cjs/src/embed/hostEventClient/utils.js +32 -2
  33. package/cjs/src/embed/hostEventClient/utils.js.map +1 -1
  34. package/cjs/src/embed/hostEventClient/utils.spec.js +178 -0
  35. package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -1
  36. package/cjs/src/embed/liveboard.d.ts +42 -1
  37. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  38. package/cjs/src/embed/liveboard.js +26 -6
  39. package/cjs/src/embed/liveboard.js.map +1 -1
  40. package/cjs/src/embed/liveboard.spec.js +83 -2
  41. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  42. package/cjs/src/embed/spotter-utils.d.ts +8 -1
  43. package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
  44. package/cjs/src/embed/spotter-utils.js +14 -1
  45. package/cjs/src/embed/spotter-utils.js.map +1 -1
  46. package/cjs/src/embed/spotter-utils.spec.js +61 -0
  47. package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
  48. package/cjs/src/embed/spotter-viz-utils.d.ts +34 -0
  49. package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
  50. package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
  51. package/cjs/src/embed/spotter-viz-utils.spec.js +17 -0
  52. package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -1
  53. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  54. package/cjs/src/embed/ts-embed.js +29 -7
  55. package/cjs/src/embed/ts-embed.js.map +1 -1
  56. package/cjs/src/embed/ts-embed.spec.js +146 -0
  57. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  58. package/cjs/src/errors.d.ts +1 -0
  59. package/cjs/src/errors.d.ts.map +1 -1
  60. package/cjs/src/errors.js +1 -0
  61. package/cjs/src/errors.js.map +1 -1
  62. package/cjs/src/index.d.ts +2 -2
  63. package/cjs/src/index.d.ts.map +1 -1
  64. package/cjs/src/index.js +3 -2
  65. package/cjs/src/index.js.map +1 -1
  66. package/cjs/src/mixpanel-service.d.ts +4 -0
  67. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  68. package/cjs/src/mixpanel-service.js +4 -0
  69. package/cjs/src/mixpanel-service.js.map +1 -1
  70. package/cjs/src/react/util.spec.js +251 -0
  71. package/cjs/src/react/util.spec.js.map +1 -1
  72. package/cjs/src/types.d.ts +573 -11
  73. package/cjs/src/types.d.ts.map +1 -1
  74. package/cjs/src/types.js +519 -2
  75. package/cjs/src/types.js.map +1 -1
  76. package/cjs/src/utils/processData.spec.js +93 -0
  77. package/cjs/src/utils/processData.spec.js.map +1 -1
  78. package/cjs/src/utils/processTrigger.spec.js +61 -0
  79. package/cjs/src/utils/processTrigger.spec.js.map +1 -1
  80. package/dist/{index-B5xoN6Cp.js → index-aBzH5ZwF.js} +1 -1
  81. package/dist/src/css-variables.d.ts +95 -0
  82. package/dist/src/css-variables.d.ts.map +1 -1
  83. package/dist/src/embed/app.d.ts +136 -15
  84. package/dist/src/embed/app.d.ts.map +1 -1
  85. package/dist/src/embed/conversation.d.ts +230 -1
  86. package/dist/src/embed/conversation.d.ts.map +1 -1
  87. package/dist/src/embed/hostEventClient/contracts.d.ts +51 -14
  88. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  89. package/dist/src/embed/hostEventClient/host-event-client.d.ts +1 -0
  90. package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  91. package/dist/src/embed/hostEventClient/utils.d.ts +2 -0
  92. package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -1
  93. package/dist/src/embed/liveboard.d.ts +42 -1
  94. package/dist/src/embed/liveboard.d.ts.map +1 -1
  95. package/dist/src/embed/spotter-utils.d.ts +8 -1
  96. package/dist/src/embed/spotter-utils.d.ts.map +1 -1
  97. package/dist/src/embed/spotter-viz-utils.d.ts +34 -0
  98. package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
  99. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  100. package/dist/src/errors.d.ts +1 -0
  101. package/dist/src/errors.d.ts.map +1 -1
  102. package/dist/src/index.d.ts +2 -2
  103. package/dist/src/index.d.ts.map +1 -1
  104. package/dist/src/mixpanel-service.d.ts +4 -0
  105. package/dist/src/mixpanel-service.d.ts.map +1 -1
  106. package/dist/src/types.d.ts +573 -11
  107. package/dist/src/types.d.ts.map +1 -1
  108. package/dist/tsembed-react.es.js +936 -142
  109. package/dist/tsembed-react.js +935 -141
  110. package/dist/tsembed.es.js +935 -142
  111. package/dist/tsembed.js +933 -140
  112. package/dist/visual-embed-sdk-react-full.d.ts +1147 -44
  113. package/dist/visual-embed-sdk-react.d.ts +1153 -46
  114. package/dist/visual-embed-sdk.d.ts +1161 -46
  115. package/lib/package.json +1 -1
  116. package/lib/src/css-variables.d.ts +95 -0
  117. package/lib/src/css-variables.d.ts.map +1 -1
  118. package/lib/src/embed/app.d.ts +136 -15
  119. package/lib/src/embed/app.d.ts.map +1 -1
  120. package/lib/src/embed/app.js +60 -38
  121. package/lib/src/embed/app.js.map +1 -1
  122. package/lib/src/embed/app.spec.js +420 -150
  123. package/lib/src/embed/app.spec.js.map +1 -1
  124. package/lib/src/embed/conversation.d.ts +230 -1
  125. package/lib/src/embed/conversation.d.ts.map +1 -1
  126. package/lib/src/embed/conversation.js +31 -17
  127. package/lib/src/embed/conversation.js.map +1 -1
  128. package/lib/src/embed/conversation.spec.js +222 -18
  129. package/lib/src/embed/conversation.spec.js.map +1 -1
  130. package/lib/src/embed/events.spec.js +635 -0
  131. package/lib/src/embed/events.spec.js.map +1 -1
  132. package/lib/src/embed/host-events.spec.js +152 -1
  133. package/lib/src/embed/host-events.spec.js.map +1 -1
  134. package/lib/src/embed/hostEventClient/contracts.d.ts +51 -14
  135. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  136. package/lib/src/embed/hostEventClient/contracts.js +10 -0
  137. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  138. package/lib/src/embed/hostEventClient/host-event-client.d.ts +1 -0
  139. package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
  140. package/lib/src/embed/hostEventClient/host-event-client.js +10 -1
  141. package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
  142. package/lib/src/embed/hostEventClient/host-event-client.spec.js +218 -0
  143. package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
  144. package/lib/src/embed/hostEventClient/utils.d.ts +2 -0
  145. package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -1
  146. package/lib/src/embed/hostEventClient/utils.js +28 -1
  147. package/lib/src/embed/hostEventClient/utils.js.map +1 -1
  148. package/lib/src/embed/hostEventClient/utils.spec.js +179 -1
  149. package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -1
  150. package/lib/src/embed/liveboard.d.ts +42 -1
  151. package/lib/src/embed/liveboard.d.ts.map +1 -1
  152. package/lib/src/embed/liveboard.js +26 -6
  153. package/lib/src/embed/liveboard.js.map +1 -1
  154. package/lib/src/embed/liveboard.spec.js +83 -2
  155. package/lib/src/embed/liveboard.spec.js.map +1 -1
  156. package/lib/src/embed/spotter-utils.d.ts +8 -1
  157. package/lib/src/embed/spotter-utils.d.ts.map +1 -1
  158. package/lib/src/embed/spotter-utils.js +12 -0
  159. package/lib/src/embed/spotter-utils.js.map +1 -1
  160. package/lib/src/embed/spotter-utils.spec.js +62 -1
  161. package/lib/src/embed/spotter-utils.spec.js.map +1 -1
  162. package/lib/src/embed/spotter-viz-utils.d.ts +34 -0
  163. package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
  164. package/lib/src/embed/spotter-viz-utils.js.map +1 -1
  165. package/lib/src/embed/spotter-viz-utils.spec.js +17 -0
  166. package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -1
  167. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  168. package/lib/src/embed/ts-embed.js +29 -7
  169. package/lib/src/embed/ts-embed.js.map +1 -1
  170. package/lib/src/embed/ts-embed.spec.js +146 -0
  171. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  172. package/lib/src/errors.d.ts +1 -0
  173. package/lib/src/errors.d.ts.map +1 -1
  174. package/lib/src/errors.js +1 -0
  175. package/lib/src/errors.js.map +1 -1
  176. package/lib/src/index.d.ts +2 -2
  177. package/lib/src/index.d.ts.map +1 -1
  178. package/lib/src/index.js +2 -2
  179. package/lib/src/index.js.map +1 -1
  180. package/lib/src/mixpanel-service.d.ts +4 -0
  181. package/lib/src/mixpanel-service.d.ts.map +1 -1
  182. package/lib/src/mixpanel-service.js +4 -0
  183. package/lib/src/mixpanel-service.js.map +1 -1
  184. package/lib/src/react/util.spec.js +251 -0
  185. package/lib/src/react/util.spec.js.map +1 -1
  186. package/lib/src/types.d.ts +573 -11
  187. package/lib/src/types.d.ts.map +1 -1
  188. package/lib/src/types.js +519 -2
  189. package/lib/src/types.js.map +1 -1
  190. package/lib/src/utils/processData.spec.js +93 -0
  191. package/lib/src/utils/processData.spec.js.map +1 -1
  192. package/lib/src/utils/processTrigger.spec.js +61 -0
  193. package/lib/src/utils/processTrigger.spec.js.map +1 -1
  194. package/lib/src/visual-embed-sdk.d.ts +1161 -46
  195. package/package.json +1 -1
  196. package/src/css-variables.ts +118 -0
  197. package/src/embed/app.spec.ts +530 -183
  198. package/src/embed/app.ts +209 -66
  199. package/src/embed/conversation.spec.ts +275 -21
  200. package/src/embed/conversation.ts +262 -17
  201. package/src/embed/events.spec.ts +757 -1
  202. package/src/embed/host-events.spec.ts +194 -0
  203. package/src/embed/hostEventClient/contracts.ts +57 -14
  204. package/src/embed/hostEventClient/host-event-client.spec.ts +338 -0
  205. package/src/embed/hostEventClient/host-event-client.ts +16 -0
  206. package/src/embed/hostEventClient/utils.spec.ts +204 -0
  207. package/src/embed/hostEventClient/utils.ts +37 -10
  208. package/src/embed/liveboard.spec.ts +108 -2
  209. package/src/embed/liveboard.ts +82 -14
  210. package/src/embed/spotter-utils.spec.ts +68 -1
  211. package/src/embed/spotter-utils.ts +16 -1
  212. package/src/embed/spotter-viz-utils.spec.ts +17 -0
  213. package/src/embed/spotter-viz-utils.ts +34 -0
  214. package/src/embed/ts-embed.spec.ts +186 -0
  215. package/src/embed/ts-embed.ts +30 -4
  216. package/src/errors.ts +1 -0
  217. package/src/index.ts +3 -1
  218. package/src/mixpanel-service.ts +4 -0
  219. package/src/react/util.spec.tsx +255 -0
  220. package/src/types.ts +575 -8
  221. package/src/utils/processData.spec.ts +97 -0
  222. package/src/utils/processTrigger.spec.ts +91 -0
@@ -3,8 +3,10 @@ import { processTrigger as processTriggerService } from '../../utils/processTrig
3
3
  import { getEmbedConfig } from '../embedConfig';
4
4
  import {
5
5
  isValidUpdateFiltersPayload,
6
+ isValidUpdateParametersPayload,
6
7
  isValidDrillDownPayload,
7
8
  throwUpdateFiltersValidationError,
9
+ throwUpdateParametersValidationError,
8
10
  throwDrillDownValidationError,
9
11
  } from './utils';
10
12
  import {
@@ -36,6 +38,7 @@ const PASSTHROUGH_MAP: Partial<Record<HostEvent, UIPassthroughEvent>> = {
36
38
  [HostEvent.GetParameters]: UIPassthroughEvent.GetParameters,
37
39
  [HostEvent.GetTML]: UIPassthroughEvent.GetTML,
38
40
  [HostEvent.GetTabs]: UIPassthroughEvent.GetTabs,
41
+ [HostEvent.GetGroups]: UIPassthroughEvent.GetGroups,
39
42
  [HostEvent.getExportRequestForCurrentPinboard]: UIPassthroughEvent.GetExportRequestForCurrentPinboard,
40
43
  };
41
44
 
@@ -58,6 +61,7 @@ export class HostEventClient {
58
61
  [HostEvent.Pin]: (p, c) => this.handlePinEvent(p, c),
59
62
  [HostEvent.SaveAnswer]: (p, c) => this.handleSaveAnswerEvent(p, c),
60
63
  [HostEvent.UpdateFilters]: (p, c) => this.handleUpdateFiltersEvent(p, c),
64
+ [HostEvent.UpdateParameters]: (p, c) => this.handleUpdateParametersEvent(p, c),
61
65
  [HostEvent.DrillDown]: (p, c) => this.handleDrillDownEvent(p, c),
62
66
  };
63
67
  }
@@ -243,6 +247,18 @@ export class HostEventClient {
243
247
  return this.handleHostEventWithParam(UIPassthroughEvent.UpdateFilters, payload, context as ContextType);
244
248
  }
245
249
 
250
+ protected handleUpdateParametersEvent(
251
+ payload: HostEventRequest<HostEvent.UpdateParameters>,
252
+ context?: ContextType,
253
+ ): Promise<any> {
254
+ if (!isValidUpdateParametersPayload(payload)) {
255
+ throwUpdateParametersValidationError();
256
+ }
257
+
258
+ // UpdateParameters has no UI passthrough contract; dispatch over the legacy channel
259
+ return this.hostEventFallback(HostEvent.UpdateParameters, payload, context);
260
+ }
261
+
246
262
  protected handleDrillDownEvent(
247
263
  payload: HostEventRequest<HostEvent.DrillDown>,
248
264
  context?: ContextType,
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  isValidUpdateFiltersPayload,
3
+ isValidUpdateParametersPayload,
3
4
  isValidDrillDownPayload,
4
5
  createValidationError,
5
6
  throwUpdateFiltersValidationError,
7
+ throwUpdateParametersValidationError,
6
8
  throwDrillDownValidationError,
7
9
  } from './utils';
8
10
  import { ERROR_MESSAGE } from '../../errors';
@@ -114,6 +116,201 @@ describe('hostEventClient utils', () => {
114
116
  filters: [{ column: 'y' }], // invalid
115
117
  } as any)).toBe(true);
116
118
  });
119
+
120
+ it('returns true for filter without applicability', () => {
121
+ expect(isValidUpdateFiltersPayload({
122
+ filter: { column: 'x', oper: 'EQ', values: ['a'] },
123
+ } as any)).toBe(true);
124
+ });
125
+
126
+ it('returns true for filter with valid applicability', () => {
127
+ expect(isValidUpdateFiltersPayload({
128
+ filter: {
129
+ column: 'x',
130
+ oper: 'EQ',
131
+ values: ['a'],
132
+ applicability: { level: 'TAB', targetId: 'tab-guid-1' },
133
+ },
134
+ } as any)).toBe(true);
135
+ });
136
+
137
+ it('returns true for filters array with applicability on some filters', () => {
138
+ expect(isValidUpdateFiltersPayload({
139
+ filters: [
140
+ {
141
+ column: 'x',
142
+ oper: 'IN',
143
+ values: ['a', 'b'],
144
+ applicability: { level: 'TAB', targetId: 'tab-guid-1' },
145
+ },
146
+ { column: 'y', oper: 'EQ', values: ['c'] },
147
+ ],
148
+ } as any)).toBe(true);
149
+ });
150
+
151
+ it('returns false for applicability missing targetId', () => {
152
+ expect(isValidUpdateFiltersPayload({
153
+ filter: {
154
+ column: 'x',
155
+ oper: 'EQ',
156
+ values: ['a'],
157
+ applicability: { level: 'TAB' },
158
+ },
159
+ } as any)).toBe(false);
160
+ });
161
+
162
+ it('returns false for applicability with empty targetId', () => {
163
+ expect(isValidUpdateFiltersPayload({
164
+ filter: {
165
+ column: 'x',
166
+ oper: 'EQ',
167
+ values: ['a'],
168
+ applicability: { level: 'TAB', targetId: '' },
169
+ },
170
+ } as any)).toBe(false);
171
+ });
172
+
173
+ it('returns false for null applicability', () => {
174
+ expect(isValidUpdateFiltersPayload({
175
+ filter: {
176
+ column: 'x',
177
+ oper: 'EQ',
178
+ values: ['a'],
179
+ applicability: null,
180
+ },
181
+ } as any)).toBe(false);
182
+ });
183
+
184
+ it('returns false for non-object applicability', () => {
185
+ expect(isValidUpdateFiltersPayload({
186
+ filter: {
187
+ column: 'x',
188
+ oper: 'EQ',
189
+ values: ['a'],
190
+ applicability: 'TAB',
191
+ },
192
+ } as any)).toBe(false);
193
+ });
194
+
195
+ it('returns true for LIVEBOARD level applicability without targetId', () => {
196
+ expect(isValidUpdateFiltersPayload({
197
+ filter: {
198
+ column: 'x',
199
+ oper: 'EQ',
200
+ values: ['a'],
201
+ applicability: { level: 'LIVEBOARD' },
202
+ },
203
+ } as any)).toBe(true);
204
+ });
205
+
206
+ it('returns false for applicability missing level', () => {
207
+ expect(isValidUpdateFiltersPayload({
208
+ filter: {
209
+ column: 'x',
210
+ oper: 'EQ',
211
+ values: ['a'],
212
+ applicability: { targetId: 'tab-guid-1' },
213
+ },
214
+ } as any)).toBe(false);
215
+ });
216
+
217
+ it('returns false for applicability with non-string level', () => {
218
+ expect(isValidUpdateFiltersPayload({
219
+ filter: {
220
+ column: 'x',
221
+ oper: 'EQ',
222
+ values: ['a'],
223
+ applicability: { level: 123, targetId: 'tab-guid-1' },
224
+ },
225
+ } as any)).toBe(false);
226
+ });
227
+
228
+ it('returns false if one filter in filters array has invalid applicability', () => {
229
+ expect(isValidUpdateFiltersPayload({
230
+ filters: [
231
+ { column: 'x', oper: 'EQ', values: ['a'] },
232
+ {
233
+ column: 'y',
234
+ oper: 'EQ',
235
+ values: ['b'],
236
+ applicability: { level: 'TAB' }, // missing targetId
237
+ },
238
+ ],
239
+ } as any)).toBe(false);
240
+ });
241
+ });
242
+
243
+ // =========================
244
+ // UpdateParameters Validation
245
+ // =========================
246
+ describe('isValidUpdateParametersPayload', () => {
247
+ it('returns true for undefined payload', () => {
248
+ expect(isValidUpdateParametersPayload(undefined)).toBe(true);
249
+ });
250
+
251
+ it('returns true for non-array payload', () => {
252
+ expect(isValidUpdateParametersPayload({ name: 'p', value: 1 })).toBe(true);
253
+ });
254
+
255
+ it('returns true for parameters without applicability', () => {
256
+ expect(isValidUpdateParametersPayload([
257
+ { name: 'p1', value: 1 },
258
+ { name: 'p2', value: 'a' },
259
+ ])).toBe(true);
260
+ });
261
+
262
+ it('returns true for null applicability', () => {
263
+ expect(isValidUpdateParametersPayload([
264
+ { name: 'p', value: 1, applicability: null },
265
+ ])).toBe(true);
266
+ });
267
+
268
+ it('returns true for valid TAB applicability with targetId', () => {
269
+ expect(isValidUpdateParametersPayload([
270
+ { name: 'p', value: 1, applicability: { level: 'TAB', targetId: 'tab-guid-1' } },
271
+ ])).toBe(true);
272
+ });
273
+
274
+ it('returns true for LIVEBOARD level applicability without targetId', () => {
275
+ expect(isValidUpdateParametersPayload([
276
+ { name: 'p', value: 1, applicability: { level: 'LIVEBOARD' } },
277
+ ])).toBe(true);
278
+ });
279
+
280
+ it('returns false for applicability missing targetId', () => {
281
+ expect(isValidUpdateParametersPayload([
282
+ { name: 'p', value: 1, applicability: { level: 'TAB' } },
283
+ ])).toBe(false);
284
+ });
285
+
286
+ it('returns false for applicability with empty targetId', () => {
287
+ expect(isValidUpdateParametersPayload([
288
+ { name: 'p', value: 1, applicability: { level: 'GROUP', targetId: ' ' } },
289
+ ])).toBe(false);
290
+ });
291
+
292
+ it('returns false for applicability with invalid level', () => {
293
+ expect(isValidUpdateParametersPayload([
294
+ { name: 'p', value: 1, applicability: { level: 'VIZ', targetId: 'guid-1' } },
295
+ ])).toBe(false);
296
+ });
297
+
298
+ it('returns false for non-object applicability', () => {
299
+ expect(isValidUpdateParametersPayload([
300
+ { name: 'p', value: 1, applicability: 'TAB' },
301
+ ])).toBe(false);
302
+ });
303
+
304
+ it('returns false if one parameter has invalid applicability', () => {
305
+ expect(isValidUpdateParametersPayload([
306
+ { name: 'p1', value: 1 },
307
+ { name: 'p2', value: 2, applicability: { level: 'GROUP' } }, // missing targetId
308
+ ])).toBe(false);
309
+ });
310
+
311
+ it('returns true for non-object entries', () => {
312
+ expect(isValidUpdateParametersPayload(['p', 1, null])).toBe(true);
313
+ });
117
314
  });
118
315
 
119
316
  // =========================
@@ -216,6 +413,13 @@ describe('hostEventClient utils', () => {
216
413
  });
217
414
  });
218
415
 
416
+ describe('throwUpdateParametersValidationError', () => {
417
+ it('throws with UPDATEPARAMETERS_INVALID_PAYLOAD message', () => {
418
+ expect(() => throwUpdateParametersValidationError())
419
+ .toThrow(ERROR_MESSAGE.UPDATEPARAMETERS_INVALID_PAYLOAD);
420
+ });
421
+ });
422
+
219
423
  describe('throwDrillDownValidationError', () => {
220
424
  it('throws with DRILLDOWN_INVALID_PAYLOAD message', () => {
221
425
  expect(() => throwDrillDownValidationError())
@@ -1,27 +1,40 @@
1
+ import isNil from 'lodash/isNil';
2
+ import isPlainObject from 'lodash/isPlainObject';
3
+ import isString from 'lodash/isString';
4
+ import isUndefined from 'lodash/isUndefined';
1
5
  import { EmbedErrorCodes, EmbedEvent, ErrorDetailsTypes, HostEvent } from '../../types';
2
6
  import { ERROR_MESSAGE } from '../../errors';
3
- import { HostEventRequest } from './contracts';
7
+ import { ApplicabilityLevel, HostEventRequest } from './contracts';
4
8
  import { embedEventStatus } from '../../utils';
5
9
 
10
+ const isValidApplicability = (a?: { level?: string; targetId?: string }) => {
11
+ if (isUndefined(a)) return true;
12
+ // targetId is not required at LIVEBOARD level, since the filter applies to the whole Liveboard
13
+ return isPlainObject(a)
14
+ && Object.values(ApplicabilityLevel).includes(a.level as ApplicabilityLevel)
15
+ && (a.level === ApplicabilityLevel.Liveboard || (isString(a.targetId) && a.targetId.trim().length > 0));
16
+ };
17
+
6
18
  export function isValidUpdateFiltersPayload(
7
19
  payload: HostEventRequest<HostEvent.UpdateFilters> | undefined,
8
20
  ): boolean {
9
21
  if (!payload) return false;
10
22
 
11
- const isValidFilter = (f: {
12
- column?: string;
13
- oper?: string;
14
- values?: unknown[];
15
- type?: string;
16
- columnName?: string;
17
- operator?: string
23
+ const isValidFilter = (f: {
24
+ column?: string;
25
+ oper?: string;
26
+ values?: unknown[];
27
+ type?: string;
28
+ columnName?: string;
29
+ operator?: string;
30
+ applicability?: { level?: string; targetId?: string };
18
31
  }) => {
19
32
  const hasColumn = typeof f.column === 'string' || typeof f.columnName === 'string';
20
33
  const hasOperator = typeof f.oper === 'string' || typeof f.operator === 'string';
21
34
  const hasValues = Array.isArray(f.values);
22
35
  const validType = !f.type || typeof f.type === 'string';
23
-
24
- return hasColumn && hasOperator && hasValues && validType;
36
+
37
+ return hasColumn && hasOperator && hasValues && validType && isValidApplicability(f.applicability);
25
38
  };
26
39
 
27
40
  const hasValidFilter = payload.filter && isValidFilter(payload.filter);
@@ -30,6 +43,16 @@ export function isValidUpdateFiltersPayload(
30
43
  return !!(hasValidFilter || hasValidFilters);
31
44
  }
32
45
 
46
+ export function isValidUpdateParametersPayload(payload: unknown): boolean {
47
+ // Only validates the applicability of each parameter (null treated as absent); the rest is forwarded as-is for backward compatibility.
48
+ if (!Array.isArray(payload)) return true;
49
+ return payload.every((p) => {
50
+ if (!isPlainObject(p)) return true;
51
+ const { applicability } = p as { applicability?: { level?: string; targetId?: string } };
52
+ return isNil(applicability) || isValidApplicability(applicability);
53
+ });
54
+ }
55
+
33
56
  export function isValidDrillDownPayload(
34
57
  payload: HostEventRequest<HostEvent.DrillDown> | undefined,
35
58
  ): boolean {
@@ -72,3 +95,7 @@ export function throwUpdateFiltersValidationError(): never {
72
95
  export function throwDrillDownValidationError(): never {
73
96
  createValidationError(ERROR_MESSAGE.DRILLDOWN_INVALID_PAYLOAD);
74
97
  }
98
+
99
+ export function throwUpdateParametersValidationError(): never {
100
+ createValidationError(ERROR_MESSAGE.UPDATEPARAMETERS_INVALID_PAYLOAD);
101
+ }
@@ -275,7 +275,7 @@ describe('Liveboard/viz embed tests', () => {
275
275
  });
276
276
  });
277
277
 
278
- test('should disable isWYSIWYGLiveboardPDFEnabled by default in url', async () => {
278
+ test('should not set isWYSIWYGLiveboardPDFEnabled in url by default', async () => {
279
279
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
280
280
  ...defaultViewConfig,
281
281
  liveboardId,
@@ -284,7 +284,7 @@ describe('Liveboard/viz embed tests', () => {
284
284
  await executeAfterWait(() => {
285
285
  expectUrlMatchesWithParams(
286
286
  getIFrameSrc(),
287
- `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isWYSIWYGLiveboardPDFEnabled=false${prefixParams}#/embed/viz/${liveboardId}`,
287
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}#/embed/viz/${liveboardId}`,
288
288
  );
289
289
  });
290
290
  });
@@ -756,6 +756,47 @@ describe('Liveboard/viz embed tests', () => {
756
756
  });
757
757
  });
758
758
 
759
+ test('should add isScopedLiveboardFilteringEnabled flag and set value to true to the iframe src', async () => {
760
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
761
+ ...defaultViewConfig,
762
+ liveboardId,
763
+ isScopedLiveboardFilteringEnabled: true,
764
+ } as LiveboardViewConfig);
765
+ liveboardEmbed.render();
766
+ await executeAfterWait(() => {
767
+ expectUrlMatchesWithParams(
768
+ getIFrameSrc(),
769
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isScopedLiveboardFilteringEnabled=true${prefixParams}#/embed/viz/${liveboardId}`,
770
+ );
771
+ });
772
+ });
773
+
774
+ test('should add isScopedLiveboardFilteringEnabled flag and set value to false to the iframe src', async () => {
775
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
776
+ ...defaultViewConfig,
777
+ liveboardId,
778
+ isScopedLiveboardFilteringEnabled: false,
779
+ } as LiveboardViewConfig);
780
+ liveboardEmbed.render();
781
+ await executeAfterWait(() => {
782
+ expectUrlMatchesWithParams(
783
+ getIFrameSrc(),
784
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}&isScopedLiveboardFilteringEnabled=false${prefixParams}#/embed/viz/${liveboardId}`,
785
+ );
786
+ });
787
+ });
788
+
789
+ test('should not add isScopedLiveboardFilteringEnabled flag to the iframe src when undefined', async () => {
790
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
791
+ ...defaultViewConfig,
792
+ liveboardId,
793
+ } as LiveboardViewConfig);
794
+ liveboardEmbed.render();
795
+ await executeAfterWait(() => {
796
+ expect(getIFrameSrc()).not.toContain('isScopedLiveboardFilteringEnabled');
797
+ });
798
+ });
799
+
759
800
  test('should not append runtime filters in URL if excludeRuntimeFiltersfromURL is true', async () => {
760
801
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
761
802
  ...defaultViewConfig,
@@ -1339,6 +1380,35 @@ describe('Liveboard/viz embed tests', () => {
1339
1380
  });
1340
1381
  });
1341
1382
 
1383
+ test('should render the liveboard embed with showSpotterRadiance', async () => {
1384
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1385
+ ...defaultViewConfig,
1386
+ liveboardId,
1387
+ showSpotterRadiance: true,
1388
+ } as LiveboardViewConfig);
1389
+ await liveboardEmbed.render();
1390
+ await executeAfterWait(() => {
1391
+ expectUrlMatchesWithParams(
1392
+ getIFrameSrc(),
1393
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&showSpotterRadiance=true#/embed/viz/${liveboardId}`,
1394
+ );
1395
+ });
1396
+ });
1397
+ test('should render the liveboard embed with showSpotterRadiance disabled', async () => {
1398
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1399
+ ...defaultViewConfig,
1400
+ liveboardId,
1401
+ showSpotterRadiance: false,
1402
+ } as LiveboardViewConfig);
1403
+ await liveboardEmbed.render();
1404
+ await executeAfterWait(() => {
1405
+ expectUrlMatchesWithParams(
1406
+ getIFrameSrc(),
1407
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&showSpotterRadiance=false#/embed/viz/${liveboardId}`,
1408
+ );
1409
+ });
1410
+ });
1411
+
1342
1412
  test('should set hideToolResponseCardBranding parameter in url params via spotterChatConfig', async () => {
1343
1413
  const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
1344
1414
  ...defaultViewConfig,
@@ -2306,3 +2376,39 @@ describe('Liveboard/viz embed tests', () => {
2306
2376
  });
2307
2377
  });
2308
2378
  });
2379
+
2380
+ describe('LiveboardEmbed updatedSpotterExperience tests', () => {
2381
+ beforeEach(() => {
2382
+ document.body.innerHTML = getDocumentBody();
2383
+ });
2384
+
2385
+ test('should render the liveboard embed with updatedSpotterExperience', async () => {
2386
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2387
+ ...defaultViewConfig,
2388
+ liveboardId,
2389
+ updatedSpotterExperience: true,
2390
+ } as LiveboardViewConfig);
2391
+ await liveboardEmbed.render();
2392
+ await executeAfterWait(() => {
2393
+ expectUrlMatchesWithParams(
2394
+ getIFrameSrc(),
2395
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&updatedSpotterExperience=true#/embed/viz/${liveboardId}`,
2396
+ );
2397
+ });
2398
+ });
2399
+
2400
+ test('should render the liveboard embed with updatedSpotterExperience disabled', async () => {
2401
+ const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
2402
+ ...defaultViewConfig,
2403
+ liveboardId,
2404
+ updatedSpotterExperience: false,
2405
+ } as LiveboardViewConfig);
2406
+ await liveboardEmbed.render();
2407
+ await executeAfterWait(() => {
2408
+ expectUrlMatchesWithParams(
2409
+ getIFrameSrc(),
2410
+ `http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}&updatedSpotterExperience=false#/embed/viz/${liveboardId}`,
2411
+ );
2412
+ });
2413
+ });
2414
+ });