@thoughtspot/ts-chart-sdk 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ts-chart-sdk.d.ts +312 -0
- package/lib/dist/ts-chart-sdk.d.ts +312 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/main/custom-chart-context.d.ts +38 -0
- package/lib/main/custom-chart-context.d.ts.map +1 -0
- package/lib/main/custom-chart-context.js +176 -0
- package/lib/main/custom-chart-context.js.map +1 -0
- package/lib/main/custom-chart-context.spec.d.ts +2 -0
- package/lib/main/custom-chart-context.spec.d.ts.map +1 -0
- package/lib/main/custom-chart-context.spec.js +315 -0
- package/lib/main/custom-chart-context.spec.js.map +1 -0
- package/lib/main/post-message-event-bridge.d.ts +6 -0
- package/lib/main/post-message-event-bridge.d.ts.map +1 -0
- package/lib/main/post-message-event-bridge.js +41 -0
- package/lib/main/post-message-event-bridge.js.map +1 -0
- package/lib/main/post-message-event-bridge.spec.d.ts +2 -0
- package/lib/main/post-message-event-bridge.spec.d.ts.map +1 -0
- package/lib/main/post-message-event-bridge.spec.js +117 -0
- package/lib/main/post-message-event-bridge.spec.js.map +1 -0
- package/lib/test/test-utils.d.ts +7 -0
- package/lib/test/test-utils.d.ts.map +1 -0
- package/lib/test/test-utils.js +11 -0
- package/lib/test/test-utils.js.map +1 -0
- package/lib/types/answer-column.types.d.ts +69 -0
- package/lib/types/answer-column.types.d.ts.map +1 -0
- package/lib/types/answer-column.types.js +56 -0
- package/lib/types/answer-column.types.js.map +1 -0
- package/lib/types/chart-to-ts-event.types.d.ts +48 -0
- package/lib/types/chart-to-ts-event.types.d.ts.map +1 -0
- package/lib/types/chart-to-ts-event.types.js +16 -0
- package/lib/types/chart-to-ts-event.types.js.map +1 -0
- package/lib/types/common.types.d.ts +51 -0
- package/lib/types/common.types.d.ts.map +1 -0
- package/lib/types/common.types.js +2 -0
- package/lib/types/common.types.js.map +1 -0
- package/lib/types/configurator.types.d.ts +15 -0
- package/lib/types/configurator.types.d.ts.map +1 -0
- package/lib/types/configurator.types.js +2 -0
- package/lib/types/configurator.types.js.map +1 -0
- package/lib/types/ts-to-chart-event.types.d.ts +67 -0
- package/lib/types/ts-to-chart-event.types.d.ts.map +1 -0
- package/lib/types/ts-to-chart-event.types.js +12 -0
- package/lib/types/ts-to-chart-event.types.js.map +1 -0
- package/lib/types/visual-prop.types.d.ts +47 -0
- package/lib/types/visual-prop.types.d.ts.map +1 -0
- package/lib/types/visual-prop.types.js +2 -0
- package/lib/types/visual-prop.types.js.map +1 -0
- package/package.json +88 -0
- package/src/index.ts +7 -0
- package/src/main/custom-chart-context.spec.ts +432 -0
- package/src/main/custom-chart-context.ts +587 -0
- package/src/main/post-message-event-bridge.spec.ts +215 -0
- package/src/main/post-message-event-bridge.ts +88 -0
- package/src/test/test-utils.ts +13 -0
- package/src/types/answer-column.types.ts +174 -0
- package/src/types/chart-to-ts-event.types.ts +159 -0
- package/src/types/common.types.ts +187 -0
- package/src/types/configurator.types.ts +102 -0
- package/src/types/ts-to-chart-event.types.ts +257 -0
- package/src/types/visual-prop.types.ts +271 -0
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Custom Chart Context
|
|
3
|
+
* @fileoverview
|
|
4
|
+
* @author Chetan Agrawal <chetan.agrawal@thoughtspot.com>
|
|
5
|
+
*
|
|
6
|
+
* Copyright: ThoughtSpot Inc. 2023
|
|
7
|
+
*/
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import {
|
|
10
|
+
ChartToTSEventsPayloadMap,
|
|
11
|
+
ErrorType,
|
|
12
|
+
} from '../types/chart-to-ts-event.types';
|
|
13
|
+
import {
|
|
14
|
+
ChartConfig,
|
|
15
|
+
ChartModel,
|
|
16
|
+
ValidationResponse,
|
|
17
|
+
VisualProps,
|
|
18
|
+
} from '../types/common.types';
|
|
19
|
+
import { ChartConfigEditorDefinition } from '../types/configurator.types';
|
|
20
|
+
import {
|
|
21
|
+
ChartConfigValidateEventPayload,
|
|
22
|
+
ChartModelUpdateEventPayload,
|
|
23
|
+
DataUpdateEventPayload,
|
|
24
|
+
GetDataQueryPayload,
|
|
25
|
+
GetDataQueryResponsePayload,
|
|
26
|
+
InitializeEventPayload,
|
|
27
|
+
InitializeEventResponsePayload,
|
|
28
|
+
Query,
|
|
29
|
+
TSToChartEvent,
|
|
30
|
+
TSToChartEventsPayloadMap,
|
|
31
|
+
TSToChartInternalEventsPayloadMap,
|
|
32
|
+
VisualPropsUpdateEventPayload,
|
|
33
|
+
VisualPropsValidateEventPayload,
|
|
34
|
+
} from '../types/ts-to-chart-event.types';
|
|
35
|
+
import { VisualPropEditorDefinition } from '../types/visual-prop.types';
|
|
36
|
+
import * as PostMessageEventBridge from './post-message-event-bridge';
|
|
37
|
+
|
|
38
|
+
let isInitialized = false;
|
|
39
|
+
|
|
40
|
+
export type CustomChartContextProps = {
|
|
41
|
+
/**
|
|
42
|
+
* Generate the default axis configuration for rendering the chart on first load.
|
|
43
|
+
*
|
|
44
|
+
* @param chartModel
|
|
45
|
+
* @returns {@link ChartConfig[]}
|
|
46
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
47
|
+
*/
|
|
48
|
+
getDefaultChartConfig: (chartModel: ChartModel) => ChartConfig[];
|
|
49
|
+
/**
|
|
50
|
+
* Generate query in the form of array of chart columns to fetch the data.
|
|
51
|
+
*
|
|
52
|
+
* @param ChartConfig[] chartConfig
|
|
53
|
+
* @returns {@link Array<Query>}
|
|
54
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
55
|
+
*/
|
|
56
|
+
getQueriesFromChartConfig: (chartConfig: ChartConfig[]) => Query[];
|
|
57
|
+
/**
|
|
58
|
+
* Main Render function that will render the chart based on the chart context provided
|
|
59
|
+
*
|
|
60
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
61
|
+
* @param {CustomChartContext} ctx the chart context sdk object
|
|
62
|
+
* @returns {@link Promise<void>} Promise object to resolve once the chart is rendered
|
|
63
|
+
*/
|
|
64
|
+
renderChart: (ctx: CustomChartContext) => Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* required to validate the current chart configuration
|
|
67
|
+
* that chart user has updated on the chart config editor
|
|
68
|
+
*
|
|
69
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
70
|
+
* @param updatedConfig
|
|
71
|
+
* @param chartModel
|
|
72
|
+
* @returns {@link ValidationResponse}
|
|
73
|
+
*/
|
|
74
|
+
validateConfig?: (
|
|
75
|
+
updatedConfig: ChartConfig[],
|
|
76
|
+
chartModel: ChartModel,
|
|
77
|
+
) => ValidationResponse;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* required to validate the custom visual props that
|
|
81
|
+
* the chart user has updated on the chart settings editor.
|
|
82
|
+
*
|
|
83
|
+
* @param updatedVisualProps
|
|
84
|
+
* @param chartModel
|
|
85
|
+
* @returns {@link ValidationResponse}
|
|
86
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
87
|
+
*/
|
|
88
|
+
validateVisualProps?: (
|
|
89
|
+
updatedVisualProps: VisualProps,
|
|
90
|
+
chartModel: ChartModel,
|
|
91
|
+
) => ValidationResponse;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Definition to help edit/customize the chart config from chart config editor on the
|
|
95
|
+
* TS app. If not provided, chart queries will not be configurable in editor
|
|
96
|
+
*
|
|
97
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
98
|
+
*/
|
|
99
|
+
chartConfigEditorDefinition?: ChartConfigEditorDefinition[];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Definition to help edit/customize the visual properties from chart settings editor
|
|
103
|
+
* on the TS app. If not provided, visual properties will not be configurable in
|
|
104
|
+
* editor
|
|
105
|
+
*
|
|
106
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
107
|
+
*/
|
|
108
|
+
visualPropEditorDefinition?: VisualPropEditorDefinition;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Default configuration options for all the chart context properties
|
|
113
|
+
*/
|
|
114
|
+
const DEFAULT_CHART_CONTEXT_PROPS: Partial<CustomChartContextProps> = {
|
|
115
|
+
validateConfig: () => ({ isValid: true }),
|
|
116
|
+
validateVisualProps: () => ({ isValid: true }),
|
|
117
|
+
chartConfigEditorDefinition: undefined,
|
|
118
|
+
visualPropEditorDefinition: undefined,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export class CustomChartContext {
|
|
122
|
+
/**
|
|
123
|
+
* Id to map to the parent chart component.
|
|
124
|
+
* This is used to differentiate between multiple chart componenets rendered on the
|
|
125
|
+
* parent app Example: liveboards with multiple charts
|
|
126
|
+
*
|
|
127
|
+
* @hidden
|
|
128
|
+
* @internal
|
|
129
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
130
|
+
*/
|
|
131
|
+
private componentId = '';
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* host app url
|
|
135
|
+
*
|
|
136
|
+
* @hidden
|
|
137
|
+
* @internal
|
|
138
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
139
|
+
*/
|
|
140
|
+
private hostUrl = '';
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Chart Model object. This contains the complete metadata persisted with TS
|
|
144
|
+
* application Also contains data.
|
|
145
|
+
*
|
|
146
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
147
|
+
*/
|
|
148
|
+
private chartModel: ChartModel = {} as any;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Chart Props Object to define the workflow of the application
|
|
152
|
+
*
|
|
153
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
154
|
+
*/
|
|
155
|
+
private chartContextProps: CustomChartContextProps =
|
|
156
|
+
DEFAULT_CHART_CONTEXT_PROPS as CustomChartContextProps;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Map of event listeners for the TS to chart events
|
|
160
|
+
*
|
|
161
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
162
|
+
*/
|
|
163
|
+
// TODO: define a better type mapping here.
|
|
164
|
+
private eventListeners: Record<string, ((...args: any[]) => void)[]> = {};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* This is a promise object to wait on till the chart context
|
|
168
|
+
* is initialized by the parent app
|
|
169
|
+
*
|
|
170
|
+
* @hidden
|
|
171
|
+
* @internal
|
|
172
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
private hasInitializedPromise: Promise<void>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* This function triggers on initialization completion from TS app.
|
|
179
|
+
*
|
|
180
|
+
* @hidden
|
|
181
|
+
* @internal
|
|
182
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
183
|
+
*/
|
|
184
|
+
private triggerInitResolve: () => void = _.noop;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Constructor to only accept context props as payload
|
|
188
|
+
*
|
|
189
|
+
* @param {CustomChartContextProps} chartContextProps
|
|
190
|
+
*/
|
|
191
|
+
constructor(chartContextProps: CustomChartContextProps) {
|
|
192
|
+
this.chartContextProps = {
|
|
193
|
+
...DEFAULT_CHART_CONTEXT_PROPS,
|
|
194
|
+
...chartContextProps,
|
|
195
|
+
};
|
|
196
|
+
this.registerEventProcessor();
|
|
197
|
+
this.hasInitializedPromise = new Promise((resolve) => {
|
|
198
|
+
this.triggerInitResolve = resolve;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Function to expose and wait on the initialize promise object.
|
|
204
|
+
* This will resolve immediately if the chart context is already initialized by TS
|
|
205
|
+
* App.
|
|
206
|
+
*
|
|
207
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
208
|
+
*/
|
|
209
|
+
public initialize = (): Promise<void> => {
|
|
210
|
+
console.log('Chart Context: initialization start');
|
|
211
|
+
return this.hasInitializedPromise;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Add event listeners on the chart context with the required callback.
|
|
216
|
+
*
|
|
217
|
+
* @param {T} eventType
|
|
218
|
+
* @param {TSToChartEventsPayloadMap[T]} callbackFn
|
|
219
|
+
* @returns void
|
|
220
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
221
|
+
*/
|
|
222
|
+
public on<T extends keyof TSToChartEventsPayloadMap>(
|
|
223
|
+
eventType: T,
|
|
224
|
+
callbackFn: TSToChartEventsPayloadMap[T],
|
|
225
|
+
): void {
|
|
226
|
+
// TODO(chetan): [FIX ME] This function doesnt fail if the function
|
|
227
|
+
// callback is mapped with different argument types
|
|
228
|
+
if (_.isNil(this.eventListeners[eventType])) {
|
|
229
|
+
this.eventListeners[eventType] = [];
|
|
230
|
+
}
|
|
231
|
+
this.eventListeners[eventType].push(callbackFn);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Add internal event listeners on the chart context with the required callback.
|
|
236
|
+
*
|
|
237
|
+
* @param {T} eventType
|
|
238
|
+
* @param {TSToChartInternalEventsPayloadMap[T]} callbackFn
|
|
239
|
+
* @returns void
|
|
240
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
241
|
+
*/
|
|
242
|
+
private onInternal<T extends keyof TSToChartInternalEventsPayloadMap>(
|
|
243
|
+
eventType: T,
|
|
244
|
+
callbackFn: TSToChartInternalEventsPayloadMap[T],
|
|
245
|
+
): void {
|
|
246
|
+
if (_.isNil(this.eventListeners[eventType])) {
|
|
247
|
+
this.eventListeners[eventType] = [];
|
|
248
|
+
}
|
|
249
|
+
this.eventListeners[eventType].push(callbackFn);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Destroy the chart context object and stop listening to the parent post message
|
|
254
|
+
* events
|
|
255
|
+
*
|
|
256
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
257
|
+
*/
|
|
258
|
+
public destroy() {
|
|
259
|
+
PostMessageEventBridge.destroyMessageListener(this.eventProcessor);
|
|
260
|
+
isInitialized = false;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Getter for the chart model object
|
|
265
|
+
*
|
|
266
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
267
|
+
*/
|
|
268
|
+
public getChartModel = (): ChartModel => this.chartModel;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Function to emit Chart to TS Events to the TS application.
|
|
272
|
+
|
|
273
|
+
* @param {T} eventType Type of the event
|
|
274
|
+
* @param {ChartToTSEventsPayloadMap[T]} eventPayload Event payload bound
|
|
275
|
+
* to the type of the event
|
|
276
|
+
* @returns Promise
|
|
277
|
+
*/
|
|
278
|
+
public emitEvent<T extends keyof ChartToTSEventsPayloadMap>(
|
|
279
|
+
eventType: T,
|
|
280
|
+
eventPayload: ChartToTSEventsPayloadMap[T],
|
|
281
|
+
): Promise<any> {
|
|
282
|
+
if (!isInitialized) {
|
|
283
|
+
console.log(
|
|
284
|
+
'Chart Context: not initialized the context, something went wrong',
|
|
285
|
+
);
|
|
286
|
+
return Promise.reject();
|
|
287
|
+
}
|
|
288
|
+
return PostMessageEventBridge.postMessageToHostApp(
|
|
289
|
+
this.componentId,
|
|
290
|
+
this.hostUrl,
|
|
291
|
+
eventPayload,
|
|
292
|
+
eventType,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* This registers the current chart context to the post message event bridge
|
|
298
|
+
* Process all the functions via the eventProcess callback
|
|
299
|
+
*/
|
|
300
|
+
private registerEventProcessor = () => {
|
|
301
|
+
if (isInitialized) {
|
|
302
|
+
console.error(
|
|
303
|
+
'The context is already initialized. you cannot have multiple contexts',
|
|
304
|
+
);
|
|
305
|
+
throw new Error(ErrorType.MultipleContextsNotSupported);
|
|
306
|
+
}
|
|
307
|
+
PostMessageEventBridge.initMessageListener(this.eventProcessor);
|
|
308
|
+
|
|
309
|
+
this.registerEvents();
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Process received host messages from the post message event bridge
|
|
314
|
+
*
|
|
315
|
+
* @param event : Message Event Object
|
|
316
|
+
*/
|
|
317
|
+
private eventProcessor = (event: MessageEvent) => {
|
|
318
|
+
if (event.data.source !== 'ts-host-app') {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
console.log(
|
|
323
|
+
'Chart Context: message received:',
|
|
324
|
+
event.data.eventType,
|
|
325
|
+
event.data,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const messageResponse = this.executeEventListenerCBs(event);
|
|
329
|
+
|
|
330
|
+
// respond back to parent to confirm/ack the receipt
|
|
331
|
+
if (!_.isNil(event.ports[0])) {
|
|
332
|
+
if (!_.isNil(messageResponse)) {
|
|
333
|
+
event.ports[0].postMessage({
|
|
334
|
+
...(messageResponse as any),
|
|
335
|
+
});
|
|
336
|
+
} else {
|
|
337
|
+
event.ports[0].postMessage({});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Register all internal and default external events for TSToChartEvent types
|
|
344
|
+
*
|
|
345
|
+
* @returns void
|
|
346
|
+
*/
|
|
347
|
+
private registerEvents = (): void => {
|
|
348
|
+
// Register Internal Events
|
|
349
|
+
// These events will not be readable by the developer
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* This event is triggered when the TS app initializes the app
|
|
353
|
+
*/
|
|
354
|
+
this.onInternal(
|
|
355
|
+
TSToChartEvent.Initialize,
|
|
356
|
+
(payload: InitializeEventPayload) =>
|
|
357
|
+
this.initializeContext(payload),
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* This event is triggered when the TS app asks for validating the updated visual
|
|
362
|
+
* props If {validateVisualProps} is not defined, default is always returned as
|
|
363
|
+
* true.
|
|
364
|
+
*/
|
|
365
|
+
this.onInternal(
|
|
366
|
+
TSToChartEvent.VisualPropsValidate,
|
|
367
|
+
(payload: VisualPropsValidateEventPayload): ValidationResponse => {
|
|
368
|
+
if (this.chartContextProps.validateVisualProps) {
|
|
369
|
+
const validationResponse =
|
|
370
|
+
this.chartContextProps.validateVisualProps(
|
|
371
|
+
payload.visualProps,
|
|
372
|
+
this.chartModel,
|
|
373
|
+
);
|
|
374
|
+
return validationResponse;
|
|
375
|
+
}
|
|
376
|
+
// this will never be true
|
|
377
|
+
return { isValid: false };
|
|
378
|
+
},
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* This event is triggered when the TS app asks for validating the updated chart
|
|
383
|
+
* configuration If {validateConfig} is not defined, default is always returned as
|
|
384
|
+
* true.
|
|
385
|
+
*/
|
|
386
|
+
this.onInternal(
|
|
387
|
+
TSToChartEvent.ChartConfigValidate,
|
|
388
|
+
(payload: ChartConfigValidateEventPayload): ValidationResponse => {
|
|
389
|
+
if (this.chartContextProps.validateConfig) {
|
|
390
|
+
const validationResponse =
|
|
391
|
+
this.chartContextProps.validateConfig(
|
|
392
|
+
payload.chartConfig,
|
|
393
|
+
this.chartModel,
|
|
394
|
+
);
|
|
395
|
+
return validationResponse;
|
|
396
|
+
}
|
|
397
|
+
// this will never be true
|
|
398
|
+
return { isValid: false };
|
|
399
|
+
},
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* This event is triggered when the TS app asks for the base queries required
|
|
404
|
+
* by the chart to render.
|
|
405
|
+
*/
|
|
406
|
+
this.onInternal(
|
|
407
|
+
TSToChartEvent.GetDataQuery,
|
|
408
|
+
(payload: GetDataQueryPayload): GetDataQueryResponsePayload => {
|
|
409
|
+
const queries =
|
|
410
|
+
this.chartContextProps.getQueriesFromChartConfig(
|
|
411
|
+
payload.config,
|
|
412
|
+
);
|
|
413
|
+
return {
|
|
414
|
+
queries,
|
|
415
|
+
};
|
|
416
|
+
},
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* This event is triggered when the TS app re-renders the chart
|
|
421
|
+
*/
|
|
422
|
+
this.onInternal(TSToChartEvent.TriggerRenderChart, async () => {
|
|
423
|
+
await this.chartContextProps.renderChart(this);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// Register External Events
|
|
427
|
+
// These events are readable by the developer
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* This event is triggered when the TS app sends the updated chart model.
|
|
431
|
+
* If event is not defined by developer, default is always sent to refresh the
|
|
432
|
+
* chart iframe.
|
|
433
|
+
*/
|
|
434
|
+
this.on(
|
|
435
|
+
TSToChartEvent.ChartModelUpdate,
|
|
436
|
+
(
|
|
437
|
+
payload: ChartModelUpdateEventPayload,
|
|
438
|
+
): { triggerRenderChart: boolean } => {
|
|
439
|
+
this.chartModel = payload.chartModel;
|
|
440
|
+
return {
|
|
441
|
+
triggerRenderChart: true,
|
|
442
|
+
};
|
|
443
|
+
},
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* This event is triggered when the TS app sends the updated data.
|
|
448
|
+
* If event is not defined by developer, default is always sent to refresh the
|
|
449
|
+
* chart iframe.
|
|
450
|
+
*/
|
|
451
|
+
this.on(
|
|
452
|
+
TSToChartEvent.DataUpdate,
|
|
453
|
+
(
|
|
454
|
+
payload: DataUpdateEventPayload,
|
|
455
|
+
): {
|
|
456
|
+
triggerRenderChart: boolean;
|
|
457
|
+
} => {
|
|
458
|
+
this.chartModel.data = payload.data;
|
|
459
|
+
return {
|
|
460
|
+
triggerRenderChart: true,
|
|
461
|
+
};
|
|
462
|
+
},
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* This event is triggered when the TS app sends the updated visual properties.
|
|
467
|
+
* If event is not defined by developer, default is always sent to refresh the
|
|
468
|
+
* chart iframe.
|
|
469
|
+
*/
|
|
470
|
+
this.on(
|
|
471
|
+
TSToChartEvent.VisualPropsUpdate,
|
|
472
|
+
(
|
|
473
|
+
payload: VisualPropsUpdateEventPayload,
|
|
474
|
+
): { triggerRenderChart: boolean } => {
|
|
475
|
+
this.chartModel.visualProps = payload.visualProps;
|
|
476
|
+
return {
|
|
477
|
+
triggerRenderChart: true,
|
|
478
|
+
};
|
|
479
|
+
},
|
|
480
|
+
);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* private function is going to initialize the flow from TS app and send back
|
|
485
|
+
* the coinfiguration back to ts app to complete the handshake.
|
|
486
|
+
*
|
|
487
|
+
* @param {InitializeEventPayload} payload
|
|
488
|
+
* @returns InitializeEventResponsePayload
|
|
489
|
+
*/
|
|
490
|
+
private initializeContext = (
|
|
491
|
+
payload: InitializeEventPayload,
|
|
492
|
+
): InitializeEventResponsePayload => {
|
|
493
|
+
this.componentId = payload.componentId;
|
|
494
|
+
this.hostUrl = payload.hostUrl;
|
|
495
|
+
this.chartModel = payload.chartModel;
|
|
496
|
+
|
|
497
|
+
// context is now initialized
|
|
498
|
+
isInitialized = true;
|
|
499
|
+
|
|
500
|
+
// TODO: following can be done behind a promise
|
|
501
|
+
this.triggerInitResolve();
|
|
502
|
+
|
|
503
|
+
return this.publishChartContextPropsToHost();
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
private publishChartContextPropsToHost =
|
|
507
|
+
(): InitializeEventResponsePayload => {
|
|
508
|
+
// for first search, this would be null
|
|
509
|
+
const hasChartConfig = !_.isEmpty(
|
|
510
|
+
this.chartModel.config.chartConfig,
|
|
511
|
+
);
|
|
512
|
+
const { isValid } =
|
|
513
|
+
hasChartConfig && this.chartContextProps.validateConfig
|
|
514
|
+
? this.chartContextProps.validateConfig(
|
|
515
|
+
this.chartModel.config.chartConfig ?? [],
|
|
516
|
+
this.chartModel,
|
|
517
|
+
)
|
|
518
|
+
: { isValid: false };
|
|
519
|
+
|
|
520
|
+
let defaultChartConfig: ChartConfig[] = [];
|
|
521
|
+
if (!isValid) {
|
|
522
|
+
defaultChartConfig =
|
|
523
|
+
this.chartContextProps.getDefaultChartConfig(
|
|
524
|
+
this.chartModel,
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return {
|
|
529
|
+
isConfigValid: isValid,
|
|
530
|
+
defaultChartConfig,
|
|
531
|
+
chartConfigEditorDefinition:
|
|
532
|
+
this.chartContextProps.chartConfigEditorDefinition,
|
|
533
|
+
visualPropEditorDefinition:
|
|
534
|
+
this.chartContextProps.visualPropEditorDefinition,
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Process each message events
|
|
540
|
+
*
|
|
541
|
+
* @param event : Message Event Object
|
|
542
|
+
* @returns response to be sent back to the message sender (host)
|
|
543
|
+
*/
|
|
544
|
+
private executeEventListenerCBs = (event: MessageEvent): any => {
|
|
545
|
+
// do basic sanity
|
|
546
|
+
const payload = event.data.payload;
|
|
547
|
+
let response;
|
|
548
|
+
if (_.isArray(this.eventListeners[event.data.eventType])) {
|
|
549
|
+
this.eventListeners[event.data.eventType].forEach((callback) => {
|
|
550
|
+
// this is a problem today if we have multipe callbacks
|
|
551
|
+
// registered. only the last responsed will be sent back to the
|
|
552
|
+
// server
|
|
553
|
+
response = callback(payload);
|
|
554
|
+
});
|
|
555
|
+
} else {
|
|
556
|
+
response = {
|
|
557
|
+
hasError: true,
|
|
558
|
+
error: `Event type not recognised or processed: ${event.data.eventType}`,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log(
|
|
563
|
+
'ChartContext: Response:',
|
|
564
|
+
event.data.eventType,
|
|
565
|
+
response,
|
|
566
|
+
this.eventListeners[event.data.eventType]?.length,
|
|
567
|
+
);
|
|
568
|
+
return response;
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Get the initialized chart context object
|
|
574
|
+
*
|
|
575
|
+
* @param {CustomChartContextProps} customChartConfig
|
|
576
|
+
* @returns Promise
|
|
577
|
+
*/
|
|
578
|
+
export const getChartContext = async (
|
|
579
|
+
customChartConfig: CustomChartContextProps,
|
|
580
|
+
): Promise<CustomChartContext> => {
|
|
581
|
+
const ctx = new CustomChartContext(customChartConfig);
|
|
582
|
+
// wait for initialization here as the host app
|
|
583
|
+
// needs to first handshake with the client app.
|
|
584
|
+
await ctx.initialize();
|
|
585
|
+
|
|
586
|
+
return ctx;
|
|
587
|
+
};
|