@thoughtspot/ts-chart-sdk 0.0.2-alpha.22 → 0.0.2-alpha.24

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.
Files changed (49) hide show
  1. package/dist/ts-chart-sdk.d.ts +18 -1
  2. package/lib/main/custom-chart-context.d.ts +1 -0
  3. package/lib/main/custom-chart-context.d.ts.map +1 -1
  4. package/lib/main/custom-chart-context.js +11 -8
  5. package/lib/main/custom-chart-context.js.map +1 -1
  6. package/lib/main/custom-chart-context.spec.js +1 -0
  7. package/lib/main/custom-chart-context.spec.js.map +1 -1
  8. package/lib/main/logger.d.ts +13 -0
  9. package/lib/main/logger.d.ts.map +1 -0
  10. package/lib/main/logger.js +64 -0
  11. package/lib/main/logger.js.map +1 -0
  12. package/lib/main/logger.spec.d.ts +2 -0
  13. package/lib/main/logger.spec.d.ts.map +1 -0
  14. package/lib/main/logger.spec.js +88 -0
  15. package/lib/main/logger.spec.js.map +1 -0
  16. package/lib/main/util.d.ts +2 -0
  17. package/lib/main/util.d.ts.map +1 -1
  18. package/lib/main/util.js +11 -0
  19. package/lib/main/util.js.map +1 -1
  20. package/lib/main/util.spec.js +43 -1
  21. package/lib/main/util.spec.js.map +1 -1
  22. package/lib/react/use-custom-chart-context.d.ts.map +1 -1
  23. package/lib/react/use-custom-chart-context.js +3 -1
  24. package/lib/react/use-custom-chart-context.js.map +1 -1
  25. package/lib/react/use-custom-chart-context.util.d.ts.map +1 -1
  26. package/lib/react/use-custom-chart-context.util.js +5 -3
  27. package/lib/react/use-custom-chart-context.util.js.map +1 -1
  28. package/lib/types/common.types.d.ts +6 -0
  29. package/lib/types/common.types.d.ts.map +1 -1
  30. package/lib/types/ts-to-chart-event.types.d.ts.map +1 -1
  31. package/lib/types/ts-to-chart-event.types.js.map +1 -1
  32. package/lib/types/visual-prop.types.d.ts +11 -1
  33. package/lib/types/visual-prop.types.d.ts.map +1 -1
  34. package/lib/utils/date-formatting.d.ts.map +1 -1
  35. package/lib/utils/date-formatting.js +4 -2
  36. package/lib/utils/date-formatting.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/main/custom-chart-context.spec.ts +1 -0
  39. package/src/main/custom-chart-context.ts +19 -9
  40. package/src/main/logger.spec.ts +114 -0
  41. package/src/main/logger.ts +97 -0
  42. package/src/main/util.spec.ts +54 -1
  43. package/src/main/util.ts +20 -0
  44. package/src/react/use-custom-chart-context.tsx +4 -1
  45. package/src/react/use-custom-chart-context.util.ts +6 -3
  46. package/src/types/common.types.ts +7 -0
  47. package/src/types/ts-to-chart-event.types.ts +0 -1
  48. package/src/types/visual-prop.types.ts +43 -2
  49. package/src/utils/date-formatting.ts +5 -2
@@ -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
+ }
@@ -1,4 +1,4 @@
1
- import { timeout } from './util';
1
+ import { getQueryParam, handleMissingValue, timeout } from './util';
2
2
 
3
3
  describe('timeout function', () => {
4
4
  jest.useFakeTimers();
@@ -39,3 +39,56 @@ describe('timeout function', () => {
39
39
  await expect(result).rejects.toThrow('Original error');
40
40
  });
41
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
+ }
@@ -12,6 +12,7 @@ import {
12
12
  CustomChartContext,
13
13
  CustomChartContextProps,
14
14
  } from '../main/custom-chart-context';
15
+ import { create } from '../main/logger';
15
16
  import { ChartModel } from '../types/common.types';
16
17
  import {
17
18
  ChartModelUpdateEventPayload,
@@ -28,6 +29,8 @@ import {
28
29
  TSChartContextProps,
29
30
  } from './use-custom-chart-types';
30
31
 
32
+ const logger = create('CustomChartContextHookSdk');
33
+
31
34
  /**
32
35
  * A custom hook to manage the Chart Context state and provide necessary
33
36
  * chart-related functionality.
@@ -143,7 +146,7 @@ export const useChartContext = (
143
146
  return true;
144
147
  })
145
148
  .catch((e) => {
146
- console.log('Error in context initialization', e);
149
+ logger.log('Error in context initialization', e);
147
150
  });
148
151
  };
149
152
 
@@ -1,5 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import { CustomChartContext } from '../main/custom-chart-context';
3
+ import { create } from '../main/logger';
3
4
  import {
4
5
  ChartToTSEvent,
5
6
  ChartToTSEventsPayloadMap,
@@ -14,6 +15,8 @@ import {
14
15
  TSToChartEventOffListener,
15
16
  } from './use-custom-chart-types';
16
17
 
18
+ const logger = create('CustomChartContextUtilSdk');
19
+
17
20
  /**
18
21
  *
19
22
  * @param ctx Custom Chart Context
@@ -31,7 +34,7 @@ export const emitter = (ctx: CustomChartContext): ChartToTSEventEmitters => {
31
34
  ...args: ChartToTSEventsPayloadMap[keyof ChartToTSEventsPayloadMap]
32
35
  ): Promise<void> => {
33
36
  if (!ctx || _.isEmpty(ctx)) {
34
- console.log('Context is not initialized');
37
+ logger.log('Context is not initialized');
35
38
  return Promise.reject(new Error('Context not initialized'));
36
39
  }
37
40
  return ctx.emitEvent(eventName, ...args);
@@ -60,7 +63,7 @@ export const eventListener = (
60
63
  callbackFn: TSToChartEventsPayloadMap[keyof TSToChartEventsPayloadMap],
61
64
  ): Promise<void> => {
62
65
  if (!ctx || _.isEmpty(ctx)) {
63
- console.log('Context is not initialized');
66
+ logger.log('Context is not initialized');
64
67
  return Promise.reject(new Error('Context not initialized'));
65
68
  }
66
69
  ctx.on(eventName, callbackFn);
@@ -89,7 +92,7 @@ export const eventOffListener = (
89
92
 
90
93
  acc[emitterKey] = (): Promise<void> => {
91
94
  if (!ctx || _.isEmpty(ctx)) {
92
- console.log('Context is not initialized');
95
+ logger.log('Context is not initialized');
93
96
  return Promise.reject(new Error('Context not initialized'));
94
97
  }
95
98
  ctx.off(eventName);
@@ -188,10 +188,17 @@ export type SuccessValidationResponse = {
188
188
  visualPropEditorDefinition: VisualPropEditorDefinition;
189
189
  };
190
190
 
191
+ export type VisualPropError = {
192
+ propElementKey: string;
193
+ propElementType: string;
194
+ value: unknown;
195
+ };
196
+
191
197
  // Generic Validation Response
192
198
  export type ValidationResponse = {
193
199
  isValid: boolean;
194
200
  validationErrorMessage?: string[];
201
+ visualPropError?: VisualPropError;
195
202
  };
196
203
 
197
204
  /**
@@ -73,7 +73,6 @@ export enum TSToChartEvent {
73
73
  * @version SDK: 0.1 | ThoughtSpot:
74
74
  */
75
75
  AxisMenuActionClick = 'AxisMenuActionClick',
76
-
77
76
  /**
78
77
  * @version SDK: 0.2 | ThoughtSpot:
79
78
  */
@@ -11,6 +11,11 @@
11
11
  import type { CustomChartContext } from '../main/custom-chart-context';
12
12
  import { ColumnType } from './answer-column.types';
13
13
  import { ChartModel } from './common.types';
14
+
15
+ export type TSTooltipConfig = {
16
+ columnIds: Array<string>;
17
+ };
18
+
14
19
  /**
15
20
  * Configuration for input validation rules
16
21
  */
@@ -386,13 +391,48 @@ export interface Section {
386
391
  */
387
392
  disabled?: boolean;
388
393
  /* Optional property to make the accordian expanded by default. If
389
- * not passed the accordian will remain closed by default. Only works with layout type 'accordian'
394
+ * not passed the accordian will remain closed by default. Only works with layout type
395
+ * 'accordian'
390
396
  *
391
397
  * @version SDK: 0.0.2-alpha.19 | ThoughtSpot:
392
398
  */
393
399
  isAccordianExpanded?: boolean;
394
400
  }
395
401
 
402
+ /**
403
+ * Native charts edit tool tip component defined for regular charts in TS Advance Chart Settings
404
+ *
405
+ * @group Visual Properties Editor
406
+ */
407
+ export interface NativeEditToolTip {
408
+ type: 'tooltipconfig';
409
+ /**
410
+ * Key to store the value
411
+ *
412
+ * @version SDK: 0.1 | ThoughtSpot:
413
+ */
414
+ key: string;
415
+
416
+ /*
417
+ List of column ids that are present in ToolTipConfig by default
418
+ */
419
+
420
+ defaultValue?: TSTooltipConfig;
421
+
422
+ /**
423
+ * I18n'ed string to show on the form label
424
+ *
425
+ * @version SDK: 0.1 | ThoughtSpot:
426
+ */
427
+ label?: string;
428
+ /**
429
+ * Determines whether it should be disabled or not
430
+ *
431
+ * @version SDK: 0.0.2-alpha.13 | ThoughtSpot:
432
+ */
433
+ disabled?: boolean;
434
+ }
435
+
396
436
  /**
397
437
  * Common type placeholder for all the input element types
398
438
  *
@@ -406,7 +446,8 @@ export type PropElement =
406
446
  | ToggleFormDetail
407
447
  | CheckboxFormDetail
408
448
  | RadioButtonFormDetail
409
- | DropDownFormDetail;
449
+ | DropDownFormDetail
450
+ | NativeEditToolTip;
410
451
 
411
452
  /**
412
453
  * Define Column settings, based on column type, settings needs to be defined in
@@ -8,6 +8,7 @@
8
8
 
9
9
  import _ from 'lodash';
10
10
  import { DateTime } from 'luxon';
11
+ import { create } from '../main/logger';
11
12
  import {
12
13
  ChartColumn,
13
14
  ColumnTimeBucket,
@@ -15,6 +16,8 @@ import {
15
16
  DataType,
16
17
  } from '../types/answer-column.types';
17
18
 
19
+ const logger = create('DateFormattingUtilsSdk');
20
+
18
21
  export interface CustomCalendarDate {
19
22
  v: {
20
23
  s: number;
@@ -615,7 +618,7 @@ export function formatDateNum(
615
618
  case dateNumTypes.DATE_NUM_HOUR_IN_DAY:
616
619
  return `${value}`;
617
620
  default:
618
- console.log(
621
+ logger.log(
619
622
  'unknown effectiveDataType for date num',
620
623
  effectiveDataType,
621
624
  );
@@ -664,7 +667,7 @@ export function formatDate(
664
667
  epochMillis = newInputDate.getTime();
665
668
  }
666
669
  if (!_.isNumber(epochMillis)) {
667
- console.log(
670
+ logger.log(
668
671
  'formatDate could not convert input date to a timestamp',
669
672
  inputDate,
670
673
  );