@thoughtspot/ts-chart-sdk 0.0.2-alpha.9 → 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 +327 -32
- 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 -4
- package/lib/main/custom-chart-context.d.ts.map +1 -1
- package/lib/main/custom-chart-context.js +44 -16
- package/lib/main/custom-chart-context.js.map +1 -1
- package/lib/main/custom-chart-context.spec.js +301 -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 +7 -4
- package/lib/types/answer-column.types.d.ts.map +1 -1
- package/lib/types/answer-column.types.js +3 -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 -6
- 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 +1 -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/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 +301 -31
- 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 +4 -1
- package/src/index.ts +3 -0
- package/src/main/custom-chart-context.spec.ts +355 -6
- package/src/main/custom-chart-context.ts +181 -16
- 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 +9 -6
- package/src/types/chart-to-ts-event.types.ts +7 -0
- package/src/types/common.types.ts +100 -10
- package/src/types/conditional-formatting.types.ts +2 -17
- package/src/types/configurator.types.ts +1 -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/date-formatting.spec.ts +375 -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,16 +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
|
-
|
|
62
|
-
|
|
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;
|
|
63
169
|
};
|
|
64
170
|
|
|
65
171
|
export type CustomChartContextProps = {
|
|
@@ -116,6 +222,7 @@ export type CustomChartContextProps = {
|
|
|
116
222
|
validateVisualProps?: (
|
|
117
223
|
updatedVisualProps: VisualProps,
|
|
118
224
|
chartModel: ChartModel,
|
|
225
|
+
activeColumnId?: string,
|
|
119
226
|
) => ValidationResponse;
|
|
120
227
|
|
|
121
228
|
/**
|
|
@@ -141,8 +248,22 @@ export type CustomChartContextProps = {
|
|
|
141
248
|
| VisualEditorDefinitionSetter
|
|
142
249
|
| VisualPropEditorDefinition;
|
|
143
250
|
|
|
144
|
-
|
|
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
|
+
*/
|
|
145
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;
|
|
146
267
|
};
|
|
147
268
|
|
|
148
269
|
export type ValidationFunctions =
|
|
@@ -159,8 +280,18 @@ const DEFAULT_CHART_CONTEXT_PROPS: Partial<CustomChartContextProps> = {
|
|
|
159
280
|
allowedConfigurations: {
|
|
160
281
|
allowColumnNumberFormatting: false,
|
|
161
282
|
allowColumnConditionalFormatting: false,
|
|
283
|
+
allowGradientColoring: false,
|
|
162
284
|
allowMeasureNamesAndValues: false,
|
|
163
285
|
},
|
|
286
|
+
chartConfigParameters: {
|
|
287
|
+
measureNameValueColumns: {
|
|
288
|
+
enableMeasureNameColumn: false,
|
|
289
|
+
enableMeasureValueColumn: false,
|
|
290
|
+
measureNameColumnAlias: 'Measure Name',
|
|
291
|
+
measureValueColumnAlias: 'Measure Values',
|
|
292
|
+
},
|
|
293
|
+
batchSizeLimit: 20000,
|
|
294
|
+
},
|
|
164
295
|
};
|
|
165
296
|
|
|
166
297
|
export class CustomChartContext {
|
|
@@ -269,6 +400,9 @@ export class CustomChartContext {
|
|
|
269
400
|
this.hasInitializedPromise = new Promise((resolve, reject) => {
|
|
270
401
|
this.triggerInitResolve = resolve;
|
|
271
402
|
});
|
|
403
|
+
// Not using this.emitEvent as the context is not yet completely
|
|
404
|
+
// initialized, thus short circuiting.
|
|
405
|
+
postMessageToHostApp('', '*', null, ChartToTSEvent.InitStart);
|
|
272
406
|
}
|
|
273
407
|
|
|
274
408
|
/**
|
|
@@ -279,7 +413,7 @@ export class CustomChartContext {
|
|
|
279
413
|
* @version SDK: 0.1 | ThoughtSpot:
|
|
280
414
|
*/
|
|
281
415
|
public initialize = (): Promise<void> => {
|
|
282
|
-
|
|
416
|
+
logger.log('Chart Context: initialization start');
|
|
283
417
|
return this.hasInitializedPromise;
|
|
284
418
|
};
|
|
285
419
|
|
|
@@ -311,7 +445,7 @@ export class CustomChartContext {
|
|
|
311
445
|
*/
|
|
312
446
|
public off<T extends keyof TSToChartEventsPayloadMap>(eventType: T): void {
|
|
313
447
|
if (_.isNil(this.eventListeners[eventType])) {
|
|
314
|
-
|
|
448
|
+
logger.log('No event listener found to remove');
|
|
315
449
|
this.eventListeners[eventType] = [];
|
|
316
450
|
return;
|
|
317
451
|
}
|
|
@@ -424,6 +558,7 @@ export class CustomChartContext {
|
|
|
424
558
|
* @returns {VisualPropEditorDefinition}
|
|
425
559
|
*/
|
|
426
560
|
private getVisualPropEditorDefinition = (
|
|
561
|
+
activeColumnId?: string,
|
|
427
562
|
currentState: Partial<ChartModel> = {},
|
|
428
563
|
) => {
|
|
429
564
|
if (_.isFunction(this.chartContextProps.visualPropEditorDefinition)) {
|
|
@@ -433,6 +568,7 @@ export class CustomChartContext {
|
|
|
433
568
|
...currentState,
|
|
434
569
|
},
|
|
435
570
|
this,
|
|
571
|
+
activeColumnId,
|
|
436
572
|
);
|
|
437
573
|
}
|
|
438
574
|
return this.chartContextProps.visualPropEditorDefinition;
|
|
@@ -500,8 +636,10 @@ export class CustomChartContext {
|
|
|
500
636
|
private validationsResponseProcessor(
|
|
501
637
|
currentValidationState: Partial<ChartModel>,
|
|
502
638
|
validationResponse: ValidationResponse,
|
|
639
|
+
activeColumnId?: string,
|
|
503
640
|
) {
|
|
504
641
|
const visualPropEditorDefinition = this.getVisualPropEditorDefinition(
|
|
642
|
+
activeColumnId,
|
|
505
643
|
currentValidationState,
|
|
506
644
|
);
|
|
507
645
|
const chartConfigEditorDefinition = this.getChartConfigEditorDefinition(
|
|
@@ -528,7 +666,7 @@ export class CustomChartContext {
|
|
|
528
666
|
...eventPayload: ChartToTSEventsPayloadMap[T]
|
|
529
667
|
): Promise<any> {
|
|
530
668
|
if (!globalThis.isInitialized) {
|
|
531
|
-
|
|
669
|
+
logger.log(
|
|
532
670
|
'Chart Context: not initialized the context, something went wrong',
|
|
533
671
|
);
|
|
534
672
|
return Promise.reject(new Error('Context not initialized'));
|
|
@@ -551,7 +689,7 @@ export class CustomChartContext {
|
|
|
551
689
|
*/
|
|
552
690
|
private registerEventProcessor = () => {
|
|
553
691
|
if (globalThis.isInitialized) {
|
|
554
|
-
|
|
692
|
+
logger.error(
|
|
555
693
|
'The context is already initialized. you cannot have multiple contexts',
|
|
556
694
|
);
|
|
557
695
|
throw new Error(ErrorType.MultipleContextsNotSupported);
|
|
@@ -567,12 +705,12 @@ export class CustomChartContext {
|
|
|
567
705
|
* @param event : Message Event Object
|
|
568
706
|
*/
|
|
569
707
|
private eventProcessor = (data: any) => {
|
|
570
|
-
|
|
708
|
+
logger.log('Chart Context: message received:', data.eventType, data);
|
|
571
709
|
|
|
572
710
|
const messageResponse = this.executeEventListenerCBs(data);
|
|
573
711
|
|
|
574
712
|
// respond back to parent to confirm/ack the receipt
|
|
575
|
-
return messageResponse;
|
|
713
|
+
return messageResponse || {};
|
|
576
714
|
};
|
|
577
715
|
|
|
578
716
|
/**
|
|
@@ -617,15 +755,17 @@ export class CustomChartContext {
|
|
|
617
755
|
this.chartContextProps.validateVisualProps(
|
|
618
756
|
payload.visualProps,
|
|
619
757
|
this.chartModel,
|
|
758
|
+
payload?.activeColumnId,
|
|
620
759
|
);
|
|
621
760
|
if (validationResponse.isValid) {
|
|
622
761
|
const currentVisualState = {
|
|
623
762
|
visualProps: payload.visualProps,
|
|
624
763
|
};
|
|
625
|
-
|
|
764
|
+
const activeColumnId = payload?.activeColumnId;
|
|
626
765
|
return this.validationsResponseProcessor(
|
|
627
766
|
currentVisualState,
|
|
628
767
|
validationResponse,
|
|
768
|
+
activeColumnId,
|
|
629
769
|
);
|
|
630
770
|
}
|
|
631
771
|
return validationResponse;
|
|
@@ -690,6 +830,28 @@ export class CustomChartContext {
|
|
|
690
830
|
},
|
|
691
831
|
);
|
|
692
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
|
+
|
|
693
855
|
/**
|
|
694
856
|
* This event is triggered when the TS app re-renders the chart
|
|
695
857
|
*/
|
|
@@ -728,7 +890,7 @@ export class CustomChartContext {
|
|
|
728
890
|
isValid: true,
|
|
729
891
|
};
|
|
730
892
|
} catch (error: unknown) {
|
|
731
|
-
|
|
893
|
+
logger.log(
|
|
732
894
|
'ContextMenuCustomAction: payload recieved:',
|
|
733
895
|
payload,
|
|
734
896
|
'CustomActionCallbackStore:',
|
|
@@ -771,7 +933,7 @@ export class CustomChartContext {
|
|
|
771
933
|
isValid: true,
|
|
772
934
|
};
|
|
773
935
|
} catch (error: unknown) {
|
|
774
|
-
|
|
936
|
+
logger.log(
|
|
775
937
|
'AxisMenuCustomAction: payload recieved:',
|
|
776
938
|
payload,
|
|
777
939
|
'CustomActionCallbackStore:',
|
|
@@ -859,7 +1021,9 @@ export class CustomChartContext {
|
|
|
859
1021
|
this.containerEl = payload.containerElSelector
|
|
860
1022
|
? document.querySelector(payload.containerElSelector)
|
|
861
1023
|
: null;
|
|
862
|
-
|
|
1024
|
+
setLocaleBasedStringFormats(
|
|
1025
|
+
this.appConfig.dateFormatsConfig?.tsLocaleBasedStringsFormats,
|
|
1026
|
+
);
|
|
863
1027
|
return this.publishChartContextPropsToHost();
|
|
864
1028
|
};
|
|
865
1029
|
|
|
@@ -901,6 +1065,8 @@ export class CustomChartContext {
|
|
|
901
1065
|
this.getVisualPropEditorDefinition(),
|
|
902
1066
|
allowedConfigurations:
|
|
903
1067
|
this.chartContextProps.allowedConfigurations,
|
|
1068
|
+
chartConfigParameters:
|
|
1069
|
+
this.chartContextProps.chartConfigParameters,
|
|
904
1070
|
};
|
|
905
1071
|
};
|
|
906
1072
|
|
|
@@ -928,7 +1094,7 @@ export class CustomChartContext {
|
|
|
928
1094
|
};
|
|
929
1095
|
}
|
|
930
1096
|
|
|
931
|
-
|
|
1097
|
+
logger.log(
|
|
932
1098
|
'ChartContext: Response:',
|
|
933
1099
|
data.eventType,
|
|
934
1100
|
response,
|
|
@@ -951,6 +1117,5 @@ export const getChartContext = async (
|
|
|
951
1117
|
// wait for initialization here as the host app
|
|
952
1118
|
// needs to first handshake with the client app.
|
|
953
1119
|
await ctx.initialize();
|
|
954
|
-
|
|
955
1120
|
return ctx;
|
|
956
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
|
+
}
|