@finos/legend-application-repl 0.0.31 → 0.0.32

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 (170) hide show
  1. package/lib/components/LegendREPLFrameworkProvider.js +1 -1
  2. package/lib/components/LegendREPLFrameworkProvider.js.map +1 -1
  3. package/lib/components/REPLStoreProvider.d.ts +1 -1
  4. package/lib/components/REPLStoreProvider.d.ts.map +1 -1
  5. package/lib/components/REPLStoreProvider.js +1 -1
  6. package/lib/components/REPLStoreProvider.js.map +1 -1
  7. package/lib/components/REPLWindow.d.ts +33 -0
  8. package/lib/components/REPLWindow.d.ts.map +1 -0
  9. package/lib/components/REPLWindow.js +117 -0
  10. package/lib/components/REPLWindow.js.map +1 -0
  11. package/lib/components/dataCube/DataCube.js +1 -1
  12. package/lib/components/dataCube/DataCube.js.map +1 -1
  13. package/lib/components/dataCube/editor/DataCubeEditor.d.ts.map +1 -1
  14. package/lib/components/dataCube/editor/DataCubeEditor.js +12 -91
  15. package/lib/components/dataCube/editor/DataCubeEditor.js.map +1 -1
  16. package/lib/components/dataCube/editor/DataCubeEditorCodePanel.d.ts.map +1 -1
  17. package/lib/components/dataCube/editor/DataCubeEditorCodePanel.js +3 -2
  18. package/lib/components/dataCube/editor/DataCubeEditorCodePanel.js.map +1 -1
  19. package/lib/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.d.ts.map +1 -1
  20. package/lib/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.js +161 -87
  21. package/lib/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.js.map +1 -1
  22. package/lib/components/dataCube/editor/DataCubeEditorColumnsPanel.js +1 -1
  23. package/lib/components/dataCube/editor/DataCubeEditorColumnsPanel.js.map +1 -1
  24. package/lib/components/dataCube/editor/DataCubeEditorColumnsSelector.d.ts.map +1 -1
  25. package/lib/components/dataCube/editor/DataCubeEditorColumnsSelector.js +0 -1
  26. package/lib/components/dataCube/editor/DataCubeEditorColumnsSelector.js.map +1 -1
  27. package/lib/components/dataCube/editor/DataCubeEditorDeveloperPanel.d.ts.map +1 -1
  28. package/lib/components/dataCube/editor/DataCubeEditorDeveloperPanel.js +3 -2
  29. package/lib/components/dataCube/editor/DataCubeEditorDeveloperPanel.js.map +1 -1
  30. package/lib/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.d.ts.map +1 -1
  31. package/lib/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.js +3 -2
  32. package/lib/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.js.map +1 -1
  33. package/lib/components/dataCube/editor/DataCubeEditorFilterPanel.d.ts.map +1 -1
  34. package/lib/components/dataCube/editor/DataCubeEditorFilterPanel.js +3 -2
  35. package/lib/components/dataCube/editor/DataCubeEditorFilterPanel.js.map +1 -1
  36. package/lib/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.d.ts.map +1 -1
  37. package/lib/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.js +96 -55
  38. package/lib/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.js.map +1 -1
  39. package/lib/components/dataCube/editor/DataCubeEditorHPivotsPanel.d.ts.map +1 -1
  40. package/lib/components/dataCube/editor/DataCubeEditorHPivotsPanel.js +3 -2
  41. package/lib/components/dataCube/editor/DataCubeEditorHPivotsPanel.js.map +1 -1
  42. package/lib/components/dataCube/editor/DataCubeEditorShared.d.ts +1 -0
  43. package/lib/components/dataCube/editor/DataCubeEditorShared.d.ts.map +1 -1
  44. package/lib/components/dataCube/editor/DataCubeEditorShared.js +44 -27
  45. package/lib/components/dataCube/editor/DataCubeEditorShared.js.map +1 -1
  46. package/lib/components/dataCube/editor/DataCubeEditorSortsPanel.js +1 -1
  47. package/lib/components/dataCube/editor/DataCubeEditorSortsPanel.js.map +1 -1
  48. package/lib/components/dataCube/editor/DataCubeEditorVPivotsPanel.d.ts.map +1 -1
  49. package/lib/components/dataCube/editor/DataCubeEditorVPivotsPanel.js +3 -2
  50. package/lib/components/dataCube/editor/DataCubeEditorVPivotsPanel.js.map +1 -1
  51. package/lib/components/dataCube/grid/DataCubeGrid.d.ts +3 -0
  52. package/lib/components/dataCube/grid/DataCubeGrid.d.ts.map +1 -1
  53. package/lib/components/dataCube/grid/DataCubeGrid.js +186 -75
  54. package/lib/components/dataCube/grid/DataCubeGrid.js.map +1 -1
  55. package/lib/components/dataCube/grid/DataCubeGridShared.d.ts +1 -1
  56. package/lib/components/dataCube/grid/DataCubeGridShared.d.ts.map +1 -1
  57. package/lib/components/dataCube/grid/DataCubeGridShared.js +1 -1
  58. package/lib/components/dataCube/grid/DataCubeGridShared.js.map +1 -1
  59. package/lib/components/dataCube/grid/menu/DataCubeGridMenu.d.ts.map +1 -1
  60. package/lib/components/dataCube/grid/menu/DataCubeGridMenu.js +60 -29
  61. package/lib/components/dataCube/grid/menu/DataCubeGridMenu.js.map +1 -1
  62. package/lib/components/dataCube/grid/menu/DataCubeGridSortsMenu.d.ts.map +1 -1
  63. package/lib/components/dataCube/grid/menu/DataCubeGridSortsMenu.js +10 -10
  64. package/lib/components/dataCube/grid/menu/DataCubeGridSortsMenu.js.map +1 -1
  65. package/lib/index.css +2 -2
  66. package/lib/index.css.map +1 -1
  67. package/lib/package.json +14 -14
  68. package/lib/stores/{dataCube/REPLStore.d.ts → REPLStore.d.ts} +5 -3
  69. package/lib/stores/REPLStore.d.ts.map +1 -0
  70. package/lib/stores/{dataCube/REPLStore.js → REPLStore.js} +5 -2
  71. package/lib/stores/REPLStore.js.map +1 -0
  72. package/lib/stores/dataCube/{core/DataCubeEngine.d.ts → DataCubeInfrastructure.d.ts} +20 -4
  73. package/lib/stores/dataCube/DataCubeInfrastructure.d.ts.map +1 -0
  74. package/lib/stores/dataCube/{core/DataCubeEngine.js → DataCubeInfrastructure.js} +31 -3
  75. package/lib/stores/dataCube/DataCubeInfrastructure.js.map +1 -0
  76. package/lib/stores/dataCube/DataCubeState.d.ts +4 -4
  77. package/lib/stores/dataCube/DataCubeState.d.ts.map +1 -1
  78. package/lib/stores/dataCube/DataCubeState.js +7 -8
  79. package/lib/stores/dataCube/DataCubeState.js.map +1 -1
  80. package/lib/stores/dataCube/core/DataCubeConfiguration.d.ts +42 -38
  81. package/lib/stores/dataCube/core/DataCubeConfiguration.d.ts.map +1 -1
  82. package/lib/stores/dataCube/core/DataCubeConfiguration.js +84 -78
  83. package/lib/stores/dataCube/core/DataCubeConfiguration.js.map +1 -1
  84. package/lib/stores/dataCube/core/DataCubeConfigurationBuilder.d.ts.map +1 -1
  85. package/lib/stores/dataCube/core/DataCubeConfigurationBuilder.js +2 -1
  86. package/lib/stores/dataCube/core/DataCubeConfigurationBuilder.js.map +1 -1
  87. package/lib/stores/dataCube/core/DataCubeCoreState.d.ts +1 -1
  88. package/lib/stores/dataCube/core/DataCubeCoreState.d.ts.map +1 -1
  89. package/lib/stores/dataCube/core/DataCubeCoreState.js +1 -1
  90. package/lib/stores/dataCube/core/DataCubeCoreState.js.map +1 -1
  91. package/lib/stores/dataCube/core/DataCubeQueryBuilder.js +6 -6
  92. package/lib/stores/dataCube/core/DataCubeQueryBuilder.js.map +1 -1
  93. package/lib/stores/dataCube/core/DataCubeQueryEngine.d.ts +46 -29
  94. package/lib/stores/dataCube/core/DataCubeQueryEngine.d.ts.map +1 -1
  95. package/lib/stores/dataCube/core/DataCubeQueryEngine.js +68 -50
  96. package/lib/stores/dataCube/core/DataCubeQueryEngine.js.map +1 -1
  97. package/lib/stores/dataCube/core/DataCubeQuerySnapshotBuilder.d.ts.map +1 -1
  98. package/lib/stores/dataCube/core/DataCubeQuerySnapshotBuilder.js +5 -5
  99. package/lib/stores/dataCube/core/DataCubeQuerySnapshotBuilder.js.map +1 -1
  100. package/lib/stores/dataCube/core/DataCubeQuerySnapshotSubscriber.d.ts +1 -3
  101. package/lib/stores/dataCube/core/DataCubeQuerySnapshotSubscriber.d.ts.map +1 -1
  102. package/lib/stores/dataCube/core/DataCubeQuerySnapshotSubscriber.js +2 -3
  103. package/lib/stores/dataCube/core/DataCubeQuerySnapshotSubscriber.js.map +1 -1
  104. package/lib/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.d.ts +3 -0
  105. package/lib/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.d.ts.map +1 -1
  106. package/lib/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.js +9 -0
  107. package/lib/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.js.map +1 -1
  108. package/lib/stores/dataCube/editor/DataCubeEditorState.d.ts +8 -7
  109. package/lib/stores/dataCube/editor/DataCubeEditorState.d.ts.map +1 -1
  110. package/lib/stores/dataCube/editor/DataCubeEditorState.js +21 -17
  111. package/lib/stores/dataCube/editor/DataCubeEditorState.js.map +1 -1
  112. package/lib/stores/dataCube/editor/DataCubeMutableConfiguration.d.ts +43 -38
  113. package/lib/stores/dataCube/editor/DataCubeMutableConfiguration.d.ts.map +1 -1
  114. package/lib/stores/dataCube/editor/DataCubeMutableConfiguration.js +209 -128
  115. package/lib/stores/dataCube/editor/DataCubeMutableConfiguration.js.map +1 -1
  116. package/lib/stores/dataCube/grid/DataCubeGridClientEngine.d.ts +32 -0
  117. package/lib/stores/dataCube/grid/DataCubeGridClientEngine.d.ts.map +1 -1
  118. package/lib/stores/dataCube/grid/DataCubeGridClientEngine.js +34 -1
  119. package/lib/stores/dataCube/grid/DataCubeGridClientEngine.js.map +1 -1
  120. package/lib/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.d.ts +4 -1
  121. package/lib/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.d.ts.map +1 -1
  122. package/lib/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.js +327 -36
  123. package/lib/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.js.map +1 -1
  124. package/lib/stores/dataCube/grid/DataCubeGridState.d.ts +16 -2
  125. package/lib/stores/dataCube/grid/DataCubeGridState.d.ts.map +1 -1
  126. package/lib/stores/dataCube/grid/DataCubeGridState.js +51 -21
  127. package/lib/stores/dataCube/grid/DataCubeGridState.js.map +1 -1
  128. package/package.json +20 -20
  129. package/src/components/LegendREPLFrameworkProvider.tsx +1 -1
  130. package/src/components/REPLStoreProvider.tsx +1 -1
  131. package/src/components/REPLWindow.tsx +179 -0
  132. package/src/components/dataCube/DataCube.tsx +1 -1
  133. package/src/components/dataCube/editor/DataCubeEditor.tsx +79 -190
  134. package/src/components/dataCube/editor/DataCubeEditorCodePanel.tsx +3 -1
  135. package/src/components/dataCube/editor/DataCubeEditorColumnPropertiesPanel.tsx +480 -279
  136. package/src/components/dataCube/editor/DataCubeEditorColumnsPanel.tsx +1 -1
  137. package/src/components/dataCube/editor/DataCubeEditorColumnsSelector.tsx +0 -1
  138. package/src/components/dataCube/editor/DataCubeEditorDeveloperPanel.tsx +3 -1
  139. package/src/components/dataCube/editor/DataCubeEditorExtendedColumnsPanel.tsx +3 -1
  140. package/src/components/dataCube/editor/DataCubeEditorFilterPanel.tsx +3 -1
  141. package/src/components/dataCube/editor/DataCubeEditorGeneralPropertiesPanel.tsx +235 -174
  142. package/src/components/dataCube/editor/DataCubeEditorHPivotsPanel.tsx +3 -1
  143. package/src/components/dataCube/editor/DataCubeEditorShared.tsx +69 -33
  144. package/src/components/dataCube/editor/DataCubeEditorSortsPanel.tsx +1 -1
  145. package/src/components/dataCube/editor/DataCubeEditorVPivotsPanel.tsx +3 -1
  146. package/src/components/dataCube/grid/DataCubeGrid.tsx +310 -149
  147. package/src/components/dataCube/grid/DataCubeGridShared.tsx +5 -1
  148. package/src/components/dataCube/grid/menu/DataCubeGridMenu.tsx +76 -29
  149. package/src/components/dataCube/grid/menu/DataCubeGridSortsMenu.tsx +10 -11
  150. package/src/stores/{dataCube/REPLStore.ts → REPLStore.ts} +6 -3
  151. package/src/stores/dataCube/{core/DataCubeEngine.ts → DataCubeInfrastructure.ts} +40 -3
  152. package/src/stores/dataCube/DataCubeState.ts +9 -9
  153. package/src/stores/dataCube/core/DataCubeConfiguration.ts +106 -86
  154. package/src/stores/dataCube/core/DataCubeConfigurationBuilder.ts +5 -1
  155. package/src/stores/dataCube/core/DataCubeCoreState.ts +4 -1
  156. package/src/stores/dataCube/core/DataCubeQueryBuilder.ts +11 -11
  157. package/src/stores/dataCube/core/DataCubeQueryEngine.ts +70 -49
  158. package/src/stores/dataCube/core/DataCubeQuerySnapshotBuilder.ts +6 -7
  159. package/src/stores/dataCube/core/DataCubeQuerySnapshotSubscriber.ts +6 -5
  160. package/src/stores/dataCube/editor/DataCubeEditorColumnPropertiesPanelState.ts +14 -0
  161. package/src/stores/dataCube/editor/DataCubeEditorState.ts +26 -19
  162. package/src/stores/dataCube/editor/DataCubeMutableConfiguration.ts +247 -139
  163. package/src/stores/dataCube/grid/DataCubeGridClientEngine.ts +55 -1
  164. package/src/stores/dataCube/grid/DataCubeGridQuerySnapshotAnalyzer.tsx +491 -43
  165. package/src/stores/dataCube/grid/DataCubeGridState.ts +73 -20
  166. package/tsconfig.json +3 -2
  167. package/lib/stores/dataCube/REPLStore.d.ts.map +0 -1
  168. package/lib/stores/dataCube/REPLStore.js.map +0 -1
  169. package/lib/stores/dataCube/core/DataCubeEngine.d.ts.map +0 -1
  170. package/lib/stores/dataCube/core/DataCubeEngine.js.map +0 -1
@@ -28,18 +28,79 @@ import {
28
28
  type DataCubeQuerySnapshot,
29
29
  type DataCubeQuerySnapshotColumn,
30
30
  } from '../core/DataCubeQuerySnapshot.js';
31
- import type { ColDef, ColGroupDef, GridOptions } from '@ag-grid-community/core';
31
+ import type {
32
+ ColDef,
33
+ ColGroupDef,
34
+ GridOptions,
35
+ ICellRendererParams,
36
+ } from '@ag-grid-community/core';
32
37
  import {
33
38
  INTERNAL__GRID_CLIENT_TREE_COLUMN_ID,
34
39
  GridClientAggregateOperation,
35
40
  GridClientSortDirection,
41
+ INTERNAL__GRID_CLIENT_COLUMN_MIN_WIDTH,
42
+ INTERNAL__GRID_CLIENT_UTILITY_CSS_CLASS_NAME,
43
+ generateFontFamilyUtilityClassName,
44
+ generateFontSizeUtilityClassName,
45
+ generateFontUnderlineUtilityClassName,
46
+ generateTextAlignUtilityClassName,
47
+ generateTextColorUtilityClassName,
48
+ generateBackgroundColorUtilityClassName,
49
+ generateFontCaseUtilityClassName,
50
+ GridClientPinnedAlignement,
51
+ INTERNAL__GRID_CLIENT_ROW_HEIGHT,
52
+ INTERNAL__GRID_CLIENT_AUTO_RESIZE_PADDING,
53
+ INTERNAL__GRID_CLIENT_HEADER_HEIGHT,
54
+ INTERNAL__GRID_CLIENT_TOOLTIP_SHOW_DELAY,
36
55
  } from './DataCubeGridClientEngine.js';
37
56
  import { PRIMITIVE_TYPE } from '@finos/legend-graph';
38
- import { IllegalStateError } from '@finos/legend-shared';
57
+ import {
58
+ getQueryParameters,
59
+ getQueryParameterValue,
60
+ guaranteeNonNullable,
61
+ IllegalStateError,
62
+ isNonNullable,
63
+ isNumber,
64
+ isValidUrl,
65
+ } from '@finos/legend-shared';
66
+ import type {
67
+ DataCubeColumnConfiguration,
68
+ DataCubeConfiguration,
69
+ } from '../core/DataCubeConfiguration.js';
70
+ import {
71
+ DataCubeColumnDataType,
72
+ DataCubeColumnPinPlacement,
73
+ DataCubeNumberScale,
74
+ DEFAULT_ROW_BUFFER,
75
+ DEFAULT_URL_LABEL_QUERY_PARAM,
76
+ getDataType,
77
+ } from '../core/DataCubeQueryEngine.js';
78
+ import type { CustomLoadingCellRendererProps } from '@ag-grid-community/react';
79
+ import { DataCubeIcon } from '@finos/legend-art';
80
+ import type { DataCubeState } from '../DataCubeState.js';
81
+ import { buildGridMenu } from '../../../components/dataCube/grid/menu/DataCubeGridMenu.js';
39
82
 
40
83
  // --------------------------------- UTILITIES ---------------------------------
41
84
 
42
- function _allowedAggFuncs(column: DataCubeQuerySnapshotColumn): string[] {
85
+ // See https://www.ag-grid.com/javascript-data-grid/cell-data-types/
86
+ function _cellDataType(column: DataCubeQuerySnapshotColumn) {
87
+ switch (column.type) {
88
+ case PRIMITIVE_TYPE.NUMBER:
89
+ case PRIMITIVE_TYPE.DECIMAL:
90
+ case PRIMITIVE_TYPE.INTEGER:
91
+ case PRIMITIVE_TYPE.FLOAT:
92
+ return 'number';
93
+ case PRIMITIVE_TYPE.DATE:
94
+ case PRIMITIVE_TYPE.DATETIME:
95
+ case PRIMITIVE_TYPE.STRICTDATE:
96
+ return 'dateString';
97
+ case PRIMITIVE_TYPE.STRING:
98
+ default:
99
+ return 'text';
100
+ }
101
+ }
102
+
103
+ function _allowedAggFuncs(column: DataCubeQuerySnapshotColumn) {
43
104
  switch (column.type) {
44
105
  case PRIMITIVE_TYPE.STRING:
45
106
  return [];
@@ -82,38 +143,286 @@ function _aggFunc(
82
143
  }
83
144
  }
84
145
 
146
+ function scaleNumber(
147
+ value: number,
148
+ type: DataCubeNumberScale | undefined,
149
+ ): { value: number; unit: string | undefined } {
150
+ switch (type) {
151
+ case DataCubeNumberScale.PERCENT:
152
+ return { value: value * 1e2, unit: '%' };
153
+ case DataCubeNumberScale.BASIS_POINT:
154
+ return { value: value * 1e4, unit: 'bp' };
155
+ case DataCubeNumberScale.THOUSANDS:
156
+ return { value: value / 1e3, unit: 'k' };
157
+ case DataCubeNumberScale.MILLIONS:
158
+ return { value: value / 1e6, unit: 'm' };
159
+ case DataCubeNumberScale.BILLIONS:
160
+ return { value: value / 1e9, unit: 'b' };
161
+ case DataCubeNumberScale.TRILLIONS:
162
+ return { value: value / 1e12, unit: 't' };
163
+ case DataCubeNumberScale.AUTO:
164
+ return scaleNumber(
165
+ value,
166
+ value >= 1e12
167
+ ? DataCubeNumberScale.TRILLIONS
168
+ : value >= 1e9
169
+ ? DataCubeNumberScale.BILLIONS
170
+ : value >= 1e6
171
+ ? DataCubeNumberScale.MILLIONS
172
+ : value >= 1e3
173
+ ? DataCubeNumberScale.THOUSANDS
174
+ : undefined,
175
+ );
176
+ default:
177
+ return { value, unit: undefined };
178
+ }
179
+ }
180
+
181
+ function DataCubeGridLoadingCellRenderer(
182
+ props: CustomLoadingCellRendererProps,
183
+ ) {
184
+ if (props.node.failedLoad) {
185
+ return <span className="inline-flex items-center">#ERR</span>;
186
+ }
187
+ return (
188
+ <span className="inline-flex items-center">
189
+ <DataCubeIcon.Loader className="mr-1 animate-spin stroke-2" />
190
+ Loading
191
+ </span>
192
+ );
193
+ }
194
+
85
195
  // --------------------------------- BUILDING BLOCKS ---------------------------------
86
196
 
87
- function _sortSpec(snapshot: DataCubeQuerySnapshot, colName: string) {
88
- const sortColumns = snapshot.data.sortColumns;
89
- const sortCol = _findCol(sortColumns, colName);
90
- if (!sortCol) {
91
- return {
92
- sort: null,
93
- sortIndex: null,
197
+ type ColumnData = {
198
+ snapshot: DataCubeQuerySnapshot;
199
+ column: DataCubeQuerySnapshotColumn;
200
+ configuration: DataCubeColumnConfiguration;
201
+ gridConfiguration: DataCubeConfiguration;
202
+ };
203
+
204
+ function getCellRenderer(columnData: ColumnData) {
205
+ const { column, configuration } = columnData;
206
+ const dataType = getDataType(column.type);
207
+ if (dataType === DataCubeColumnDataType.TEXT && configuration.displayAsLink) {
208
+ return function LinkRenderer(params: ICellRendererParams) {
209
+ const isUrl = isValidUrl(params.value);
210
+ if (!isUrl) {
211
+ return params.value;
212
+ }
213
+ const url = params.value as string;
214
+ const label = getQueryParameterValue(
215
+ configuration.linkLabelParameter ?? DEFAULT_URL_LABEL_QUERY_PARAM,
216
+ getQueryParameters(url, true),
217
+ );
218
+ return (
219
+ <a
220
+ href={url}
221
+ target="_blank"
222
+ rel="noreferrer"
223
+ className="text-blue-600 underline"
224
+ >
225
+ {label ?? url}
226
+ </a>
227
+ );
94
228
  };
95
229
  }
230
+ return null;
231
+ }
232
+
233
+ function _displaySpec(columnData: ColumnData) {
234
+ const { column, configuration, gridConfiguration } = columnData;
235
+ const dataType = getDataType(column.type);
236
+ const fontFamily = configuration.fontFamily ?? gridConfiguration.fontFamily;
237
+ const fontSize = configuration.fontSize ?? gridConfiguration.fontSize;
238
+ const fontBold = configuration.fontBold ?? gridConfiguration.fontBold;
239
+ const fontItalic = configuration.fontItalic ?? gridConfiguration.fontItalic;
240
+ const fontStrikethrough =
241
+ configuration.fontStrikethrough ?? gridConfiguration.fontStrikethrough;
242
+ const fontUnderline =
243
+ configuration.fontUnderline ?? gridConfiguration.fontUnderline;
244
+ const fontCase = configuration.fontCase ?? gridConfiguration.fontCase;
245
+ const textAlign = configuration.textAlign ?? gridConfiguration.textAlign;
246
+ const normalForegroundColor =
247
+ configuration.normalForegroundColor ??
248
+ gridConfiguration.normalForegroundColor;
249
+ const normalBackgroundColor =
250
+ configuration.normalBackgroundColor ??
251
+ gridConfiguration.normalBackgroundColor;
252
+ const negativeForegroundColor =
253
+ configuration.negativeForegroundColor ??
254
+ gridConfiguration.negativeForegroundColor;
255
+ const negativeBackgroundColor =
256
+ configuration.negativeBackgroundColor ??
257
+ gridConfiguration.negativeBackgroundColor;
258
+ const zeroForegroundColor =
259
+ configuration.zeroForegroundColor ?? gridConfiguration.zeroForegroundColor;
260
+ const zeroBackgroundColor =
261
+ configuration.zeroBackgroundColor ?? gridConfiguration.zeroBackgroundColor;
262
+ const errorForegroundColor =
263
+ configuration.errorForegroundColor ??
264
+ gridConfiguration.errorForegroundColor;
265
+ const errorBackgroundColor =
266
+ configuration.errorBackgroundColor ??
267
+ gridConfiguration.errorBackgroundColor;
268
+ const cellRenderer = getCellRenderer(columnData);
269
+ return {
270
+ // setting the cell data type might helps guide the grid to render the cell properly
271
+ // and optimize the grid performance slightly by avoiding unnecessary type inference
272
+ cellDataType: _cellDataType(column),
273
+ valueFormatter:
274
+ dataType === DataCubeColumnDataType.NUMBER
275
+ ? (params) => {
276
+ const value = params.value as number | null | undefined;
277
+ if (value === null || value === undefined) {
278
+ return null;
279
+ }
280
+ const showNegativeNumberInParens =
281
+ configuration.negativeNumberInParens && value < 0;
282
+ // 1. apply the number scale
283
+ const scaledNumber = scaleNumber(value, configuration.numberScale);
284
+ // 2. apply the number formatter
285
+ const formattedValue = (
286
+ showNegativeNumberInParens
287
+ ? Math.abs(scaledNumber.value)
288
+ : scaledNumber.value
289
+ ).toLocaleString(undefined, {
290
+ useGrouping: configuration.displayCommas,
291
+ ...(configuration.decimals !== undefined
292
+ ? {
293
+ minimumFractionDigits: configuration.decimals,
294
+ maximumFractionDigits: configuration.decimals,
295
+ }
296
+ : {}),
297
+ });
298
+ // 3. add the parentheses (and then the unit)
299
+ return (
300
+ (showNegativeNumberInParens
301
+ ? `(${formattedValue})`
302
+ : formattedValue) +
303
+ (scaledNumber.unit ? ` ${scaledNumber.unit}` : '')
304
+ );
305
+ }
306
+ : (params) => params.value,
307
+ loadingCellRenderer: DataCubeGridLoadingCellRenderer,
308
+ cellClassRules: {
309
+ [generateFontFamilyUtilityClassName(fontFamily)]: () => true,
310
+ [generateFontSizeUtilityClassName(fontSize)]: () => true,
311
+ [INTERNAL__GRID_CLIENT_UTILITY_CSS_CLASS_NAME.FONT_BOLD]: () => fontBold,
312
+ [INTERNAL__GRID_CLIENT_UTILITY_CSS_CLASS_NAME.FONT_ITALIC]: () =>
313
+ fontItalic,
314
+ [INTERNAL__GRID_CLIENT_UTILITY_CSS_CLASS_NAME.FONT_STRIKETHROUGH]: () =>
315
+ fontStrikethrough,
316
+ [generateFontUnderlineUtilityClassName(fontUnderline)]: () =>
317
+ Boolean(fontUnderline),
318
+ [generateFontCaseUtilityClassName(fontCase)]: (params) =>
319
+ dataType === DataCubeColumnDataType.TEXT && Boolean(fontCase),
320
+ [generateTextAlignUtilityClassName(textAlign)]: () => true,
321
+ [generateTextColorUtilityClassName(normalForegroundColor, 'normal')]:
322
+ () => true,
323
+ [generateBackgroundColorUtilityClassName(
324
+ normalBackgroundColor,
325
+ 'normal',
326
+ )]: () => true,
327
+ [generateTextColorUtilityClassName(zeroForegroundColor, 'zero')]: (
328
+ params,
329
+ ) =>
330
+ dataType === DataCubeColumnDataType.NUMBER &&
331
+ isNumber(params.value) &&
332
+ params.value === 0,
333
+ [generateBackgroundColorUtilityClassName(zeroBackgroundColor, 'zero')]: (
334
+ params,
335
+ ) =>
336
+ dataType === DataCubeColumnDataType.NUMBER &&
337
+ isNumber(params.value) &&
338
+ params.value === 0,
339
+ [generateTextColorUtilityClassName(negativeForegroundColor, 'negative')]:
340
+ (params) =>
341
+ dataType === DataCubeColumnDataType.NUMBER &&
342
+ isNumber(params.value) &&
343
+ params.value < 0,
344
+ [generateBackgroundColorUtilityClassName(
345
+ negativeBackgroundColor,
346
+ 'negative',
347
+ )]: (params) =>
348
+ dataType === DataCubeColumnDataType.NUMBER &&
349
+ isNumber(params.value) &&
350
+ params.value < 0,
351
+ [generateTextColorUtilityClassName(errorForegroundColor, 'error')]: (
352
+ params,
353
+ ) => params.node.failedLoad,
354
+ [generateBackgroundColorUtilityClassName(errorBackgroundColor, 'error')]:
355
+ (params) => params.node.failedLoad,
356
+ [INTERNAL__GRID_CLIENT_UTILITY_CSS_CLASS_NAME.BLUR]: () =>
357
+ configuration.blur,
358
+ },
359
+ cellRenderer: cellRenderer,
360
+ pinned:
361
+ configuration.pinned !== undefined
362
+ ? configuration.pinned === DataCubeColumnPinPlacement.RIGHT
363
+ ? GridClientPinnedAlignement.RIGHT
364
+ : GridClientPinnedAlignement.LEFT
365
+ : null,
366
+ tooltipValueGetter: (params) =>
367
+ isNonNullable(params.value)
368
+ ? `Value = ${params.value === '' ? "''" : params.value === true ? 'TRUE' : params.value === false ? 'FALSE' : params.value}`
369
+ : `Missing Value`,
370
+ } as ColDef;
371
+ }
372
+
373
+ function _sizeSpec(columnData: ColumnData) {
374
+ const { configuration } = columnData;
96
375
  return {
97
- sort:
98
- sortCol.operation === DataCubeQuerySnapshotSortOperation.ASCENDING
376
+ // NOTE: there is a problem with ag-grid when scrolling horizontally, the header row
377
+ // lags behind the data, it seems to be caused by synchronizing scroll not working properly
378
+ // There is currently, no way around this
379
+ // See https://github.com/ag-grid/ag-grid/issues/5233
380
+ // See https://github.com/ag-grid/ag-grid/issues/7620
381
+ // See https://github.com/ag-grid/ag-grid/issues/6292
382
+ // See https://issues.chromium.org/issues/40890343#comment11
383
+ //
384
+ // TODO: if we support column resize to fit content, should we disable this behavior?
385
+ resizable: configuration.fixedWidth === undefined,
386
+ // suppressAutoSize: columnConfiguration.fixedWidth !== undefined,
387
+ width: configuration.fixedWidth,
388
+ minWidth: Math.max(
389
+ configuration.minWidth ?? INTERNAL__GRID_CLIENT_COLUMN_MIN_WIDTH,
390
+ INTERNAL__GRID_CLIENT_COLUMN_MIN_WIDTH,
391
+ ),
392
+ maxWidth: configuration.maxWidth,
393
+ } as ColDef;
394
+ }
395
+
396
+ function _sortSpec(columnData: ColumnData) {
397
+ const { snapshot, column } = columnData;
398
+ const sortColumns = snapshot.data.sortColumns;
399
+ const sortCol = _findCol(sortColumns, column.name);
400
+ return {
401
+ sortable: true, // if this is pivot column, no sorting is allowed
402
+ sort: sortCol
403
+ ? sortCol.operation === DataCubeQuerySnapshotSortOperation.ASCENDING
99
404
  ? GridClientSortDirection.ASCENDING
100
- : GridClientSortDirection.DESCENDING,
101
- sortIndex: sortColumns.indexOf(sortCol),
102
- } satisfies ColDef;
405
+ : GridClientSortDirection.DESCENDING
406
+ : null,
407
+ sortIndex: sortCol ? sortColumns.indexOf(sortCol) : null,
408
+ } as ColDef;
103
409
  }
104
410
 
105
- function _rowGroupSpec(snapshot: DataCubeQuerySnapshot, colName: string) {
411
+ function _rowGroupSpec(columnData: ColumnData) {
412
+ const { snapshot, column } = columnData;
106
413
  const data = snapshot.data;
107
414
  const columns = snapshot.stageCols('aggregation');
108
- const column = _findCol(columns, colName);
109
- const groupByCol = _findCol(data.groupBy?.columns, colName);
110
- const aggCol = _findCol(data.groupBy?.aggColumns, colName);
415
+ const rowGroupColumn = _findCol(columns, column.name);
416
+ const groupByCol = _findCol(data.groupBy?.columns, column.name);
417
+ const aggCol = _findCol(data.groupBy?.aggColumns, column.name);
111
418
  return {
419
+ enableRowGroup: true,
420
+ enableValue: true,
112
421
  rowGroup: Boolean(groupByCol),
113
422
  // TODO: @akphi - add this from configuration object
114
423
  aggFunc: aggCol
115
424
  ? _aggFunc(aggCol.function)
116
- : column
425
+ : rowGroupColumn
117
426
  ? (
118
427
  [
119
428
  PRIMITIVE_TYPE.NUMBER,
@@ -121,20 +430,151 @@ function _rowGroupSpec(snapshot: DataCubeQuerySnapshot, colName: string) {
121
430
  PRIMITIVE_TYPE.FLOAT,
122
431
  PRIMITIVE_TYPE.INTEGER,
123
432
  ] as string[]
124
- ).includes(column.type)
433
+ ).includes(rowGroupColumn.type)
125
434
  ? GridClientAggregateOperation.SUM
126
435
  : null
127
436
  : null,
128
437
  // TODO: @akphi - add this from configuration object
129
- allowedAggFuncs: column ? _allowedAggFuncs(column) : [],
438
+ allowedAggFuncs: rowGroupColumn ? _allowedAggFuncs(rowGroupColumn) : [],
130
439
  } satisfies ColDef;
131
440
  }
132
441
 
442
+ // --------------------------------- MAIN ---------------------------------
443
+
444
+ export function generateBaseGridOptions(dataCube: DataCubeState): GridOptions {
445
+ const grid = dataCube.grid;
446
+
447
+ return {
448
+ // -------------------------------------- README --------------------------------------
449
+ // NOTE: we observe performance degradataion when configuring the grid via React component
450
+ // props when the options is non-static, i.e. changed when the query configuration changes.
451
+ // As such, we must ONLY ADD STATIC CONFIGURATION HERE, and dynamic configuration should be
452
+ // programatically updated when the query is modified.
453
+ //
454
+ //
455
+ // -------------------------------------- ROW GROUPING --------------------------------------
456
+ rowGroupPanelShow: 'always',
457
+ groupDisplayType: 'custom', // keeps the column set stable even when row grouping is used
458
+ suppressRowGroupHidesColumns: true, // keeps the column set stable even when row grouping is used
459
+ suppressAggFuncInHeader: true, // keeps the columns stable when aggregation is used
460
+ // -------------------------------------- PIVOT --------------------------------------
461
+ // pivotPanelShow: "always"
462
+ // pivotMode:true,
463
+ // -------------------------------------- SORT --------------------------------------
464
+ // Force multi-sorting since this is what the query supports anyway
465
+ alwaysMultiSort: true,
466
+ // -------------------------------------- DISPLAY --------------------------------------
467
+ rowHeight: INTERNAL__GRID_CLIENT_ROW_HEIGHT,
468
+ headerHeight: INTERNAL__GRID_CLIENT_HEADER_HEIGHT,
469
+ suppressBrowserResizeObserver: true,
470
+ noRowsOverlayComponent: () => (
471
+ <div className="flex items-center border-[1.5px] border-neutral-300 p-2 font-medium text-neutral-400">
472
+ <div>
473
+ <DataCubeIcon.WarningCircle className="mr-1 stroke-2 text-lg" />
474
+ </div>
475
+ 0 rows
476
+ </div>
477
+ ),
478
+ loadingOverlayComponent: () => (
479
+ <div className="flex items-center border-[1.5px] border-neutral-300 p-2 font-medium text-neutral-400">
480
+ <div>
481
+ <DataCubeIcon.Loader className="mr-1 animate-spin stroke-2 text-lg" />
482
+ </div>
483
+ Loading...
484
+ </div>
485
+ ),
486
+ // Show cursor position when scrolling
487
+ onBodyScroll: (event) => {
488
+ const rowCount = event.api.getDisplayedRowCount();
489
+ const range = event.api.getVerticalPixelRange();
490
+ const start = Math.max(
491
+ 1,
492
+ Math.ceil(range.top / INTERNAL__GRID_CLIENT_ROW_HEIGHT) + 1,
493
+ );
494
+ const end = Math.min(
495
+ rowCount,
496
+ Math.floor(range.bottom / INTERNAL__GRID_CLIENT_ROW_HEIGHT),
497
+ );
498
+ grid.setScrollHintText(`${start}-${end}/${rowCount}`);
499
+ event.api.hidePopupMenu(); // hide context-menu while scrolling
500
+ },
501
+ onBodyScrollEnd: () => grid.setScrollHintText(''),
502
+ // -------------------------------------- CONTEXT MENU --------------------------------------
503
+ preventDefaultOnContextMenu: true, // prevent showing the browser's context menu
504
+ columnMenu: 'new', // ensure context menu works on header
505
+ getContextMenuItems: buildGridMenu,
506
+ getMainMenuItems: buildGridMenu,
507
+ // -------------------------------------- COLUMN SIZING --------------------------------------
508
+ autoSizePadding: INTERNAL__GRID_CLIENT_AUTO_RESIZE_PADDING,
509
+ autoSizeStrategy: {
510
+ // resize to fit content initially
511
+ type: 'fitCellContents',
512
+ },
513
+ // -------------------------------------- TOOLTIP --------------------------------------
514
+ tooltipShowDelay: INTERNAL__GRID_CLIENT_TOOLTIP_SHOW_DELAY,
515
+ tooltipInteraction: true,
516
+ // -------------------------------------- COLUMN MOVING --------------------------------------
517
+ suppressDragLeaveHidesColumns: true,
518
+ // -------------------------------------- SERVER SIDE ROW MODEL --------------------------------------
519
+ suppressScrollOnNewData: true,
520
+ suppressServerSideFullWidthLoadingRow: true, // make sure each column has its own loading indicator instead of the whole row
521
+ // -------------------------------------- SELECTION --------------------------------------
522
+ enableRangeSelection: true,
523
+ // -------------------------------------- PERFORMANCE --------------------------------------
524
+ animateRows: false, // improve performance
525
+ suppressColumnMoveAnimation: true, // improve performance
526
+ };
527
+ }
528
+
133
529
  export function generateGridOptionsFromSnapshot(
134
530
  snapshot: DataCubeQuerySnapshot,
531
+ configuration: DataCubeConfiguration,
532
+ dataCube: DataCubeState,
135
533
  ): GridOptions {
136
534
  const data = snapshot.data;
137
- const gridOptions: GridOptions = {
535
+ const gridOptions = {
536
+ /**
537
+ * NOTE: there is a strange issue where if we put dynamic configuration directly
538
+ * such as rowClassRules which depends on some changing state (e.g. alternateRows)
539
+ * as the grid component's props, the grid performance will be heavily compromised
540
+ * while if we programatically set it like this, it does not seem so taxing to the
541
+ * performance; perhaps something to do with React component rendering on props change
542
+ * so in general for grid options which are not static, we must configure them here
543
+ */
544
+ rowClassRules: configuration.alternateRows
545
+ ? {
546
+ [INTERNAL__GRID_CLIENT_UTILITY_CSS_CLASS_NAME.HIGHLIGHT_ROW]: (
547
+ params,
548
+ ) =>
549
+ params.rowIndex % (configuration.alternateRowsCount * 2) >=
550
+ configuration.alternateRowsCount,
551
+ }
552
+ : null,
553
+ rowBuffer: DEFAULT_ROW_BUFFER,
554
+
555
+ // -------------------------------------- EVENT HANDLERS --------------------------------------
556
+
557
+ onColumnPinned: (event) => {
558
+ if (event.column) {
559
+ const column = event.column;
560
+ const columnConfiguration =
561
+ dataCube.editor.columnProperties.getColumnConfiguration(
562
+ column.getColId(),
563
+ );
564
+ const pinned = column.getPinned();
565
+ columnConfiguration?.setPinned(
566
+ pinned === null
567
+ ? undefined
568
+ : pinned === GridClientPinnedAlignement.LEFT
569
+ ? DataCubeColumnPinPlacement.LEFT
570
+ : DataCubeColumnPinPlacement.RIGHT,
571
+ );
572
+ dataCube.editor.applyChanges();
573
+ }
574
+ },
575
+
576
+ // -------------------------------------- COLUMNS --------------------------------------
577
+
138
578
  columnDefs: [
139
579
  {
140
580
  headerName: '',
@@ -159,34 +599,42 @@ export function generateGridOptionsFromSnapshot(
159
599
  hide: !snapshot.data.groupBy,
160
600
  lockPinned: true,
161
601
  lockPosition: true,
602
+ pinned: GridClientPinnedAlignement.LEFT,
162
603
  cellStyle: {
163
604
  flex: 1,
164
605
  justifyContent: 'space-between',
165
606
  display: 'flex',
166
607
  },
608
+ // TODO: display: coloring, text, etc.
609
+ // TODO: pinning (should we pin this left by default?)
610
+ // TODO: tooltip
611
+ loadingCellRenderer: DataCubeGridLoadingCellRenderer,
167
612
  sortable: false, // TODO: @akphi - we can support this in the configuration
168
613
  } satisfies ColDef,
169
- ...data.selectColumns.map(
170
- (col) =>
171
- ({
172
- headerName: col.name,
173
- field: col.name,
174
-
175
- // TODO: configure
176
- flex: 1, // when the column supposed to fill the remainig space of the grid
177
- resizable: true,
178
- minWidth: 50,
179
-
180
- sortable: true, // if this is pivot column, no sorting is allowed
181
- enableRowGroup: true,
182
- enableValue: true,
183
- menuTabs: ['generalMenuTab', 'columnsMenuTab'],
184
- ..._sortSpec(snapshot, col.name),
185
- ..._rowGroupSpec(snapshot, col.name),
186
- }) satisfies ColDef | ColGroupDef,
187
- ),
614
+ // TODO: handle pivot and column grouping
615
+ ...data.selectColumns.map((column) => {
616
+ const columnData = {
617
+ snapshot,
618
+ column,
619
+ configuration: guaranteeNonNullable(
620
+ configuration.columns.find((col) => col.name === column.name),
621
+ ),
622
+ gridConfiguration: configuration,
623
+ };
624
+ return {
625
+ headerName: column.name,
626
+ field: column.name,
627
+ menuTabs: [],
628
+ suppressMovable: true,
629
+
630
+ ..._displaySpec(columnData),
631
+ ..._sizeSpec(columnData),
632
+ ..._sortSpec(columnData),
633
+ ..._rowGroupSpec(columnData),
634
+ } satisfies ColDef | ColGroupDef;
635
+ }),
188
636
  ],
189
- };
637
+ } as GridOptions;
190
638
 
191
639
  return gridOptions;
192
640
  }