@thoughtspot/visual-embed-sdk 1.6.0-alpha.1 → 1.6.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/README.md +8 -8
- package/dist/src/embed/app.d.ts +14 -3
- package/dist/src/embed/liveboard.d.ts +101 -0
- package/dist/src/embed/liveboard.spec.d.ts +1 -0
- package/dist/src/embed/pinboard.d.ts +6 -0
- package/dist/src/embed/search.d.ts +4 -0
- package/dist/src/embed/ts-embed.d.ts +2 -11
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/react/index.d.ts +4 -3
- package/dist/src/types.d.ts +24 -20
- package/dist/src/v1/api.d.ts +19 -0
- package/dist/tsembed.es.js +87 -72
- package/dist/tsembed.js +86 -70
- package/lib/package.json +5 -1
- package/lib/src/embed/app.d.ts +14 -3
- package/lib/src/embed/app.js +25 -2
- package/lib/src/embed/app.js.map +1 -1
- package/lib/src/embed/app.spec.js +32 -0
- package/lib/src/embed/app.spec.js.map +1 -1
- package/lib/src/embed/events.spec.js +55 -2
- package/lib/src/embed/events.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +101 -0
- package/lib/src/embed/liveboard.js +115 -0
- package/lib/src/embed/liveboard.js.map +1 -0
- package/lib/src/embed/liveboard.spec.d.ts +1 -0
- package/lib/src/embed/liveboard.spec.js +159 -0
- package/lib/src/embed/liveboard.spec.js.map +1 -0
- package/lib/src/embed/pinboard.d.ts +6 -0
- package/lib/src/embed/pinboard.js +4 -1
- package/lib/src/embed/pinboard.js.map +1 -1
- package/lib/src/embed/pinboard.spec.js +1 -1
- package/lib/src/embed/pinboard.spec.js.map +1 -1
- package/lib/src/embed/search.d.ts +4 -0
- package/lib/src/embed/search.js +1 -1
- package/lib/src/embed/search.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +2 -11
- package/lib/src/embed/ts-embed.js +4 -23
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +63 -6
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/errors.d.ts +1 -1
- package/lib/src/errors.js +1 -1
- package/lib/src/errors.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.js +2 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/react/index.d.ts +4 -3
- package/lib/src/react/index.js +3 -2
- package/lib/src/react/index.js.map +1 -1
- package/lib/src/types.d.ts +24 -20
- package/lib/src/types.js +21 -18
- package/lib/src/types.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +84 -58
- package/package.json +5 -1
- package/src/embed/app.spec.ts +41 -0
- package/src/embed/app.ts +28 -3
- package/src/embed/events.spec.ts +64 -5
- package/src/embed/liveboard.spec.ts +199 -0
- package/src/embed/{pinboard.ts → liveboard.ts} +60 -42
- package/src/embed/pinboard.spec.ts +11 -11
- package/src/embed/search.ts +5 -0
- package/src/embed/ts-embed.spec.ts +81 -8
- package/src/embed/ts-embed.ts +6 -25
- package/src/errors.ts +2 -2
- package/src/index.ts +7 -2
- package/src/react/index.tsx +14 -8
- package/src/types.ts +24 -20
package/src/embed/app.ts
CHANGED
|
@@ -31,7 +31,11 @@ export enum Page {
|
|
|
31
31
|
*/
|
|
32
32
|
Answers = 'answers',
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Liveboards listing page
|
|
35
|
+
*/
|
|
36
|
+
Liveboards = 'liveboards',
|
|
37
|
+
/**
|
|
38
|
+
* @hidden
|
|
35
39
|
*/
|
|
36
40
|
Pinboards = 'pinboards',
|
|
37
41
|
/**
|
|
@@ -68,7 +72,7 @@ export interface AppViewConfig extends ViewConfig {
|
|
|
68
72
|
pageId?: Page;
|
|
69
73
|
/**
|
|
70
74
|
* This puts a filter tag on the application. All metadata lists in the application, such as
|
|
71
|
-
*
|
|
75
|
+
* Liveboards and answers, would be filtered by this tag.
|
|
72
76
|
*/
|
|
73
77
|
tag?: string;
|
|
74
78
|
/**
|
|
@@ -91,7 +95,7 @@ export class AppEmbed extends V1Embed {
|
|
|
91
95
|
|
|
92
96
|
/**
|
|
93
97
|
* Constructs a map of parameters to be passed on to the
|
|
94
|
-
* embedded
|
|
98
|
+
* embedded Liveboard or visualization.
|
|
95
99
|
*/
|
|
96
100
|
private getEmbedParams() {
|
|
97
101
|
const params = this.getBaseQueryParams();
|
|
@@ -139,6 +143,8 @@ export class AppEmbed extends V1Embed {
|
|
|
139
143
|
return 'answer';
|
|
140
144
|
case Page.Answers:
|
|
141
145
|
return 'answers';
|
|
146
|
+
case Page.Liveboards:
|
|
147
|
+
return 'pinboards';
|
|
142
148
|
case Page.Pinboards:
|
|
143
149
|
return 'pinboards';
|
|
144
150
|
case Page.Data:
|
|
@@ -167,6 +173,25 @@ export class AppEmbed extends V1Embed {
|
|
|
167
173
|
return path;
|
|
168
174
|
}
|
|
169
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Navigate to particular page for app embed. eg:answers/pinboards/home
|
|
178
|
+
* This is used for embedding answers, pinboards, visualizations and full application only.
|
|
179
|
+
* @param path The string, set to iframe src and navigate to new page
|
|
180
|
+
* eg: appEmbed.navigateToPage('pinboards')
|
|
181
|
+
*/
|
|
182
|
+
public navigateToPage(path: string): void {
|
|
183
|
+
if (this.iFrame) {
|
|
184
|
+
const iframeSrc = this.iFrame.src;
|
|
185
|
+
const embedPath = '#/embed';
|
|
186
|
+
const currentPath = iframeSrc.includes(embedPath) ? embedPath : '#';
|
|
187
|
+
this.iFrame.src = `${
|
|
188
|
+
iframeSrc.split(currentPath)[0]
|
|
189
|
+
}${currentPath}/${path.replace(/^\/?#?\//, '')}`;
|
|
190
|
+
} else {
|
|
191
|
+
console.log('Please call render before invoking this method');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
170
195
|
/**
|
|
171
196
|
* Renders the embedded application pages in the ThoughtSpot app.
|
|
172
197
|
* @param renderOptions An object containing the page ID
|
package/src/embed/events.spec.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
EmbedEvent,
|
|
5
5
|
SearchEmbed,
|
|
6
6
|
PinboardEmbed,
|
|
7
|
+
LiveboardEmbed,
|
|
7
8
|
HostEvent,
|
|
8
9
|
} from '../index';
|
|
9
10
|
import {
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
getRootEl2,
|
|
16
17
|
postMessageToParent,
|
|
17
18
|
} from '../test/test-utils';
|
|
18
|
-
import {
|
|
19
|
+
import { LiveboardViewConfig } from './liveboard';
|
|
19
20
|
|
|
20
21
|
const thoughtSpotHost = 'tshost';
|
|
21
22
|
const defaultViewConfig = {
|
|
@@ -119,8 +120,14 @@ describe('test communication between host app and ThoughtSpot', () => {
|
|
|
119
120
|
const embedTwo = new PinboardEmbed(getRootEl2(), {
|
|
120
121
|
...defaultViewConfig,
|
|
121
122
|
pinboardId: 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0',
|
|
122
|
-
} as
|
|
123
|
+
} as LiveboardViewConfig);
|
|
124
|
+
const spyThree = jest.fn();
|
|
125
|
+
const embedThree = new LiveboardEmbed(getRootEl2(), {
|
|
126
|
+
...defaultViewConfig,
|
|
127
|
+
liveboardId: 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0',
|
|
128
|
+
} as LiveboardViewConfig);
|
|
123
129
|
embedTwo.on(EmbedEvent.CustomAction, spyTwo).render();
|
|
130
|
+
embedThree.on(EmbedEvent.CustomAction, spyThree).render();
|
|
124
131
|
|
|
125
132
|
await executeAfterWait(() => {
|
|
126
133
|
const iframeOne = getIFrameEl();
|
|
@@ -133,15 +140,34 @@ describe('test communication between host app and ThoughtSpot', () => {
|
|
|
133
140
|
await executeAfterWait(() => {
|
|
134
141
|
expect(spyOne).toHaveBeenCalled();
|
|
135
142
|
expect(spyTwo).not.toHaveBeenCalled();
|
|
143
|
+
expect(spyThree).not.toHaveBeenCalled();
|
|
136
144
|
}, EVENT_WAIT_TIME);
|
|
137
145
|
});
|
|
138
146
|
|
|
139
147
|
test('send getIframeCenter Event without eventPort', async () => {
|
|
148
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
149
|
+
...defaultViewConfig,
|
|
150
|
+
fullHeight: true,
|
|
151
|
+
pinboardId: 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0',
|
|
152
|
+
} as LiveboardViewConfig);
|
|
153
|
+
liveboardEmbed.render();
|
|
154
|
+
const spy1 = jest.spyOn(global.console, 'log');
|
|
155
|
+
|
|
156
|
+
await executeAfterWait(() => {
|
|
157
|
+
const iframe = getIFrameEl();
|
|
158
|
+
postMessageToParent(iframe.contentWindow, {
|
|
159
|
+
type: EmbedEvent.EmbedIframeCenter,
|
|
160
|
+
data: PAYLOAD,
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
expect(spy1).toHaveBeenCalledWith('Event Port is not defined');
|
|
164
|
+
});
|
|
165
|
+
test('send getIframeCenter Event without eventPort - pinboard', async () => {
|
|
140
166
|
const pinboardEmbed = new PinboardEmbed(getRootEl(), {
|
|
141
167
|
...defaultViewConfig,
|
|
142
168
|
fullHeight: true,
|
|
143
169
|
pinboardId: 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0',
|
|
144
|
-
} as
|
|
170
|
+
} as LiveboardViewConfig);
|
|
145
171
|
pinboardEmbed.render();
|
|
146
172
|
const spy1 = jest.spyOn(global.console, 'log');
|
|
147
173
|
|
|
@@ -155,12 +181,12 @@ describe('test communication between host app and ThoughtSpot', () => {
|
|
|
155
181
|
expect(spy1).toHaveBeenCalledWith('Event Port is not defined');
|
|
156
182
|
});
|
|
157
183
|
|
|
158
|
-
test('send getIframeCenter Event with eventPort', async () => {
|
|
184
|
+
test('send getIframeCenter Event with eventPort - pinboard', async () => {
|
|
159
185
|
const pinboardEmbed = new PinboardEmbed(getRootEl(), {
|
|
160
186
|
...defaultViewConfig,
|
|
161
187
|
fullHeight: true,
|
|
162
188
|
pinboardId: 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0',
|
|
163
|
-
} as
|
|
189
|
+
} as LiveboardViewConfig);
|
|
164
190
|
pinboardEmbed.render();
|
|
165
191
|
const mockPort: any = {
|
|
166
192
|
postMessage: jest.fn(),
|
|
@@ -188,4 +214,37 @@ describe('test communication between host app and ThoughtSpot', () => {
|
|
|
188
214
|
};
|
|
189
215
|
expect(mockPort.postMessage).toHaveBeenCalledWith(heightObj);
|
|
190
216
|
});
|
|
217
|
+
test('send getIframeCenter Event with eventPort', async () => {
|
|
218
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
219
|
+
...defaultViewConfig,
|
|
220
|
+
fullHeight: true,
|
|
221
|
+
pinboardId: 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0',
|
|
222
|
+
} as LiveboardViewConfig);
|
|
223
|
+
liveboardEmbed.render();
|
|
224
|
+
const mockPort: any = {
|
|
225
|
+
postMessage: jest.fn(),
|
|
226
|
+
};
|
|
227
|
+
await executeAfterWait(() => {
|
|
228
|
+
const iframe = getIFrameEl();
|
|
229
|
+
postMessageToParent(
|
|
230
|
+
iframe.contentWindow,
|
|
231
|
+
{
|
|
232
|
+
type: EmbedEvent.EmbedIframeCenter,
|
|
233
|
+
data: PAYLOAD,
|
|
234
|
+
},
|
|
235
|
+
mockPort,
|
|
236
|
+
);
|
|
237
|
+
});
|
|
238
|
+
const heightObj = {
|
|
239
|
+
data: {
|
|
240
|
+
iframeCenter: 0,
|
|
241
|
+
iframeHeight: 0,
|
|
242
|
+
iframeScrolled: 0,
|
|
243
|
+
iframeVisibleViewPort: 0,
|
|
244
|
+
viewPortHeight: 768,
|
|
245
|
+
},
|
|
246
|
+
type: EmbedEvent.EmbedIframeCenter,
|
|
247
|
+
};
|
|
248
|
+
expect(mockPort.postMessage).toHaveBeenCalledWith(heightObj);
|
|
249
|
+
});
|
|
191
250
|
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { LiveboardEmbed, LiveboardViewConfig } from './liveboard';
|
|
2
|
+
import { init } from '../index';
|
|
3
|
+
import { Action, AuthType, EmbedEvent, RuntimeFilterOp } from '../types';
|
|
4
|
+
import {
|
|
5
|
+
executeAfterWait,
|
|
6
|
+
getDocumentBody,
|
|
7
|
+
getIFrameSrc,
|
|
8
|
+
getRootEl,
|
|
9
|
+
} from '../test/test-utils';
|
|
10
|
+
import { version } from '../../package.json';
|
|
11
|
+
|
|
12
|
+
const defaultViewConfig = {
|
|
13
|
+
frameParams: {
|
|
14
|
+
width: 1280,
|
|
15
|
+
height: 720,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const liveboardId = 'eca215d4-0d2c-4a55-90e3-d81ef6848ae0';
|
|
19
|
+
const vizId = '6e73f724-660e-11eb-ae93-0242ac130002';
|
|
20
|
+
const thoughtSpotHost = 'tshost';
|
|
21
|
+
const defaultParams = `&hostAppUrl=local-host&viewPortHeight=768&viewPortWidth=1024&sdkVersion=${version}`;
|
|
22
|
+
const prefixParams = '&isLiveboardEmbed=true';
|
|
23
|
+
|
|
24
|
+
beforeAll(() => {
|
|
25
|
+
init({
|
|
26
|
+
thoughtSpotHost,
|
|
27
|
+
authType: AuthType.None,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('Liveboard/viz embed tests', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
document.body.innerHTML = getDocumentBody();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('should render liveboard', async () => {
|
|
37
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
38
|
+
...defaultViewConfig,
|
|
39
|
+
liveboardId,
|
|
40
|
+
} as LiveboardViewConfig);
|
|
41
|
+
liveboardEmbed.render();
|
|
42
|
+
await executeAfterWait(() => {
|
|
43
|
+
expect(getIFrameSrc()).toBe(
|
|
44
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}#/embed/viz/${liveboardId}`,
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should set disabled actions', async () => {
|
|
50
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
51
|
+
disabledActions: [
|
|
52
|
+
Action.DownloadAsCsv,
|
|
53
|
+
Action.DownloadAsPdf,
|
|
54
|
+
Action.DownloadAsXlsx,
|
|
55
|
+
],
|
|
56
|
+
disabledActionReason: 'Action denied',
|
|
57
|
+
...defaultViewConfig,
|
|
58
|
+
liveboardId,
|
|
59
|
+
} as LiveboardViewConfig);
|
|
60
|
+
liveboardEmbed.render();
|
|
61
|
+
await executeAfterWait(() => {
|
|
62
|
+
expect(getIFrameSrc()).toBe(
|
|
63
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}&disableAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]&disableHint=Action%20denied${prefixParams}#/embed/viz/${liveboardId}`,
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should set hidden actions', async () => {
|
|
69
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
70
|
+
hiddenActions: [
|
|
71
|
+
Action.DownloadAsCsv,
|
|
72
|
+
Action.DownloadAsPdf,
|
|
73
|
+
Action.DownloadAsXlsx,
|
|
74
|
+
],
|
|
75
|
+
...defaultViewConfig,
|
|
76
|
+
liveboardId,
|
|
77
|
+
} as LiveboardViewConfig);
|
|
78
|
+
liveboardEmbed.render();
|
|
79
|
+
await executeAfterWait(() => {
|
|
80
|
+
expect(getIFrameSrc()).toBe(
|
|
81
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}&hideAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${liveboardId}`,
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('should set visible actions', async () => {
|
|
87
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
88
|
+
visibleActions: [
|
|
89
|
+
Action.DownloadAsCsv,
|
|
90
|
+
Action.DownloadAsPdf,
|
|
91
|
+
Action.DownloadAsXlsx,
|
|
92
|
+
],
|
|
93
|
+
...defaultViewConfig,
|
|
94
|
+
liveboardId,
|
|
95
|
+
} as LiveboardViewConfig);
|
|
96
|
+
liveboardEmbed.render();
|
|
97
|
+
await executeAfterWait(() => {
|
|
98
|
+
expect(getIFrameSrc()).toBe(
|
|
99
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}&visibleAction=[%22${Action.DownloadAsCsv}%22,%22${Action.DownloadAsPdf}%22,%22${Action.DownloadAsXlsx}%22]${prefixParams}#/embed/viz/${liveboardId}`,
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('should set visible actions as empty array', async () => {
|
|
105
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
106
|
+
visibleActions: [],
|
|
107
|
+
...defaultViewConfig,
|
|
108
|
+
liveboardId,
|
|
109
|
+
} as LiveboardViewConfig);
|
|
110
|
+
liveboardEmbed.render();
|
|
111
|
+
await executeAfterWait(() => {
|
|
112
|
+
expect(getIFrameSrc()).toBe(
|
|
113
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}&visibleAction=[]${prefixParams}#/embed/viz/${liveboardId}`,
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should enable viz transformations true', async () => {
|
|
119
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
120
|
+
enableVizTransformations: true,
|
|
121
|
+
...defaultViewConfig,
|
|
122
|
+
liveboardId,
|
|
123
|
+
} as LiveboardViewConfig);
|
|
124
|
+
liveboardEmbed.render();
|
|
125
|
+
await executeAfterWait(() => {
|
|
126
|
+
expect(getIFrameSrc()).toBe(
|
|
127
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enableVizTransform=true${prefixParams}#/embed/viz/${liveboardId}`,
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('should disable viz transformations when enableVizTransformations false', async () => {
|
|
133
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
134
|
+
enableVizTransformations: false,
|
|
135
|
+
...defaultViewConfig,
|
|
136
|
+
liveboardId,
|
|
137
|
+
} as LiveboardViewConfig);
|
|
138
|
+
liveboardEmbed.render();
|
|
139
|
+
await executeAfterWait(() => {
|
|
140
|
+
expect(getIFrameSrc()).toBe(
|
|
141
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}&enableVizTransform=false${prefixParams}#/embed/viz/${liveboardId}`,
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('should render viz', async () => {
|
|
147
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
148
|
+
...defaultViewConfig,
|
|
149
|
+
liveboardId,
|
|
150
|
+
vizId,
|
|
151
|
+
} as LiveboardViewConfig);
|
|
152
|
+
liveboardEmbed.render();
|
|
153
|
+
await executeAfterWait(() => {
|
|
154
|
+
expect(getIFrameSrc()).toBe(
|
|
155
|
+
`http://${thoughtSpotHost}/?embedApp=true${defaultParams}${prefixParams}#/embed/viz/${liveboardId}/${vizId}`,
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('should apply runtime filters', async () => {
|
|
161
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
162
|
+
...defaultViewConfig,
|
|
163
|
+
liveboardId,
|
|
164
|
+
vizId,
|
|
165
|
+
runtimeFilters: [
|
|
166
|
+
{
|
|
167
|
+
columnName: 'sales',
|
|
168
|
+
operator: RuntimeFilterOp.EQ,
|
|
169
|
+
values: [1000],
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
} as LiveboardViewConfig);
|
|
173
|
+
liveboardEmbed.render();
|
|
174
|
+
await executeAfterWait(() => {
|
|
175
|
+
expect(getIFrameSrc()).toBe(
|
|
176
|
+
`http://${thoughtSpotHost}/?embedApp=true&col1=sales&op1=EQ&val1=1000${defaultParams}${prefixParams}#/embed/viz/${liveboardId}/${vizId}`,
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('should register event handler to adjust iframe height', async () => {
|
|
182
|
+
const liveboardEmbed = new LiveboardEmbed(getRootEl(), {
|
|
183
|
+
...defaultViewConfig,
|
|
184
|
+
fullHeight: true,
|
|
185
|
+
liveboardId,
|
|
186
|
+
vizId,
|
|
187
|
+
} as LiveboardViewConfig);
|
|
188
|
+
|
|
189
|
+
const onSpy = jest.spyOn(liveboardEmbed, 'on');
|
|
190
|
+
liveboardEmbed.render();
|
|
191
|
+
|
|
192
|
+
executeAfterWait(() => {
|
|
193
|
+
expect(onSpy).toHaveBeenCalledWith(
|
|
194
|
+
EmbedEvent.EmbedHeight,
|
|
195
|
+
expect.anything(),
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Copyright (c) 2021
|
|
3
3
|
*
|
|
4
|
-
* Embed a ThoughtSpot
|
|
4
|
+
* Embed a ThoughtSpot Liveboard or visualization
|
|
5
5
|
* https://developers.thoughtspot.com/docs/?pageid=embed-pinboard
|
|
6
6
|
* https://developers.thoughtspot.com/docs/?pageid=embed-a-viz
|
|
7
7
|
*
|
|
8
|
-
* @summary
|
|
8
|
+
* @summary Liveboard & visualization embed
|
|
9
9
|
* @author Ayon Ghosh <ayon.ghosh@thoughtspot.com>
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -22,21 +22,21 @@ import { getFilterQuery, getQueryParamString } from '../utils';
|
|
|
22
22
|
import { V1Embed, ViewConfig } from './ts-embed';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* The configuration for the embedded
|
|
26
|
-
* @Category
|
|
25
|
+
* The configuration for the embedded Liveboard or visualization page view.
|
|
26
|
+
* @Category Liveboards and Charts
|
|
27
27
|
*/
|
|
28
|
-
export interface
|
|
28
|
+
export interface LiveboardViewConfig extends ViewConfig {
|
|
29
29
|
/**
|
|
30
30
|
* If set to true, the embedded object container dynamically resizes
|
|
31
|
-
* according to the height of the
|
|
31
|
+
* according to the height of the Liveboard.
|
|
32
32
|
*/
|
|
33
33
|
fullHeight?: boolean;
|
|
34
34
|
/**
|
|
35
|
-
* This is the minimum height(in pixels) for a full height
|
|
36
|
-
* Setting this height helps resolves issues with empty
|
|
37
|
-
* other screens navigable from a
|
|
35
|
+
* This is the minimum height(in pixels) for a full height Liveboard.
|
|
36
|
+
* Setting this height helps resolves issues with empty Liveboards and
|
|
37
|
+
* other screens navigable from a Liveboard.
|
|
38
|
+
* *_since 1.5.0_
|
|
38
39
|
* @default 500
|
|
39
|
-
* * _since 1.5.0_
|
|
40
40
|
*/
|
|
41
41
|
defaultHeight?: number;
|
|
42
42
|
/**
|
|
@@ -44,47 +44,61 @@ export interface PinboardViewConfig extends ViewConfig {
|
|
|
44
44
|
*/
|
|
45
45
|
enableVizTransformations?: boolean;
|
|
46
46
|
/**
|
|
47
|
-
* The
|
|
47
|
+
* The Liveboard to display in the embedded view.
|
|
48
|
+
* Use either of liveboardId or pinboardId to reference the Liveboard to embed.
|
|
48
49
|
*/
|
|
49
|
-
|
|
50
|
+
liveboardId?: string;
|
|
50
51
|
/**
|
|
51
|
-
*
|
|
52
|
+
* To support backward compatibilty
|
|
53
|
+
* @hidden
|
|
54
|
+
*/
|
|
55
|
+
pinboardId?: string;
|
|
56
|
+
/**
|
|
57
|
+
* The visualization within the Liveboard to display.
|
|
52
58
|
*/
|
|
53
59
|
vizId?: string;
|
|
54
60
|
/**
|
|
55
61
|
* If set to true, all filter chips from a
|
|
56
|
-
*
|
|
62
|
+
* Liveboard page will be read-only (no X buttons)
|
|
63
|
+
*/
|
|
64
|
+
preventLiveboardFilterRemoval?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* To support backward compatibilty
|
|
67
|
+
* @hidden
|
|
57
68
|
*/
|
|
58
69
|
preventPinboardFilterRemoval?: boolean;
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
/**
|
|
62
|
-
* Embed a ThoughtSpot
|
|
63
|
-
* @Category
|
|
73
|
+
* Embed a ThoughtSpot Liveboard or visualization
|
|
74
|
+
* @Category Liveboards and Charts
|
|
64
75
|
*/
|
|
65
|
-
export class
|
|
66
|
-
protected viewConfig:
|
|
76
|
+
export class LiveboardEmbed extends V1Embed {
|
|
77
|
+
protected viewConfig: LiveboardViewConfig;
|
|
67
78
|
|
|
68
79
|
private defaultHeight = 500;
|
|
69
80
|
|
|
70
81
|
// eslint-disable-next-line no-useless-constructor
|
|
71
|
-
constructor(domSelector: DOMSelector, viewConfig:
|
|
82
|
+
constructor(domSelector: DOMSelector, viewConfig: LiveboardViewConfig) {
|
|
72
83
|
super(domSelector, viewConfig);
|
|
73
84
|
}
|
|
74
85
|
|
|
75
86
|
/**
|
|
76
87
|
* Construct a map of params to be passed on to the
|
|
77
|
-
* embedded
|
|
88
|
+
* embedded Liveboard or visualization.
|
|
78
89
|
*/
|
|
79
90
|
private getEmbedParams() {
|
|
80
91
|
const params = this.getBaseQueryParams();
|
|
81
92
|
const {
|
|
82
93
|
enableVizTransformations,
|
|
83
94
|
fullHeight,
|
|
84
|
-
preventPinboardFilterRemoval,
|
|
85
95
|
defaultHeight,
|
|
86
96
|
} = this.viewConfig;
|
|
87
97
|
|
|
98
|
+
const preventLiveboardFilterRemoval =
|
|
99
|
+
this.viewConfig.preventLiveboardFilterRemoval ||
|
|
100
|
+
this.viewConfig.preventPinboardFilterRemoval;
|
|
101
|
+
|
|
88
102
|
if (fullHeight === true) {
|
|
89
103
|
params[Param.fullHeight] = true;
|
|
90
104
|
}
|
|
@@ -96,8 +110,8 @@ export class PinboardEmbed extends V1Embed {
|
|
|
96
110
|
Param.EnableVizTransformations
|
|
97
111
|
] = enableVizTransformations.toString();
|
|
98
112
|
}
|
|
99
|
-
if (
|
|
100
|
-
params[Param.
|
|
113
|
+
if (preventLiveboardFilterRemoval) {
|
|
114
|
+
params[Param.preventLiveboardFilterRemoval] = true;
|
|
101
115
|
}
|
|
102
116
|
params[Param.livedBoardEmbed] = true;
|
|
103
117
|
const queryParams = getQueryParamString(params, true);
|
|
@@ -106,15 +120,15 @@ export class PinboardEmbed extends V1Embed {
|
|
|
106
120
|
}
|
|
107
121
|
|
|
108
122
|
/**
|
|
109
|
-
* Construct the URL of the embedded ThoughtSpot
|
|
123
|
+
* Construct the URL of the embedded ThoughtSpot Liveboard or visualization
|
|
110
124
|
* to be loaded within the iframe.
|
|
111
|
-
* @param
|
|
112
|
-
* @param vizId The optional GUID of a visualization within the
|
|
125
|
+
* @param liveboardId The GUID of the Liveboard.
|
|
126
|
+
* @param vizId The optional GUID of a visualization within the Liveboard.
|
|
113
127
|
* @param runtimeFilters A list of runtime filters to be applied to
|
|
114
|
-
* the
|
|
128
|
+
* the Liveboard or visualization on load.
|
|
115
129
|
*/
|
|
116
130
|
private getIFrameSrc(
|
|
117
|
-
|
|
131
|
+
liveboardId: string,
|
|
118
132
|
vizId?: string,
|
|
119
133
|
runtimeFilters?: RuntimeFilter[],
|
|
120
134
|
) {
|
|
@@ -128,7 +142,7 @@ export class PinboardEmbed extends V1Embed {
|
|
|
128
142
|
true,
|
|
129
143
|
false,
|
|
130
144
|
false,
|
|
131
|
-
)}/viz/${
|
|
145
|
+
)}/viz/${liveboardId}`;
|
|
132
146
|
if (vizId) {
|
|
133
147
|
url = `${url}/${vizId}`;
|
|
134
148
|
}
|
|
@@ -150,31 +164,30 @@ export class PinboardEmbed extends V1Embed {
|
|
|
150
164
|
responder({ type: EmbedEvent.EmbedIframeCenter, data: obj });
|
|
151
165
|
};
|
|
152
166
|
|
|
153
|
-
private
|
|
154
|
-
if (
|
|
155
|
-
data.data.canvasState !== 'EMBED' &&
|
|
156
|
-
data.data.canvasState !== 'pinboard'
|
|
157
|
-
) {
|
|
167
|
+
private setIframeHeightForNonEmbedLiveboard = (data: MessagePayload) => {
|
|
168
|
+
if (!data.data.currentPath.startsWith('/embed/viz/')) {
|
|
158
169
|
this.setIFrameHeight(this.defaultHeight);
|
|
159
170
|
}
|
|
160
171
|
};
|
|
161
172
|
|
|
162
173
|
/**
|
|
163
|
-
* Render an embedded ThoughtSpot
|
|
164
|
-
* @param renderOptions An object specifying the
|
|
174
|
+
* Render an embedded ThoughtSpot Liveboard or visualization
|
|
175
|
+
* @param renderOptions An object specifying the Liveboard ID,
|
|
165
176
|
* visualization ID and the runtime filters.
|
|
166
177
|
*/
|
|
167
|
-
public render():
|
|
168
|
-
const {
|
|
178
|
+
public render(): LiveboardEmbed {
|
|
179
|
+
const { vizId, runtimeFilters } = this.viewConfig;
|
|
180
|
+
const liveboardId =
|
|
181
|
+
this.viewConfig.liveboardId ?? this.viewConfig.pinboardId;
|
|
169
182
|
|
|
170
|
-
if (!
|
|
171
|
-
this.handleError(ERROR_MESSAGE.
|
|
183
|
+
if (!liveboardId) {
|
|
184
|
+
this.handleError(ERROR_MESSAGE.LIVEBOARD_VIZ_ID_VALIDATION);
|
|
172
185
|
}
|
|
173
186
|
|
|
174
187
|
if (this.viewConfig.fullHeight === true) {
|
|
175
188
|
this.on(
|
|
176
189
|
EmbedEvent.RouteChange,
|
|
177
|
-
this.
|
|
190
|
+
this.setIframeHeightForNonEmbedLiveboard,
|
|
178
191
|
);
|
|
179
192
|
this.on(EmbedEvent.EmbedHeight, this.updateIFrameHeight);
|
|
180
193
|
this.on(EmbedEvent.EmbedIframeCenter, this.embedIframeCenter);
|
|
@@ -182,9 +195,14 @@ export class PinboardEmbed extends V1Embed {
|
|
|
182
195
|
|
|
183
196
|
super.render();
|
|
184
197
|
|
|
185
|
-
const src = this.getIFrameSrc(
|
|
198
|
+
const src = this.getIFrameSrc(liveboardId, vizId, runtimeFilters);
|
|
186
199
|
this.renderV1Embed(src);
|
|
187
200
|
|
|
188
201
|
return this;
|
|
189
202
|
}
|
|
190
203
|
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @hidden
|
|
207
|
+
*/
|
|
208
|
+
export class PinboardEmbed extends LiveboardEmbed {}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PinboardEmbed,
|
|
1
|
+
import { PinboardEmbed, LiveboardViewConfig } from './liveboard';
|
|
2
2
|
import { init } from '../index';
|
|
3
3
|
import { Action, AuthType, EmbedEvent, RuntimeFilterOp } from '../types';
|
|
4
4
|
import {
|
|
@@ -37,7 +37,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
37
37
|
const pinboardEmbed = new PinboardEmbed(getRootEl(), {
|
|
38
38
|
...defaultViewConfig,
|
|
39
39
|
pinboardId,
|
|
40
|
-
} as
|
|
40
|
+
} as LiveboardViewConfig);
|
|
41
41
|
pinboardEmbed.render();
|
|
42
42
|
await executeAfterWait(() => {
|
|
43
43
|
expect(getIFrameSrc()).toBe(
|
|
@@ -56,7 +56,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
56
56
|
disabledActionReason: 'Action denied',
|
|
57
57
|
...defaultViewConfig,
|
|
58
58
|
pinboardId,
|
|
59
|
-
} as
|
|
59
|
+
} as LiveboardViewConfig);
|
|
60
60
|
pinboardEmbed.render();
|
|
61
61
|
await executeAfterWait(() => {
|
|
62
62
|
expect(getIFrameSrc()).toBe(
|
|
@@ -74,7 +74,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
74
74
|
],
|
|
75
75
|
...defaultViewConfig,
|
|
76
76
|
pinboardId,
|
|
77
|
-
} as
|
|
77
|
+
} as LiveboardViewConfig);
|
|
78
78
|
pinboardEmbed.render();
|
|
79
79
|
await executeAfterWait(() => {
|
|
80
80
|
expect(getIFrameSrc()).toBe(
|
|
@@ -92,7 +92,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
92
92
|
],
|
|
93
93
|
...defaultViewConfig,
|
|
94
94
|
pinboardId,
|
|
95
|
-
} as
|
|
95
|
+
} as LiveboardViewConfig);
|
|
96
96
|
pinboardEmbed.render();
|
|
97
97
|
await executeAfterWait(() => {
|
|
98
98
|
expect(getIFrameSrc()).toBe(
|
|
@@ -106,7 +106,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
106
106
|
visibleActions: [],
|
|
107
107
|
...defaultViewConfig,
|
|
108
108
|
pinboardId,
|
|
109
|
-
} as
|
|
109
|
+
} as LiveboardViewConfig);
|
|
110
110
|
pinboardEmbed.render();
|
|
111
111
|
await executeAfterWait(() => {
|
|
112
112
|
expect(getIFrameSrc()).toBe(
|
|
@@ -120,7 +120,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
120
120
|
enableVizTransformations: true,
|
|
121
121
|
...defaultViewConfig,
|
|
122
122
|
pinboardId,
|
|
123
|
-
} as
|
|
123
|
+
} as LiveboardViewConfig);
|
|
124
124
|
pinboardEmbed.render();
|
|
125
125
|
await executeAfterWait(() => {
|
|
126
126
|
expect(getIFrameSrc()).toBe(
|
|
@@ -134,7 +134,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
134
134
|
enableVizTransformations: false,
|
|
135
135
|
...defaultViewConfig,
|
|
136
136
|
pinboardId,
|
|
137
|
-
} as
|
|
137
|
+
} as LiveboardViewConfig);
|
|
138
138
|
pinboardEmbed.render();
|
|
139
139
|
await executeAfterWait(() => {
|
|
140
140
|
expect(getIFrameSrc()).toBe(
|
|
@@ -148,7 +148,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
148
148
|
...defaultViewConfig,
|
|
149
149
|
pinboardId,
|
|
150
150
|
vizId,
|
|
151
|
-
} as
|
|
151
|
+
} as LiveboardViewConfig);
|
|
152
152
|
pinboardEmbed.render();
|
|
153
153
|
await executeAfterWait(() => {
|
|
154
154
|
expect(getIFrameSrc()).toBe(
|
|
@@ -169,7 +169,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
169
169
|
values: [1000],
|
|
170
170
|
},
|
|
171
171
|
],
|
|
172
|
-
} as
|
|
172
|
+
} as LiveboardViewConfig);
|
|
173
173
|
pinboardEmbed.render();
|
|
174
174
|
await executeAfterWait(() => {
|
|
175
175
|
expect(getIFrameSrc()).toBe(
|
|
@@ -184,7 +184,7 @@ describe('Pinboard/viz embed tests', () => {
|
|
|
184
184
|
fullHeight: true,
|
|
185
185
|
pinboardId,
|
|
186
186
|
vizId,
|
|
187
|
-
} as
|
|
187
|
+
} as LiveboardViewConfig);
|
|
188
188
|
|
|
189
189
|
const onSpy = jest.spyOn(pinboardEmbed, 'on');
|
|
190
190
|
pinboardEmbed.render();
|