@thoughtspot/ts-chart-sdk 0.0.2-alpha.8 → 1.0.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/README.md +126 -50
- package/dist/ts-chart-sdk.d.ts +337 -31
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/main/custom-chart-context.d.ts +15 -3
- package/lib/main/custom-chart-context.d.ts.map +1 -1
- package/lib/main/custom-chart-context.js +45 -16
- package/lib/main/custom-chart-context.js.map +1 -1
- package/lib/main/custom-chart-context.spec.js +302 -4
- package/lib/main/custom-chart-context.spec.js.map +1 -1
- package/lib/main/logger.d.ts +13 -0
- package/lib/main/logger.d.ts.map +1 -0
- package/lib/main/logger.js +64 -0
- package/lib/main/logger.js.map +1 -0
- package/lib/main/logger.spec.d.ts +2 -0
- package/lib/main/logger.spec.d.ts.map +1 -0
- package/lib/main/logger.spec.js +88 -0
- package/lib/main/logger.spec.js.map +1 -0
- package/lib/main/util.d.ts +2 -0
- package/lib/main/util.d.ts.map +1 -1
- package/lib/main/util.js +11 -0
- package/lib/main/util.js.map +1 -1
- package/lib/main/util.spec.d.ts +2 -0
- package/lib/main/util.spec.d.ts.map +1 -0
- package/lib/main/util.spec.js +73 -0
- package/lib/main/util.spec.js.map +1 -0
- package/lib/react/use-custom-chart-context.d.ts.map +1 -1
- package/lib/react/use-custom-chart-context.js +3 -1
- package/lib/react/use-custom-chart-context.js.map +1 -1
- package/lib/react/use-custom-chart-context.spec.js +0 -1
- package/lib/react/use-custom-chart-context.spec.js.map +1 -1
- package/lib/react/use-custom-chart-context.util.d.ts.map +1 -1
- package/lib/react/use-custom-chart-context.util.js +5 -3
- package/lib/react/use-custom-chart-context.util.js.map +1 -1
- package/lib/types/answer-column.types.d.ts +15 -5
- package/lib/types/answer-column.types.d.ts.map +1 -1
- package/lib/types/answer-column.types.js +10 -3
- package/lib/types/answer-column.types.js.map +1 -1
- package/lib/types/chart-to-ts-event.types.d.ts +2 -0
- package/lib/types/chart-to-ts-event.types.d.ts.map +1 -1
- package/lib/types/chart-to-ts-event.types.js +1 -0
- package/lib/types/chart-to-ts-event.types.js.map +1 -1
- package/lib/types/common.types.d.ts +65 -5
- package/lib/types/common.types.d.ts.map +1 -1
- package/lib/types/common.types.js.map +1 -1
- package/lib/types/conditional-formatting.types.d.ts +1 -16
- package/lib/types/conditional-formatting.types.d.ts.map +1 -1
- package/lib/types/conditional-formatting.types.js.map +1 -1
- package/lib/types/configurator.types.d.ts +3 -1
- package/lib/types/configurator.types.d.ts.map +1 -1
- package/lib/types/number-formatting.types.d.ts +55 -0
- package/lib/types/number-formatting.types.d.ts.map +1 -0
- package/lib/types/number-formatting.types.js +23 -0
- package/lib/types/number-formatting.types.js.map +1 -0
- package/lib/types/ts-to-chart-event.types.d.ts +19 -6
- package/lib/types/ts-to-chart-event.types.d.ts.map +1 -1
- package/lib/types/ts-to-chart-event.types.js +1 -0
- package/lib/types/ts-to-chart-event.types.js.map +1 -1
- package/lib/types/visual-prop.types.d.ts +71 -3
- package/lib/types/visual-prop.types.d.ts.map +1 -1
- package/lib/types/visual-prop.types.js +32 -1
- package/lib/types/visual-prop.types.js.map +1 -1
- package/lib/utils/conditional-formatting/conditional-formatting.spec.js +2 -1
- package/lib/utils/conditional-formatting/conditional-formatting.spec.js.map +1 -1
- package/lib/utils/date-formatting.d.ts +85 -1
- package/lib/utils/date-formatting.d.ts.map +1 -1
- package/lib/utils/date-formatting.js +344 -9
- package/lib/utils/date-formatting.js.map +1 -1
- package/lib/utils/date-formatting.spec.js +303 -32
- package/lib/utils/date-formatting.spec.js.map +1 -1
- package/lib/utils/date-utils.d.ts +6 -0
- package/lib/utils/date-utils.d.ts.map +1 -0
- package/lib/utils/date-utils.js +20 -0
- package/lib/utils/date-utils.js.map +1 -0
- package/lib/utils/date-utils.spec.d.ts +2 -0
- package/lib/utils/date-utils.spec.d.ts.map +1 -0
- package/lib/utils/date-utils.spec.js +63 -0
- package/lib/utils/date-utils.spec.js.map +1 -0
- package/lib/utils/formatting-util.d.ts +10 -0
- package/lib/utils/formatting-util.d.ts.map +1 -0
- package/lib/utils/formatting-util.js +78 -0
- package/lib/utils/formatting-util.js.map +1 -0
- package/lib/utils/formatting-util.spec.d.ts +2 -0
- package/lib/utils/formatting-util.spec.d.ts.map +1 -0
- package/lib/utils/formatting-util.spec.js +247 -0
- package/lib/utils/formatting-util.spec.js.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.d.ts +16 -0
- package/lib/utils/globalize-Initializer/globalize-utils.d.ts.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.js +101 -0
- package/lib/utils/globalize-Initializer/globalize-utils.js.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts +2 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.d.ts.map +1 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.js +149 -0
- package/lib/utils/globalize-Initializer/globalize-utils.spec.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.d.ts +20 -0
- package/lib/utils/number-formatting/number-formatting-utils.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.js +159 -0
- package/lib/utils/number-formatting/number-formatting-utils.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts +2 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.js +221 -0
- package/lib/utils/number-formatting/number-formatting-utils.spec.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting.d.ts +5 -0
- package/lib/utils/number-formatting/number-formatting.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting.js +128 -0
- package/lib/utils/number-formatting/number-formatting.js.map +1 -0
- package/lib/utils/number-formatting/number-formatting.spec.d.ts +2 -0
- package/lib/utils/number-formatting/number-formatting.spec.d.ts.map +1 -0
- package/lib/utils/number-formatting/number-formatting.spec.js +159 -0
- package/lib/utils/number-formatting/number-formatting.spec.js.map +1 -0
- package/package.json +5 -2
- package/src/index.ts +3 -0
- package/src/main/custom-chart-context.spec.ts +356 -6
- package/src/main/custom-chart-context.ts +182 -15
- package/src/main/logger.spec.ts +114 -0
- package/src/main/logger.ts +97 -0
- package/src/main/util.spec.ts +94 -0
- package/src/main/util.ts +20 -0
- package/src/react/use-custom-chart-context.spec.tsx +0 -1
- package/src/react/use-custom-chart-context.tsx +4 -1
- package/src/react/use-custom-chart-context.util.ts +6 -3
- package/src/types/answer-column.types.ts +29 -6
- package/src/types/chart-to-ts-event.types.ts +7 -0
- package/src/types/common.types.ts +103 -8
- package/src/types/conditional-formatting.types.ts +2 -17
- package/src/types/configurator.types.ts +15 -1
- package/src/types/number-formatting.types.ts +80 -0
- package/src/types/ts-to-chart-event.types.ts +54 -5
- package/src/types/visual-prop.types.ts +197 -3
- package/src/utils/conditional-formatting/conditional-formatting.spec.ts +2 -0
- package/src/utils/date-formatting.spec.ts +377 -32
- package/src/utils/date-formatting.ts +587 -14
- package/src/utils/date-utils.spec.ts +93 -0
- package/src/utils/date-utils.ts +69 -0
- package/src/utils/formatting-util.spec.ts +312 -0
- package/src/utils/formatting-util.ts +234 -0
- package/src/utils/globalize-Initializer/globalize-utils.spec.ts +192 -0
- package/src/utils/globalize-Initializer/globalize-utils.ts +216 -0
- package/src/utils/number-formatting/number-formatting-utils.spec.ts +296 -0
- package/src/utils/number-formatting/number-formatting-utils.ts +260 -0
- package/src/utils/number-formatting/number-formatting.spec.ts +243 -0
- package/src/utils/number-formatting/number-formatting.ts +264 -0
|
@@ -35,6 +35,8 @@ import {
|
|
|
35
35
|
ChartModelUpdateEventPayload,
|
|
36
36
|
ContextMenuCustomActionPayload,
|
|
37
37
|
DataUpdateEventPayload,
|
|
38
|
+
GetColumnDataPayload,
|
|
39
|
+
GetColumnDataResponsePayload,
|
|
38
40
|
GetDataQueryPayload,
|
|
39
41
|
GetDataQueryResponsePayload,
|
|
40
42
|
InitializeEventPayload,
|
|
@@ -50,15 +52,120 @@ import {
|
|
|
50
52
|
VisualEditorDefinitionSetter,
|
|
51
53
|
VisualPropEditorDefinition,
|
|
52
54
|
} from '../types/visual-prop.types';
|
|
55
|
+
import { setLocaleBasedStringFormats } from '../utils/number-formatting/number-formatting-utils';
|
|
56
|
+
import { create } from './logger';
|
|
53
57
|
import {
|
|
54
58
|
globalThis,
|
|
55
59
|
initMessageListener,
|
|
56
60
|
postMessageToHostApp,
|
|
57
61
|
} from './post-message-event-bridge';
|
|
58
62
|
|
|
63
|
+
const logger = create('TsChartSDKContext');
|
|
64
|
+
/**
|
|
65
|
+
* Configuration for allowing or disallowing specific TS UI features.
|
|
66
|
+
*
|
|
67
|
+
* @fileoverview
|
|
68
|
+
* This configuration defines the ability to toggle specific features such as
|
|
69
|
+
* column number formatting, conditional formatting, and measure names/values.
|
|
70
|
+
*
|
|
71
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
72
|
+
*/
|
|
59
73
|
export type AllowedConfigurations = {
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Allows column-level number formatting.
|
|
76
|
+
*
|
|
77
|
+
* @default false
|
|
78
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
79
|
+
*/
|
|
80
|
+
allowColumnNumberFormatting?: boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Allows conditional formatting at the column level.
|
|
84
|
+
* This allows users to apply rules that visually highlight or differentiate data.
|
|
85
|
+
*
|
|
86
|
+
* @default false
|
|
87
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
88
|
+
*/
|
|
89
|
+
allowColumnConditionalFormatting?: boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Allows Gradient coloring at the column level.
|
|
93
|
+
*
|
|
94
|
+
* @default false
|
|
95
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
96
|
+
*/
|
|
97
|
+
allowGradientColoring?: boolean;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Enables measure_name and measure_values in the chart configuration.
|
|
101
|
+
*
|
|
102
|
+
* @default false
|
|
103
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
104
|
+
*/
|
|
105
|
+
allowMeasureNamesAndValues?: boolean;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Configuration parameters for setting chart-specific options.
|
|
110
|
+
*
|
|
111
|
+
* @fileoverview
|
|
112
|
+
* This configuration includes settings for controlling measure name/value columns
|
|
113
|
+
* and batch size limits for data processing.
|
|
114
|
+
*
|
|
115
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
116
|
+
*/
|
|
117
|
+
export type ChartConfigParameters = {
|
|
118
|
+
/**
|
|
119
|
+
* Configurations related to measure name and value columns.
|
|
120
|
+
* These parameters allow for enabling/disabling and aliasing the columns
|
|
121
|
+
* used to represent measure names and values.
|
|
122
|
+
*
|
|
123
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
124
|
+
*/
|
|
125
|
+
measureNameValueColumns?: {
|
|
126
|
+
/**
|
|
127
|
+
* Enables or disables the measure_name column.
|
|
128
|
+
*
|
|
129
|
+
* @default false
|
|
130
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
131
|
+
*/
|
|
132
|
+
enableMeasureNameColumn?: boolean;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Enables or disables the measure_value column.
|
|
136
|
+
*
|
|
137
|
+
* @default false
|
|
138
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
139
|
+
*/
|
|
140
|
+
enableMeasureValueColumn?: boolean;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Alias for the measure_name column.
|
|
144
|
+
* This allows users to define a custom name for the measure_name column.
|
|
145
|
+
*
|
|
146
|
+
* @default 'Measure Name'
|
|
147
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
148
|
+
*/
|
|
149
|
+
measureNameColumnAlias?: string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Alias for the measure_value column.
|
|
153
|
+
* This allows users to define a custom name for the measure_value column.
|
|
154
|
+
*
|
|
155
|
+
* @default 'Measure Value'
|
|
156
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
157
|
+
*/
|
|
158
|
+
measureValueColumnAlias?: string;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Limit on the batch size for data processing.
|
|
163
|
+
* This sets an upper limit on how much data can be processed in a single batch.
|
|
164
|
+
*
|
|
165
|
+
* @default 20000
|
|
166
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
167
|
+
*/
|
|
168
|
+
batchSizeLimit?: number;
|
|
62
169
|
};
|
|
63
170
|
|
|
64
171
|
export type CustomChartContextProps = {
|
|
@@ -115,6 +222,7 @@ export type CustomChartContextProps = {
|
|
|
115
222
|
validateVisualProps?: (
|
|
116
223
|
updatedVisualProps: VisualProps,
|
|
117
224
|
chartModel: ChartModel,
|
|
225
|
+
activeColumnId?: string,
|
|
118
226
|
) => ValidationResponse;
|
|
119
227
|
|
|
120
228
|
/**
|
|
@@ -140,8 +248,22 @@ export type CustomChartContextProps = {
|
|
|
140
248
|
| VisualEditorDefinitionSetter
|
|
141
249
|
| VisualPropEditorDefinition;
|
|
142
250
|
|
|
143
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Optional configuration to toggle native TS UI configurations, such as column number
|
|
253
|
+
* formatting and conditional formatting.
|
|
254
|
+
*
|
|
255
|
+
* @type {AllowedConfigurations}
|
|
256
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
257
|
+
*/
|
|
144
258
|
allowedConfigurations?: AllowedConfigurations;
|
|
259
|
+
/**
|
|
260
|
+
* Optional parameters for configuring specific chart-related features, such as measure name
|
|
261
|
+
* and value columns.
|
|
262
|
+
*
|
|
263
|
+
* @type {ChartConfigParameters}
|
|
264
|
+
* @version SDK: 0.1 | ThoughtSpot:
|
|
265
|
+
*/
|
|
266
|
+
chartConfigParameters?: ChartConfigParameters;
|
|
145
267
|
};
|
|
146
268
|
|
|
147
269
|
export type ValidationFunctions =
|
|
@@ -158,6 +280,17 @@ const DEFAULT_CHART_CONTEXT_PROPS: Partial<CustomChartContextProps> = {
|
|
|
158
280
|
allowedConfigurations: {
|
|
159
281
|
allowColumnNumberFormatting: false,
|
|
160
282
|
allowColumnConditionalFormatting: false,
|
|
283
|
+
allowGradientColoring: false,
|
|
284
|
+
allowMeasureNamesAndValues: false,
|
|
285
|
+
},
|
|
286
|
+
chartConfigParameters: {
|
|
287
|
+
measureNameValueColumns: {
|
|
288
|
+
enableMeasureNameColumn: false,
|
|
289
|
+
enableMeasureValueColumn: false,
|
|
290
|
+
measureNameColumnAlias: 'Measure Name',
|
|
291
|
+
measureValueColumnAlias: 'Measure Values',
|
|
292
|
+
},
|
|
293
|
+
batchSizeLimit: 20000,
|
|
161
294
|
},
|
|
162
295
|
};
|
|
163
296
|
|
|
@@ -267,6 +400,9 @@ export class CustomChartContext {
|
|
|
267
400
|
this.hasInitializedPromise = new Promise((resolve, reject) => {
|
|
268
401
|
this.triggerInitResolve = resolve;
|
|
269
402
|
});
|
|
403
|
+
// Not using this.emitEvent as the context is not yet completely
|
|
404
|
+
// initialized, thus short circuiting.
|
|
405
|
+
postMessageToHostApp('', '*', null, ChartToTSEvent.InitStart);
|
|
270
406
|
}
|
|
271
407
|
|
|
272
408
|
/**
|
|
@@ -277,7 +413,7 @@ export class CustomChartContext {
|
|
|
277
413
|
* @version SDK: 0.1 | ThoughtSpot:
|
|
278
414
|
*/
|
|
279
415
|
public initialize = (): Promise<void> => {
|
|
280
|
-
|
|
416
|
+
logger.log('Chart Context: initialization start');
|
|
281
417
|
return this.hasInitializedPromise;
|
|
282
418
|
};
|
|
283
419
|
|
|
@@ -309,7 +445,7 @@ export class CustomChartContext {
|
|
|
309
445
|
*/
|
|
310
446
|
public off<T extends keyof TSToChartEventsPayloadMap>(eventType: T): void {
|
|
311
447
|
if (_.isNil(this.eventListeners[eventType])) {
|
|
312
|
-
|
|
448
|
+
logger.log('No event listener found to remove');
|
|
313
449
|
this.eventListeners[eventType] = [];
|
|
314
450
|
return;
|
|
315
451
|
}
|
|
@@ -422,6 +558,7 @@ export class CustomChartContext {
|
|
|
422
558
|
* @returns {VisualPropEditorDefinition}
|
|
423
559
|
*/
|
|
424
560
|
private getVisualPropEditorDefinition = (
|
|
561
|
+
activeColumnId?: string,
|
|
425
562
|
currentState: Partial<ChartModel> = {},
|
|
426
563
|
) => {
|
|
427
564
|
if (_.isFunction(this.chartContextProps.visualPropEditorDefinition)) {
|
|
@@ -431,6 +568,7 @@ export class CustomChartContext {
|
|
|
431
568
|
...currentState,
|
|
432
569
|
},
|
|
433
570
|
this,
|
|
571
|
+
activeColumnId,
|
|
434
572
|
);
|
|
435
573
|
}
|
|
436
574
|
return this.chartContextProps.visualPropEditorDefinition;
|
|
@@ -498,8 +636,10 @@ export class CustomChartContext {
|
|
|
498
636
|
private validationsResponseProcessor(
|
|
499
637
|
currentValidationState: Partial<ChartModel>,
|
|
500
638
|
validationResponse: ValidationResponse,
|
|
639
|
+
activeColumnId?: string,
|
|
501
640
|
) {
|
|
502
641
|
const visualPropEditorDefinition = this.getVisualPropEditorDefinition(
|
|
642
|
+
activeColumnId,
|
|
503
643
|
currentValidationState,
|
|
504
644
|
);
|
|
505
645
|
const chartConfigEditorDefinition = this.getChartConfigEditorDefinition(
|
|
@@ -526,7 +666,7 @@ export class CustomChartContext {
|
|
|
526
666
|
...eventPayload: ChartToTSEventsPayloadMap[T]
|
|
527
667
|
): Promise<any> {
|
|
528
668
|
if (!globalThis.isInitialized) {
|
|
529
|
-
|
|
669
|
+
logger.log(
|
|
530
670
|
'Chart Context: not initialized the context, something went wrong',
|
|
531
671
|
);
|
|
532
672
|
return Promise.reject(new Error('Context not initialized'));
|
|
@@ -549,7 +689,7 @@ export class CustomChartContext {
|
|
|
549
689
|
*/
|
|
550
690
|
private registerEventProcessor = () => {
|
|
551
691
|
if (globalThis.isInitialized) {
|
|
552
|
-
|
|
692
|
+
logger.error(
|
|
553
693
|
'The context is already initialized. you cannot have multiple contexts',
|
|
554
694
|
);
|
|
555
695
|
throw new Error(ErrorType.MultipleContextsNotSupported);
|
|
@@ -565,12 +705,12 @@ export class CustomChartContext {
|
|
|
565
705
|
* @param event : Message Event Object
|
|
566
706
|
*/
|
|
567
707
|
private eventProcessor = (data: any) => {
|
|
568
|
-
|
|
708
|
+
logger.log('Chart Context: message received:', data.eventType, data);
|
|
569
709
|
|
|
570
710
|
const messageResponse = this.executeEventListenerCBs(data);
|
|
571
711
|
|
|
572
712
|
// respond back to parent to confirm/ack the receipt
|
|
573
|
-
return messageResponse;
|
|
713
|
+
return messageResponse || {};
|
|
574
714
|
};
|
|
575
715
|
|
|
576
716
|
/**
|
|
@@ -615,15 +755,17 @@ export class CustomChartContext {
|
|
|
615
755
|
this.chartContextProps.validateVisualProps(
|
|
616
756
|
payload.visualProps,
|
|
617
757
|
this.chartModel,
|
|
758
|
+
payload?.activeColumnId,
|
|
618
759
|
);
|
|
619
760
|
if (validationResponse.isValid) {
|
|
620
761
|
const currentVisualState = {
|
|
621
762
|
visualProps: payload.visualProps,
|
|
622
763
|
};
|
|
623
|
-
|
|
764
|
+
const activeColumnId = payload?.activeColumnId;
|
|
624
765
|
return this.validationsResponseProcessor(
|
|
625
766
|
currentVisualState,
|
|
626
767
|
validationResponse,
|
|
768
|
+
activeColumnId,
|
|
627
769
|
);
|
|
628
770
|
}
|
|
629
771
|
return validationResponse;
|
|
@@ -688,6 +830,28 @@ export class CustomChartContext {
|
|
|
688
830
|
},
|
|
689
831
|
);
|
|
690
832
|
|
|
833
|
+
/**
|
|
834
|
+
* This event is triggered when the TS app asks for data in a specific columns
|
|
835
|
+
* for certain validations for settings and drop down options related to Conditional
|
|
836
|
+
* formatting and other advanced settings
|
|
837
|
+
*/
|
|
838
|
+
this.onInternal(
|
|
839
|
+
TSToChartEvent.GetColumnData,
|
|
840
|
+
(payload: GetColumnDataPayload): GetColumnDataResponsePayload => {
|
|
841
|
+
const parsedData = this.chartModel.data?.[0].data;
|
|
842
|
+
const dataIdx = parsedData?.columns.findIndex(
|
|
843
|
+
(columnId) => columnId === payload.columnId,
|
|
844
|
+
);
|
|
845
|
+
const dataArray =
|
|
846
|
+
!_.isNil(dataIdx) && dataIdx > -1
|
|
847
|
+
? parsedData?.dataValue.map((it) => it[dataIdx])
|
|
848
|
+
: [];
|
|
849
|
+
return {
|
|
850
|
+
data: dataArray,
|
|
851
|
+
};
|
|
852
|
+
},
|
|
853
|
+
);
|
|
854
|
+
|
|
691
855
|
/**
|
|
692
856
|
* This event is triggered when the TS app re-renders the chart
|
|
693
857
|
*/
|
|
@@ -726,7 +890,7 @@ export class CustomChartContext {
|
|
|
726
890
|
isValid: true,
|
|
727
891
|
};
|
|
728
892
|
} catch (error: unknown) {
|
|
729
|
-
|
|
893
|
+
logger.log(
|
|
730
894
|
'ContextMenuCustomAction: payload recieved:',
|
|
731
895
|
payload,
|
|
732
896
|
'CustomActionCallbackStore:',
|
|
@@ -769,7 +933,7 @@ export class CustomChartContext {
|
|
|
769
933
|
isValid: true,
|
|
770
934
|
};
|
|
771
935
|
} catch (error: unknown) {
|
|
772
|
-
|
|
936
|
+
logger.log(
|
|
773
937
|
'AxisMenuCustomAction: payload recieved:',
|
|
774
938
|
payload,
|
|
775
939
|
'CustomActionCallbackStore:',
|
|
@@ -857,7 +1021,9 @@ export class CustomChartContext {
|
|
|
857
1021
|
this.containerEl = payload.containerElSelector
|
|
858
1022
|
? document.querySelector(payload.containerElSelector)
|
|
859
1023
|
: null;
|
|
860
|
-
|
|
1024
|
+
setLocaleBasedStringFormats(
|
|
1025
|
+
this.appConfig.dateFormatsConfig?.tsLocaleBasedStringsFormats,
|
|
1026
|
+
);
|
|
861
1027
|
return this.publishChartContextPropsToHost();
|
|
862
1028
|
};
|
|
863
1029
|
|
|
@@ -899,6 +1065,8 @@ export class CustomChartContext {
|
|
|
899
1065
|
this.getVisualPropEditorDefinition(),
|
|
900
1066
|
allowedConfigurations:
|
|
901
1067
|
this.chartContextProps.allowedConfigurations,
|
|
1068
|
+
chartConfigParameters:
|
|
1069
|
+
this.chartContextProps.chartConfigParameters,
|
|
902
1070
|
};
|
|
903
1071
|
};
|
|
904
1072
|
|
|
@@ -926,7 +1094,7 @@ export class CustomChartContext {
|
|
|
926
1094
|
};
|
|
927
1095
|
}
|
|
928
1096
|
|
|
929
|
-
|
|
1097
|
+
logger.log(
|
|
930
1098
|
'ChartContext: Response:',
|
|
931
1099
|
data.eventType,
|
|
932
1100
|
response,
|
|
@@ -949,6 +1117,5 @@ export const getChartContext = async (
|
|
|
949
1117
|
// wait for initialization here as the host app
|
|
950
1118
|
// needs to first handshake with the client app.
|
|
951
1119
|
await ctx.initialize();
|
|
952
|
-
|
|
953
1120
|
return ctx;
|
|
954
1121
|
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { create, LogLevel, logMethods } from './logger';
|
|
2
|
+
|
|
3
|
+
jest.mock('./util', () => ({
|
|
4
|
+
getQueryParam: jest.fn().mockReturnValue('true'),
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
describe('Logger', () => {
|
|
8
|
+
let originalConsole: Record<string, any>;
|
|
9
|
+
let logger: any;
|
|
10
|
+
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
// Save original console methods
|
|
13
|
+
originalConsole = {
|
|
14
|
+
error: console.error,
|
|
15
|
+
warn: console.warn,
|
|
16
|
+
info: console.info,
|
|
17
|
+
log: console.log,
|
|
18
|
+
trace: console.trace,
|
|
19
|
+
};
|
|
20
|
+
// Mock console methods
|
|
21
|
+
const error = jest.fn();
|
|
22
|
+
const warn = jest.fn();
|
|
23
|
+
const info = jest.fn();
|
|
24
|
+
const log = jest.fn();
|
|
25
|
+
const trace = jest.fn();
|
|
26
|
+
logMethods[LogLevel.ERROR] = error;
|
|
27
|
+
logMethods[LogLevel.WARN] = warn;
|
|
28
|
+
logMethods[LogLevel.INFO] = info;
|
|
29
|
+
logMethods[LogLevel.DEBUG] = log;
|
|
30
|
+
logMethods[LogLevel.TRACE] = trace;
|
|
31
|
+
console.error = error;
|
|
32
|
+
console.warn = warn;
|
|
33
|
+
console.info = info;
|
|
34
|
+
console.log = log;
|
|
35
|
+
console.trace = trace;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
afterAll(() => {
|
|
39
|
+
// Restore original console methods
|
|
40
|
+
logMethods[LogLevel.ERROR] = originalConsole.error;
|
|
41
|
+
logMethods[LogLevel.WARN] = originalConsole.warn;
|
|
42
|
+
logMethods[LogLevel.INFO] = originalConsole.info;
|
|
43
|
+
logMethods[LogLevel.DEBUG] = originalConsole.log;
|
|
44
|
+
logMethods[LogLevel.TRACE] = originalConsole.trace;
|
|
45
|
+
console.error = originalConsole.error;
|
|
46
|
+
console.warn = originalConsole.warn;
|
|
47
|
+
console.info = originalConsole.info;
|
|
48
|
+
console.log = originalConsole.log;
|
|
49
|
+
console.trace = originalConsole.trace;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
// Set debug to 'true' to enable logging
|
|
54
|
+
(global as any).window = {
|
|
55
|
+
location: { href: 'https://example.com/?debug=true' },
|
|
56
|
+
};
|
|
57
|
+
logger = create('TestLogger');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
jest.clearAllMocks();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('logMessages', () => {
|
|
65
|
+
it('should log messages with appropriate prefixes for DEBUG level', async () => {
|
|
66
|
+
await logger.debug('Debug message');
|
|
67
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
68
|
+
'DEBUG (TestLogger)(] Debug message)',
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should log messages with appropriate prefixes for INFO level', async () => {
|
|
73
|
+
await logger.info('Info message');
|
|
74
|
+
expect(console.info).toHaveBeenCalledWith(
|
|
75
|
+
'INFO (TestLogger)(] Info message)',
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should log messages with appropriate prefixes for WARN level', async () => {
|
|
80
|
+
await logger.warn('Warn message');
|
|
81
|
+
expect(console.warn).toHaveBeenCalledWith(
|
|
82
|
+
'WARN (TestLogger)(] Warn message)',
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should log messages with appropriate prefixes for ERROR level', async () => {
|
|
87
|
+
await logger.error('Error message');
|
|
88
|
+
expect(console.error).toHaveBeenCalledWith(
|
|
89
|
+
'ERROR (TestLogger)(] Error message)',
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should log messages with appropriate prefixes for TRACE level', async () => {
|
|
94
|
+
await logger.trace('Trace message');
|
|
95
|
+
expect(console.trace).toHaveBeenCalledWith(
|
|
96
|
+
'TRACE (TestLogger)(] Trace message)',
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('create function', () => {
|
|
102
|
+
it('should create a new logger instance if one does not exist', () => {
|
|
103
|
+
const newLogger = create('NewLogger');
|
|
104
|
+
expect(newLogger).not.toBe(undefined);
|
|
105
|
+
expect(newLogger).toBeInstanceOf(Object);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should return the same logger instance if it already exists', () => {
|
|
109
|
+
const logger1 = create('SharedLogger');
|
|
110
|
+
const logger2 = create('SharedLogger');
|
|
111
|
+
expect(logger1).toBe(logger2);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { getQueryParam } from './util';
|
|
2
|
+
|
|
3
|
+
const loggers: Record<string, any> = {};
|
|
4
|
+
const url = window.location.href;
|
|
5
|
+
|
|
6
|
+
export enum LogLevel {
|
|
7
|
+
SILENT = -1 as number,
|
|
8
|
+
ERROR = 0 as number,
|
|
9
|
+
WARN = 1 as number,
|
|
10
|
+
INFO = 2 as number,
|
|
11
|
+
DEBUG = 3 as number,
|
|
12
|
+
TRACE = 4 as number,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const logMethods: { [key: number]: any } = {
|
|
16
|
+
[LogLevel.ERROR]: console.error,
|
|
17
|
+
[LogLevel.WARN]: console.warn,
|
|
18
|
+
[LogLevel.INFO]: console.info,
|
|
19
|
+
[LogLevel.DEBUG]: console.log,
|
|
20
|
+
[LogLevel.TRACE]: console.trace,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
class Logger {
|
|
24
|
+
private msgPrefix: string;
|
|
25
|
+
|
|
26
|
+
constructor(name: string) {
|
|
27
|
+
this.msgPrefix = name ? `(${name})` : '';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private getFormattedMessage(msg: string, logLevel: LogLevel) {
|
|
31
|
+
return (
|
|
32
|
+
`${LogLevel[logLevel]} ${this.msgPrefix}` +
|
|
33
|
+
`(${msg ? `] ${msg}` : ''})`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public async logMessages(args: any, logLevel: LogLevel) {
|
|
38
|
+
const newArgs = args;
|
|
39
|
+
if (getQueryParam(url, 'debug') !== 'true') {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const logFn = logMethods[logLevel];
|
|
43
|
+
newArgs[0] = this.getFormattedMessage(newArgs[0], logLevel);
|
|
44
|
+
if (logFn) {
|
|
45
|
+
logFn(...newArgs);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async trace(...args: any) {
|
|
50
|
+
this.logMessages(args, LogLevel.TRACE);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Wrapper for log.log() with debug level
|
|
55
|
+
* @param msg
|
|
56
|
+
*/
|
|
57
|
+
public async debug(...args: any) {
|
|
58
|
+
this.logMessages(args, LogLevel.DEBUG);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public async log(...args: any) {
|
|
62
|
+
this.debug(...args);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Wrapper for log.info() with info level
|
|
67
|
+
* @param msg
|
|
68
|
+
*/
|
|
69
|
+
public async info(...args: any) {
|
|
70
|
+
this.logMessages(args, LogLevel.INFO);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Wrapper for log.warn() with warn level
|
|
75
|
+
*
|
|
76
|
+
* @param {string} msg The log message
|
|
77
|
+
*/
|
|
78
|
+
public async warn(...args: any) {
|
|
79
|
+
this.logMessages(args, LogLevel.WARN);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Wrapper for log.error() with error level
|
|
84
|
+
* Error is propagated via callback
|
|
85
|
+
* @param {string} msg The log message
|
|
86
|
+
*/
|
|
87
|
+
public async error(...args: any) {
|
|
88
|
+
const stackTrace = this.logMessages(args, LogLevel.ERROR);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function create(name: string): any {
|
|
93
|
+
if (!loggers[name]) {
|
|
94
|
+
loggers[name] = new Logger(name);
|
|
95
|
+
}
|
|
96
|
+
return loggers[name];
|
|
97
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { getQueryParam, handleMissingValue, timeout } from './util';
|
|
2
|
+
|
|
3
|
+
describe('timeout function', () => {
|
|
4
|
+
jest.useFakeTimers();
|
|
5
|
+
|
|
6
|
+
it('should resolve with the original promise result if it completes before timeout', async () => {
|
|
7
|
+
const promise = Promise.resolve('success');
|
|
8
|
+
const result = timeout(promise, 1000);
|
|
9
|
+
|
|
10
|
+
await expect(result).resolves.toBe('success');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should reject with a timeout error if the promise takes too long', async () => {
|
|
14
|
+
const promise = new Promise((resolve) => {
|
|
15
|
+
setTimeout(resolve, 2000);
|
|
16
|
+
});
|
|
17
|
+
const result = timeout(promise, 1000);
|
|
18
|
+
|
|
19
|
+
jest.advanceTimersByTime(1000);
|
|
20
|
+
|
|
21
|
+
await expect(result).rejects.toThrow('Operation timed out.');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should use the custom error message when provided', async () => {
|
|
25
|
+
const promise = new Promise((resolve) => {
|
|
26
|
+
setTimeout(resolve, 2000);
|
|
27
|
+
});
|
|
28
|
+
const result = timeout(promise, 1000, 'Custom timeout message');
|
|
29
|
+
|
|
30
|
+
jest.advanceTimersByTime(1000);
|
|
31
|
+
|
|
32
|
+
await expect(result).rejects.toThrow('Custom timeout message');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should reject with the original promise error if it rejects before timeout', async () => {
|
|
36
|
+
const promise = Promise.reject(new Error('Original error'));
|
|
37
|
+
const result = timeout(promise, 1000);
|
|
38
|
+
|
|
39
|
+
await expect(result).rejects.toThrow('Original error');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('getQueryParam', () => {
|
|
44
|
+
it('should return the value of a query parameter if it exists', () => {
|
|
45
|
+
const url = 'https://example.com/?key=value';
|
|
46
|
+
expect(getQueryParam(url, 'key')).toBe('value');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should return an empty string if the query parameter does not exist', () => {
|
|
50
|
+
const url = 'https://example.com/';
|
|
51
|
+
expect(getQueryParam(url, 'missingKey')).toBe('');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return "false" if the query parameter is "debug" and it is not present', () => {
|
|
55
|
+
const url = 'https://example.com/';
|
|
56
|
+
expect(getQueryParam(url, 'debug')).toBe('false');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should return the default value "false" if the query parameter is "debug" and is set to an empty value', () => {
|
|
60
|
+
const url = 'https://example.com/?debug=';
|
|
61
|
+
expect(getQueryParam(url, 'debug')).toBe('');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle complex URLs with multiple parameters correctly', () => {
|
|
65
|
+
const url = 'https://example.com/?key1=value1&key2=value2';
|
|
66
|
+
expect(getQueryParam(url, 'key2')).toBe('value2');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('handleMissingValue', () => {
|
|
71
|
+
it('should return "false" if paramKey is "debug" and paramValue is undefined', () => {
|
|
72
|
+
expect(handleMissingValue('debug', undefined)).toBe('false');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should return "false" if paramKey is "debug" and paramValue is null', () => {
|
|
76
|
+
expect(handleMissingValue('debug', null)).toBe('false');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should return an empty string if paramValue is undefined and paramKey is not "debug"', () => {
|
|
80
|
+
expect(handleMissingValue('param', undefined)).toBe('');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should return an empty string if paramValue is null and paramKey is not "debug"', () => {
|
|
84
|
+
expect(handleMissingValue('param', null)).toBe('');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should return the paramValue if paramValue is defined and not null', () => {
|
|
88
|
+
expect(handleMissingValue('param', 'value')).toBe('value');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should return the paramValue even if paramKey is "debug" and paramValue is defined', () => {
|
|
92
|
+
expect(handleMissingValue('debug', 'true')).toBe('true');
|
|
93
|
+
});
|
|
94
|
+
});
|
package/src/main/util.ts
CHANGED
|
@@ -9,3 +9,23 @@ export function timeout(promise: Promise<any>, ms: number, message?: string) {
|
|
|
9
9
|
}),
|
|
10
10
|
]);
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
export function handleMissingValue(
|
|
14
|
+
paramKey: string,
|
|
15
|
+
paramValue?: string | null,
|
|
16
|
+
): string {
|
|
17
|
+
if (paramKey === 'debug') {
|
|
18
|
+
return paramValue ?? 'false';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return paramValue ?? '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getQueryParam(url: string, paramName: string): string {
|
|
25
|
+
const urlObj = new URL(url);
|
|
26
|
+
const paramValue = handleMissingValue(
|
|
27
|
+
paramName,
|
|
28
|
+
urlObj.searchParams.get(paramName),
|
|
29
|
+
);
|
|
30
|
+
return paramValue;
|
|
31
|
+
}
|