@thoughtspot/visual-embed-sdk 1.52.1 → 1.52.2-beta
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 +11 -4
- package/cjs/src/contracts/host-event-contracts.d.ts +49 -11
- package/cjs/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/cjs/src/embed/app.d.ts +4 -3
- package/cjs/src/embed/app.d.ts.map +1 -1
- package/cjs/src/embed/app.js +1 -1
- package/cjs/src/embed/app.js.map +1 -1
- package/cjs/src/embed/app.spec.js +10 -0
- package/cjs/src/embed/app.spec.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.js +1 -1
- package/cjs/src/embed/auto-frame-renderer.js.map +1 -1
- package/cjs/src/embed/auto-frame-renderer.spec.js +24 -13
- package/cjs/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/cjs/src/embed/bodyless-conversation.js +1 -1
- package/cjs/src/embed/bodyless-conversation.js.map +1 -1
- package/cjs/src/embed/conversation.d.ts +1 -0
- package/cjs/src/embed/conversation.d.ts.map +1 -1
- package/cjs/src/embed/conversation.js +4 -4
- package/cjs/src/embed/conversation.js.map +1 -1
- package/cjs/src/embed/conversation.spec.js +35 -24
- package/cjs/src/embed/conversation.spec.js.map +1 -1
- package/cjs/src/embed/embedConfig.spec.js +2 -1
- package/cjs/src/embed/embedConfig.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts +2 -2
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.js +16 -10
- package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js +14 -8
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.d.ts +9 -0
- package/cjs/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.js +49 -3
- package/cjs/src/embed/hostEventClient/utils.js.map +1 -1
- package/cjs/src/embed/hostEventClient/utils.spec.js +151 -0
- package/cjs/src/embed/hostEventClient/utils.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +4 -3
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +18 -13
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +2 -1
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/search-bar.js +1 -1
- package/cjs/src/embed/search-bar.js.map +1 -1
- package/cjs/src/embed/search.js +1 -1
- package/cjs/src/embed/search.js.map +1 -1
- package/cjs/src/embed/search.spec.js +20 -0
- package/cjs/src/embed/search.spec.js.map +1 -1
- package/cjs/src/embed/spotter-utils.d.ts +8 -1
- package/cjs/src/embed/spotter-utils.d.ts.map +1 -1
- package/cjs/src/embed/spotter-utils.js +14 -1
- package/cjs/src/embed/spotter-utils.js.map +1 -1
- package/cjs/src/embed/spotter-utils.spec.js +26 -0
- package/cjs/src/embed/spotter-utils.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +3 -0
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +108 -29
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +163 -23
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/errors.js +1 -1
- package/cjs/src/errors.js.map +1 -1
- package/cjs/src/index.d.ts +2 -1
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +3 -1
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/react/all-types-export.d.ts +1 -1
- package/cjs/src/react/all-types-export.d.ts.map +1 -1
- package/cjs/src/react/all-types-export.js +2 -1
- package/cjs/src/react/all-types-export.js.map +1 -1
- package/cjs/src/types.d.ts +45 -22
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +44 -21
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js +2 -1
- package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/cjs/src/utils/custom-actions.spec.js +4 -2
- package/cjs/src/utils/custom-actions.spec.js.map +1 -1
- package/cjs/src/utils/filterConverter.d.ts +106 -0
- package/cjs/src/utils/filterConverter.d.ts.map +1 -0
- package/cjs/src/utils/filterConverter.js +215 -0
- package/cjs/src/utils/filterConverter.js.map +1 -0
- package/cjs/src/utils/filterConverter.spec.d.ts +2 -0
- package/cjs/src/utils/filterConverter.spec.d.ts.map +1 -0
- package/cjs/src/utils/filterConverter.spec.js +709 -0
- package/cjs/src/utils/filterConverter.spec.js.map +1 -0
- package/cjs/src/utils/processData.spec.js +2 -1
- package/cjs/src/utils/processData.spec.js.map +1 -1
- package/dist/{index-C1pmYb5H.js → index-CcBYlGo9.js} +1 -1
- package/dist/src/contracts/host-event-contracts.d.ts +49 -11
- package/dist/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/dist/src/embed/app.d.ts +4 -3
- package/dist/src/embed/app.d.ts.map +1 -1
- package/dist/src/embed/conversation.d.ts +1 -0
- package/dist/src/embed/conversation.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/host-event-client.d.ts +2 -2
- package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/utils.d.ts +9 -0
- package/dist/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +4 -3
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/spotter-utils.d.ts +8 -1
- package/dist/src/embed/spotter-utils.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +3 -0
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/react/all-types-export.d.ts +1 -1
- package/dist/src/react/all-types-export.d.ts.map +1 -1
- package/dist/src/types.d.ts +45 -22
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/filterConverter.d.ts +106 -0
- package/dist/src/utils/filterConverter.d.ts.map +1 -0
- package/dist/src/utils/filterConverter.spec.d.ts +2 -0
- package/dist/src/utils/filterConverter.spec.d.ts.map +1 -0
- package/dist/tsembed-react.es.js +257 -87
- package/dist/tsembed-react.js +256 -86
- package/dist/tsembed.es.js +466 -89
- package/dist/tsembed.js +465 -87
- package/dist/visual-embed-sdk-react-full.d.ts +202 -40
- package/dist/visual-embed-sdk-react.d.ts +108 -40
- package/dist/visual-embed-sdk.d.ts +202 -40
- package/lib/package.json +11 -4
- package/lib/src/contracts/host-event-contracts.d.ts +49 -11
- package/lib/src/contracts/host-event-contracts.d.ts.map +1 -1
- package/lib/src/embed/app.d.ts +4 -3
- package/lib/src/embed/app.d.ts.map +1 -1
- package/lib/src/embed/app.js +1 -1
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +10 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.js +1 -1
- package/lib/src/embed/auto-frame-renderer.js.map +1 -1
- package/lib/src/embed/auto-frame-renderer.spec.js +24 -13
- package/lib/src/embed/auto-frame-renderer.spec.js.map +1 -1
- package/lib/src/embed/bodyless-conversation.js +1 -1
- package/lib/src/embed/bodyless-conversation.js.map +1 -1
- package/lib/src/embed/conversation.d.ts +1 -0
- package/lib/src/embed/conversation.d.ts.map +1 -1
- package/lib/src/embed/conversation.js +5 -5
- package/lib/src/embed/conversation.js.map +1 -1
- package/lib/src/embed/conversation.spec.js +35 -24
- package/lib/src/embed/conversation.spec.js.map +1 -1
- package/lib/src/embed/embedConfig.spec.js +2 -1
- package/lib/src/embed/embedConfig.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.d.ts +2 -2
- package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.js +17 -11
- package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.spec.js +14 -8
- package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/utils.d.ts +9 -0
- package/lib/src/embed/hostEventClient/utils.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/utils.js +47 -2
- package/lib/src/embed/hostEventClient/utils.js.map +1 -1
- package/lib/src/embed/hostEventClient/utils.spec.js +152 -1
- package/lib/src/embed/hostEventClient/utils.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +4 -3
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +18 -13
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +2 -1
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/search-bar.js +1 -1
- package/lib/src/embed/search-bar.js.map +1 -1
- package/lib/src/embed/search.js +1 -1
- package/lib/src/embed/search.js.map +1 -1
- package/lib/src/embed/search.spec.js +20 -0
- package/lib/src/embed/search.spec.js.map +1 -1
- package/lib/src/embed/spotter-utils.d.ts +8 -1
- package/lib/src/embed/spotter-utils.d.ts.map +1 -1
- package/lib/src/embed/spotter-utils.js +12 -0
- package/lib/src/embed/spotter-utils.js.map +1 -1
- package/lib/src/embed/spotter-utils.spec.js +27 -1
- package/lib/src/embed/spotter-utils.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +3 -0
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +108 -29
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +164 -24
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/errors.js +1 -1
- package/lib/src/errors.js.map +1 -1
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +2 -1
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/all-types-export.d.ts +1 -1
- package/lib/src/react/all-types-export.d.ts.map +1 -1
- package/lib/src/react/all-types-export.js +1 -1
- package/lib/src/react/all-types-export.js.map +1 -1
- package/lib/src/types.d.ts +45 -22
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +44 -21
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/authService/tokenizedAuthService.spec.js +2 -1
- package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -1
- package/lib/src/utils/custom-actions.spec.js +4 -2
- package/lib/src/utils/custom-actions.spec.js.map +1 -1
- package/lib/src/utils/filterConverter.d.ts +106 -0
- package/lib/src/utils/filterConverter.d.ts.map +1 -0
- package/lib/src/utils/filterConverter.js +210 -0
- package/lib/src/utils/filterConverter.js.map +1 -0
- package/lib/src/utils/filterConverter.spec.d.ts +2 -0
- package/lib/src/utils/filterConverter.spec.d.ts.map +1 -0
- package/lib/src/utils/filterConverter.spec.js +707 -0
- package/lib/src/utils/filterConverter.spec.js.map +1 -0
- package/lib/src/utils/processData.spec.js +2 -1
- package/lib/src/utils/processData.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +202 -40
- package/package.json +11 -4
- package/src/contracts/host-event-contracts.ts +55 -11
- package/src/embed/app.spec.ts +15 -0
- package/src/embed/app.ts +5 -4
- package/src/embed/auto-frame-renderer.spec.ts +24 -13
- package/src/embed/auto-frame-renderer.ts +1 -1
- package/src/embed/bodyless-conversation.ts +1 -1
- package/src/embed/conversation.spec.ts +38 -27
- package/src/embed/conversation.ts +5 -5
- package/src/embed/embedConfig.spec.ts +2 -1
- package/src/embed/hostEventClient/host-event-client.spec.ts +14 -8
- package/src/embed/hostEventClient/host-event-client.ts +18 -10
- package/src/embed/hostEventClient/utils.spec.ts +176 -1
- package/src/embed/hostEventClient/utils.ts +51 -2
- package/src/embed/liveboard.spec.ts +4 -3
- package/src/embed/liveboard.ts +22 -16
- package/src/embed/search-bar.tsx +1 -1
- package/src/embed/search.spec.ts +23 -0
- package/src/embed/search.ts +1 -1
- package/src/embed/spotter-utils.spec.ts +29 -0
- package/src/embed/spotter-utils.ts +16 -0
- package/src/embed/ts-embed.spec.ts +204 -23
- package/src/embed/ts-embed.ts +114 -28
- package/src/errors.ts +1 -1
- package/src/index.ts +10 -0
- package/src/react/all-types-export.ts +4 -0
- package/src/types.ts +44 -21
- package/src/utils/authService/tokenizedAuthService.spec.ts +2 -1
- package/src/utils/custom-actions.spec.ts +4 -2
- package/src/utils/filterConverter.spec.ts +801 -0
- package/src/utils/filterConverter.ts +304 -0
- package/src/utils/processData.spec.ts +2 -1
|
@@ -10,7 +10,8 @@ import { embedEventStatus } from '../../utils';
|
|
|
10
10
|
|
|
11
11
|
const isValidApplicability = (a?: { level?: string; targetId?: string }) => {
|
|
12
12
|
if (isUndefined(a)) return true;
|
|
13
|
-
// targetId is not required at LIVEBOARD level, since the filter applies to
|
|
13
|
+
// targetId is not required at LIVEBOARD level, since the filter applies to
|
|
14
|
+
// the whole Liveboard
|
|
14
15
|
return isPlainObject(a)
|
|
15
16
|
&& Object.values(ApplicabilityLevel).includes(a.level as ApplicabilityLevel)
|
|
16
17
|
&& (a.level === ApplicabilityLevel.Liveboard || (isString(a.targetId) && a.targetId.trim().length > 0));
|
|
@@ -44,8 +45,56 @@ export function isValidUpdateFiltersPayload(
|
|
|
44
45
|
return !!(hasValidFilter || hasValidFilters);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Rewrites one filter's `columnName`/`operator` to `column`/`oper`.
|
|
50
|
+
*
|
|
51
|
+
* Callers may use either spelling: `columnName`/`operator` match
|
|
52
|
+
* {@link RuntimeFilter} and the `EmbedEvent.FilterChanged` payload, so a
|
|
53
|
+
* converted payload can be replayed as-is. But the payload is forwarded to the
|
|
54
|
+
* embedded app unchanged, and only `column`/`oper` are known to be understood
|
|
55
|
+
* there - so the alias must be swapped here, or it would pass validation and
|
|
56
|
+
* then be silently ignored.
|
|
57
|
+
*
|
|
58
|
+
* If a caller supplies both spellings of a field - which TypeScript rejects,
|
|
59
|
+
* but JavaScript callers can still do - the documented `columnName`/`operator`
|
|
60
|
+
* wins. Deferring to the deprecated spelling would quietly discard the value
|
|
61
|
+
* the rest of the SDK tells people to use.
|
|
62
|
+
* @param filter One entry from the UpdateFilters payload.
|
|
63
|
+
*/
|
|
64
|
+
function resolveFilterAliases<T extends { column?: string; columnName?: string; oper?: string; operator?: string }>(
|
|
65
|
+
filter: T,
|
|
66
|
+
): T {
|
|
67
|
+
if (!isPlainObject(filter)) return filter;
|
|
68
|
+
|
|
69
|
+
const column = filter.columnName ?? filter.column;
|
|
70
|
+
const oper = filter.operator ?? filter.oper;
|
|
71
|
+
const { columnName, operator, ...rest } = filter;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
...rest,
|
|
75
|
+
...(isUndefined(column) ? {} : { column }),
|
|
76
|
+
...(isUndefined(oper) ? {} : { oper }),
|
|
77
|
+
} as T;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Rewrites every filter in an UpdateFilters payload to use `column`/`oper`,
|
|
82
|
+
* whichever spelling the caller supplied. Call after validation.
|
|
83
|
+
* @param payload The UpdateFilters host event payload.
|
|
84
|
+
*/
|
|
85
|
+
export function resolveUpdateFiltersAliases<T extends { filter?: any; filters?: any[] }>(payload: T): T {
|
|
86
|
+
if (!isPlainObject(payload)) return payload;
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
...payload,
|
|
90
|
+
...(payload.filter ? { filter: resolveFilterAliases(payload.filter) } : {}),
|
|
91
|
+
...(Array.isArray(payload.filters) ? { filters: payload.filters.map(resolveFilterAliases) } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
47
95
|
export function isValidUpdateParametersPayload(payload: unknown): boolean {
|
|
48
|
-
// Only validates the applicability of each parameter (null treated as
|
|
96
|
+
// Only validates the applicability of each parameter (null treated as
|
|
97
|
+
// absent); the rest is forwarded as-is for backward compatibility.
|
|
49
98
|
if (!Array.isArray(payload)) return true;
|
|
50
99
|
return payload.every((p) => {
|
|
51
100
|
if (!isPlainObject(p)) return true;
|
|
@@ -3054,8 +3054,8 @@ describe('LiveboardEmbed updatedSpotterExperience tests', () => {
|
|
|
3054
3054
|
|
|
3055
3055
|
describe('trigger typing contracts (compile-time)', () => {
|
|
3056
3056
|
// Enforced by ts-jest at compile time. LiveboardEmbed OVERRIDES
|
|
3057
|
-
// TsEmbed.trigger, so its generic defaults must be asserted separately
|
|
3058
|
-
// a bare `PayloadT` on the override silently collapses no-payload
|
|
3057
|
+
// TsEmbed.trigger, so its generic defaults must be asserted separately
|
|
3058
|
+
// — a bare `PayloadT` on the override silently collapses no-payload
|
|
3059
3059
|
// responses back to `any` for every LiveboardEmbed consumer.
|
|
3060
3060
|
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
3061
3061
|
type Extends<A, B> = A extends B ? true : false;
|
|
@@ -3073,7 +3073,8 @@ describe('LiveboardEmbed updatedSpotterExperience tests', () => {
|
|
|
3073
3073
|
{ numberOfTabs: number; orderedTabIds: string[] }
|
|
3074
3074
|
> = true;
|
|
3075
3075
|
const probeUnknownField = (r: TabsResponse) =>
|
|
3076
|
-
// @ts-expect-error — field not on the GetTabs contract (was
|
|
3076
|
+
// @ts-expect-error — field not on the GetTabs contract (was
|
|
3077
|
+
// silent when `any`)
|
|
3077
3078
|
r.tabCount;
|
|
3078
3079
|
void probeUnknownField;
|
|
3079
3080
|
|
package/src/embed/liveboard.ts
CHANGED
|
@@ -37,8 +37,9 @@ import { SpotterChatViewConfig, StarterPromptsConfig } from './conversation';
|
|
|
37
37
|
import { buildStarterPromptsAppInitData } from './spotter-utils';
|
|
38
38
|
import { SpotterVizConfig, buildSpotterVizAppInitData } from './spotter-viz-utils';
|
|
39
39
|
|
|
40
|
-
// Home unmounts the liveboard container, which is how its state gets cleared.
|
|
41
|
-
// settle window gives the container time to do it before we ask for the
|
|
40
|
+
// Home unmounts the liveboard container, which is how its state gets cleared.
|
|
41
|
+
// The settle window gives the container time to do it before we ask for the
|
|
42
|
+
// liveboard back.
|
|
42
43
|
const HOME_ROUTE = 'home';
|
|
43
44
|
const HOME_SETTLE_MS = 200;
|
|
44
45
|
|
|
@@ -354,9 +355,10 @@ export interface LiveboardViewConfig
|
|
|
354
355
|
*/
|
|
355
356
|
isPNGInScheduledEmailsEnabled?: boolean;
|
|
356
357
|
/**
|
|
357
|
-
* Enables the 'what you see is what you get' PDF export for Liveboards. Each tab is
|
|
358
|
-
* following the exact UI layout, instead of splitting
|
|
359
|
-
* This feature is GA from SDK version
|
|
358
|
+
* Enables the 'what you see is what you get' PDF export for Liveboards. Each tab is
|
|
359
|
+
* rendered on a single page following the exact UI layout, instead of splitting
|
|
360
|
+
* visualizations across multiple A4 pages. This feature is GA from SDK version
|
|
361
|
+
* 1.51.0 and ThoughtSpot version 26.8.0.cl.
|
|
360
362
|
*
|
|
361
363
|
* Supported embed types: `AppEmbed`, `LiveboardEmbed`
|
|
362
364
|
* @type {boolean}
|
|
@@ -597,7 +599,7 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
597
599
|
* embedded Liveboard or visualization.
|
|
598
600
|
*/
|
|
599
601
|
protected getEmbedParams() {
|
|
600
|
-
const params = this.
|
|
602
|
+
const params = this.getUrlQueryParamsObject();
|
|
601
603
|
const queryParams = getQueryParamString(params, true);
|
|
602
604
|
return queryParams;
|
|
603
605
|
}
|
|
@@ -952,22 +954,25 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
952
954
|
protected beforePrerenderVisible(): void {
|
|
953
955
|
super.beforePrerenderVisible();
|
|
954
956
|
|
|
955
|
-
// Captured before showPreRender() hands the wrapper over to this
|
|
956
|
-
// Itself means a hide/show, not a hand-over, so there is
|
|
957
|
+
// Captured before showPreRender() hands the wrapper over to this
|
|
958
|
+
// instance. Itself means a hide/show, not a hand-over, so there is
|
|
959
|
+
// nothing stale to clear.
|
|
957
960
|
const previous = this.getPreRenderObj<LiveboardEmbed>();
|
|
958
961
|
const showing = previous === this ? undefined : previous?.currentLiveboardState;
|
|
959
962
|
|
|
960
963
|
this.executeAfterEmbedContainerLoaded(async () => {
|
|
961
|
-
// Without this the params callback suspends on its await and
|
|
962
|
-
// goes out first, so the container loads with the previous
|
|
964
|
+
// Without this the params callback suspends on its await and
|
|
965
|
+
// Navigate goes out first, so the container loads with the previous
|
|
966
|
+
// config's filters.
|
|
963
967
|
await this.preRenderParamsApplied;
|
|
964
968
|
if (this.isShowingLiveboardRoute(showing)) {
|
|
965
|
-
// Navigate to the route we are already on is a no-op, so the
|
|
966
|
-
// keeps its state. Home unmounts the container, which
|
|
969
|
+
// Navigate to the route we are already on is a no-op, so the
|
|
970
|
+
// liveboard keeps its state. Home unmounts the container, which
|
|
971
|
+
// clears it.
|
|
967
972
|
this.trigger(HostEvent.Navigate, HOME_ROUTE)
|
|
968
973
|
.catch((error) => logger.warn('Could not route via home', error));
|
|
969
|
-
// Not awaited above: the container never acks Navigate, so
|
|
970
|
-
// only settles on the 30s trigger timeout.
|
|
974
|
+
// Not awaited above: the container never acks Navigate, so
|
|
975
|
+
// that promise only settles on the 30s trigger timeout.
|
|
971
976
|
await new Promise((resolve) => {
|
|
972
977
|
setTimeout(resolve, HOME_SETTLE_MS);
|
|
973
978
|
});
|
|
@@ -987,8 +992,9 @@ export class LiveboardEmbed extends V1Embed {
|
|
|
987
992
|
});
|
|
988
993
|
}
|
|
989
994
|
|
|
990
|
-
// The whole route, not just the liveboard id: the path is built from the
|
|
991
|
-
// and view too, so a same-liveboard show onto another tab is a
|
|
995
|
+
// The whole route, not just the liveboard id: the path is built from the
|
|
996
|
+
// viz, tab and view too, so a same-liveboard show onto another tab is a
|
|
997
|
+
// real navigation.
|
|
992
998
|
private isShowingLiveboardRoute(showing?: LiveboardEmbed['currentLiveboardState']): boolean {
|
|
993
999
|
if (!showing?.liveboardId) return false;
|
|
994
1000
|
const {
|
package/src/embed/search-bar.tsx
CHANGED
|
@@ -163,7 +163,7 @@ export class SearchBarEmbed extends TsEmbed {
|
|
|
163
163
|
* @param dataSources A list of data source GUIDs
|
|
164
164
|
*/
|
|
165
165
|
private getIFrameSrc() {
|
|
166
|
-
const queryParams = this.
|
|
166
|
+
const queryParams = this.getUrlQueryParamsObject();
|
|
167
167
|
const path = 'search-bar-embed';
|
|
168
168
|
|
|
169
169
|
let query = '';
|
package/src/embed/search.spec.ts
CHANGED
|
@@ -854,6 +854,29 @@ test('should pass forceTable parameter when forceTable is true', async () => {
|
|
|
854
854
|
});
|
|
855
855
|
|
|
856
856
|
describe('SearchBarEmbed tests', () => {
|
|
857
|
+
test('should keep view config off the URL when excludeConfigFromURL is set', async () => {
|
|
858
|
+
const searchBarEmbed = new SearchBarEmbed(getRootEl() as any, {
|
|
859
|
+
...defaultViewConfig,
|
|
860
|
+
dataSources: ['source-1', 'source-2'],
|
|
861
|
+
additionalFlags: { excludeConfigFromURL: true },
|
|
862
|
+
} as any);
|
|
863
|
+
searchBarEmbed.render();
|
|
864
|
+
await executeAfterWait(() => {
|
|
865
|
+
const iframeSrc = getIFrameSrc();
|
|
866
|
+
|
|
867
|
+
// Bootstrap params stay: the handshake, the embed marker that
|
|
868
|
+
// picks the app shell, and the data sources it boots against.
|
|
869
|
+
expect(iframeSrc).toContain('hostAppUrl=');
|
|
870
|
+
expect(iframeSrc).toContain('isSearchEmbed=true');
|
|
871
|
+
expect(iframeSrc).toContain('dataSources');
|
|
872
|
+
|
|
873
|
+
// The rest of the view config goes over
|
|
874
|
+
// HostEvent.UpdateEmbedParams.
|
|
875
|
+
expect(iframeSrc).not.toContain('hideAction');
|
|
876
|
+
expect(iframeSrc).not.toContain('useLastSelectedDataSource');
|
|
877
|
+
});
|
|
878
|
+
});
|
|
879
|
+
|
|
857
880
|
test('should pass dataSources parameter when dataSources array is provided', async () => {
|
|
858
881
|
const searchBarEmbed = new SearchBarEmbed(getRootEl() as any, {
|
|
859
882
|
...defaultViewConfig,
|
package/src/embed/search.ts
CHANGED
|
@@ -546,7 +546,7 @@ export class SearchEmbed extends TsEmbed {
|
|
|
546
546
|
excludeRuntimeParametersfromURL,
|
|
547
547
|
excludeRuntimeFiltersfromURL,
|
|
548
548
|
} = this.viewConfig;
|
|
549
|
-
const queryParams = this.
|
|
549
|
+
const queryParams = this.getUrlQueryParamsObject();
|
|
550
550
|
let query = '';
|
|
551
551
|
const queryParamsString = getQueryParamString(queryParams, true);
|
|
552
552
|
if (queryParamsString) {
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
buildSpotterSidebarAppInitData,
|
|
4
4
|
buildSpotterShareConversationAppInitData,
|
|
5
5
|
buildStarterPromptsAppInitData,
|
|
6
|
+
buildSpotterAnalystAppInitData,
|
|
6
7
|
} from './spotter-utils';
|
|
7
8
|
import { ErrorDetailsTypes, EmbedErrorCodes } from '../types';
|
|
8
9
|
import { ERROR_MESSAGE } from '../errors';
|
|
@@ -245,3 +246,31 @@ describe('buildStarterPromptsAppInitData', () => {
|
|
|
245
246
|
expect(result.embedParams?.starterPrompts).toEqual({ enable: true, liveboard });
|
|
246
247
|
});
|
|
247
248
|
});
|
|
249
|
+
|
|
250
|
+
describe('buildSpotterAnalystAppInitData', () => {
|
|
251
|
+
const base = { type: 'APP_INIT' } as any;
|
|
252
|
+
|
|
253
|
+
it('returns the payload unchanged when analystId is absent', () => {
|
|
254
|
+
expect(buildSpotterAnalystAppInitData(base, {})).toBe(base);
|
|
255
|
+
expect(buildSpotterAnalystAppInitData(base, { spotterAnalystConfig: {} })).toBe(base);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('nests spotterAnalystConfig under embedParams', () => {
|
|
259
|
+
const result = buildSpotterAnalystAppInitData(base, {
|
|
260
|
+
spotterAnalystConfig: { analystId: 'analyst-id-1234' },
|
|
261
|
+
});
|
|
262
|
+
expect(result.embedParams?.spotterAnalystConfig).toEqual({ analystId: 'analyst-id-1234' });
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('preserves existing embedParams keys', () => {
|
|
266
|
+
const withExisting = {
|
|
267
|
+
...base,
|
|
268
|
+
embedParams: { spotterSidebarConfig: { enablePastConversationsSidebar: true } },
|
|
269
|
+
} as any;
|
|
270
|
+
const result = buildSpotterAnalystAppInitData(withExisting, {
|
|
271
|
+
spotterAnalystConfig: { analystId: 'analyst-id-1234' },
|
|
272
|
+
});
|
|
273
|
+
expect(result.embedParams?.spotterSidebarConfig).toEqual({ enablePastConversationsSidebar: true });
|
|
274
|
+
expect(result.embedParams?.spotterAnalystConfig).toEqual({ analystId: 'analyst-id-1234' });
|
|
275
|
+
});
|
|
276
|
+
});
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
SpotterShareConversationConfig,
|
|
7
7
|
SpotterChatViewConfig,
|
|
8
8
|
StarterPromptsConfig,
|
|
9
|
+
SpotterAnalystConfig,
|
|
9
10
|
} from './conversation';
|
|
10
11
|
import type { VisualizationOverrides } from '../types';
|
|
11
12
|
|
|
@@ -114,3 +115,18 @@ export function buildStarterPromptsAppInitData<T extends DefaultAppInitData>(
|
|
|
114
115
|
},
|
|
115
116
|
};
|
|
116
117
|
}
|
|
118
|
+
|
|
119
|
+
export function buildSpotterAnalystAppInitData<T extends DefaultAppInitData>(
|
|
120
|
+
initData: T,
|
|
121
|
+
viewConfig: { spotterAnalystConfig?: SpotterAnalystConfig },
|
|
122
|
+
): T & { embedParams?: { spotterAnalystConfig?: SpotterAnalystConfig } } {
|
|
123
|
+
const { spotterAnalystConfig } = viewConfig;
|
|
124
|
+
if (!spotterAnalystConfig?.analystId) return initData;
|
|
125
|
+
return {
|
|
126
|
+
...initData,
|
|
127
|
+
embedParams: {
|
|
128
|
+
...((initData as T & { embedParams?: Record<string, unknown> }).embedParams || {}),
|
|
129
|
+
spotterAnalystConfig,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -2964,8 +2964,8 @@ describe('Unit test case for ts embed', () => {
|
|
|
2964
2964
|
|
|
2965
2965
|
// Reverts to the exact value the container had before.
|
|
2966
2966
|
expect(customContainer.style.position).toBe('static');
|
|
2967
|
-
// The custom container reference is dropped (back to the
|
|
2968
|
-
// body) so a destroyed embed does not pin the (possibly
|
|
2967
|
+
// The custom container reference is dropped (back to the
|
|
2968
|
+
// default body) so a destroyed embed does not pin the (possibly
|
|
2969
2969
|
// detached) element in memory.
|
|
2970
2970
|
expect((libEmbed as any).preRenderContainerEl).toBe(document.body);
|
|
2971
2971
|
|
|
@@ -3019,8 +3019,8 @@ describe('Unit test case for ts embed', () => {
|
|
|
3019
3019
|
|
|
3020
3020
|
libEmbed.destroy();
|
|
3021
3021
|
|
|
3022
|
-
// The body sentinel must never be treated as a custom
|
|
3023
|
-
// no position override to apply and none to restore.
|
|
3022
|
+
// The body sentinel must never be treated as a custom
|
|
3023
|
+
// container: no position override to apply and none to restore.
|
|
3024
3024
|
expect(document.body.style.position).toBe(originalBodyPosition);
|
|
3025
3025
|
expect(document.body.dataset.tsEmbedOriginalPosition).toBeUndefined();
|
|
3026
3026
|
});
|
|
@@ -3155,10 +3155,11 @@ describe('Unit test case for ts embed', () => {
|
|
|
3155
3155
|
|
|
3156
3156
|
libEmbed.syncPreRenderStyle();
|
|
3157
3157
|
|
|
3158
|
-
// applyPreRenderContainerPositioning() reads
|
|
3159
|
-
// instead of taking the container as an
|
|
3160
|
-
// to assign the field before calling
|
|
3161
|
-
// lands on the detached node and
|
|
3158
|
+
// applyPreRenderContainerPositioning() reads
|
|
3159
|
+
// preRenderContainerEl instead of taking the container as an
|
|
3160
|
+
// argument, so reconcile has to assign the field before calling
|
|
3161
|
+
// it — otherwise the override lands on the detached node and
|
|
3162
|
+
// the fresh one stays static.
|
|
3162
3163
|
expect((libEmbed as any).preRenderContainerEl).toBe(newContainer);
|
|
3163
3164
|
expect(newContainer.style.position).toBe('relative');
|
|
3164
3165
|
expect(newContainer.dataset.tsEmbedOriginalPosition).toBe('static');
|
|
@@ -3289,7 +3290,8 @@ describe('Unit test case for ts embed', () => {
|
|
|
3289
3290
|
await firstEmbed.preRender();
|
|
3290
3291
|
await waitFor(() => !!getIFrameEl());
|
|
3291
3292
|
|
|
3292
|
-
// Reset position to static so the connecting embed also
|
|
3293
|
+
// Reset position to static so the connecting embed also
|
|
3294
|
+
// triggers the guard.
|
|
3293
3295
|
customContainer.style.position = 'static';
|
|
3294
3296
|
delete customContainer.dataset['preRenderContainerOriginalPosition'];
|
|
3295
3297
|
|
|
@@ -3393,8 +3395,8 @@ describe('Unit test case for ts embed', () => {
|
|
|
3393
3395
|
await firstEmbed.preRender();
|
|
3394
3396
|
await waitFor(() => !!getIFrameEl());
|
|
3395
3397
|
|
|
3396
|
-
// Same config on both components — the value is redundant
|
|
3397
|
-
// not wrong, so nagging about it would be noise.
|
|
3398
|
+
// Same config on both components — the value is redundant
|
|
3399
|
+
// but not wrong, so nagging about it would be noise.
|
|
3398
3400
|
const connectingEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
3399
3401
|
preRenderId: 'connect-same-element',
|
|
3400
3402
|
liveboardId: 'myLiveboardId',
|
|
@@ -3427,8 +3429,9 @@ describe('Unit test case for ts embed', () => {
|
|
|
3427
3429
|
await firstEmbed.preRender();
|
|
3428
3430
|
await waitFor(() => !!getIFrameEl());
|
|
3429
3431
|
|
|
3430
|
-
// A selector that resolves to the owner's element is the
|
|
3431
|
-
// container, so the comparison must be by resolved
|
|
3432
|
+
// A selector that resolves to the owner's element is the
|
|
3433
|
+
// same container, so the comparison must be by resolved
|
|
3434
|
+
// node.
|
|
3432
3435
|
const connectingEmbed = new LiveboardEmbed('#tsEmbedDiv', {
|
|
3433
3436
|
preRenderId: 'connect-same-selector',
|
|
3434
3437
|
liveboardId: 'myLiveboardId',
|
|
@@ -3492,8 +3495,8 @@ describe('Unit test case for ts embed', () => {
|
|
|
3492
3495
|
await waitFor(() => !!getIFrameEl());
|
|
3493
3496
|
|
|
3494
3497
|
// Simulate a wrapper with no live embed behind it: the
|
|
3495
|
-
// __tsEmbed stamp used to locate the owner is gone, so
|
|
3496
|
-
// is no container to inherit.
|
|
3498
|
+
// __tsEmbed stamp used to locate the owner is gone, so
|
|
3499
|
+
// there is no container to inherit.
|
|
3497
3500
|
const wrapper = document.getElementById(
|
|
3498
3501
|
firstEmbed.getPreRenderIds().wrapper,
|
|
3499
3502
|
);
|
|
@@ -5361,12 +5364,14 @@ describe('Trigger method edge cases', () => {
|
|
|
5361
5364
|
const handleErrorSpy = jest.spyOn(searchEmbed as any, 'handleError').mockImplementation(() => {});
|
|
5362
5365
|
await searchEmbed.render();
|
|
5363
5366
|
|
|
5364
|
-
// First processTrigger call is getAvailableUIPassthroughKeys for
|
|
5367
|
+
// First processTrigger call is getAvailableUIPassthroughKeys for
|
|
5368
|
+
// DrillDown
|
|
5365
5369
|
mockProcessTrigger.mockResolvedValueOnce([
|
|
5366
5370
|
{ value: { keys: Object.values(UIPassthroughEvent) } },
|
|
5367
5371
|
]);
|
|
5368
5372
|
|
|
5369
|
-
// DrillDown with no points → throwDrillDownValidationError →
|
|
5373
|
+
// DrillDown with no points → throwDrillDownValidationError →
|
|
5374
|
+
// isValidationError=true
|
|
5370
5375
|
await expect(
|
|
5371
5376
|
searchEmbed.trigger(HostEvent.DrillDown, {} as any),
|
|
5372
5377
|
).rejects.toThrow('DrillDown requires a valid points object');
|
|
@@ -5541,7 +5546,8 @@ describe('Fullscreen change handler behavior', () => {
|
|
|
5541
5546
|
init({
|
|
5542
5547
|
thoughtSpotHost: 'tshost',
|
|
5543
5548
|
authType: AuthType.None,
|
|
5544
|
-
// disableFullscreenPresentation not set → defaults to true via ??
|
|
5549
|
+
// disableFullscreenPresentation not set → defaults to true via ??
|
|
5550
|
+
// true
|
|
5545
5551
|
});
|
|
5546
5552
|
|
|
5547
5553
|
const embed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
@@ -5567,7 +5573,8 @@ describe('Fullscreen change handler behavior', () => {
|
|
|
5567
5573
|
|
|
5568
5574
|
embed['setupFullscreenChangeHandler']();
|
|
5569
5575
|
|
|
5570
|
-
// Capture the registered handler directly instead of dispatching to
|
|
5576
|
+
// Capture the registered handler directly instead of dispatching to
|
|
5577
|
+
// document
|
|
5571
5578
|
const fullscreenCall = addEventListenerSpy.mock.calls.find((c) => c[0] === 'fullscreenchange');
|
|
5572
5579
|
expect(fullscreenCall).toBeTruthy();
|
|
5573
5580
|
const handler = fullscreenCall[1] as EventListener;
|
|
@@ -6039,8 +6046,8 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
6039
6046
|
undefined,
|
|
6040
6047
|
);
|
|
6041
6048
|
|
|
6042
|
-
// A parameter always carries a value, so the payload says
|
|
6043
|
-
// there is to say — no follow-up event.
|
|
6049
|
+
// A parameter always carries a value, so the payload says
|
|
6050
|
+
// everything there is to say — no follow-up event.
|
|
6044
6051
|
const parameterCalls = mockProcessTrigger.mock.calls.filter(
|
|
6045
6052
|
(call: any[]) => call[1] === HostEvent.UpdateParameters,
|
|
6046
6053
|
);
|
|
@@ -6641,7 +6648,8 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
6641
6648
|
expect(hostElement.querySelector(`#${placeHolderId}`)).toBe(staleNestedPlaceholder);
|
|
6642
6649
|
// Before the fix this threw NotFoundError.
|
|
6643
6650
|
await expect(embed.showPreRender()).resolves.toBeDefined();
|
|
6644
|
-
// The stale nested placeholder is gone; the fresh one is a direct
|
|
6651
|
+
// The stale nested placeholder is gone; the fresh one is a direct
|
|
6652
|
+
// child.
|
|
6645
6653
|
expect(staleNestedPlaceholder.isConnected).toBe(false);
|
|
6646
6654
|
const currentPlaceholder = (
|
|
6647
6655
|
embed as any
|
|
@@ -6673,7 +6681,8 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
6673
6681
|
{ numberOfTabs: number; orderedTabIds: string[] }
|
|
6674
6682
|
> = true;
|
|
6675
6683
|
const probeUnknownField = (r: TabsResponse) =>
|
|
6676
|
-
// @ts-expect-error — field not on the GetTabs contract (was
|
|
6684
|
+
// @ts-expect-error — field not on the GetTabs contract (was
|
|
6685
|
+
// silent when `any`)
|
|
6677
6686
|
r.tabCount;
|
|
6678
6687
|
void probeUnknownField;
|
|
6679
6688
|
|
|
@@ -6686,3 +6695,175 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
6686
6695
|
});
|
|
6687
6696
|
});
|
|
6688
6697
|
});
|
|
6698
|
+
|
|
6699
|
+
describe('excludeConfigFromURL', () => {
|
|
6700
|
+
const lbConfig = {
|
|
6701
|
+
liveboardId,
|
|
6702
|
+
hiddenActions: [Action.Download],
|
|
6703
|
+
additionalFlags: { internalBlinkFlag: true },
|
|
6704
|
+
liveboardV2: true,
|
|
6705
|
+
};
|
|
6706
|
+
|
|
6707
|
+
const withPostMessage = (viewConfig: any) => ({
|
|
6708
|
+
...viewConfig,
|
|
6709
|
+
additionalFlags: { ...viewConfig.additionalFlags, excludeConfigFromURL: true },
|
|
6710
|
+
});
|
|
6711
|
+
|
|
6712
|
+
const renderAndGetSrc = async (viewConfig: any) => {
|
|
6713
|
+
const embed = new LiveboardEmbed(getRootEl(), { ...defaultViewConfig, ...viewConfig });
|
|
6714
|
+
await embed.render();
|
|
6715
|
+
await waitFor(() => !!getIFrameEl());
|
|
6716
|
+
return { embed, src: getIFrameSrc() };
|
|
6717
|
+
};
|
|
6718
|
+
|
|
6719
|
+
const signalFrameReady = () => {
|
|
6720
|
+
postMessageToParent(getIFrameEl().contentWindow, {
|
|
6721
|
+
type: EmbedEvent.EmbedListenerReady,
|
|
6722
|
+
});
|
|
6723
|
+
};
|
|
6724
|
+
|
|
6725
|
+
beforeEach(() => {
|
|
6726
|
+
document.body.innerHTML = getDocumentBody();
|
|
6727
|
+
mockProcessTrigger.mockReset();
|
|
6728
|
+
mockProcessTrigger.mockResolvedValue({});
|
|
6729
|
+
init({
|
|
6730
|
+
thoughtSpotHost,
|
|
6731
|
+
authType: AuthType.None,
|
|
6732
|
+
});
|
|
6733
|
+
});
|
|
6734
|
+
|
|
6735
|
+
test('leaves the URL untouched when the flag is not set', async () => {
|
|
6736
|
+
const { src } = await renderAndGetSrc(lbConfig);
|
|
6737
|
+
|
|
6738
|
+
expect(src).toContain('hideAction=');
|
|
6739
|
+
expect(src).toContain('internalBlinkFlag=true');
|
|
6740
|
+
expect(src).toContain('isPinboardV2Enabled=true');
|
|
6741
|
+
});
|
|
6742
|
+
|
|
6743
|
+
test('keeps only the bootstrap params on the URL when the flag is set', async () => {
|
|
6744
|
+
const { src } = await renderAndGetSrc(withPostMessage(lbConfig));
|
|
6745
|
+
|
|
6746
|
+
// Boot and auth handshake stays on the URL.
|
|
6747
|
+
expect(src).toContain('hostAppUrl=');
|
|
6748
|
+
expect(src).toContain(`authType=${AuthType.None}`);
|
|
6749
|
+
expect(src).toContain(`sdkVersion=${version}`);
|
|
6750
|
+
expect(src).toContain('blockNonEmbedFullAppAccess=true');
|
|
6751
|
+
expect(src).toContain('viewPortHeight=');
|
|
6752
|
+
|
|
6753
|
+
// View configuration and internal flags do not.
|
|
6754
|
+
expect(src).not.toContain('hideAction=');
|
|
6755
|
+
expect(src).not.toContain('internalBlinkFlag');
|
|
6756
|
+
expect(src).not.toContain('isPinboardV2Enabled');
|
|
6757
|
+
expect(src).not.toContain('enableDataPanelV2');
|
|
6758
|
+
});
|
|
6759
|
+
|
|
6760
|
+
test('strips a non-bootstrap additionalFlag from the URL when the flag is set', async () => {
|
|
6761
|
+
const { src } = await renderAndGetSrc({
|
|
6762
|
+
...lbConfig,
|
|
6763
|
+
additionalFlags: {
|
|
6764
|
+
internalBlinkFlag: true,
|
|
6765
|
+
someCustomFlag: 'abc',
|
|
6766
|
+
excludeConfigFromURL: true,
|
|
6767
|
+
},
|
|
6768
|
+
});
|
|
6769
|
+
|
|
6770
|
+
expect(src).not.toContain('internalBlinkFlag');
|
|
6771
|
+
expect(src).not.toContain('someCustomFlag');
|
|
6772
|
+
});
|
|
6773
|
+
|
|
6774
|
+
test('keeps an additionalFlag that overrides a bootstrap param on the URL', async () => {
|
|
6775
|
+
const { src } = await renderAndGetSrc({
|
|
6776
|
+
...lbConfig,
|
|
6777
|
+
additionalFlags: { [Param.OverrideOrgId]: 42, excludeConfigFromURL: true },
|
|
6778
|
+
});
|
|
6779
|
+
|
|
6780
|
+
expect(src).toContain(`${Param.OverrideOrgId}=42`);
|
|
6781
|
+
});
|
|
6782
|
+
|
|
6783
|
+
test('keeps the deep-link route on the URL when the flag is set', async () => {
|
|
6784
|
+
const { src } = await renderAndGetSrc(withPostMessage(lbConfig));
|
|
6785
|
+
|
|
6786
|
+
expect(src).toContain(`/embed/viz/${liveboardId}`);
|
|
6787
|
+
});
|
|
6788
|
+
|
|
6789
|
+
test('sends the full config over UpdateEmbedParams once the frame is ready', async () => {
|
|
6790
|
+
await renderAndGetSrc(withPostMessage(lbConfig));
|
|
6791
|
+
|
|
6792
|
+
signalFrameReady();
|
|
6793
|
+
|
|
6794
|
+
await executeAfterWait(() => {
|
|
6795
|
+
expect(mockProcessTrigger).toHaveBeenCalledWith(
|
|
6796
|
+
expect.any(Object),
|
|
6797
|
+
HostEvent.UpdateEmbedParams,
|
|
6798
|
+
expect.any(String),
|
|
6799
|
+
expect.objectContaining({
|
|
6800
|
+
liveboardId,
|
|
6801
|
+
hiddenActions: [Action.Download],
|
|
6802
|
+
internalBlinkFlag: true,
|
|
6803
|
+
[Param.HideActions]: expect.arrayContaining([Action.Download]),
|
|
6804
|
+
}),
|
|
6805
|
+
undefined,
|
|
6806
|
+
);
|
|
6807
|
+
});
|
|
6808
|
+
});
|
|
6809
|
+
|
|
6810
|
+
test('sends UpdateEmbedParams again every time the frame signals ready', async () => {
|
|
6811
|
+
await renderAndGetSrc(withPostMessage(lbConfig));
|
|
6812
|
+
signalFrameReady();
|
|
6813
|
+
signalFrameReady();
|
|
6814
|
+
|
|
6815
|
+
await executeAfterWait(() => {
|
|
6816
|
+
const updateCalls = mockProcessTrigger.mock.calls.filter(
|
|
6817
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
6818
|
+
);
|
|
6819
|
+
expect(updateCalls).toHaveLength(2);
|
|
6820
|
+
});
|
|
6821
|
+
});
|
|
6822
|
+
|
|
6823
|
+
test('does not send UpdateEmbedParams when the flag is not set', async () => {
|
|
6824
|
+
await renderAndGetSrc(lbConfig);
|
|
6825
|
+
|
|
6826
|
+
signalFrameReady();
|
|
6827
|
+
|
|
6828
|
+
await executeAfterWait(() => {
|
|
6829
|
+
const updateCalls = mockProcessTrigger.mock.calls.filter(
|
|
6830
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
6831
|
+
);
|
|
6832
|
+
expect(updateCalls).toHaveLength(0);
|
|
6833
|
+
});
|
|
6834
|
+
});
|
|
6835
|
+
|
|
6836
|
+
test('does not double-send for a pre-rendered embed that is shown', async () => {
|
|
6837
|
+
mockMessageChannel();
|
|
6838
|
+
(window as any).ResizeObserver =
|
|
6839
|
+
window.ResizeObserver ||
|
|
6840
|
+
jest.fn().mockImplementation(() => ({
|
|
6841
|
+
disconnect: jest.fn(),
|
|
6842
|
+
observe: jest.fn(),
|
|
6843
|
+
unobserve: jest.fn(),
|
|
6844
|
+
}));
|
|
6845
|
+
|
|
6846
|
+
const embed = new LiveboardEmbed(getRootEl(), {
|
|
6847
|
+
...defaultViewConfig,
|
|
6848
|
+
...withPostMessage(lbConfig),
|
|
6849
|
+
preRenderId: 'send-config-post-message',
|
|
6850
|
+
});
|
|
6851
|
+
await embed.preRender();
|
|
6852
|
+
await waitFor(() => !!getIFrameEl());
|
|
6853
|
+
|
|
6854
|
+
signalFrameReady();
|
|
6855
|
+
await executeAfterWait(() => {
|
|
6856
|
+
expect(embed.isEmbedContainerLoaded).toBe(true);
|
|
6857
|
+
});
|
|
6858
|
+
|
|
6859
|
+
mockProcessTrigger.mockClear();
|
|
6860
|
+
await embed.showPreRender();
|
|
6861
|
+
|
|
6862
|
+
await executeAfterWait(() => {
|
|
6863
|
+
const updateCalls = mockProcessTrigger.mock.calls.filter(
|
|
6864
|
+
(call) => call[1] === HostEvent.UpdateEmbedParams,
|
|
6865
|
+
);
|
|
6866
|
+
expect(updateCalls).toHaveLength(1);
|
|
6867
|
+
});
|
|
6868
|
+
});
|
|
6869
|
+
});
|