@finos/legend-data-cube 0.0.24 → 0.0.26
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/docs/column-configuration.display-value-as-link.md +6 -0
- package/docs/column-configuration.kind.md +14 -0
- package/docs/column-configuration.missing-value-format.md +5 -0
- package/docs/column-configuration.unit.md +5 -0
- package/docs/extended-column.level.md +14 -0
- package/docs/grid-configuration.row-limit.md +5 -0
- package/lib/__lib__/DataCubeDocumentation.d.ts +5 -3
- package/lib/__lib__/DataCubeDocumentation.d.ts.map +1 -1
- package/lib/__lib__/DataCubeDocumentation.js +5 -3
- package/lib/__lib__/DataCubeDocumentation.js.map +1 -1
- package/lib/components/core/DataCubeFormUtils.d.ts +1 -0
- package/lib/components/core/DataCubeFormUtils.d.ts.map +1 -1
- package/lib/components/core/DataCubeFormUtils.js +4 -3
- package/lib/components/core/DataCubeFormUtils.js.map +1 -1
- package/lib/components/view/editor/DataCubeEditorColumnPropertiesPanel.d.ts.map +1 -1
- package/lib/components/view/editor/DataCubeEditorColumnPropertiesPanel.js +12 -9
- package/lib/components/view/editor/DataCubeEditorColumnPropertiesPanel.js.map +1 -1
- package/lib/components/view/editor/DataCubeEditorColumnSelector.js +2 -2
- package/lib/components/view/editor/DataCubeEditorGeneralPropertiesPanel.d.ts.map +1 -1
- package/lib/components/view/editor/DataCubeEditorGeneralPropertiesPanel.js +8 -7
- package/lib/components/view/editor/DataCubeEditorGeneralPropertiesPanel.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +3 -3
- package/lib/stores/core/DataCubeQueryBuilder.d.ts +3 -0
- package/lib/stores/core/DataCubeQueryBuilder.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilder.js +8 -1
- package/lib/stores/core/DataCubeQueryBuilder.js.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts +1 -0
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.js +14 -7
- package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
- package/lib/stores/core/DataCubeQueryEngine.d.ts +6 -0
- package/lib/stores/core/DataCubeQueryEngine.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryEngine.js +7 -0
- package/lib/stores/core/DataCubeQueryEngine.js.map +1 -1
- package/lib/stores/core/models/DataCubeConfiguration.d.ts +1 -0
- package/lib/stores/core/models/DataCubeConfiguration.d.ts.map +1 -1
- package/lib/stores/core/models/DataCubeConfiguration.js +2 -0
- package/lib/stores/core/models/DataCubeConfiguration.js.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.d.ts +2 -2
- package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.d.ts.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.js +4 -3
- package/lib/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.js.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.d.ts +1 -0
- package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.d.ts.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.js +5 -0
- package/lib/stores/view/editor/DataCubeEditorMutableConfiguration.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts +14 -2
- package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.js +48 -42
- package/lib/stores/view/grid/DataCubeGridClientEngine.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts +20 -3
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js +89 -40
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridMenuBuilder.js +1 -1
- package/lib/stores/view/grid/DataCubeGridMenuBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts +13 -4
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.js +40 -9
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.d.ts +2 -2
- package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.js +30 -14
- package/lib/stores/view/grid/DataCubeGridQuerySnapshotBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridState.d.ts +2 -0
- package/lib/stores/view/grid/DataCubeGridState.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridState.js +5 -1
- package/lib/stores/view/grid/DataCubeGridState.js.map +1 -1
- package/package.json +8 -8
- package/src/__lib__/DataCubeDocumentation.ts +5 -3
- package/src/components/core/DataCubeFormUtils.tsx +5 -1
- package/src/components/view/editor/DataCubeEditorColumnPropertiesPanel.tsx +40 -14
- package/src/components/view/editor/DataCubeEditorColumnSelector.tsx +2 -2
- package/src/components/view/editor/DataCubeEditorGeneralPropertiesPanel.tsx +41 -30
- package/src/stores/core/DataCubeQueryBuilder.ts +13 -0
- package/src/stores/core/DataCubeQueryBuilderUtils.ts +32 -6
- package/src/stores/core/DataCubeQueryEngine.ts +8 -0
- package/src/stores/core/models/DataCubeConfiguration.ts +2 -0
- package/src/stores/view/editor/DataCubeEditorGeneralPropertiesPanelState.ts +5 -4
- package/src/stores/view/editor/DataCubeEditorMutableConfiguration.ts +7 -0
- package/src/stores/view/grid/DataCubeGridClientEngine.ts +67 -52
- package/src/stores/view/grid/DataCubeGridConfigurationBuilder.tsx +99 -42
- package/src/stores/view/grid/DataCubeGridMenuBuilder.tsx +1 -1
- package/src/stores/view/grid/DataCubeGridQueryBuilder.ts +71 -15
- package/src/stores/view/grid/DataCubeGridQuerySnapshotBuilder.ts +40 -20
- package/src/stores/view/grid/DataCubeGridState.ts +12 -1
- package/tsconfig.json +2 -0
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
DEFAULT_NEGATIVE_FOREGROUND_COLOR,
|
|
30
30
|
DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR,
|
|
31
31
|
DEFAULT_ZERO_FOREGROUND_COLOR,
|
|
32
|
+
EMPTY_VALUE_PLACEHOLDER,
|
|
32
33
|
} from '../../../stores/core/DataCubeQueryEngine.js';
|
|
33
34
|
import {
|
|
34
35
|
FormCheckbox,
|
|
@@ -40,8 +41,10 @@ import {
|
|
|
40
41
|
FormTextInput,
|
|
41
42
|
FormNumberInput,
|
|
42
43
|
FormBadge_WIP,
|
|
44
|
+
FormDocumentation,
|
|
43
45
|
} from '../../core/DataCubeFormUtils.js';
|
|
44
46
|
import type { DataCubeViewState } from '../../../stores/view/DataCubeViewState.js';
|
|
47
|
+
import { DocumentationKey } from '../../../__lib__/DataCubeDocumentation.js';
|
|
45
48
|
|
|
46
49
|
export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
47
50
|
(props: { view: DataCubeViewState }) => {
|
|
@@ -117,9 +120,7 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
117
120
|
!configuration.showRootAggregation,
|
|
118
121
|
)
|
|
119
122
|
}
|
|
120
|
-
disabled={true}
|
|
121
123
|
/>
|
|
122
|
-
<FormBadge_WIP />
|
|
123
124
|
<FormCheckbox
|
|
124
125
|
className="ml-3"
|
|
125
126
|
label="Show leaf count"
|
|
@@ -128,7 +129,11 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
128
129
|
configuration.setShowLeafCount(!configuration.showLeafCount)
|
|
129
130
|
}
|
|
130
131
|
/>
|
|
131
|
-
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<div className="mt-2 flex h-5 w-full items-center">
|
|
135
|
+
<div className="flex h-full w-32 flex-shrink-0 items-center text-sm" />
|
|
136
|
+
<div className="mr-1 flex h-full flex-shrink-0 items-center text-sm">
|
|
132
137
|
Sort:
|
|
133
138
|
</div>
|
|
134
139
|
<FormDropdownMenuTrigger
|
|
@@ -160,19 +165,18 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
160
165
|
</FormDropdownMenuItem>
|
|
161
166
|
))}
|
|
162
167
|
</FormDropdownMenu>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<div className="mt-2 flex h-5 w-full items-center">
|
|
166
|
-
<div className="flex h-full w-32 flex-shrink-0 items-center text-sm" />
|
|
167
|
-
<div className="mr-1.5 flex h-full flex-shrink-0 items-center text-sm">
|
|
168
|
+
<div className="ml-3 mr-1 flex h-full flex-shrink-0 items-center text-sm">
|
|
168
169
|
Initially expand to level:
|
|
169
170
|
</div>
|
|
170
171
|
<FormDropdownMenuTrigger
|
|
171
172
|
className="w-16"
|
|
172
173
|
onClick={openInitialExpandLevelDropdown}
|
|
173
174
|
open={initialExpandLevelDropdownPropsOpen}
|
|
175
|
+
showAsPlaceholder={
|
|
176
|
+
configuration.initialExpandLevel === undefined
|
|
177
|
+
}
|
|
174
178
|
>
|
|
175
|
-
{configuration.initialExpandLevel ??
|
|
179
|
+
{configuration.initialExpandLevel ?? EMPTY_VALUE_PLACEHOLDER}
|
|
176
180
|
</FormDropdownMenuTrigger>
|
|
177
181
|
<FormDropdownMenu
|
|
178
182
|
className="w-16"
|
|
@@ -187,7 +191,7 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
187
191
|
}}
|
|
188
192
|
autoFocus={level === configuration.initialExpandLevel}
|
|
189
193
|
>
|
|
190
|
-
{level ??
|
|
194
|
+
{level ?? EMPTY_VALUE_PLACEHOLDER}
|
|
191
195
|
</FormDropdownMenuItem>
|
|
192
196
|
))}
|
|
193
197
|
</FormDropdownMenu>
|
|
@@ -196,20 +200,22 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
196
200
|
<div className="mt-2 flex h-5 w-full items-center">
|
|
197
201
|
<div className="flex h-full w-32 flex-shrink-0 items-center text-sm">
|
|
198
202
|
Row Limit:
|
|
203
|
+
<FormDocumentation
|
|
204
|
+
className="ml-1"
|
|
205
|
+
documentationKey={
|
|
206
|
+
DocumentationKey.DATA_CUBE_GRID_CONFIGURATION_ROW_LIMIT
|
|
207
|
+
}
|
|
208
|
+
/>
|
|
199
209
|
</div>
|
|
200
210
|
<FormNumberInput
|
|
201
211
|
className="w-16 text-sm"
|
|
202
212
|
value={panel.limit}
|
|
203
|
-
min={
|
|
213
|
+
min={0}
|
|
204
214
|
step={1}
|
|
205
|
-
defaultValue={
|
|
206
|
-
|
|
207
|
-
setValue={(value) => panel.setLimit(value
|
|
215
|
+
defaultValue={undefined}
|
|
216
|
+
placeholder={EMPTY_VALUE_PLACEHOLDER}
|
|
217
|
+
setValue={(value) => panel.setLimit(value)}
|
|
208
218
|
/>
|
|
209
|
-
<div className="flex-shrink-0 pl-1 text-sm italic text-neutral-500">
|
|
210
|
-
Truncate result to this many rows at every level. Use -1 for
|
|
211
|
-
unlimited.
|
|
212
|
-
</div>
|
|
213
219
|
</div>
|
|
214
220
|
|
|
215
221
|
<div className="mt-2 flex h-5 w-full items-center">
|
|
@@ -264,9 +270,10 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
264
270
|
)
|
|
265
271
|
}
|
|
266
272
|
/>
|
|
267
|
-
<div className="ml-
|
|
273
|
+
<div className="ml-3 mr-1 flex h-full flex-shrink-0 items-center text-sm">
|
|
274
|
+
Color:
|
|
275
|
+
</div>
|
|
268
276
|
<FormColorPickerButton
|
|
269
|
-
className="ml-2"
|
|
270
277
|
color={configuration.gridLineColor}
|
|
271
278
|
defaultColor={DEFAULT_GRID_LINE_COLOR}
|
|
272
279
|
onChange={(value) => configuration.setGridLineColor(value)}
|
|
@@ -291,7 +298,6 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
291
298
|
/>
|
|
292
299
|
<FormCheckbox
|
|
293
300
|
className="ml-3"
|
|
294
|
-
label="Custom: Alternate color every"
|
|
295
301
|
checked={configuration.alternateRows}
|
|
296
302
|
onChange={() => {
|
|
297
303
|
if (configuration.alternateRows) {
|
|
@@ -302,8 +308,20 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
302
308
|
}
|
|
303
309
|
}}
|
|
304
310
|
/>
|
|
311
|
+
<div className="ml-1 mr-1 flex h-full flex-shrink-0 items-center text-sm">
|
|
312
|
+
Custom: Alternate color:
|
|
313
|
+
</div>
|
|
314
|
+
<FormColorPickerButton
|
|
315
|
+
disabled={!configuration.alternateRows}
|
|
316
|
+
color={configuration.alternateRowsColor}
|
|
317
|
+
defaultColor={DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR}
|
|
318
|
+
onChange={(value) => configuration.setAlternateRowsColor(value)}
|
|
319
|
+
/>
|
|
320
|
+
<div className="ml-1 flex h-full flex-shrink-0 items-center text-sm">
|
|
321
|
+
every:
|
|
322
|
+
</div>
|
|
305
323
|
<FormNumberInput
|
|
306
|
-
className="ml-1
|
|
324
|
+
className="ml-1 w-16 text-sm"
|
|
307
325
|
disabled={!configuration.alternateRows}
|
|
308
326
|
min={1}
|
|
309
327
|
step={1}
|
|
@@ -314,14 +332,7 @@ export const DataCubeEditorGeneralPropertiesPanel = observer(
|
|
|
314
332
|
configuration.setAlternateRowsCount(value ?? 1)
|
|
315
333
|
}
|
|
316
334
|
/>
|
|
317
|
-
<div className="ml-1
|
|
318
|
-
<FormColorPickerButton
|
|
319
|
-
className="ml-[5px]"
|
|
320
|
-
disabled={!configuration.alternateRows}
|
|
321
|
-
color={configuration.alternateRowsColor}
|
|
322
|
-
defaultColor={DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR}
|
|
323
|
-
onChange={(value) => configuration.setAlternateRowsColor(value)}
|
|
324
|
-
/>
|
|
335
|
+
<div className="ml-1 flex-shrink-0 text-sm">rows</div>
|
|
325
336
|
</div>
|
|
326
337
|
|
|
327
338
|
<div className="my-2 h-[1px] w-full bg-neutral-200" />
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
_primitiveValue,
|
|
47
47
|
_var,
|
|
48
48
|
_functionCompositionProcessor,
|
|
49
|
+
_extendRootAggregation,
|
|
49
50
|
} from './DataCubeQueryBuilderUtils.js';
|
|
50
51
|
import type { DataCubeQueryAggregateOperation } from './aggregation/DataCubeQueryAggregateOperation.js';
|
|
51
52
|
import type { DataCubeSource } from './models/DataCubeSource.js';
|
|
@@ -67,6 +68,11 @@ export function buildExecutableQuery(
|
|
|
67
68
|
filterOperations: DataCubeQueryFilterOperation[],
|
|
68
69
|
aggregateOperations: DataCubeQueryAggregateOperation[],
|
|
69
70
|
) => void;
|
|
71
|
+
rootAggregation?:
|
|
72
|
+
| {
|
|
73
|
+
columnName: string;
|
|
74
|
+
}
|
|
75
|
+
| undefined;
|
|
70
76
|
pagination?:
|
|
71
77
|
| {
|
|
72
78
|
start: number;
|
|
@@ -91,6 +97,8 @@ export function buildExecutableQuery(
|
|
|
91
97
|
_col(col.name, _deserializeLambda(col.mapFn)),
|
|
92
98
|
]),
|
|
93
99
|
);
|
|
100
|
+
// instead of batching all the extend() functions, we sequence them, and reference the first one
|
|
101
|
+
// in the function map
|
|
94
102
|
_process('leafExtend', guaranteeNonNullable(leafExtendedFuncs[0]));
|
|
95
103
|
leafExtendedFuncs.slice(1).forEach((func) => {
|
|
96
104
|
sequence.push(func);
|
|
@@ -163,6 +171,9 @@ export function buildExecutableQuery(
|
|
|
163
171
|
|
|
164
172
|
if (data.groupBy) {
|
|
165
173
|
const groupBy = data.groupBy;
|
|
174
|
+
if (configuration.showRootAggregation && options?.rootAggregation) {
|
|
175
|
+
sequence.push(_extendRootAggregation(options.rootAggregation.columnName));
|
|
176
|
+
}
|
|
166
177
|
_process(
|
|
167
178
|
'groupBy',
|
|
168
179
|
_function(DataCubeFunction.GROUP_BY, [
|
|
@@ -203,6 +214,8 @@ export function buildExecutableQuery(
|
|
|
203
214
|
_col(col.name, _deserializeLambda(col.mapFn)),
|
|
204
215
|
]),
|
|
205
216
|
);
|
|
217
|
+
// instead of batching all the extend() functions, we sequence them, and reference the first one
|
|
218
|
+
// in the function map
|
|
206
219
|
_process('groupExtend', guaranteeNonNullable(groupExtendedFuncs[0]));
|
|
207
220
|
groupExtendedFuncs.slice(1).forEach((func) => {
|
|
208
221
|
sequence.push(func);
|
|
@@ -49,6 +49,10 @@ import {
|
|
|
49
49
|
extractPackagePathFromPath,
|
|
50
50
|
CORE_PURE_PATH,
|
|
51
51
|
V1_GenericTypeInstance,
|
|
52
|
+
V1_createGenericTypeWithElementPath,
|
|
53
|
+
V1_createGenericTypeWithRawType,
|
|
54
|
+
V1_createRelationType,
|
|
55
|
+
V1_createRelationTypeColumn,
|
|
52
56
|
} from '@finos/legend-graph';
|
|
53
57
|
import {
|
|
54
58
|
type DataCubeQuerySnapshotFilterCondition,
|
|
@@ -75,6 +79,7 @@ import {
|
|
|
75
79
|
type DataCubeQueryFunctionMap,
|
|
76
80
|
isPivotResultColumnName,
|
|
77
81
|
getPivotResultColumnBaseColumnName,
|
|
82
|
+
DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE,
|
|
78
83
|
} from './DataCubeQueryEngine.js';
|
|
79
84
|
import type { DataCubeQueryFilterOperation } from './filter/DataCubeQueryFilterOperation.js';
|
|
80
85
|
import type { DataCubeQueryAggregateOperation } from './aggregation/DataCubeQueryAggregateOperation.js';
|
|
@@ -380,14 +385,18 @@ export function _pivotAggCols(
|
|
|
380
385
|
}
|
|
381
386
|
|
|
382
387
|
export function _castCols(columns: DataCubeColumn[]) {
|
|
383
|
-
const
|
|
384
|
-
genericType
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
+
const genericTypeInstance = new V1_GenericTypeInstance();
|
|
389
|
+
genericTypeInstance.genericType = V1_createGenericTypeWithElementPath(
|
|
390
|
+
CORE_PURE_PATH.RELATION,
|
|
391
|
+
);
|
|
392
|
+
genericTypeInstance.genericType.typeArguments = [
|
|
393
|
+
V1_createGenericTypeWithRawType(
|
|
394
|
+
V1_createRelationType(
|
|
395
|
+
columns.map((col) => V1_createRelationTypeColumn(col.name, col.type)),
|
|
396
|
+
),
|
|
388
397
|
),
|
|
389
398
|
];
|
|
390
|
-
return
|
|
399
|
+
return genericTypeInstance;
|
|
391
400
|
}
|
|
392
401
|
|
|
393
402
|
export function _groupByAggCols(
|
|
@@ -487,6 +496,23 @@ export function _groupByAggCols(
|
|
|
487
496
|
]);
|
|
488
497
|
}
|
|
489
498
|
|
|
499
|
+
export function _extendRootAggregation(columnName: string) {
|
|
500
|
+
return _function(DataCubeFunction.EXTEND, [
|
|
501
|
+
_col(
|
|
502
|
+
columnName,
|
|
503
|
+
_lambda(
|
|
504
|
+
[_var()],
|
|
505
|
+
[
|
|
506
|
+
_primitiveValue(
|
|
507
|
+
PRIMITIVE_TYPE.STRING,
|
|
508
|
+
DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE,
|
|
509
|
+
),
|
|
510
|
+
],
|
|
511
|
+
),
|
|
512
|
+
),
|
|
513
|
+
]);
|
|
514
|
+
}
|
|
515
|
+
|
|
490
516
|
export function _filter(
|
|
491
517
|
filter: DataCubeQuerySnapshotFilter | DataCubeQuerySnapshotFilterCondition,
|
|
492
518
|
filterOperations: DataCubeQueryFilterOperation[],
|
|
@@ -305,6 +305,7 @@ export const DEFAULT_REPORT_NAME = 'New Report';
|
|
|
305
305
|
export const DEFAULT_TREE_COLUMN_SORT_DIRECTION =
|
|
306
306
|
DataCubeQuerySortDirection.ASCENDING;
|
|
307
307
|
export const DEFAULT_PIVOT_STATISTIC_COLUMN_NAME = 'Total';
|
|
308
|
+
export const DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE = '[ROOT]';
|
|
308
309
|
|
|
309
310
|
export const DEFAULT_URL_LABEL_QUERY_PARAM = 'dataCube.linkLabel';
|
|
310
311
|
export const DEFAULT_MISSING_VALUE_DISPLAY_TEXT = '';
|
|
@@ -330,3 +331,10 @@ export const DEFAULT_ROW_BACKGROUND_COLOR = TailwindCSSPalette.white;
|
|
|
330
331
|
export const DEFAULT_NEGATIVE_FOREGROUND_COLOR = TailwindCSSPalette.red[500];
|
|
331
332
|
export const DEFAULT_ZERO_FOREGROUND_COLOR = TailwindCSSPalette.neutral[400];
|
|
332
333
|
export const DEFAULT_ERROR_FOREGROUND_COLOR = TailwindCSSPalette.blue[600];
|
|
334
|
+
|
|
335
|
+
// settings
|
|
336
|
+
export const TAB_SIZE = 2;
|
|
337
|
+
export const DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
|
|
338
|
+
export const TYPEAHEAD_SEARCH_MINIMUM_SEARCH_LENGTH = 3;
|
|
339
|
+
export const TYPEAHEAD_SEARCH_LIMIT = 10;
|
|
340
|
+
export const EMPTY_VALUE_PLACEHOLDER = '(None)';
|
|
@@ -63,6 +63,7 @@ export class DataCubeColumnConfiguration {
|
|
|
63
63
|
negativeNumberInParens = false;
|
|
64
64
|
numberScale?: DataCubeNumberScale | undefined;
|
|
65
65
|
missingValueDisplayText?: string | undefined;
|
|
66
|
+
unit?: string | undefined;
|
|
66
67
|
|
|
67
68
|
fontFamily?: DataCubeFont | undefined;
|
|
68
69
|
fontSize?: number | undefined;
|
|
@@ -154,6 +155,7 @@ export class DataCubeColumnConfiguration {
|
|
|
154
155
|
pivotStatisticColumnFunction: optional(primitive()),
|
|
155
156
|
textAlign: optional(primitive()),
|
|
156
157
|
type: primitive(),
|
|
158
|
+
unit: optional(primitive()),
|
|
157
159
|
zeroBackgroundColor: optional(primitive()),
|
|
158
160
|
zeroForegroundColor: optional(primitive()),
|
|
159
161
|
}),
|
|
@@ -28,7 +28,7 @@ export class DataCubeEditorGeneralPropertiesPanelState
|
|
|
28
28
|
readonly view!: DataCubeViewState;
|
|
29
29
|
readonly editor!: DataCubeEditorState;
|
|
30
30
|
|
|
31
|
-
limit =
|
|
31
|
+
limit: number | undefined = undefined;
|
|
32
32
|
configuration = new DataCubeEditorMutableConfiguration();
|
|
33
33
|
|
|
34
34
|
constructor(editor: DataCubeEditorState) {
|
|
@@ -45,7 +45,7 @@ export class DataCubeEditorGeneralPropertiesPanelState
|
|
|
45
45
|
this.view = editor.view;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
setLimit(val: number) {
|
|
48
|
+
setLimit(val: number | undefined): void {
|
|
49
49
|
this.limit = val;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -56,7 +56,7 @@ export class DataCubeEditorGeneralPropertiesPanelState
|
|
|
56
56
|
this.setLimit(
|
|
57
57
|
snapshot.data.limit !== undefined && snapshot.data.limit >= 0
|
|
58
58
|
? snapshot.data.limit
|
|
59
|
-
:
|
|
59
|
+
: undefined,
|
|
60
60
|
);
|
|
61
61
|
this.configuration = DataCubeEditorMutableConfiguration.create(
|
|
62
62
|
snapshot.data.configuration,
|
|
@@ -68,7 +68,8 @@ export class DataCubeEditorGeneralPropertiesPanelState
|
|
|
68
68
|
baseSnapshot: DataCubeQuerySnapshot,
|
|
69
69
|
) {
|
|
70
70
|
const data = newSnapshot.data;
|
|
71
|
-
data.limit =
|
|
71
|
+
data.limit =
|
|
72
|
+
this.limit === undefined || this.limit < 0 ? undefined : this.limit;
|
|
72
73
|
data.configuration = this.configuration.serialize();
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -96,6 +96,9 @@ export class DataCubeEditorMutableColumnConfiguration extends DataCubeColumnConf
|
|
|
96
96
|
missingValueDisplayText: observable,
|
|
97
97
|
setMissingValueDisplayText: action,
|
|
98
98
|
|
|
99
|
+
unit: observable,
|
|
100
|
+
setUnit: action,
|
|
101
|
+
|
|
99
102
|
fontFamily: observable,
|
|
100
103
|
setFontFamily: action,
|
|
101
104
|
|
|
@@ -273,6 +276,10 @@ export class DataCubeEditorMutableColumnConfiguration extends DataCubeColumnConf
|
|
|
273
276
|
this.missingValueDisplayText = value;
|
|
274
277
|
}
|
|
275
278
|
|
|
279
|
+
setUnit(value: string | undefined) {
|
|
280
|
+
this.unit = value;
|
|
281
|
+
}
|
|
282
|
+
|
|
276
283
|
setFontFamily(value: DataCubeFont | undefined) {
|
|
277
284
|
this.fontFamily = value;
|
|
278
285
|
}
|
|
@@ -32,7 +32,6 @@ import {
|
|
|
32
32
|
} from '@finos/legend-shared';
|
|
33
33
|
import { buildExecutableQuery } from '../../core/DataCubeQueryBuilder.js';
|
|
34
34
|
import { type TabularDataSet, V1_Lambda } from '@finos/legend-graph';
|
|
35
|
-
import { generateRowGroupingDrilldownExecutableQueryPostProcessor } from './DataCubeGridQueryBuilder.js';
|
|
36
35
|
import { makeObservable, observable, runInAction } from 'mobx';
|
|
37
36
|
import type {
|
|
38
37
|
DataCubeConfiguration,
|
|
@@ -49,10 +48,15 @@ import { buildQuerySnapshot } from './DataCubeGridQuerySnapshotBuilder.js';
|
|
|
49
48
|
import { AlertType } from '../../../components/core/DataCubeAlert.js';
|
|
50
49
|
import { sum } from 'mathjs';
|
|
51
50
|
import type { DataCubeViewState } from '../DataCubeViewState.js';
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
import {
|
|
52
|
+
_aggCountCol,
|
|
53
|
+
buildGridDataFetchExecutableQuery,
|
|
54
|
+
} from './DataCubeGridQueryBuilder.js';
|
|
55
|
+
import { _colSpecArrayParam } from '../../core/DataCubeQuerySnapshotBuilderUtils.js';
|
|
56
|
+
|
|
57
|
+
type DataCubeGridClientCellValue = string | number | boolean | null | undefined;
|
|
58
|
+
type DataCubeGridClientRowData = {
|
|
59
|
+
[key: string]: DataCubeGridClientCellValue;
|
|
56
60
|
};
|
|
57
61
|
|
|
58
62
|
export enum DataCubeGridClientExportFormat {
|
|
@@ -128,17 +132,19 @@ export const INTERNAL__GRID_CLIENT_TOOLTIP_SHOW_DELAY = 1500;
|
|
|
128
132
|
export const INTERNAL__GRID_CLIENT_AUTO_RESIZE_PADDING = 10;
|
|
129
133
|
export const INTERNAL__GRID_CLIENT_MISSING_VALUE = '__MISSING';
|
|
130
134
|
export const INTERNAL__GRID_CLIENT_TREE_COLUMN_ID = 'ag-Grid-AutoColumn';
|
|
135
|
+
export const INTERNAL__GRID_CLIENT_ROOT_AGGREGATION_COLUMN_ID =
|
|
136
|
+
'INTERNAL__rootAggregation';
|
|
131
137
|
export const INTERNAL__GRID_CLIENT_DATA_FETCH_MANUAL_TRIGGER_COLUMN_ID =
|
|
132
138
|
'INTERNAL__dataFetchManualTrigger';
|
|
133
139
|
export const INTERNAL__GRID_CLIENT_ROW_GROUPING_COUNT_AGG_COLUMN_ID =
|
|
134
140
|
'INTERNAL__count';
|
|
135
141
|
|
|
136
|
-
export enum
|
|
142
|
+
export enum DataCubeGridClientPinnedAlignement {
|
|
137
143
|
LEFT = 'left',
|
|
138
144
|
RIGHT = 'right',
|
|
139
145
|
}
|
|
140
146
|
|
|
141
|
-
export enum
|
|
147
|
+
export enum DataCubeGridClientSortDirection {
|
|
142
148
|
ASCENDING = 'asc',
|
|
143
149
|
DESCENDING = 'desc',
|
|
144
150
|
}
|
|
@@ -209,9 +215,9 @@ export function computeHashCodeForDataFetchManualTrigger(
|
|
|
209
215
|
function buildRowData(
|
|
210
216
|
result: TabularDataSet,
|
|
211
217
|
snapshot: DataCubeQuerySnapshot,
|
|
212
|
-
):
|
|
218
|
+
): DataCubeGridClientRowData[] {
|
|
213
219
|
return result.rows.map((_row, rowIdx) => {
|
|
214
|
-
const row:
|
|
220
|
+
const row: DataCubeGridClientRowData = {};
|
|
215
221
|
const cols = result.columns;
|
|
216
222
|
_row.values.forEach((value, colIdx) => {
|
|
217
223
|
// `ag-grid` shows `false` value as empty string so we have
|
|
@@ -281,6 +287,12 @@ async function getCastColumns(
|
|
|
281
287
|
if (funcMap.groupExtend) {
|
|
282
288
|
_unprocess('groupExtend');
|
|
283
289
|
}
|
|
290
|
+
|
|
291
|
+
// when both pivot and groupBy present, we need to account for the count column
|
|
292
|
+
// in the cast expression
|
|
293
|
+
if (funcMap.pivot && currentSnapshot.data.groupBy) {
|
|
294
|
+
_colSpecArrayParam(funcMap.pivot, 1).colSpecs.push(_aggCountCol());
|
|
295
|
+
}
|
|
284
296
|
},
|
|
285
297
|
},
|
|
286
298
|
);
|
|
@@ -299,6 +311,18 @@ async function getCastColumns(
|
|
|
299
311
|
}));
|
|
300
312
|
}
|
|
301
313
|
|
|
314
|
+
export type DataCubeGridClientDataFetchRequest = {
|
|
315
|
+
startRow: number | undefined;
|
|
316
|
+
endRow: number | undefined;
|
|
317
|
+
rowGroupColumns: string[];
|
|
318
|
+
groupKeys: (string | null | undefined)[]; // NOTE: it's possible for these values to be nullish depending on row data
|
|
319
|
+
pivotColumns: string[];
|
|
320
|
+
sortColumns: {
|
|
321
|
+
name: string;
|
|
322
|
+
direction: DataCubeGridClientSortDirection;
|
|
323
|
+
}[];
|
|
324
|
+
};
|
|
325
|
+
|
|
302
326
|
export class DataCubeGridClientServerSideDataSource
|
|
303
327
|
implements IServerSideDatasource
|
|
304
328
|
{
|
|
@@ -316,39 +340,34 @@ export class DataCubeGridClientServerSideDataSource
|
|
|
316
340
|
async fetchRows(params: IServerSideGetRowsParams<unknown, unknown>) {
|
|
317
341
|
const task = this.grid.view.newTask('Fetching data');
|
|
318
342
|
|
|
319
|
-
// ------------------------------ GRID OPTIONS ------------------------------
|
|
320
|
-
// Here, we make adjustments to the grid display in response to the new
|
|
321
|
-
// request, in case the grid action has not impacted the layout in an
|
|
322
|
-
// adequate way.
|
|
323
|
-
|
|
324
|
-
// Toggle the visibility of the tree column based on the presence of row-group columns
|
|
325
|
-
if (params.request.rowGroupCols.length) {
|
|
326
|
-
params.api.setColumnsVisible(
|
|
327
|
-
[INTERNAL__GRID_CLIENT_TREE_COLUMN_ID],
|
|
328
|
-
true,
|
|
329
|
-
);
|
|
330
|
-
} else {
|
|
331
|
-
params.api.setColumnsVisible(
|
|
332
|
-
[INTERNAL__GRID_CLIENT_TREE_COLUMN_ID],
|
|
333
|
-
false,
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
343
|
// ------------------------------ SNAPSHOT ------------------------------
|
|
338
344
|
|
|
339
345
|
const currentSnapshot = guaranteeNonNullable(this.grid.getLatestSnapshot());
|
|
346
|
+
const request: DataCubeGridClientDataFetchRequest = {
|
|
347
|
+
startRow: params.request.startRow,
|
|
348
|
+
endRow: params.request.endRow,
|
|
349
|
+
rowGroupColumns: params.request.rowGroupCols.map((col) => col.id),
|
|
350
|
+
groupKeys: params.request.groupKeys.map((key) => key),
|
|
351
|
+
pivotColumns: params.request.pivotCols.map((col) => col.id),
|
|
352
|
+
sortColumns: params.request.sortModel.map((item) => ({
|
|
353
|
+
name: item.colId,
|
|
354
|
+
direction: item.sort as DataCubeGridClientSortDirection,
|
|
355
|
+
})),
|
|
356
|
+
};
|
|
357
|
+
const isTopLevelRequest = request.groupKeys.length === 0;
|
|
358
|
+
|
|
340
359
|
let newSnapshot = currentSnapshot;
|
|
341
360
|
|
|
342
361
|
// only recompute the snapshot if this is not a drilldown request
|
|
343
|
-
if (
|
|
344
|
-
newSnapshot = buildQuerySnapshot(
|
|
362
|
+
if (isTopLevelRequest) {
|
|
363
|
+
newSnapshot = buildQuerySnapshot(request, currentSnapshot);
|
|
345
364
|
|
|
346
365
|
// NOTE: if h-pivot is enabled, update the cast columns
|
|
347
366
|
// and panels which might be affected by this (e.g. sorts)
|
|
348
367
|
// Because is an expensive operation in certain case, we only
|
|
349
368
|
// recompute when it's not a drilldown or paging request,
|
|
350
369
|
// but we could still optimize further if needed.
|
|
351
|
-
if (!this.grid.isPaginationEnabled ||
|
|
370
|
+
if (!this.grid.isPaginationEnabled || request.startRow === 0) {
|
|
352
371
|
if (newSnapshot.data.pivot) {
|
|
353
372
|
try {
|
|
354
373
|
const castColumns = await getCastColumns(
|
|
@@ -390,27 +409,14 @@ export class DataCubeGridClientServerSideDataSource
|
|
|
390
409
|
// ------------------------------ DATA ------------------------------
|
|
391
410
|
|
|
392
411
|
try {
|
|
393
|
-
const executableQuery =
|
|
412
|
+
const executableQuery = buildGridDataFetchExecutableQuery(
|
|
413
|
+
request,
|
|
394
414
|
newSnapshot,
|
|
395
415
|
this.grid.view.source,
|
|
396
416
|
(source) => this.grid.view.engine.buildExecutionContext(source),
|
|
397
417
|
this.grid.view.engine.filterOperations,
|
|
398
418
|
this.grid.view.engine.aggregateOperations,
|
|
399
|
-
|
|
400
|
-
postProcessor:
|
|
401
|
-
generateRowGroupingDrilldownExecutableQueryPostProcessor(
|
|
402
|
-
params.request.groupKeys,
|
|
403
|
-
),
|
|
404
|
-
pagination:
|
|
405
|
-
this.grid.isPaginationEnabled &&
|
|
406
|
-
params.request.startRow !== undefined &&
|
|
407
|
-
params.request.endRow !== undefined
|
|
408
|
-
? {
|
|
409
|
-
start: params.request.startRow,
|
|
410
|
-
end: params.request.endRow,
|
|
411
|
-
}
|
|
412
|
-
: undefined,
|
|
413
|
-
},
|
|
419
|
+
this.grid.isPaginationEnabled,
|
|
414
420
|
);
|
|
415
421
|
const lambda = new V1_Lambda();
|
|
416
422
|
lambda.body.push(executableQuery);
|
|
@@ -436,16 +442,16 @@ export class DataCubeGridClientServerSideDataSource
|
|
|
436
442
|
if (this.grid.isPaginationEnabled) {
|
|
437
443
|
params.success({ rowData });
|
|
438
444
|
// only update row count when loading the top-level drilldown data
|
|
439
|
-
if (
|
|
445
|
+
if (isTopLevelRequest) {
|
|
440
446
|
runInAction(() => {
|
|
441
|
-
this.rowCount = (
|
|
447
|
+
this.rowCount = (request.startRow ?? 0) + rowData.length;
|
|
442
448
|
});
|
|
443
449
|
}
|
|
444
450
|
|
|
445
451
|
// toggle no-rows overlay
|
|
446
452
|
if (
|
|
447
|
-
|
|
448
|
-
|
|
453
|
+
isTopLevelRequest &&
|
|
454
|
+
request.startRow === 0 &&
|
|
449
455
|
rowData.length === 0
|
|
450
456
|
) {
|
|
451
457
|
this.grid.client.showNoRowsOverlay();
|
|
@@ -506,19 +512,28 @@ export class DataCubeGridClientServerSideDataSource
|
|
|
506
512
|
});
|
|
507
513
|
|
|
508
514
|
// only update row count when loading the top-level drilldown data
|
|
509
|
-
if (
|
|
515
|
+
if (isTopLevelRequest) {
|
|
510
516
|
runInAction(() => {
|
|
511
517
|
this.rowCount = rowData.length;
|
|
512
518
|
});
|
|
513
519
|
}
|
|
514
520
|
|
|
515
521
|
// toggle no-rows overlay
|
|
516
|
-
if (
|
|
522
|
+
if (isTopLevelRequest && rowData.length === 0) {
|
|
517
523
|
this.grid.client.showNoRowsOverlay();
|
|
518
524
|
} else {
|
|
519
525
|
this.grid.client.hideOverlay();
|
|
520
526
|
}
|
|
521
527
|
}
|
|
528
|
+
|
|
529
|
+
// Resize columns to fit content on all actions (drilldown, changing queries, fetching new page, etc.)
|
|
530
|
+
// NOTE: we might want to restrict this to only happen on certain actions
|
|
531
|
+
//
|
|
532
|
+
// `setTimeout()` is need to ensure this runs after the grid has been updated with the new data
|
|
533
|
+
// since ag-grid does not provide an event hook for this action for server-side row model.
|
|
534
|
+
setTimeout(() => {
|
|
535
|
+
this.grid.client.autoSizeAllColumns();
|
|
536
|
+
}, 0);
|
|
522
537
|
} catch (error) {
|
|
523
538
|
assertErrorThrown(error);
|
|
524
539
|
this.grid.view.engine.alertError(error, {
|