@thoughtspot/ts-chart-sdk 2.5.8 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/ts-chart-sdk.d.ts +39 -1
  2. package/lib/index.d.ts +1 -0
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/index.js +1 -0
  5. package/lib/index.js.map +1 -1
  6. package/lib/main/custom-chart-context.d.ts.map +1 -1
  7. package/lib/main/custom-chart-context.js +3 -0
  8. package/lib/main/custom-chart-context.js.map +1 -1
  9. package/lib/main/custom-chart-context.spec.js +10 -0
  10. package/lib/main/custom-chart-context.spec.js.map +1 -1
  11. package/lib/react/mocks/custom-chart-context-mock.d.ts.map +1 -1
  12. package/lib/react/mocks/custom-chart-context-mock.js +3 -7
  13. package/lib/react/mocks/custom-chart-context-mock.js.map +1 -1
  14. package/lib/react/use-custom-chart-context.d.ts.map +1 -1
  15. package/lib/react/use-custom-chart-context.js +1 -0
  16. package/lib/react/use-custom-chart-context.js.map +1 -1
  17. package/lib/react/use-custom-chart-context.spec.js +68 -1
  18. package/lib/react/use-custom-chart-context.spec.js.map +1 -1
  19. package/lib/types/common.types.d.ts +31 -1
  20. package/lib/types/common.types.d.ts.map +1 -1
  21. package/lib/types/common.types.js +11 -0
  22. package/lib/types/common.types.js.map +1 -1
  23. package/lib/types/conditional-formatting.types.d.ts +1 -0
  24. package/lib/types/conditional-formatting.types.d.ts.map +1 -1
  25. package/lib/types/conditional-formatting.types.js.map +1 -1
  26. package/lib/types/ts-to-chart-event.types.d.ts +1 -0
  27. package/lib/types/ts-to-chart-event.types.d.ts.map +1 -1
  28. package/lib/utils/chart-config.d.ts +8 -0
  29. package/lib/utils/chart-config.d.ts.map +1 -0
  30. package/lib/utils/chart-config.js +56 -0
  31. package/lib/utils/chart-config.js.map +1 -0
  32. package/lib/utils/chart-config.spec.d.ts +2 -0
  33. package/lib/utils/chart-config.spec.d.ts.map +1 -0
  34. package/lib/utils/chart-config.spec.js +574 -0
  35. package/lib/utils/chart-config.spec.js.map +1 -0
  36. package/package.json +2 -1
  37. package/src/index.ts +1 -0
  38. package/src/main/custom-chart-context.spec.ts +10 -0
  39. package/src/main/custom-chart-context.ts +3 -0
  40. package/src/react/mocks/custom-chart-context-mock.ts +4 -13
  41. package/src/react/use-custom-chart-context.spec.tsx +82 -1
  42. package/src/react/use-custom-chart-context.tsx +1 -0
  43. package/src/types/common.types.ts +116 -7
  44. package/src/types/conditional-formatting.types.ts +1 -0
  45. package/src/types/ts-to-chart-event.types.ts +9 -0
  46. package/src/utils/chart-config.spec.ts +680 -0
  47. package/src/utils/chart-config.ts +100 -0
@@ -1788,6 +1788,7 @@ describe('CustomChartContext', () => {
1788
1788
  });
1789
1789
 
1790
1790
  expect(response).toEqual({
1791
+ isDownloadHandled: true,
1791
1792
  fileName: '',
1792
1793
  error: '',
1793
1794
  message: 'Download Excel not implemented.',
@@ -1796,6 +1797,7 @@ describe('CustomChartContext', () => {
1796
1797
 
1797
1798
  test('should use custom handler when provided', async () => {
1798
1799
  const mockDownloadHandler = jest.fn().mockReturnValue({
1800
+ isDownloadHandled: true,
1799
1801
  fileName: 'custom-report.xlsx',
1800
1802
  error: '',
1801
1803
  message: 'Success',
@@ -1825,6 +1827,7 @@ describe('CustomChartContext', () => {
1825
1827
 
1826
1828
  expect(mockDownloadHandler).toHaveBeenCalledWith(testPayload);
1827
1829
  expect(response).toEqual({
1830
+ isDownloadHandled: true,
1828
1831
  fileName: 'custom-report.xlsx',
1829
1832
  error: '',
1830
1833
  message: 'Success',
@@ -1833,6 +1836,7 @@ describe('CustomChartContext', () => {
1833
1836
 
1834
1837
  test('should handle errors in custom handler', async () => {
1835
1838
  const mockDownloadHandler = jest.fn().mockReturnValue({
1839
+ isDownloadHandled: true,
1836
1840
  fileName: '',
1837
1841
  error: 'Failed to generate excel',
1838
1842
  message: 'Error occurred',
@@ -1858,6 +1862,7 @@ describe('CustomChartContext', () => {
1858
1862
 
1859
1863
  expect(mockDownloadHandler).toHaveBeenCalled();
1860
1864
  expect(response).toEqual({
1865
+ isDownloadHandled: true,
1861
1866
  fileName: '',
1862
1867
  error: 'Failed to generate excel',
1863
1868
  message: 'Error occurred',
@@ -1866,6 +1871,7 @@ describe('CustomChartContext', () => {
1866
1871
 
1867
1872
  test('should pass through payload to custom handler', async () => {
1868
1873
  const mockDownloadHandler = jest.fn().mockReturnValue({
1874
+ isDownloadHandled: true,
1869
1875
  fileName: 'test.xlsx',
1870
1876
  error: '',
1871
1877
  message: 'Success',
@@ -1912,6 +1918,7 @@ describe('CustomChartContext', () => {
1912
1918
  return response;
1913
1919
  }
1914
1920
  return {
1921
+ isDownloadHandled: true,
1915
1922
  fileName: 'first.xlsx',
1916
1923
  error: '',
1917
1924
  message: 'First handler response',
@@ -1921,6 +1928,7 @@ describe('CustomChartContext', () => {
1921
1928
  );
1922
1929
 
1923
1930
  const secondHandler = jest.fn().mockReturnValue({
1931
+ isDownloadHandled: true,
1924
1932
  fileName: 'second.xlsx',
1925
1933
  error: '',
1926
1934
  message: 'Second handler response',
@@ -1958,6 +1966,7 @@ describe('CustomChartContext', () => {
1958
1966
  // Verify handlers were called in correct order
1959
1967
  expect(secondHandler).toHaveBeenCalledWith(testPayload, undefined);
1960
1968
  expect(firstHandler).toHaveBeenCalledWith(testPayload, {
1969
+ isDownloadHandled: true,
1961
1970
  fileName: 'second.xlsx',
1962
1971
  error: '',
1963
1972
  message: 'Second handler response',
@@ -1967,6 +1976,7 @@ describe('CustomChartContext', () => {
1967
1976
  // Verify final result comes from first handler's return value
1968
1977
  // (last custom handler to execute)
1969
1978
  expect(result).toEqual({
1979
+ isDownloadHandled: true,
1970
1980
  fileName: 'second.xlsx',
1971
1981
  error: '',
1972
1982
  message: 'Second handler response',
@@ -59,6 +59,7 @@ import {
59
59
  VisualEditorDefinitionSetter,
60
60
  VisualPropEditorDefinition,
61
61
  } from '../types/visual-prop.types';
62
+ import { validateAllChartConfigs } from '../utils/chart-config';
62
63
  import { setLocaleBasedStringFormats } from '../utils/number-formatting/number-formatting-utils';
63
64
  import { create } from './logger';
64
65
  import {
@@ -1185,6 +1186,7 @@ export class CustomChartContext {
1185
1186
  return response;
1186
1187
  }
1187
1188
  return Promise.resolve({
1189
+ isDownloadHandled: true,
1188
1190
  fileName: '',
1189
1191
  error: '',
1190
1192
  message: 'Download Excel not implemented.',
@@ -1275,6 +1277,7 @@ export class CustomChartContext {
1275
1277
  this.appConfig,
1276
1278
  );
1277
1279
  }
1280
+ validateAllChartConfigs(defaultChartConfig);
1278
1281
  return {
1279
1282
  isConfigValid: isValid,
1280
1283
  defaultChartConfig,
@@ -3,6 +3,7 @@ import { CustomChartContextProps } from '../../main/custom-chart-context';
3
3
  import { ColumnType } from '../../types/answer-column.types';
4
4
  import { ChartConfig, ChartModel } from '../../types/common.types';
5
5
  import { Query } from '../../types/ts-to-chart-event.types';
6
+ import { fetchQueryColumns } from '../../utils/chart-config';
6
7
 
7
8
  export const contextChartProps: CustomChartContextProps = {
8
9
  getDefaultChartConfig: (chartModel: ChartModel): ChartConfig[] => {
@@ -35,19 +36,9 @@ export const contextChartProps: CustomChartContextProps = {
35
36
  },
36
37
  getQueriesFromChartConfig: (chartConfig: ChartConfig[]): Array<Query> => {
37
38
  const queries = chartConfig.map(
38
- (config: ChartConfig): Query =>
39
- _.reduce(
40
- config.dimensions,
41
- (acc: Query, dimension) => ({
42
- queryColumns: [
43
- ...acc.queryColumns,
44
- ...dimension.columns,
45
- ],
46
- }),
47
- {
48
- queryColumns: [],
49
- } as Query,
50
- ),
39
+ (config: ChartConfig): Query => ({
40
+ queryColumns: fetchQueryColumns(config),
41
+ }),
51
42
  );
52
43
  return queries;
53
44
  },
@@ -5,6 +5,7 @@ import * as PostMessageEventBridge from '../main/post-message-event-bridge';
5
5
  import { mockInitializeContextPayload } from '../test/test-utils';
6
6
  import { ColumnType } from '../types/answer-column.types';
7
7
  import { ChartToTSEvent } from '../types/chart-to-ts-event.types';
8
+ import { AxisType, ChartConfigMode } from '../types/common.types';
8
9
  import { TSToChartEvent } from '../types/ts-to-chart-event.types';
9
10
  import { contextChartProps } from './mocks/custom-chart-context-mock';
10
11
  import { useChartContext } from './use-custom-chart-context';
@@ -71,7 +72,7 @@ describe('useChartContext initialization', () => {
71
72
  });
72
73
  });
73
74
 
74
- test('should trigger getDataQuery and fetch correct query response', async () => {
75
+ test('should trigger getDataQuery and fetch correct query response for column driven dimension config', async () => {
75
76
  // Render the hook with the custom chart context props
76
77
  const { result, waitFor } = renderHook(() =>
77
78
  useChartContext(contextChartProps),
@@ -131,6 +132,85 @@ describe('useChartContext initialization', () => {
131
132
  });
132
133
  });
133
134
 
135
+ test('should trigger getDataQuery and fetch correct query response for config driven dimension config', async () => {
136
+ // Render the hook with the custom chart context props
137
+ const { result, waitFor } = renderHook(() =>
138
+ useChartContext(contextChartProps),
139
+ );
140
+
141
+ // Assert that the context is not initialized initially
142
+ expect(result.current.hasInitialized).toBe(false);
143
+ expect(result.current.chartModel).toBeUndefined();
144
+ await eventProcessor({
145
+ payload: {
146
+ componentId: 'COMPONENT_ID',
147
+ hostUrl: 'https://some.chart.app',
148
+ chartModel: mockedChartModel,
149
+ },
150
+ eventType: TSToChartEvent.Initialize,
151
+ });
152
+
153
+ const response = await eventProcessor({
154
+ payload: {
155
+ config: [
156
+ {
157
+ key: 'column',
158
+ dimensions: [
159
+ {
160
+ key: 'x',
161
+ mode: ChartConfigMode.AXIS_DRIVEN,
162
+ axes: [
163
+ {
164
+ type: AxisType.FLAT,
165
+ column: mockedChartModel.columns[0],
166
+ },
167
+ ],
168
+ },
169
+ {
170
+ key: 'y',
171
+ mode: ChartConfigMode.AXIS_DRIVEN,
172
+ axes: [
173
+ {
174
+ type: AxisType.MERGED,
175
+ columns: [
176
+ mockedChartModel.columns[1],
177
+ mockedChartModel.columns[2],
178
+ ],
179
+ },
180
+ ],
181
+ },
182
+ ],
183
+ },
184
+ ],
185
+ },
186
+ eventType: TSToChartEvent.GetDataQuery,
187
+ source: 'ts-host-app',
188
+ });
189
+ await eventProcessor({
190
+ payload: {},
191
+ eventType: TSToChartEvent.TriggerRenderChart,
192
+ source: 'ts-host-app',
193
+ });
194
+ await eventProcessor({
195
+ payload: {},
196
+ eventType: TSToChartEvent.InitializeComplete,
197
+ source: 'ts-host-app',
198
+ });
199
+
200
+ await waitFor(() => {
201
+ expect(response.queries[0].queryColumns[0]).toBe(
202
+ mockedChartModel.columns[0],
203
+ );
204
+ expect(response.queries[0].queryColumns[1]).toBe(
205
+ mockedChartModel.columns[1],
206
+ );
207
+ expect(response.queries[0].queryColumns[2]).toBe(
208
+ mockedChartModel.columns[2],
209
+ );
210
+ expect(result.current.hasInitialized).toBeTruthy();
211
+ });
212
+ });
213
+
134
214
  test('should make sure hasInitialized to remain false when context initialization failed', async () => {
135
215
  jest.mock('../main/custom-chart-context', () => ({
136
216
  CustomChartContext: jest.fn().mockImplementation(() => ({
@@ -549,6 +629,7 @@ describe('useChartContext DownloadExcelTrigger event handler', () => {
549
629
 
550
630
  await waitFor(() => {
551
631
  expect(response).toEqual({
632
+ isDownloadHandled: true,
552
633
  fileName: '',
553
634
  error: '',
554
635
  message: 'Download Excel not implemented.',
@@ -113,6 +113,7 @@ export const useChartContext = (
113
113
  ) => {
114
114
  setChartModel(context.getChartModel());
115
115
  return Promise.resolve({
116
+ isDownloadHandled: true,
116
117
  fileName: '',
117
118
  error: '',
118
119
  message: 'Download Excel not implemented.',
@@ -59,14 +59,78 @@ export enum CustomizableChartFeature {
59
59
  }
60
60
 
61
61
  /**
62
- * List of Columns for a dimension in the Custom Chart Config.
63
- * Associated with the key defined in the chart config editor definition
64
- * Relates to ChartConfigSection
62
+ * Enum to indicate the type of dimension config
65
63
  *
66
- * @version SDK: 0.1 | ThoughtSpot:
64
+ * @version SDK: 2.6.0 | ThoughtSpot:
65
+ * @group Chart Model
66
+ */
67
+ export enum AxisType {
68
+ FLAT = 'flat',
69
+ MERGED = 'merged',
70
+ DUAL = 'dual',
71
+ }
72
+
73
+ /**
74
+ * Flat axis config: single column, unmodified.
75
+ *
76
+ * @version SDK: 2.6.0 | ThoughtSpot:
67
77
  * @group Chart Model
68
78
  */
69
- export interface ChartConfigDimension {
79
+ export interface FlatAxis {
80
+ type: AxisType.FLAT;
81
+ /** Single column for this axis slot */
82
+ column: ChartColumn;
83
+ }
84
+
85
+ /**
86
+ * Merged axis config: multiple columns combined into one logical series.
87
+ *
88
+ * @version SDK: 2.6.0 | ThoughtSpot:
89
+ * @group Chart Model
90
+ */
91
+ export interface MergedAxis {
92
+ type: AxisType.MERGED;
93
+ /** Columns that are merged into one axis slot */
94
+ columns: ChartColumn[];
95
+ }
96
+
97
+ /**
98
+ * Dual axis config: primary and secondary axis, each can be flat or merged.
99
+ *
100
+ * @version SDK: 2.6.0 | ThoughtSpot:
101
+ * @group Chart Model
102
+ */
103
+ export interface DualAxis {
104
+ type: AxisType.DUAL;
105
+ /** Primary axis config (flat or merged) */
106
+ primary: FlatAxis | MergedAxis;
107
+ /** Secondary axis config (flat or merged) */
108
+ secondary: FlatAxis | MergedAxis;
109
+ }
110
+
111
+ /**
112
+ * Union of all supported axis types for a dimension.
113
+ */
114
+ export type AxisConfig = FlatAxis | MergedAxis | DualAxis;
115
+
116
+ /**
117
+ * Enum to indicate whether dimension config uses columns or structured config
118
+ *
119
+ * @version SDK: 2.6.0 | ThoughtSpot:
120
+ * @group Chart Model
121
+ */
122
+ export enum ChartConfigMode {
123
+ COLUMN_DRIVEN = 'COLUMN_DRIVEN',
124
+ AXIS_DRIVEN = 'AXIS_DRIVEN',
125
+ }
126
+
127
+ /**
128
+ * Column driven dimension config: single column or multiple columns.
129
+ *
130
+ * @version SDK: 2.6.0 | ThoughtSpot:
131
+ * @group Chart Model
132
+ */
133
+ export interface ColumnDrivenChartConfigDimension {
70
134
  /**
71
135
  * Key for the dimension in the chart config
72
136
  *
@@ -74,13 +138,58 @@ export interface ChartConfigDimension {
74
138
  */
75
139
  key: string;
76
140
  /**
77
- * List of columns added for the dimension
141
+ * Mode of the chart config
78
142
  *
79
- * @version SDK: 0.1 | ThoughtSpot:
143
+ * @version SDK: 2.6.0 | ThoughtSpot:
144
+ */
145
+ mode?: ChartConfigMode.COLUMN_DRIVEN;
146
+ /**
147
+ * List of columns added for the dimension
148
+ * If chart config mode is COLUMN_DRIVEN, this is required
149
+ * @version SDK: 2.6.0 | ThoughtSpot:
80
150
  */
81
151
  columns: ChartColumn[];
82
152
  }
83
153
 
154
+ /**
155
+ * Axis driven dimension config: multiple axes, each can be flat or merged.
156
+ *
157
+ * @version SDK: 2.6.0 | ThoughtSpot:
158
+ * @group Chart Model
159
+ */
160
+ export interface AxisDrivenChartConfigDimension {
161
+ /**
162
+ * Key for the dimension in the chart config
163
+ *
164
+ * @version SDK: 2.6.0 | ThoughtSpot:
165
+ */
166
+ key: string;
167
+ /**
168
+ * Mode of the chart config
169
+ *
170
+ * @version SDK: 2.6.0 | ThoughtSpot:
171
+ */
172
+ mode: ChartConfigMode.AXIS_DRIVEN;
173
+ /**
174
+ * Axis config of the dimension
175
+ *
176
+ * @version SDK: 2.6.0 | ThoughtSpot:
177
+ */
178
+ axes: AxisConfig[];
179
+ }
180
+
181
+ /**
182
+ * List of Columns for a dimension in the Custom Chart Config.
183
+ * Associated with the key defined in the chart config editor definition
184
+ * Relates to ChartConfigSection
185
+ *
186
+ * @version SDK: 0.1 | ThoughtSpot:
187
+ * @group Chart Model
188
+ */
189
+ export type ChartConfigDimension =
190
+ | ColumnDrivenChartConfigDimension
191
+ | AxisDrivenChartConfigDimension;
192
+
84
193
  /**
85
194
  * Custom Chart Config values stored in the metadata
86
195
  * Relates to ChartConfigEditorDefinition
@@ -34,6 +34,7 @@ export type GradientBackgroundAttrs = {
34
34
  backgroundFormatMidpoint?: Maybe<Scalars['Float']>;
35
35
  backgroundFormatRange?: Maybe<Array<Maybe<Scalars['Float']>>>;
36
36
  colors?: Maybe<Array<Maybe<Scalars['String']>>>;
37
+ isAutoScaled?: Maybe<Scalars['Boolean']>;
37
38
  };
38
39
  export enum Operators {
39
40
  Contains = 'CONTAINS',
@@ -93,6 +93,15 @@ export interface DownloadExcelTriggerPayload {
93
93
  answerTitle: string;
94
94
  }
95
95
  export interface DownloadExcelTriggerResponse {
96
+ // This `isDownloadHandled` flag indicates whether the custom chart has
97
+ // handled the XLSX download. If true, the custom chart managed the
98
+ // download. If false, the ThoughtSpot default XLSX downloader will be used
99
+ // instead. For example, in Muze Studio, only pivot tables support XLSX
100
+ // export. For other chart types like bar or line charts, this flag should
101
+ // be set to false to signal that the download could not be processed by the
102
+ // custom chart, allowing the default ThoughtSpot downloader to handle the
103
+ // export.
104
+ isDownloadHandled: boolean;
96
105
  fileName: string;
97
106
  error: string;
98
107
  message: string;