@thoughtspot/visual-embed-sdk 1.50.0 → 1.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/package.json +1 -1
- package/cjs/src/css-variables.d.ts +59 -0
- package/cjs/src/css-variables.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +31 -2
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +13 -2
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +101 -0
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +26 -0
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +12 -2
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +23 -0
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/events.spec.js +593 -0
- package/cjs/src/embed/events.spec.js.map +1 -1
- package/cjs/src/embed/host-events.spec.js +106 -0
- package/cjs/src/embed/host-events.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/contracts.d.ts +36 -14
- package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/contracts.js +10 -1
- package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts +1 -0
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.js +8 -0
- package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js +209 -0
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.d.ts +2 -0
- package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.js +32 -2
- package/cjs/src/embed/hostEventClient/utils.js.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.spec.js +178 -0
- package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +6 -0
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.d.ts +34 -0
- package/cjs/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.js.map +1 -1
- package/cjs/src/embed/spotter-viz-utils.spec.js +17 -0
- package/cjs/src/embed/spotter-viz-utils.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +14 -7
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +146 -0
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/errors.d.ts +1 -0
- package/cjs/src/errors.d.ts.map +1 -1
- package/cjs/src/errors.js +1 -0
- package/cjs/src/errors.js.map +1 -1
- package/cjs/src/index.d.ts +2 -2
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +3 -2
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/react/util.spec.js +251 -0
- package/cjs/src/react/util.spec.js.map +1 -1
- package/cjs/src/types.d.ts +119 -2
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +97 -0
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/processData.spec.js +93 -0
- package/cjs/src/utils/processData.spec.js.map +1 -1
- package/cjs/src/utils/processTrigger.spec.js +61 -0
- package/cjs/src/utils/processTrigger.spec.js.map +1 -1
- package/dist/{index-B5xoN6Cp.js → index-fCne7kmU.js} +1 -1
- package/dist/src/css-variables.d.ts +59 -0
- package/dist/src/css-variables.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +31 -2
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +26 -0
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/contracts.d.ts +36 -14
- package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/host-event-client.d.ts +1 -0
- package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/utils.d.ts +2 -0
- package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +6 -0
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-viz-utils.d.ts +34 -0
- package/dist/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/errors.d.ts +1 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +119 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +389 -84
- package/dist/tsembed-react.js +388 -83
- package/dist/tsembed.es.js +390 -85
- package/dist/tsembed.js +388 -83
- package/dist/visual-embed-sdk-react-full.d.ts +302 -17
- package/dist/visual-embed-sdk-react.d.ts +302 -17
- package/dist/visual-embed-sdk.d.ts +306 -17
- package/lib/package.json +1 -1
- package/lib/src/css-variables.d.ts +59 -0
- package/lib/src/css-variables.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +31 -2
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +13 -2
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +101 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +26 -0
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +11 -1
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +24 -1
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/events.spec.js +593 -0
- package/lib/src/embed/events.spec.js.map +1 -1
- package/lib/src/embed/host-events.spec.js +107 -1
- package/lib/src/embed/host-events.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/contracts.d.ts +36 -14
- package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/contracts.js +9 -0
- package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.d.ts +1 -0
- package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.js +9 -1
- package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.spec.js +209 -0
- package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/utils.d.ts +2 -0
- package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/utils.js +28 -1
- package/lib/src/embed/hostEventClient/utils.js.map +1 -1
- package/lib/src/embed/hostEventClient/utils.spec.js +179 -1
- package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +6 -0
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.d.ts +34 -0
- package/lib/src/embed/spotter-viz-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-viz-utils.js.map +1 -1
- package/lib/src/embed/spotter-viz-utils.spec.js +17 -0
- package/lib/src/embed/spotter-viz-utils.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +14 -7
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +146 -0
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/errors.d.ts +1 -0
- package/lib/src/errors.d.ts.map +1 -1
- package/lib/src/errors.js +1 -0
- package/lib/src/errors.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +2 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/util.spec.js +251 -0
- package/lib/src/react/util.spec.js.map +1 -1
- package/lib/src/types.d.ts +119 -2
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +97 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/processData.spec.js +93 -0
- package/lib/src/utils/processData.spec.js.map +1 -1
- package/lib/src/utils/processTrigger.spec.js +61 -0
- package/lib/src/utils/processTrigger.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +306 -17
- package/package.json +1 -1
- package/src/css-variables.ts +73 -0
- package/src/embed/app.spec.ts +140 -0
- package/src/embed/app.ts +38 -2
- package/src/embed/conversation.spec.ts +32 -1
- package/src/embed/conversation.ts +29 -0
- package/src/embed/events.spec.ts +705 -1
- package/src/embed/host-events.spec.ts +124 -0
- package/src/embed/hostEventClient/contracts.ts +41 -14
- package/src/embed/hostEventClient/host-event-client.spec.ts +326 -0
- package/src/embed/hostEventClient/host-event-client.ts +15 -0
- package/src/embed/hostEventClient/utils.spec.ts +204 -0
- package/src/embed/hostEventClient/utils.ts +37 -10
- package/src/embed/liveboard.ts +6 -0
- package/src/embed/spotter-viz-utils.spec.ts +17 -0
- package/src/embed/spotter-viz-utils.ts +34 -0
- package/src/embed/ts-embed.spec.ts +186 -0
- package/src/embed/ts-embed.ts +12 -4
- package/src/errors.ts +1 -0
- package/src/index.ts +2 -1
- package/src/react/util.spec.tsx +255 -0
- package/src/types.ts +119 -0
- package/src/utils/processData.spec.ts +97 -0
- package/src/utils/processTrigger.spec.ts +91 -0
|
@@ -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
|
+
}
|
package/src/embed/liveboard.ts
CHANGED
|
@@ -580,6 +580,12 @@ export interface LiveboardViewConfig extends BaseViewConfig, LiveboardOtherViewC
|
|
|
580
580
|
* { label: 'Tip', text: 'try asking about revenue by region' },
|
|
581
581
|
* { label: 'Tip', text: 'use natural language' },
|
|
582
582
|
* ],
|
|
583
|
+
* // liveboardBrandName, spotterBrandName, insightTileBrandName, insightTileViewPlanLabel and insightTileLoaderText require SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
584
|
+
* liveboardBrandName: 'Reports',
|
|
585
|
+
* spotterBrandName: 'Analyst',
|
|
586
|
+
* insightTileBrandName: 'Insight card',
|
|
587
|
+
* insightTileViewPlanLabel: 'View plan',
|
|
588
|
+
* insightTileLoaderText: 'Generating insight',
|
|
583
589
|
* },
|
|
584
590
|
* })
|
|
585
591
|
* ```
|
|
@@ -20,6 +20,23 @@ describe('buildSpotterVizAppInitData', () => {
|
|
|
20
20
|
expect(result.embedParams?.spotterVizConfig?.brandHeadline).toBe("Hi, there! I'm");
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
+
it('passes liveboardBrandName, spotterBrandName, insightTileBrandName, insightTileViewPlanLabel and insightTileLoaderText through spotterVizConfig', () => {
|
|
24
|
+
const spotterViz = {
|
|
25
|
+
brandName: 'MyBrand',
|
|
26
|
+
liveboardBrandName: 'Reports',
|
|
27
|
+
spotterBrandName: 'Analyst',
|
|
28
|
+
insightTileBrandName: 'Insight card',
|
|
29
|
+
insightTileViewPlanLabel: 'View plan',
|
|
30
|
+
insightTileLoaderText: 'Generating insight',
|
|
31
|
+
};
|
|
32
|
+
const result = buildSpotterVizAppInitData(base, { spotterViz });
|
|
33
|
+
expect(result.embedParams?.spotterVizConfig?.liveboardBrandName).toBe('Reports');
|
|
34
|
+
expect(result.embedParams?.spotterVizConfig?.spotterBrandName).toBe('Analyst');
|
|
35
|
+
expect(result.embedParams?.spotterVizConfig?.insightTileBrandName).toBe('Insight card');
|
|
36
|
+
expect(result.embedParams?.spotterVizConfig?.insightTileViewPlanLabel).toBe('View plan');
|
|
37
|
+
expect(result.embedParams?.spotterVizConfig?.insightTileLoaderText).toBe('Generating insight');
|
|
38
|
+
});
|
|
39
|
+
|
|
23
40
|
it('preserves existing embedParams when adding spotterVizConfig', () => {
|
|
24
41
|
const existing = { ...base, embedParams: { spotterSidebarConfig: { enablePastConversationsSidebar: true } } };
|
|
25
42
|
const spotterViz = { brandName: 'MyBrand' };
|
|
@@ -38,6 +38,12 @@ export interface SpotterVizStarterPrompt {
|
|
|
38
38
|
* { label: 'Tip', text: 'try asking about revenue by region' },
|
|
39
39
|
* { label: 'Tip', text: 'use natural language' },
|
|
40
40
|
* ],
|
|
41
|
+
* // liveboardBrandName, spotterBrandName, insightTileBrandName, insightTileViewPlanLabel and insightTileLoaderText require SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
42
|
+
* liveboardBrandName: 'Reports',
|
|
43
|
+
* spotterBrandName: 'Analyst',
|
|
44
|
+
* insightTileBrandName: 'Insight card',
|
|
45
|
+
* insightTileViewPlanLabel: 'View plan',
|
|
46
|
+
* insightTileLoaderText: 'Generating insight',
|
|
41
47
|
* },
|
|
42
48
|
* })
|
|
43
49
|
* ```
|
|
@@ -94,6 +100,34 @@ export interface SpotterVizConfig {
|
|
|
94
100
|
* @version SDK: 1.51.0 | ThoughtSpot Cloud: 26.8.0.cl
|
|
95
101
|
*/
|
|
96
102
|
loaderTips?: SpotterVizLoaderTip[];
|
|
103
|
+
/**
|
|
104
|
+
* Custom term used to replace "Liveboard" in the agent's responses.
|
|
105
|
+
* @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
106
|
+
* @default ''
|
|
107
|
+
*/
|
|
108
|
+
liveboardBrandName?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Custom term used to replace "Spotter" in the agent's responses.
|
|
111
|
+
* @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
112
|
+
* @default ''
|
|
113
|
+
*/
|
|
114
|
+
spotterBrandName?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Custom term used to replace "Insight tile" in the UI and in the agent's responses.
|
|
117
|
+
* @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
118
|
+
* @default ''
|
|
119
|
+
*/
|
|
120
|
+
insightTileBrandName?: string;
|
|
121
|
+
/**
|
|
122
|
+
* Custom term used to replace "View plan" in the insight tile menu.
|
|
123
|
+
* @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
124
|
+
*/
|
|
125
|
+
insightTileViewPlanLabel?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Custom loader text shown on the insight tile.
|
|
128
|
+
* @version SDK: 1.52.0 | ThoughtSpot Cloud: 26.9.0.cl
|
|
129
|
+
*/
|
|
130
|
+
insightTileLoaderText?: string;
|
|
97
131
|
}
|
|
98
132
|
|
|
99
133
|
/**
|
|
@@ -1409,6 +1409,40 @@ describe('Unit test case for ts embed', () => {
|
|
|
1409
1409
|
const { mockGetPreauthInfo } = await setup(true, 123);
|
|
1410
1410
|
expect(mockGetPreauthInfo).toHaveBeenCalledTimes(0);
|
|
1411
1411
|
});
|
|
1412
|
+
|
|
1413
|
+
test('should NOT trigger InfoSuccess when getPreauthInfo resolves with no .info field', async () => {
|
|
1414
|
+
jest.spyOn(window, 'addEventListener').mockImplementationOnce(
|
|
1415
|
+
(event, handler) => {
|
|
1416
|
+
(handler as EventListener)({
|
|
1417
|
+
data: { type: 'xyz' },
|
|
1418
|
+
ports: [3000],
|
|
1419
|
+
source: null,
|
|
1420
|
+
} as any);
|
|
1421
|
+
},
|
|
1422
|
+
);
|
|
1423
|
+
mockProcessTrigger.mockResolvedValueOnce({ session: 'test' });
|
|
1424
|
+
jest.spyOn(authService, 'fetchPreauthInfoService').mockResolvedValueOnce({
|
|
1425
|
+
ok: true,
|
|
1426
|
+
headers: new Headers({ 'content-type': 'application/json' }),
|
|
1427
|
+
json: async () => ({}), // no .info field
|
|
1428
|
+
} as any);
|
|
1429
|
+
const iFrame: any = document.createElement('div');
|
|
1430
|
+
jest.spyOn(baseInstance, 'getAuthPromise').mockResolvedValueOnce(true as any);
|
|
1431
|
+
const tsEmbed = new SearchEmbed(getRootEl(), {});
|
|
1432
|
+
iFrame.contentWindow = { postMessage: jest.fn() };
|
|
1433
|
+
jest.spyOn(iFrame, 'addEventListener').mockImplementationOnce(
|
|
1434
|
+
(event, handler) => { (handler as EventListener)({} as Event); },
|
|
1435
|
+
);
|
|
1436
|
+
jest.spyOn(document, 'createElement').mockReturnValueOnce(iFrame);
|
|
1437
|
+
await tsEmbed.render();
|
|
1438
|
+
|
|
1439
|
+
await executeAfterWait(() => {
|
|
1440
|
+
const infoSuccessCall = mockProcessTrigger.mock.calls.find(
|
|
1441
|
+
(call) => call[1] === HostEvent.InfoSuccess,
|
|
1442
|
+
);
|
|
1443
|
+
expect(infoSuccessCall).toBeUndefined();
|
|
1444
|
+
});
|
|
1445
|
+
});
|
|
1412
1446
|
});
|
|
1413
1447
|
|
|
1414
1448
|
describe('Preauth Cache for FullAppEmbed with PrimaryNavBar', () => {
|
|
@@ -2281,6 +2315,46 @@ describe('Unit test case for ts embed', () => {
|
|
|
2281
2315
|
});
|
|
2282
2316
|
});
|
|
2283
2317
|
|
|
2318
|
+
it('Sets the overrideHistoryState param', async () => {
|
|
2319
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
2320
|
+
frameParams: {
|
|
2321
|
+
width: '100%',
|
|
2322
|
+
height: '100%',
|
|
2323
|
+
},
|
|
2324
|
+
overrideHistoryState: true,
|
|
2325
|
+
});
|
|
2326
|
+
await appEmbed.render();
|
|
2327
|
+
expectUrlToHaveParamsWithValues(getIFrameSrc(), {
|
|
2328
|
+
overrideHistoryState: true,
|
|
2329
|
+
});
|
|
2330
|
+
});
|
|
2331
|
+
|
|
2332
|
+
it('Sets the overrideHistoryState param to false', async () => {
|
|
2333
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
2334
|
+
frameParams: {
|
|
2335
|
+
width: '100%',
|
|
2336
|
+
height: '100%',
|
|
2337
|
+
},
|
|
2338
|
+
overrideHistoryState: false,
|
|
2339
|
+
});
|
|
2340
|
+
await appEmbed.render();
|
|
2341
|
+
expectUrlToHaveParamsWithValues(getIFrameSrc(), {
|
|
2342
|
+
overrideHistoryState: false,
|
|
2343
|
+
});
|
|
2344
|
+
});
|
|
2345
|
+
|
|
2346
|
+
it('Should not add overrideHistoryState param when it is undefined', async () => {
|
|
2347
|
+
const appEmbed = new AppEmbed(getRootEl(), {
|
|
2348
|
+
frameParams: {
|
|
2349
|
+
width: '100%',
|
|
2350
|
+
height: '100%',
|
|
2351
|
+
},
|
|
2352
|
+
});
|
|
2353
|
+
await appEmbed.render();
|
|
2354
|
+
const url = getIFrameSrc();
|
|
2355
|
+
expect(url).not.toContain('overrideHistoryState');
|
|
2356
|
+
});
|
|
2357
|
+
|
|
2284
2358
|
it('Should not add contextMenuEnabledOnWhichClick flag to the iframe src when it is not passed', async () => {
|
|
2285
2359
|
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
2286
2360
|
...defaultViewConfig,
|
|
@@ -4570,6 +4644,28 @@ describe('Trigger method edge cases', () => {
|
|
|
4570
4644
|
expect(result).toBeNull();
|
|
4571
4645
|
});
|
|
4572
4646
|
});
|
|
4647
|
+
|
|
4648
|
+
test('isValidationError catch: handleError called with embedErrorDetails and error is rethrown', async () => {
|
|
4649
|
+
const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
4650
|
+
const handleErrorSpy = jest.spyOn(searchEmbed as any, 'handleError').mockImplementation(() => {});
|
|
4651
|
+
await searchEmbed.render();
|
|
4652
|
+
|
|
4653
|
+
// First processTrigger call is getAvailableUIPassthroughKeys for DrillDown
|
|
4654
|
+
mockProcessTrigger.mockResolvedValueOnce([
|
|
4655
|
+
{ value: { keys: Object.values(UIPassthroughEvent) } },
|
|
4656
|
+
]);
|
|
4657
|
+
|
|
4658
|
+
// DrillDown with no points → throwDrillDownValidationError → isValidationError=true
|
|
4659
|
+
await expect(
|
|
4660
|
+
searchEmbed.trigger(HostEvent.DrillDown, {} as any),
|
|
4661
|
+
).rejects.toThrow('DrillDown requires a valid points object');
|
|
4662
|
+
|
|
4663
|
+
expect(handleErrorSpy).toHaveBeenCalledWith(
|
|
4664
|
+
expect.objectContaining({
|
|
4665
|
+
data: expect.objectContaining({ code: EmbedErrorCodes.HOST_EVENT_VALIDATION }),
|
|
4666
|
+
}),
|
|
4667
|
+
);
|
|
4668
|
+
});
|
|
4573
4669
|
});
|
|
4574
4670
|
|
|
4575
4671
|
describe('PreRender replaceExistingPreRender scenarios', () => {
|
|
@@ -4580,6 +4676,10 @@ describe('PreRender replaceExistingPreRender scenarios', () => {
|
|
|
4580
4676
|
});
|
|
4581
4677
|
});
|
|
4582
4678
|
|
|
4679
|
+
beforeEach(() => {
|
|
4680
|
+
document.body.innerHTML = getDocumentBody();
|
|
4681
|
+
});
|
|
4682
|
+
|
|
4583
4683
|
afterEach(() => {
|
|
4584
4684
|
const rootEle = document.getElementById('myRoot');
|
|
4585
4685
|
rootEle?.remove();
|
|
@@ -4725,6 +4825,52 @@ describe('Fullscreen change handler behavior', () => {
|
|
|
4725
4825
|
);
|
|
4726
4826
|
});
|
|
4727
4827
|
});
|
|
4828
|
+
|
|
4829
|
+
test('disableFullscreenPresentation undefined defaults to true — no fullscreenchange listener registered', () => {
|
|
4830
|
+
init({
|
|
4831
|
+
thoughtSpotHost: 'tshost',
|
|
4832
|
+
authType: AuthType.None,
|
|
4833
|
+
// disableFullscreenPresentation not set → defaults to true via ?? true
|
|
4834
|
+
});
|
|
4835
|
+
|
|
4836
|
+
const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
4837
|
+
const addEventListenerSpy = jest.spyOn(document, 'addEventListener');
|
|
4838
|
+
|
|
4839
|
+
embed['setupFullscreenChangeHandler']();
|
|
4840
|
+
|
|
4841
|
+
expect(addEventListenerSpy).not.toHaveBeenCalledWith('fullscreenchange', expect.any(Function));
|
|
4842
|
+
|
|
4843
|
+
addEventListenerSpy.mockRestore();
|
|
4844
|
+
// Restore for other tests in this describe
|
|
4845
|
+
init({ thoughtSpotHost: 'tshost', authType: AuthType.None, disableFullscreenPresentation: false });
|
|
4846
|
+
});
|
|
4847
|
+
|
|
4848
|
+
test('fullscreenchange fires but iFrame.contentWindow is null — trigger NOT called, debug log emitted', () => {
|
|
4849
|
+
const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
4850
|
+
// Give the embed a fake iFrame with null contentWindow
|
|
4851
|
+
(embed as any).iFrame = { contentWindow: null };
|
|
4852
|
+
|
|
4853
|
+
const addEventListenerSpy = jest.spyOn(document, 'addEventListener');
|
|
4854
|
+
const loggerDebugSpy = jest.spyOn(logger, 'debug').mockImplementation(() => {});
|
|
4855
|
+
const triggerSpy = jest.spyOn(embed, 'trigger' as any).mockImplementation(() => Promise.resolve(null));
|
|
4856
|
+
|
|
4857
|
+
embed['setupFullscreenChangeHandler']();
|
|
4858
|
+
|
|
4859
|
+
// Capture the registered handler directly instead of dispatching to document
|
|
4860
|
+
const fullscreenCall = addEventListenerSpy.mock.calls.find((c) => c[0] === 'fullscreenchange');
|
|
4861
|
+
expect(fullscreenCall).toBeTruthy();
|
|
4862
|
+
const handler = fullscreenCall[1] as EventListener;
|
|
4863
|
+
|
|
4864
|
+
Object.defineProperty(document, 'fullscreenElement', { value: null, writable: true, configurable: true });
|
|
4865
|
+
handler(new Event('fullscreenchange'));
|
|
4866
|
+
|
|
4867
|
+
expect(triggerSpy).not.toHaveBeenCalled();
|
|
4868
|
+
expect(loggerDebugSpy).toHaveBeenCalledWith(expect.stringContaining('Skipping ExitPresentMode'));
|
|
4869
|
+
|
|
4870
|
+
addEventListenerSpy.mockRestore();
|
|
4871
|
+
loggerDebugSpy.mockRestore();
|
|
4872
|
+
triggerSpy.mockRestore();
|
|
4873
|
+
});
|
|
4728
4874
|
});
|
|
4729
4875
|
|
|
4730
4876
|
describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
@@ -5315,5 +5461,45 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
5315
5461
|
|
|
5316
5462
|
embed.destroy();
|
|
5317
5463
|
});
|
|
5464
|
+
|
|
5465
|
+
// showPreRender located the stale placeholder with a subtree-wide
|
|
5466
|
+
// querySelector but removed it with hostElement.removeChild(), which
|
|
5467
|
+
// only accepts direct children. With fullHeight the placeholder can be
|
|
5468
|
+
// nested deeper than a direct child, so removeChild threw
|
|
5469
|
+
// "NotFoundError: Failed to execute 'removeChild' on 'Node'".
|
|
5470
|
+
it('showPreRender removes a placeholder nested below a direct child without throwing', async () => {
|
|
5471
|
+
createRootEleForEmbed();
|
|
5472
|
+
const embed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
5473
|
+
preRenderId: 'ph-nested-test',
|
|
5474
|
+
liveboardId: 'lb-id',
|
|
5475
|
+
fullHeight: true,
|
|
5476
|
+
} as any);
|
|
5477
|
+
await embed.preRender();
|
|
5478
|
+
await waitFor(
|
|
5479
|
+
() => !!document.querySelector('#tsEmbed-pre-render-child-ph-nested-test'),
|
|
5480
|
+
);
|
|
5481
|
+
|
|
5482
|
+
const hostElement = document.querySelector('#tsEmbedDiv') as HTMLElement;
|
|
5483
|
+
const placeHolderId = 'tsEmbed-pre-render-placeholder-ph-nested-test';
|
|
5484
|
+
// Simulate the fullHeight layout where the placeholder ends up as
|
|
5485
|
+
// a grandchild of the host element rather than a direct child.
|
|
5486
|
+
const intermediateWrapper = document.createElement('div');
|
|
5487
|
+
const staleNestedPlaceholder = document.createElement('div');
|
|
5488
|
+
staleNestedPlaceholder.id = placeHolderId;
|
|
5489
|
+
intermediateWrapper.appendChild(staleNestedPlaceholder);
|
|
5490
|
+
hostElement.appendChild(intermediateWrapper);
|
|
5491
|
+
|
|
5492
|
+
expect(hostElement.querySelector(`#${placeHolderId}`)).toBe(staleNestedPlaceholder);
|
|
5493
|
+
// Before the fix this threw NotFoundError.
|
|
5494
|
+
await expect(embed.showPreRender()).resolves.toBeDefined();
|
|
5495
|
+
// The stale nested placeholder is gone; the fresh one is a direct child.
|
|
5496
|
+
expect(staleNestedPlaceholder.isConnected).toBe(false);
|
|
5497
|
+
const currentPlaceholder = (
|
|
5498
|
+
embed as any
|
|
5499
|
+
).getPreRenderPlaceHolderElement() as HTMLDivElement;
|
|
5500
|
+
expect(currentPlaceholder.parentElement).toBe(hostElement);
|
|
5501
|
+
|
|
5502
|
+
embed.destroy();
|
|
5503
|
+
});
|
|
5318
5504
|
});
|
|
5319
5505
|
});
|
package/src/embed/ts-embed.ts
CHANGED
|
@@ -771,6 +771,7 @@ export class TsEmbed {
|
|
|
771
771
|
insertInToSlide,
|
|
772
772
|
disableRedirectionLinksInNewTab,
|
|
773
773
|
overrideOrgId,
|
|
774
|
+
overrideHistoryState,
|
|
774
775
|
exposeTranslationIDs,
|
|
775
776
|
primaryAction,
|
|
776
777
|
} = this.viewConfig;
|
|
@@ -869,6 +870,9 @@ export class TsEmbed {
|
|
|
869
870
|
if (overrideOrgId !== undefined) {
|
|
870
871
|
queryParams[Param.OverrideOrgId] = overrideOrgId;
|
|
871
872
|
}
|
|
873
|
+
if (overrideHistoryState !== undefined) {
|
|
874
|
+
queryParams[Param.OverrideHistoryState] = overrideHistoryState;
|
|
875
|
+
}
|
|
872
876
|
|
|
873
877
|
if (this.isPreAuthCacheEnabled()) {
|
|
874
878
|
queryParams[Param.preAuthCache] = true;
|
|
@@ -1999,10 +2003,14 @@ export class TsEmbed {
|
|
|
1999
2003
|
}
|
|
2000
2004
|
|
|
2001
2005
|
const placeHolderId = this.getPreRenderIds().placeHolder;
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
+
// Remove any stale placeholder from a previous cycle. It is located
|
|
2007
|
+
// via a subtree-wide querySelector, so it may be nested deeper than a
|
|
2008
|
+
// direct child (E.g.: with fullHeight the host app can wrap it). Use
|
|
2009
|
+
// Element.remove() — which detaches from whatever the real parent is —
|
|
2010
|
+
// rather than hostElement.removeChild(), which throws NotFoundError
|
|
2011
|
+
// when the match is not a direct child. Mirrors the wrapper/child
|
|
2012
|
+
// cleanup in createPreRenderWrapper()/createPreRenderChild().
|
|
2013
|
+
this.hostElement.querySelector(`#${placeHolderId}`)?.remove();
|
|
2006
2014
|
|
|
2007
2015
|
this.hostElement.appendChild(this.insertedDomEl);
|
|
2008
2016
|
|
package/src/errors.ts
CHANGED
|
@@ -31,6 +31,7 @@ export const ERROR_MESSAGE = {
|
|
|
31
31
|
INVALID_SPOTTER_DOCUMENTATION_URL: 'Invalid spotterDocumentationUrl. Please provide a valid http or https URL.',
|
|
32
32
|
UPDATEFILTERS_INVALID_PAYLOAD: 'UpdateFilters requires a valid filter or filters array. Expected: { filter: { column, oper, values } } or { filters: [{ column, oper, values }, ...] }',
|
|
33
33
|
DRILLDOWN_INVALID_PAYLOAD: 'DrillDown requires a valid points object. Expected: { points: { clickedPoint?, selectedPoints? }, autoDrillDown?, vizId? }',
|
|
34
|
+
UPDATEPARAMETERS_INVALID_PAYLOAD: 'UpdateParameters received an invalid applicability. Expected: { level: LIVEBOARD | TAB | GROUP, targetId } where targetId is required for TAB and GROUP levels',
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export const CUSTOM_ACTIONS_ERROR_MESSAGE = {
|
package/src/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/live
|
|
|
32
32
|
import { SearchEmbed, SearchViewConfig } from './embed/search';
|
|
33
33
|
import { SearchBarEmbed, SearchBarViewConfig } from './embed/search-bar';
|
|
34
34
|
import { SpotterAgentEmbed, SpotterAgentEmbedViewConfig, BodylessConversation, BodylessConversationViewConfig} from './embed/bodyless-conversation';
|
|
35
|
-
import { SpotterEmbed, SpotterEmbedViewConfig, SpotterChatViewConfig, SpotterSidebarViewConfig, ConversationEmbed, ConversationViewConfig } from './embed/conversation';
|
|
35
|
+
import { SpotterEmbed, SpotterEmbedViewConfig, SpotterChatViewConfig, SpotterSidebarViewConfig, SpotterQueryMode, ConversationEmbed, ConversationViewConfig } from './embed/conversation';
|
|
36
36
|
import { SpotterVizConfig, SpotterVizStarterPrompt, SpotterVizLoaderTip } from './embed/spotter-viz-utils';
|
|
37
37
|
import {
|
|
38
38
|
AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter,
|
|
@@ -117,6 +117,7 @@ export {
|
|
|
117
117
|
SpotterEmbedViewConfig,
|
|
118
118
|
SpotterChatViewConfig,
|
|
119
119
|
SpotterSidebarViewConfig,
|
|
120
|
+
SpotterQueryMode,
|
|
120
121
|
ConversationViewConfig,
|
|
121
122
|
ConversationEmbed,
|
|
122
123
|
AuthFailureType,
|